From 61698f09d25871a85e6f5141ef9b0c7fb9bc29e1 Mon Sep 17 00:00:00 2001 From: Djalal Harouni Date: Wed, 14 Feb 2024 16:44:01 +0100 Subject: [PATCH] docs:policylibrary: add fileless execution example Signed-off-by: Djalal Harouni --- .../policy-library/observability/_index.md | 43 +++++++++++++++++++ testdata/demos/tools/exec-memfd.py | 34 +++++++++++++++ 2 files changed, 77 insertions(+) create mode 100755 testdata/demos/tools/exec-memfd.py diff --git a/docs/content/en/docs/policy-library/observability/_index.md b/docs/content/en/docs/policy-library/observability/_index.md index bfbbb6980b0..80f368fcabe 100644 --- a/docs/content/en/docs/policy-library/observability/_index.md +++ b/docs/content/en/docs/policy-library/observability/_index.md @@ -18,6 +18,7 @@ description: > - [Privileges Escalation via Setuid system calls]({{< ref "#privileges-setuid" >}}) - [Privileges Escalation via Unprivileged User Namespaces]({{< ref "#privileges-userns" >}}) - [Privileges Change via Capset system call]({{< ref "#privileges-capset" >}}) +- [Fileless Execution]({{< ref "#exec-fileless" >}}) ### System Activity @@ -275,6 +276,48 @@ jq 'select(.process_kprobe != null) | select(.process_kprobe.policy_name | test( "2024-02-05T21:12:14.774175889Z null null /usr/local/sbin/runc --root /run/containerd/runc/k8s.io --log /run/containerd/io.containerd.runtime.v2.task/k8s.io/024daa4cc70eb683355f6f67beda3012c65d64f479d958e421cd209738a75392/log.json --log-format json --systemd-cgroup exec --process /tmp/runc-process2888400204 --detach --pid-file /run/containerd/io.containerd.runtime.v2.task/k8s.io/024daa4cc70eb683355f6f67beda3012c65d64f479d958e421cd209738a75392/d8b8598320fe3d874b901c70863f36233760b3e63650a2474f707cc51b4340f9.pid 024daa4cc70eb683355f6f67beda3012c65d64f479d958e421cd209738a75392 security_capset {\"cap_permitted_arg\":\"000001ffffffffff\"} {\"cap_effective_arg\":\"000001ffffffffff\"}" ``` +## Fileless Execution {#exec-fileless} + +### Description + +Monitor the execution of binaries that exist exclusively as a computer memory-based artifact. + +### Use Case + +Often attackers execute fileless binaries that reside only in memory rather than on the file system to cover their traces. On Linux +this is possible with the help of [memfd_create()](https://man7.org/linux/man-pages/man2/memfd_create.2.html) and +[shared memory](https://man7.org/linux/man-pages/man7/shm_overview.7.html) anonymous files. Therefore, detecting execution +of such binaries that live only in RAM or backed by volatile storage is a common best-practice. + +### Requirement + +Tetragon must run with the Process Credentials visibility enabled, please +refer to [Enable Process Credentials]({{< ref "docs/installation/configuration#enable-process-credentials" >}}) documentation. + +### Policy + +No policy needs to be loaded, standard process execution observability is sufficient. + +### Demo to reproduce + +You can use the [exec-memfd.py](https://raw.githubusercontent.com/cilium/tetragon/main/testdata/demos/tools/exec-memfd.py) python script as +an example which will copy the binary `/bin/true` into an anonymous memory then execute it. The binary will not be linked on the file system. + +### Example jq Filter + +```shell +jq 'select(.process_exec != null) | select(.process_exec.process.binary_properties != null) | select(.process_exec.process.binary_properties.file) | "\(.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) binary_properties=\(.process_exec.process.binary_properties)"' +``` + +### Example Output + +```shell +"2024-02-14T15:17:48.758997159Z null null /proc/self/fd/3 null uid=1000 euid=1000 binary_properties={\"file\":{\"inode\":{\"number\":\"45021\",\"links\":0}}}" +``` + +The output shows that the executed binary refers to a file descriptor `/proc/self/fd/3` that it is not linked on the file system. +The [binary_properties]({{< ref "/docs/reference/grpc-api#binaryproperties" >}}) includes an [inode]({{< ref "/docs/reference/grpc-api#inodeproperties" >}}) with zero links on the file system. + ## eBPF Subsystem Interactions {#ebpf} ### Description diff --git a/testdata/demos/tools/exec-memfd.py b/testdata/demos/tools/exec-memfd.py new file mode 100755 index 00000000000..68cc1e65670 --- /dev/null +++ b/testdata/demos/tools/exec-memfd.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python3 + +# SPDX-License-Identifier: Apache-2.0 +# Copyright Authors of Tetragon + + +import os +import subprocess +import time + +def run_memfd(binary: str) -> None: + try: + fd = os.memfd_create("fileless-exec-tetragon") + except OSError as e: + print("Failed to create memfd: {0}: {1}".format(e.errno, e.strerror)) + sys.exit() + + os.lseek(fd, 0, os.SEEK_SET) + + with open(binary, mode='rb') as fdinput: + data = fdinput.read() + try: + nbytes = os.write(fd, data) + except OSError as e: + print("Failed to write binary into memfd: {0}: {1}".format(e.errno, e.strerror)) + sys.exit() + + print("Copied {0} bytes {1} into memfd {2}".format(binary, nbytes, fd)) + print("Executing {0} from memfd {1}".format(binary, fd)) + + os.execv("/proc/self/fd/%d" % fd, ['fileless-exec-tetragon']) + +if __name__ == '__main__': + run_memfd("/bin/true")