Skip to content

Commit

Permalink
add bunch of k8s related signatures (#1031)
Browse files Browse the repository at this point in the history
add bunch of k8s related signatures
  • Loading branch information
roikol committed Oct 6, 2021
1 parent c8b18f5 commit fccbca3
Show file tree
Hide file tree
Showing 14 changed files with 612 additions and 0 deletions.
1 change: 1 addition & 0 deletions tracee-rules/signatures/golang/export.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ import "github.com/aquasecurity/tracee/tracee-rules/types"
// this is a list of signatures that this plugin exports
var ExportedSignatures []types.Signature = []types.Signature{
&stdioOverSocket{},
&K8sApiConnection{},
}
134 changes: 134 additions & 0 deletions tracee-rules/signatures/golang/kubernetes_api_connection.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package main

import (
"fmt"
"strings"

tracee "github.com/aquasecurity/tracee/tracee-ebpf/external"
"github.com/aquasecurity/tracee/tracee-rules/signatures/helpers"
"github.com/aquasecurity/tracee/tracee-rules/types"
)

type K8sApiConnection struct {
cb types.SignatureHandler
apiAddressContainerId map[string]string
}

func (sig *K8sApiConnection) Init(cb types.SignatureHandler) error {
sig.cb = cb
sig.apiAddressContainerId = make(map[string]string)

return nil
}

func (sig *K8sApiConnection) GetMetadata() (types.SignatureMetadata, error) {
return types.SignatureMetadata{
ID: "TRC-13",
Version: "0.1.0",
Name: "Kubernetes API server connection detected",
Description: "A connection to the kubernetes API server was detected. The K8S API server is the brain of your K8S cluster, adversaries may try and communicate with the K8S API server to gather information/credentials, or even run more containers and laterally expand their grip on your systems.",
Tags: []string{"container"},
Properties: map[string]interface{}{
"Severity": 1,
"MITRE ATT&CK": "Discovery: Cloud Service Discovery",
},
}, nil
}

func (sig *K8sApiConnection) GetSelectedEvents() ([]types.SignatureEventSelector, error) {
return []types.SignatureEventSelector{
{Source: "tracee", Name: "execve", Origin: "container"},
{Source: "tracee", Name: "security_socket_connect", Origin: "container"},
}, nil
}

func (sig *K8sApiConnection) OnEvent(e types.Event) error {
eventObj, ok := e.(tracee.Event)
if !ok {
return fmt.Errorf("invalid event")
}

containerID := eventObj.ContainerID
if containerID == "" {
return nil
}

switch eventObj.EventName {

case "execve":
// the usage of 'envp' argument of the execve event is vulnerable to TOCTOU attack.
// in the future we plan to add 'envp' argument to sched_process_exec, and when it'll happen, we should start
// using sched_process_exec instead of execve in this signature.
envpArg, err := helpers.GetTraceeArgumentByName(eventObj, "envp")
if err != nil {
return nil
}
envs := envpArg.Value.([]string)

apiIPAddress := getApiAddressFromEnvs(envs)
if apiIPAddress != "" {
sig.apiAddressContainerId[containerID] = apiIPAddress
}

case "security_socket_connect":

apiAddress, exists := sig.apiAddressContainerId[containerID]
if !exists {
return nil
}

remoteAddrArg, err := helpers.GetTraceeArgumentByName(eventObj, "remote_addr")
if err != nil {
return err
}
ip, err := getIPFromAddr(remoteAddrArg)
if err != nil || ip == "" {
return err
}

if ip == apiAddress {
m, _ := sig.GetMetadata()
sig.cb(types.Finding{
SigMetadata: m,
Context: eventObj,
Data: map[string]interface{}{
"ip": apiAddress,
},
})
}
}
return nil
}

func (sig *K8sApiConnection) OnSignal(s types.Signal) error {
return nil
}

func (sig *K8sApiConnection) Close() {}

func getApiAddressFromEnvs(envs []string) string {
for _, env := range envs {
if strings.Contains(env, "KUBERNETES_SERVICE_HOST=") {
i := strings.Index(env, "=")
return strings.TrimSpace(env[i+1:])
}
}
return ""
}

func getIPFromAddr(addrArg tracee.Argument) (string, error) {
var connectData helpers.ConnectAddrData

err := helpers.GetAddrStructFromArg(addrArg, &connectData)
if err != nil {
return "", err
}

if connectData.SaFamily == "AF_INET" {
return connectData.SinAddr, nil
} else if connectData.SaFamily == "AF_INET6" {
return connectData.SinAddr6, nil
}

return "", nil
}
99 changes: 99 additions & 0 deletions tracee-rules/signatures/golang/kubernetes_api_connection_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package main

import (
tracee "github.com/aquasecurity/tracee/tracee-ebpf/external"
"testing"

"github.com/aquasecurity/tracee/tracee-rules/signatures/signaturestest"
"github.com/aquasecurity/tracee/tracee-rules/types"
)

func TestK8sApiConnection(t *testing.T) {
SigTests := []signaturestest.SigTest{
{
Events: []types.Event{
tracee.Event{
EventName: "execve",
ContainerID: "0907ef86d7be",
Args: []tracee.Argument{
{
ArgMeta: tracee.ArgMeta{
Name: "argv",
},
Value: []string{"/bin/ls"},
},
{
ArgMeta: tracee.ArgMeta{
Name: "envp",
},
Value: []string{"CURL_CA_BUNDLE=/cacert.pem", "HOSTNAME=3c5f9dbcb5da", "CURL_RELEASE_TAG=curl-7_76_1", "CURL_GIT_REPO=https://github.com/curl/curl.git", "SHLVL=2", "HOME=/home/curl_user", "TERM=xterm", "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "PWD=/", "KUBERNETES_SERVICE_HOST=1.1.1.1", "CURL_VERSION=7_76_1"},
},
},
},
tracee.Event{
EventName: "security_socket_connect",
ContainerID: "0907ef86d7be",
Args: []tracee.Argument{
{
ArgMeta: tracee.ArgMeta{
Name: "remote_addr",
},
Value: "{'sa_family': 'AF_INET','sin_port': '80','sin_addr': '1.1.1.1'}",
},
},
},
},
Expect: true,
},
{
Events: []types.Event{
tracee.Event{
EventName: "execve",
ContainerID: "0907ef86d7be",
Args: []tracee.Argument{
{
ArgMeta: tracee.ArgMeta{
Name: "argv",
},
Value: []string{"/bin/ls"},
},
{
ArgMeta: tracee.ArgMeta{
Name: "envp",
},
Value: []string{"CURL_CA_BUNDLE=/cacert.pem", "HOSTNAME=3c5f9dbcb5da", "CURL_RELEASE_TAG=curl-7_76_1", "CURL_GIT_REPO=https://github.com/curl/curl.git", "SHLVL=2", "HOME=/home/curl_user", "TERM=xterm", "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "PWD=/", "KUBERNETES_SERVICE_HOST=1.1.1.1", "CURL_VERSION=7_76_1"},
},
},
},
tracee.Event{
EventName: "security_socket_connect",
ContainerID: "0907ef86d7be",
Args: []tracee.Argument{
{
ArgMeta: tracee.ArgMeta{
Name: "remote_addr",
},
Value: "{'sa_family': 'AF_INET','sin_port': '80','sin_addr': '169.254.169.254'}",
},
},
},
},
Expect: false,
},
}

for _, st := range SigTests {
sig := K8sApiConnection{}
st.Init(&sig)
for _, e := range st.Events {
err := sig.OnEvent(e)
if err != nil {
t.Error(err, st)
}
}

if st.Expect != st.Status {
t.Error("Unexpected result", st)
}
}
}
37 changes: 37 additions & 0 deletions tracee-rules/signatures/rego/disk_mount.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package tracee.TRC_11

import data.tracee.helpers

__rego_metadoc__ := {
"id": "TRC-11",
"version": "0.1.0",
"name": "Container Host Mount Detected",
"description": "Container root host filesystem mount detected. A mount to the host filesystem can be exploited by adversaries to perform container escape.",
"tags": ["container"],
"properties": {
"Severity": 3,
"MITRE ATT&CK": "Privilege Escalation: Escape to Host"
}
}

eventSelectors := [
{
"source": "tracee",
"name": "security_sb_mount",
"origin": "container"
}
]

tracee_selected_events[eventSelector] {
eventSelector := eventSelectors[_]
}

tracee_match = res {

input.eventName == "security_sb_mount"

devname := helpers.get_tracee_argument("dev_name")
regex.match(`/dev/sd\w\d+`, devname)

res := {"mounted device": devname}
}
31 changes: 31 additions & 0 deletions tracee-rules/signatures/rego/disk_mount_test.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package tracee.TRC_11

test_match_1 {
tracee_match with input as {
"eventName": "security_sb_mount",
"argsNum": 1,
"args": [
{
"name": "dev_name",
"type": "const char*",
"value": "/dev/sda3"
}
]
}
}


test_match_wrong_request {
not tracee_match with input as {
"eventName": "security_sb_mount",
"argsNum": 1,
"args": [
{
"name": "dev_name",
"type": "const char*",
"value": "/dev/sd3"
}
]
}
}

38 changes: 38 additions & 0 deletions tracee-rules/signatures/rego/dropped_executable.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package tracee.TRC_9

import data.tracee.helpers

__rego_metadoc__ := {
"id": "TRC-9",
"version": "0.1.0",
"name": "New Executable Was Dropped During Runtime",
"description": "An Executable file was dropped in your system during runtime. Usually container images are built with all binaries needed inside, a dropped binary may indicate an adversary infiltrated into your container.",
"tags": ["linux", "container"],
"properties": {
"Severity": 2,
"MITRE ATT&CK": "Defense Evasion: Masquerading"
}
}

eventSelectors := [
{
"source": "tracee",
"name": "magic_write",
"origin": "container"
}
]

tracee_selected_events[eventSelector] {
eventSelector := eventSelectors[_]
}

tracee_match = res {

input.eventName == "magic_write"

file_header := helpers.get_tracee_argument("bytes")
helpers.is_elf_file(file_header)

pathname := helpers.get_tracee_argument("pathname")
res := {"file path": pathname}
}
29 changes: 29 additions & 0 deletions tracee-rules/signatures/rego/dropped_executable_test.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package tracee.TRC_9

test_match_1 {
tracee_match == {"file path": "new_file"} with input as {
"eventName": "magic_write",
"args": [
{
"name": "bytes",
"value": "f0VMRgIBAQAAAAAAAAAAAA=="
},
{
"name": "pathname",
"value": "new_file"
}
]
}
}

test_match_wrong_request {
not tracee_match with input as {
"eventName": "magic_write",
"args": [
{
"name": "bytes",
"value": "fMMVMRgIBAQAAAAAAAAAAAA=="
}
]
}
}

0 comments on commit fccbca3

Please sign in to comment.