0x00 前言
Tracee 是一个用于 Linux 的运行时安全和取证工具,基于 Linux eBPF 技术在运行时跟踪系统和应用程序,并分析收集的事件以检测可疑的行为模式,整体架构如下:
- 基于eBPF的事件采集器(Capture):在内核中捕获事件
- 事件处理管道(Pipeline机制):处理和丰富化事件
- 签名引擎:检测安全威胁
- 策略管理:控制事件过滤和选择
本文关联版本为v0.23.1、二进制版本v0.23.1,运行内核版本6.6.30-5.tl4.x86_64
Tracee 包括两大基础组件:
Trace-eBPF
:使用 eBPF 进行 Linux 追踪和取证,BPF 底层代码实现参见 tracee.bpf.cTrace-Rules
:运行时安全检测引擎,可通过管道的方式从Trace-eBPF
中接受数据并进行处理
基础使用(采集)
1、./tracee-ebpf --output option:parse-arguments
,每一行代表Tracee所采集到的(一条)单一事件,其中包含下列信息:
表项 | 意义 |
---|---|
TIME | 显示系统启动后事件的发生时间,单位为秒 |
UID | 调用进程的用户ID |
COMM | 调用进程名称 |
PID | 调用进程PID |
TID | 调用线程TID |
RET | 函数返回的值 |
EVENT | 事件识别符 |
ARGS | 提供给函数的参数列表 |
root@VM-16-15-ubuntu:~/tracee/dist# ./tracee-ebpf --output option:parse-arguments
TIME UID COMM PID TID RET EVENT ARGS
14:20:53:862128 0 barad_agent 1209425 1593323 0 fchown fd: 14, owner: 0, group: 0
14:20:53:865935 0 barad_agent 1209425 1593323 0 security_inode_unlink pathname: /usr/local/qcloud/monitor/barad/log/20240822_record.db-journal, inode: 812791, dev: 264241154, ctime: 1724307653858917003
14:20:53:867070 0 barad_agent 1209425 1593323 0 fchown fd: 14, owner: 0, group: 0
14:20:53:870378 0 barad_agent 1209425 1593323 0 security_inode_unlink pathname: /usr/local/qcloud/monitor/barad/log/20240822_record.db-journal, inode: 812791, dev: 264241154, ctime: 1724307653862917021
14:20:53:871062 0 barad_agent 1209425 1593323 0 fchown fd: 14, owner: 0, group: 0
14:20:53:874137 0 barad_agent 1209425 1593323 0 security_inode_unlink pathname: /usr/local/qcloud/monitor/barad/log/20240822_record.db-journal, inode: 812791, dev: 264241154, ctime: 1724307653866917041
14:20:53:874842 0 barad_agent 1209425 1593323 0 fchown fd: 14, owner: 0, group: 0
14:20:53:878247 0 barad_agent 1209425 1593323 0 security_inode_unlink pathname: /usr/local/qcloud/monitor/barad/log/20240822_record.db-journal, inode: 812791, dev: 264241154, ctime: 1724307653870917060
14:20:54:746947 0 idsagent 1189601 1189632 0 security_socket_connect sockfd: 8, type: SOCK_DGRAM, remote_addr: map[sa_family:AF_INET sin_addr:127.0.0.53 sin_port:53]
14:20:54:747032 0 idsagent 1189601 1189632 0 net_packet_dns_request metadata: 127.0.0.1 127.0.0.53 53167 53 17 73 any, dns_questions: [grpc.ids.store AAAA IN]
14:20:54:746947 0 idsagent 1189601 1189606 0 security_socket_connect sockfd: 7, type: SOCK_DGRAM, remote_addr: map[sa_family:AF_INET sin_addr:127.0.0.53 sin_port:53]
14:20:54:747032 0 idsagent 1189601 1189606 0 net_packet_dns_request metadata: 127.0.0.1 127.0.0.53 38957 53 17 73 any, dns_questions: [grpc.ids.store A IN]
14:20:54:747706 102 systemd-resolve 1372634 1372634 0 net_packet_dns_response metadata: 127.0.0.53 127.0.0.1 53 38957 17 89 any, dns_response: [grpc.ids.store A IN [A 560 127.0.0.1]]
14:20:54:747721 102 systemd-resolve 1372634 1372634 0 net_packet_dns_response metadata: 127.0.0.53 127.0.0.1 53 38957 17 89 any, dns_response: [grpc.ids.store A IN [A 560 127.0.0.1]]
14:20:54:748012 102 systemd-resolve 1372634 1372634 0 security_socket_connect sockfd: 11, type: SOCK_DGRAM, remote_addr: map[sa_family:AF_INET sin_addr:183.60.83.19 sin_port:53]
14:20:54:748183 102 systemd-resolve 1372634 1372634 0 net_packet_dns_request metadata: 10.206.16.15 183.60.83.19 33864 53 17 62 any, dns_questions: [grpc.ids.store AAAA IN]
14:20:54:749719 0 swapper/1 0 0 0 net_packet_dns_response metadata: 183.60.83.19 10.206.16.15 53 33864 17 126 any, dns_response: [grpc.ids.store AAAA IN []]
14:20:54:749932 102 systemd-resolve 1372634 1372634 0 net_packet_dns_response metadata: 127.0.0.53 127.0.0.1 53 53167 17 137 any, dns_response: [grpc.ids.store AAAA IN []]
14:20:54:749952 102 systemd-resolve 1372634 1372634 0 net_packet_dns_response metadata: 127.0.0.53 127.0.0.1 53 53167 17 137 any, dns_response: [grpc.ids.store AAAA IN []]
14:20:54:750033 0 idsagent 1189601 1189604 0 security_socket_connect sockfd: 7, type: SOCK_STREAM, remote_addr: map[sa_family:AF_INET sin_addr:127.0.0.1 sin_port:8000]
14:20:54:865306 0 sh 1593326 1593326 0 sched_process_exec cmdpath: /bin/sh, pathname: /usr/bin/dash, dev: 264241154, inode: 601, ctime: 1650801788632000000, inode_mode: 33261, interpreter_pathname: /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2, interpreter_dev: 264241154, interpreter_inode: 83, interpreter_ctime: 1717491233490378804, argv: [/bin/sh -c cat /proc/meminfo |grep 'HardwareCorrupted' |awk 'print $2'], interp: /bin/sh, stdin_type: S_IFCHR, stdin_path: /dev/null, invoked_from_kernel: 0, env: <nil>
14:20:54:867010 0 awk 1593329 1593329 0 sched_process_exec cmdpath: /usr/bin/awk, pathname: /usr/bin/gawk, dev: 264241154, inode: 394, ctime: 1696647869063262130, inode_mode: 33261, interpreter_pathname: /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2, interpreter_dev: 264241154, interpreter_inode: 83, interpreter_ctime: 1717491233490378804, argv: [awk print $2], interp: /usr/bin/awk, stdin_type: S_IFIFO, stdin_path: , invoked_from_kernel: 0, env: <nil>
14:20:54:868613 0 grep 1593328 1593328 0 sched_process_exec cmdpath: /usr/bin/grep, pathname: /usr/bin/grep, dev: 264241154, inode: 709, ctime: 1650801789108000000, inode_mode: 33261, interpreter_pathname: /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2, interpreter_dev: 264241154, interpreter_inode: 83, interpreter_ctime: 1717491233490378804, argv: [grep HardwareCorrupted], interp: /usr/bin/grep, stdin_type: S_IFIFO, stdin_path: , invoked_from_kernel: 0, env: <nil>
14:20:54:869617 0 cat 1593327 1593327 0 sched_process_exec cmdpath: /usr/bin/cat, pathname: /usr/bin/cat, dev: 264241154, inode: 558, ctime: 1650801788564000000, inode_mode: 33261, interpreter_pathname: /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2, interpreter_dev: 264241154, interpreter_inode: 83, interpreter_ctime: 1717491233490378804, argv: [cat /proc/meminfo], interp: /usr/bin/cat, stdin_type: S_IFCHR, stdin_path: /dev/null, invoked_from_kernel: 0, env: <nil>
14:20:54:966874 0 barad_agent 1209425 1593324 0 security_socket_connect sockfd: 13, type: SOCK_DGRAM, remote_addr: map[sa_family:AF_INET sin_addr:172.0.0.1 sin_port:80]
14:20:54:968809 0 barad_agent 1209424 1209424 0 security_socket_connect sockfd: 13, type: SOCK_STREAM, remote_addr: map[sa_family:AF_INET sin_addr:169.254.0.4 sin_port:80]
14:20:54:972065 0 barad_agent 1209424 1209424 0 net_packet_http_request metadata: 10.206.16.15 169.254.0.4 57850 80 6 221 any, http_request: POST HTTP/1.1 169.254.0.4 /ca_report.cgi map[Accept-Encoding:[identity] Connection:[close] Content-Length:[796] Content-Type:[application/json] User-Agent:[Python-urllib/2.6]] 796
14:20:55:099351 0 swapper/1 0 0 0 net_packet_http_response metadata: 169.254.0.4 10.206.16.15 80 57850 6 256 any, http_response: 200 OK 200 HTTP/1.1 map[Content-Length:[74] Content-Type:[application/json; charset=utf-8] Date:[Thu, 22 Aug 2024 06:20:55 GMT]] 74
支持的 event
参考 Events,包含了如下(其中 syscalls 是笔者关心的部分):
- Security Events
- Network Events
- Extra Events
- Syscalls:https://aquasecurity.github.io/tracee/dev/docs/events/builtin/syscalls/
0x01 工作原理
采集器
Tracee 中的 tracee-ebpf
模块的核心能力包括: 事件跟踪(trace)、抓取(capture)和输出(output),tracee-ebpf
的核心能力在于底层 eBPF 机制抓取事件的能力,tracee-ebpf
默认实现了诸多的事件抓取功能,可以通过 trace-ebpf -l
参看到底层支持的函数全集(本版本约1800+
)
root@VM-16-15-ubuntu:~/tracee/dist# ./tracee-ebpf -l|wc -l
1838
Syscall Events
+------------------------------+--------------------------------+------------------------------------------+
| RULE | SETS | ARGUMENTS |
+------------------------------+--------------------------------+------------------------------------------+
| read | syscalls, fs, fs_read_write | int fd, void* buf, size_t |
| | | count |
+------------------------------+--------------------------------+------------------------------------------+
| write | syscalls, fs, fs_read_write | int fd, void* buf, size_t |
| | | count |
+------------------------------+--------------------------------+------------------------------------------+
| open | syscalls, fs, fs_file_ops | const char* pathname, int |
| | | flags, mode_t mode |
+------------------------------+--------------------------------+------------------------------------------+
| close | syscalls, fs, fs_file_ops | int fd |
+------------------------------+--------------------------------+------------------------------------------+
| stat | syscalls, fs, fs_file_attr | const char* pathname, struct |
| | | stat* statbuf |
+------------------------------+--------------------------------+------------------------------------------+
| fstat | syscalls, fs, fs_file_attr | int fd, struct stat* statbuf |
+------------------------------+--------------------------------+------------------------------------------+
| lstat | syscalls, fs, fs_file_attr | const char* pathname, struct |
| | | stat* statbuf |
+------------------------------+--------------------------------+------------------------------------------+
RULE
:系统调用函数SETS
:该函数归属为的子类(注可归属多个,比如read
函数,归属于syscalls
/fs
/fs_read_write
3 个子类,除了fs
外,net
集合中也包含了许多的跟踪函数)ARGUMENTS
:为该函数的原型,可以使用参数中的字段进行过滤,支持特定的运算,比如==
、!=
等逻辑操作符,对于字符串也支持通配符操作
例如:
--trace s=fs --trace e!=open,openat 跟踪 fs 集合中的所有事件,但是不包括 open,openat 两个函数
--trace openat.pathname!=/tmp/1,/bin/ls 这里表示不跟踪 openat 事件中,pathname 为 /tmp/1,/bin/ls 的事件,注意这里的 openat.pathname 为跟踪函数名与函数参数的组合
以上跟踪事件的过滤条件会通过接口设置进内核中对应的 map 结构中,在完成过滤和事件跟踪以后,通过 perf_event 的方式上报到用户空间程序中,可以保存到文件后续进行处理,或者直接通过管道发送至 tracee-rule
进行解析和进行更高级别的上报
Tracee Pipeline Concept
Pipeline的作用
签名引擎
0x02 内核态开发
笔者感兴趣的内核态hook实现集中在此tracee.bpf.c
,除此之外: