-
Notifications
You must be signed in to change notification settings - Fork 390
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add bunch of k8s related signatures (#1031)
add bunch of k8s related signatures
- Loading branch information
Showing
14 changed files
with
612 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
134 changes: 134 additions & 0 deletions
134
tracee-rules/signatures/golang/kubernetes_api_connection.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
99
tracee-rules/signatures/golang/kubernetes_api_connection_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" | ||
} | ||
] | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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==" | ||
} | ||
] | ||
} | ||
} |
Oops, something went wrong.