Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

policylibrary: add a catch all for setuid root and suid execution #1706

Merged
merged 3 commits into from
Nov 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 98 additions & 0 deletions docs/content/en/docs/policy-library/observability/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ description: >

- [Binary Execution in /tmp]({{< ref "#tmp-execs" >}})
- [sudo Monitoring]({{< ref "#sudo" >}})
- [SUID Binary Execution]({{< ref "#suid" >}})
- [Setuid system calls]({{< ref "#setuid" >}})

### Networking

Expand Down Expand Up @@ -160,6 +162,102 @@ jq 'select(.process_exec != null) | select(.process_exec.process.binary | contai
"2023-10-31T19:03:35.273111185Z null /usr/bin/sudo -i"
```

## SUID Binary Execution {#suid}

### Description

Monitor execution of SUID "Set User ID" binaries.

### Use Case

The "Set User Identity" and "Set Group Identity" are permission flags. When set on a binary file, the binary will execute with the permissions
of the owner or group associated with the executable file, rather than the user executing it. Usually it is used to run programs with elevated privileges to perform specific tasks.

Detecting the execution of `setuid` and `setgid` binaries is a common
best-practice as attackers may abuse such binaries, or even create them
during an exploit for subsequent execution.

### Requirement

Run Tetragon with `enable-process-creds` setting set to enable visibility
into [process_credentials]({{< ref "/docs/reference/grpc-api#processcredentials" >}}) and [binary_properties]({{< ref "/docs/reference/grpc-api#binaryproperties" >}}).

{{< tabpane lang=shell-session >}}

{{< tab Kubernetes >}}
kubectl edit cm -n kube-system tetragon-config
# Change "enable-process-cred" from "false" to "true", then save and exit
# Restart Tetragon daemonset
kubectl rollout restart -n kube-system ds/tetragon
{{< /tab >}}
{{< tab docker >}}
docker run --name tetragon --rm -d \
--pid=host --cgroupns=host --privileged \
-v /sys/kernel:/sys/kernel \
-v /var/log/tetragon:/var/log/tetragon \
quay.io/cilium/tetragon:{{< latest-version >}} \
/usr/bin/tetragon --enable-process-cred \
--export-filename /var/log/tetragon/tetragon.log
{{< /tab >}}
{{< tab systemd >}}
# Write to the drop-in file /etc/tetragon/tetragon.conf.d/enable-process-cred true
# Run the following as a privileged user then restart tetragon service
echo "true" > /etc/tetragon/tetragon.conf.d/enable-process-cred
systemctl restart tetragon
{{< /tab >}}
{{< /tabpane >}}

### Policy

No policy needs to be loaded, standard process execution observability is sufficient.

### Example jq Filter

```shell-session
jq 'select(.process_exec != null) | select(.process_exec.process.binary_properties != null) | select(.process_exec.process.binary_properties.setuid != null or .process_exec.process.binary_properties.setgid != null) | "\(.time) \(.process_exec.process.pod.namespace) \(.process_exec.process.pod.name) \(.process_exec.process.binary) \(.process_exec.process.arguments) uid=\(.process_exec.process.process_credentials.uid) euid=\(.process_exec.process.process_credentials.euid) gid=\(.process_exec.process.process_credentials.gid) egid=\(.process_exec.process.process_credentials.egid)"'
```

### Example Output

```shell-session
"2023-11-13T08:20:43.615672640Z null null /usr/bin/sudo id uid=1000 euid=0 gid=1000 egid=1000"
"2023-11-13T08:20:45.591560940Z null null /usr/bin/wall hello uid=1000 euid=1000 gid=1000 egid=5"
"2023-11-13T08:20:47.036760043Z null null /usr/bin/su - uid=1000 euid=0 gid=1000 egid=1000"
```

## Setuid System Calls {#setuid}

### Description

Monitor execution of the [setuid()](https://www.man7.org/linux/man-pages/man2/setuid.2.html) system calls family.

### Use Case

The [setuid()](https://www.man7.org/linux/man-pages/man2/setuid.2.html) and [setgid()](https://www.man7.org/linux/man-pages/man2/setgid.2.html)
system calls family allow to change the effective user ID and group ID of the calling process.

Detecting [setuid()](https://www.man7.org/linux/man-pages/man2/setuid.2.html) and [setgid()](https://www.man7.org/linux/man-pages/man2/setgid.2.html) calls that set the user ID or group ID to root is a common
best-practice to identify when privileges are raised.

### Policy

The [privileges-setuid-root.yaml](https://raw.githubusercontent.com/cilium/tetragon/main/examples/policylibrary/privileges/privileges-setuid-root.yaml) is a catch all to the various interfaces of `setuid()` and `setgid()` to root.

### Example jq Filter

```shell-session
jq 'select(.process_kprobe != null) | select(.process_kprobe.policy_name | test("privileges-setuid-root")) | "\(.time) \(.process_kprobe.process.pod.namespace) \(.process_kprobe.process.pod.name) \(.process_kprobe.process.binary) \(.process_kprobe.process.arguments) \(.process_kprobe.function_name) \(.process_kprobe.args)"'
```

### Example Output

```shell-session
"2023-11-12T22:17:40.754680857Z null null /usr/bin/sudo id __sys_setresgid [{\"int_arg\":-1},{\"int_arg\":0},{\"int_arg\":-1}]"
"2023-11-12T22:17:40.754730285Z null null /usr/bin/sudo id __sys_setresuid [{\"int_arg\":-1},{\"int_arg\":0},{\"int_arg\":-1}]"
"2023-11-12T22:17:40.758125709Z null null /usr/bin/sudo id __sys_setgid [{\"int_arg\":0}]"
"2023-11-12T22:17:40.758747395Z null null /usr/bin/sudo id __sys_setresuid [{\"int_arg\":0},{\"int_arg\":0},{\"int_arg\":0}]"
```

## SSHd connection monitoring {#ssh-network}

### Description
Expand Down
246 changes: 246 additions & 0 deletions examples/policylibrary/privileges/privileges-setuid-root.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,246 @@
# This 'privileges-setuid-root' Tracing Policy monitors processes trying
# to change their uids/gids to user root.
#
# __sys_setuid
# - __x64_sys_setuid
# - __ia32_sys_setuid
# - __x64_sys_setuid16
# - __ia32_sys_setuid16
#
# __sys_setgid
# - __x64_sys_setgid
# - __ia32_sys_setgid
# - __x64_sys_setgid16
# - __ia32_sys_setgid16
#
# __sys_setreuid
# - __x64_sys_setreuid
# - __ia32_sys_setreuid
# - __x64_sys_setreuid16
# - __ia32_sys_setreuid16
#
# __sys_setregid
# - __x64_sys_setregid
# - __ia32_sys_setregid
# - __x64_sys_setregid16
# - __ia32_sys_setregid16
#
# __sys_setresuid
# - __x64_sys_setresuid
# - __ia32_sys_setresuid
# - __x64_sys_setresuid16
# - __ia32_sys_setresuid16
#
# __sys_setresgid
# - __x64_sys_setresgid
# - __ia32_sys_setresgid
# - __x64_sys_setresgid16
# - __ia32_sys_setresgid16
#
# __sys_setfsuid
# - __x64_sys_setfsuid
# - __ia32_sys_setfsuid
# - __x64_sys_setfsuid16
# - __ia32_sys_setfsuid16
#
# __sys_setfsgid
# - __x64_sys_setfsgid
# - __ia32_sys_setfsgid
# - __x64_sys_setfsgid16
# - __ia32_sys_setfsgid16
#
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we miss seteuid/setegid ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The seteuid/setegid are usually library that call syscall setreuid and setregid which is handled

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm, but it's still separate syscall right? should we cover any possible way? I might misunderstood the purpose of that spec though

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Jiri so the seteuid/setegid are wrappers https://www.man7.org/linux/man-pages/man2/seteuid.2.html check c library, internally they are calling the real system calls setreuid/setregid (there is no seteuid syscall). In this tracing library we handle all the syscalls around that, if you check, the setreuid/setregid are covered ;-)

Thank you Jiri for the review ;-)


apiVersion: cilium.io/v1alpha1
kind: TracingPolicy
metadata:
name: "privileges-setuid-root.yaml"
spec:
kprobes:
- call: "__sys_setuid"
syscall: false
return: true
args:
- index: 0
type: "int"
returnArg:
index: 0
type: "int"
selectors:
- matchArgs:
- index: 0
operator: "Equal"
values:
- "0"
matchActions:
- action: Post
rateLimit: "1m" # Rate limit messages to 1min
- call: "__sys_setgid"
syscall: false
return: true
args:
- index: 0
type: "int"
returnArg:
index: 0
type: "int"
selectors:
- matchArgs:
- index: 0
operator: "Equal"
values:
- "0"
matchActions:
- action: Post
rateLimit: "1m" # Rate limit messages to 1min
- call: "__sys_setreuid"
syscall: false
return: true
args:
- index: 0
type: "int"
- index: 1
type: "int"
returnArg:
index: 0
type: "int"
selectors:
- matchArgs:
- index: 0
operator: "Equal"
values:
- "0"
matchActions:
- action: Post
rateLimit: "1m" # Rate limit messages to 1min
- matchArgs:
- index: 1
operator: "Equal"
values:
- "0"
matchActions:
- action: Post
rateLimit: "1m" # Rate limit messages to 1min
- call: "__sys_setregid"
syscall: false
return: true
args:
- index: 0
type: "int"
- index: 1
type: "int"
returnArg:
index: 0
type: "int"
selectors:
- matchArgs:
- index: 0
operator: "Equal"
values:
- "0"
matchActions:
- action: Post
rateLimit: "1m" # Rate limit messages to 1min
- matchArgs:
- index: 1
operator: "Equal"
values:
- "0"
matchActions:
- action: Post
rateLimit: "1m" # Rate limit messages to 1min
- call: "__sys_setresuid"
syscall: false
return: true
args:
- index: 0
type: "int"
- index: 1
type: "int"
- index: 2
type: "int"
returnArg:
index: 0
type: "int"
selectors:
- matchArgs:
- index: 1 # We care about the effective user id to reduce noise
operator: "Equal"
values:
- "0"
matchActions:
- action: Post
rateLimit: "1m" # Rate limit messages to 1min
- matchArgs:
- index: 2
operator: "Equal"
values:
- "0"
matchActions:
- action: Post
rateLimit: "1m" # Rate limit messages to 1min
- call: "__sys_setresgid"
syscall: false
return: true
args:
- index: 0
type: "int"
- index: 1
type: "int"
- index: 2
type: "int"
returnArg:
index: 0
type: "int"
selectors:
- matchArgs:
- index: 1 # We care about the effective group id to reduce noise
operator: "Equal"
values:
- "0"
matchActions:
- action: Post
rateLimit: "1m" # Rate limit messages to 1min
- matchArgs:
- index: 2
operator: "Equal"
values:
- "0"
matchActions:
- action: Post
rateLimit: "1m" # Rate limit messages to 1min
- call: "__sys_setfsuid"
syscall: false
return: true
args:
- index: 0
type: "int"
returnArg:
index: 0
type: "int"
selectors:
- matchArgs:
- index: 0
operator: "Equal"
values:
- "0"
matchActions:
- action: Post
rateLimit: "1m" # Rate limit messages to 1min
- call: "__sys_setfsgid"
syscall: false
return: true
args:
- index: 0
type: "int"
returnArg:
index: 0
type: "int"
selectors:
- matchArgs:
- index: 0
operator: "Equal"
values:
- "0"
matchActions:
- action: Post
rateLimit: "1m" # Rate limit messages to 1min
Loading