tarsal-oss/kflowd

GitHub: tarsal-oss/kflowd

基于 eBPF 的 Linux 端点进程监控代理,实时采集文件系统与 TCP/UDP 网络事件并可选解析 DNS、HTTP、SYSLOG 协议,输出 JSON 供安全分析管道消费。

Stars: 71 | Forks: 4

## 通过 eBPF 在 Linux 端点上基于内核的进程监控 ### kflowd 作为代理运行在 Linux 端点上,通过 eBPF 内核子系统监控进程的文件系统和 TCP、UDP 网络事件,从而能够立即检测可疑活动中的威胁和异常。 #### 诸如 DNS、HTTP 和 SYSLOG 应用消息解码、用于病毒检测的校验和计算、用于漏洞检测的进程和文件版本控制,以及用于文件和进程的文件设备、网络接口和用户组识别等高级非 eBPF 相关功能,可以通过 open-binary 插件模块启用。
预构建的 kflowd 和 kflowd-plugins 包可以从 [Releases](https://github.com/tarsal-oss/kflowd/releases) 部分下载以进行快速安装。 如果您想加入我们的社区 Slack 频道,请发送电子邮件至 [devs@tarsal.co](mailto:devs@tarsal.co) 以接收邀请。如有任何疑问,您也可以直接通过 [kflow@tarsal.co](mailto:kflow@tarsal.co) 联系我们。 kflowd 包含一个运行在内核上下文中的 eBPF 程序和一个运行在用户空间的控制应用程序。
eBPF 程序跟踪内核函数,以基于文件系统和网络事件监控进程。事件被聚合成记录并提交到 ringbuffer,然后由用户空间控制应用程序进行轮询。所有记录都 enriched 了进程信息,然后转换为 JSON 输出格式的消息。
最终消息打印到 stdout 控制台,并可以通过 UDP 协议发送到指定的主机,以便在安全数据管道中进行摄取。 kflowd 运行在 Linux 内核 5.10+ 上,并使用 **libbpf+CO-RE**(一次编译,到处运行)eBPF 开发工具链构建,利用 **BTF**(BPF 类型格式)通过避免依赖部署时不同内核版本之间内核头文件的差异来实现可移植性。
### JSON 输出 kflowd 为每条聚合的文件系统和 TCP、UDP 网络事件记录输出 JSON 消息,以及可选的 DNS、HTTP 和 SYSLOG 应用消息,格式如下例所示:
 文件系统记录 ``` { "InfoSequenceNumber": 1, "InfoTimestamp": "Thu, Apr 04 2024 15:34:35.643031330 UTC", "InfoMonitor": "filesystem", "InfoHostName": "dev.kflow.co", "InfoHostIP": "38.110.1.24", "InfoSystem": "Linux", "InfoKernel": "6.1.0-10-amd64", "InfoVersion": "kflowd-v0.9.1", "InfoUptime": 21.262713426, "ProcParent": "sshd", "Proc": "sftp-server", "ProcVersion": "1:9.2p1-2+deb12u1", "ProcUser": "dirk", "ProcGroup": "dirk", "ProcPPID": 183546, "ProcPID": 183547, "ProcTID": 183547, "ProcUID": 1002, "ProcGID": 1002, "ProcAge": 2.408293862, "FilePath": "/home/dirk/", "File": "malware", "FileVersion": "0.9", "FileMode": "regular", "FileEventCount": 4, "FileEvents": { "OPEN": 1, "MODIFY": 2, "CLOSE_WRITE": 1 }, "FileEventsDuration": 0.811829334, "FileInode": 19567988, "FileInodeLinkCount": 1, "FileDevice": "902h:/dev/md2:/:ext4", "FilePermissions": "0755/-rwxr-xr-x", "FileUser": "dirk", "FileGroup": "dirk", "FileUID": 1002, "FileGID": 1002, "FileSize": 41, "FileSizeChange": 41, "FileAccessTime": "Thu, Apr 04 2024 15:12:01.435718956 UTC", "FileStatusChangeTime": "Thu, Apr 04 2024 15:34:35.154106191 UTC", "FileModificationTime": "Thu, Apr 04 2024 15:34:35.154106191 UTC", "FileModificationTimeChange": 0.327993681, "FileMD5": "96760f46bd29ba986279f22bed9839f5", "FileSHA256": "72c58c2d02ae3a87f521594373433b7d05477c4994fc0ab4376827cadb29ba7e" } ```
 UDP + DNS 网络记录 ``` { "InfoSequenceNumber": 2, "InfoTimestamp": "Thu, Apr 04 2024 15:39:11.463732866 UTC", "InfoMonitor": "socket", "InfoHostName": "dev.kflow.co", "InfoHostIP": "38.110.1.24", "InfoSystem": "Linux", "InfoKernel": "6.1.0-10-amd64", "InfoVersion": "kflowd-v0.9.1", "InfoUptime": 23.972984597, "ProcParent": "bash", "Proc": "curl", "ProcVersion": "7.45.2-3", "ProcUser": "dirk", "ProcGroup": "dirk", "ProcPPID": 199853, "ProcPID": 199856, "ProcTID": 199857, "ProcUID": 1002, "ProcGID": 1002, "ProcAge": 0.044454620, "SockProtocol": "UDP", "SockRole": "CLIENT", "SockState": "UDP_ESTABLISHED", "SockFamily": "AF_INET", "SockLocalIP": "38.110.1.24", "SockLocalPort": 56664, "SockRemoteIP": "8.8.4.4", "SockRemotePort": 53, "SockTxInterface": "4:enp5s0:0c:c4:7a:88:84:c2", "SockTxPackets": 2, "SockTxDuration": 0.000048490, "SockTxBytes": 52, "SockTxInterface": "4:enp5s0:0c:c4:7a:88:84:c2", "SockRxPackets": 2, "SockRxPacketsQueued": 0, "SockRxPacketsDrop": 0, "SockRxPacketsFrag": 0, "SockRxDuration": 22.475134750, "SockRxBytes": 155, "SockRxTTL": 125, "SockAge": 0.043689149, "App": "DNS", "AppTxDns": [{ "_Timestamp": 0.000001177, "TransactionId": 56864, "OpCode": "QUERY", "Flags": ["RD"], "ResourceRecords": [ ["A", "kflow.co"] ] }, { "_Timestamp": 0.000048627, "TransactionId": 52515, "OpCode": "QUERY", "Flags": ["RD"], "ResourceRecords": [ ["AAAA", "kflow.co"] ] }], "AppRxDns": [{ "_Timestamp": 0.037965555, "TransactionId": 52515, "ResponseCode": "NOERROR", "Flags": ["QR", "RD", "RA"], "AnswerCount": 0, "ResourceRecords": [] }, { "_Timestamp": 0.043688644, "TransactionId": 56864, "ResponseCode": "NOERROR", "Flags": ["QR", "RD", "RA"], "AnswerCount": 2, "ResourceRecords": [ ["A", "kflow.co", 600, "IN", "15.197.142.173"], ["A", "kflow.co", 600, "IN", "3.33.152.147"] ] }] } ```
 TCP + HTTP 网络记录 ``` { "InfoSequenceNumber": 3, "InfoTimestamp": "Thu, Apr 04 2024 15:39:11.928989997 UTC", "InfoMonitor": "socket", "InfoHostName": "dev.kflow.co", "InfoHostIP": "38.110.1.24", "InfoSystem": "Linux", "InfoKernel": "6.1.0-10-amd64", "InfoVersion": "kflowd-v0.9.1", "InfoUptime": 24.873001288, "ProcParent": "bash", "Proc": "curl", "ProcVersion": "7.45.2-3", "ProcUser": "dirk", "ProcGroup": "dirk", "ProcPPID": 199853, "ProcPID": 216998, "ProcTID": 216998, "ProcUID": 1002, "ProcGID": 1002, "ProcAge": 0.114196829, "SockProtocol": "TCP", "SockRole": "CLIENT", "SockState": "TCP_CLOSE", "SockFamily": "AF_INET", "SockLocalIP": "38.110.1.24", "SockLocalPort": 43302, "SockRemoteIP": "15.197.142.173", "SockRemotePort": 80, "SockTxInterface": "4:enp5s0:0c:c4:7a:88:84:c2", "SockTxDataPackets": 1, "SockTxPackets": 6, "SockTxPacketsRetrans": 0, "SockTxPacketsDups": 0, "SockTxFlags": { "SYN": 1, "ACK": 3, "PSH-ACK": 1, "FIN-ACK": 1 }, "SockTxDuration": 0.057274799, "SockTxBytes": 72, "SockTxBytesAcked": 74, "SockTxBytesRetrans": 0, "SockTxRTO": 51, "SockTxInterface": "4:enp5s0:0c:c4:7a:88:84:c2", "SockRxDataPackets": 1, "SockRxPackets": 4, "SockRxPacketsQueued": 0, "SockRxPacketsDrop": 0, "SockRxPacketsReorder": 0, "SockRxPacketsFrag": 0, "SockRxFlags": { "SYN-ACK": 1, "ACK": 1, "PSH-ACK": 1, "FIN-ACK": 1 }, "SockRxDuration": 0.057197399, "SockRxBytes": 342, "SockRxTTL": 185, "SockRTT": 0.000450625, "SockAge": 0.057344028, "App": "HTTP", "AppTxHttp": [{ "_Timestamp": 0.000876589, "_Method": "GET", "_Url": "/", "_Version": "HTTP/1.1", "Host": "kflow.co", "User-Agent": "curl/7.88.1", "Accept": "*/*" }], "AppRxHttp": [{ "_Timestamp": 0.056237469, "_Version": "HTTP/1.1", "_Status": 301, "_Reason": "Moved Permanently", "Date": "Thu, 04 Apr 2024 15:49:12 GMT", "Content-Type": "text/html; charset=utf-8", "Content-Length": "59", "Connection": "keep-alive", "Location": "https://kflowd.github.io", "Server": "ip-10-123-123-119.ec2.internal", "X-Request-Id": "5c331cbe-fbe1-40ea-ba2b-989691e687a0", "_Body": "Moved Permanently." }] } ```
 UNIX Socket + SYSLOG 记录 ``` { "InfoSequenceNumber": 4, "InfoTimestamp": "Mon, Sep 16 2024 14:30:19.409100980 UTC", "InfoMonitor": "socket", "InfoHostName": "dev.kflow.co", "InfoHostIP": "38.110.1.24", "InfoSystem": "Linux", "InfoKernel": "6.1.0-10-amd64", "InfoVersion": "kflowd-v0.9.11", "ProcParent": "cron", "Proc": "cron", "ProcVersion": "3.0pl1-137", "ProcUser": "root", "ProcGroup": "root", "ProcPPID": 990, "ProcPID": 2122368, "ProcTID": 2122368, "ProcUID": 0, "ProcGID": 0, "ProcAge": 18.100170007, "SockRole": "CLIENT", "SockAddress": "/run/systemd/journal/dev-log", "SockFamily": "AF_UNIX", "SockTxBytes": 192, "SockAge": 18.095146325, "App": "SYSLOG", "AppTxSyslog": [{ "Facility": "Security/Authorization", "Severity": "Notice (5)", "Priority": 85, "Version": 0, "Timestamp": "Sep 16 14:30:01", "Appname": "CRON", "ProcId": "2122368", "Message": "pam_unix(cron:session): session opened for user root(uid=0) by (uid=0)" }, { "Facility": "Security/Authorization", "Severity": "Informational (6)", "Priority": 86, "Version": 0, "Timestamp": "Sep 16 14:30:01", "Appname": "CRON", "ProcId": "2122368", "Message": "pam_unix(cron:session): session closed for user root" }] } ```
### 运行时要求 内核 5.10+ 编译时需包含: - CONFIG_BPF=y - CONFIG_KPROBES=y - CONFIG_KRETPROBES=y - CONFIG_DEBUG_INFO_BTF=y - Maps (4.1+) 用于在哈希表中执行文件系统事件聚合 - Ringbuffer (5.8+) 用于在内核 eBPF 程序和用户空间应用程序之间共享数据 - Global variables (5.5) 用于应用程序行为的参数化 - 二进制格式的 vmlinux.h 文件位于 /sys/kernel/btf/vmlinux - 已安装库 libelf 和 libz ### 运行时性能建议 内核 5.10+ 使用即时 eBPF 编译器 (JIT) 编译: - CONFIG_BPF_JIT=y 启用的 JIT 系统控制设置: - net.core.bpf_jit_enable=1 以下链接提供了默认启用 eBPF CO-RE 和 BTF 的 Linux 发行版概述:
**[Linux Distributions w/ eBPF CO-RE & BTF](https://github.com/libbpf/libbpf#bpf-co-re-compile-once--run-everywhere)** 为了获得高性能 UDP 输出,建议使用以下内核网络设置: - sysctl -w net.core.rmem_max=134217728 - sysctl -w net.core.wmem_max=134217728 ### 运行时选项 ``` Usage: kflowd [-m file,socket] [-t IDLE,ACTIVE] [-e EVENTS] [-o json|json-min|table] [-v] [-c] [-p dns|http|syslog=PROTO/PORT,...] [-u IP:PORT] [-q] [-d] [-V] [-T TOKEN] [-P PATH] [-D PROCESS], [-l] [--legend], [-h] [--help], [--version] -m file,socket Monitor only specified kernel subsystem (filesystem or sockets) (default: all, option omitted!) -t IDLE,ACTIVE Timeout in seconds for idle or active network sockets until export (default: idle '15' seconds, active '1800' seconds) -e EVENTS Max number of filesystem events per aggregated record until export (default: disabled, '1': no aggregation) -o json Json output with formatting (default) json-min Json output with minimal formatting table Tabular output with limited keys and no UDP output -v Version of executable files identified by installed package (supported only for rpm- and deb-based package management) -c Checksum hashes of MD5 and SHA256 calculated for executables -p dns=PROTO/PORT,... Port(s) examined for decoding of DNS application protocol (default: 'dns=udp/53,tcp/53', disabled: 'dns=off') -p http=PROTO/PORT,... Port(s) examined for decoding of HTTP application protocol (default: 'http=tcp/80', disabled: 'http=off') -p syslog=PROTO/PORT,... Port(s) examined for decoding of SYSLOG application protocol (default: 'syslog=udp/514,tcp/514,unix', disabled: 'syslog=off') -u IP:PORT,... UDP server(s) IPv4 or IPv6 address to send json output to. Output also printed to stdout console unless quiet option -q or daemon mode -d specified -q Quiet mode to suppress output to stdout console -d Daemonize program to run in background -V Verbose output Print eBPF load and co-re messages on start of eBPF program to stderr console -T TOKEN Token specified on host to be included in json output -P PATH Path to search for kflowd plugin modules (default: '../lib/') -l, --legend Show legend -h, --help Show help --version Show version -D PROCESS Debug Print ebpf kernel log messages of process or expiration queue to kernel trace pipe (any process: '*', with quotes!, queue: 'q') Use command: 'sudo cat /sys/kernel/debug/tracing/trace_pipe' Examples: sudo ./kflowd # terminal mode sudo ./kflowd -m file,socket -v -c -u 1.2.3.4:2056,127.0.0.1:2057 -d # daemon mode sudo ./kflowd -m socket -v -c -u 1.2.3.4:2056 -V -D '*' # debug mode sudo ./kflowd --legend # show legend sudo ./kflowd --version # show version ``` ### 构建要求 - 内核版本 5.10+,使用 BTF for CO-RE 编译: uname -a cat /boot/config-* | grep CONFIG_DEBUG_INFO_BTF - 在文件 /etc/sysctl.conf 中启用 BPF: ... kernel.bpf_stats_enabled=1 kernel.unprivileged_bpf_disabled=0 ### 构建先决条件 - 基于 Debian (Ubuntu, Mint) - 安装库: sudo apt install libz-dev sudo apt install libelf-dev sudo apt install libcap-dev sudo apt install libbfd-dev sudo apt install libc6-dev-i386 - 安装 Clang 16+ 工具链: sudo apt install build-essential sudo apt install pkg-config sudo apt install clang-16* sudo apt install llvm-16* sudo ln -s /usr/bin/clang-16 /usr/bin/clang sudo ln -s /usr/bin/llvm-strip-16 /usr/bin/llvm-strip - 安装 nfpm Linux 打包器: echo 'deb [trusted=yes] https://repo.goreleaser.com/apt/ /' | sudo tee /etc/apt/sources.list.d/goreleaser.list sudo apt update sudo apt install nfpm - 基于 Redhat (Amazon Linux, Fedora) - 安装库: sudo yum install zlib-devel sudo yum install elfutils-libelf-devel sudo yum install libcap-devel sudo yum install binutils-devel sudo yum install glibc-devel.i386 or .i686 - 安装 Clang 16+ 工具链: sudo yum groupinstall 'Development Tools' sudo yum install pkgconfig sudo yum install clang* sudo yum install llvm* - 安装 nfpm Linux 打包器: echo '[goreleaser] name=GoReleaser baseurl=https://repo.goreleaser.com/yum/ enabled=1 gpgcheck=0' | sudo tee /etc/yum.repos.d/goreleaser.repo sudo yum install nfpm ### 构建说明 ``` git clone https://github.com/tarsal-oss/kflowd.git cd kflowd git submodule update --init --recursive cd src make make rpm deb ``` ### 安装说明 包可以安装在 Linux x86_64 和 arm64 平台上: - Debian ``` sudo apt install ./kflowd_x.x.x_amd64.deb sudo apt install ./kflowd_x.x.x_arm64.deb ``` - Redhat ``` sudo yum install ./kflowd-x.x.x.x86_64.rpm sudo yum install ./kflowd-x.x.x.aarch64.rpm ``` 注意,构建产物可以在 GitHub Actions 中 kflowd-ci 工作流运行的 Artifacts 部分下载,其中包含适用于 x86_64 和 arm64 平台(glibc 2.31+)的二进制文件和包:\ [预构建的二进制文件、RPM 和 DEB 包(已压缩)](https://github.com/tarsal-oss/kflowd/actions/workflows/kflowd-ci.yml)
### 许可证 此作品根据 [GNU General Public License v2.0](https://github.com/tarsal-oss/kflowd/blob/master/LICENSE) 获得许可。 ``` SPDX-License-Identifier: GPL-2.0 ``` ### 致谢 - **libbpf+CO-RE:** Andrii Nakryiko's Blog, **[BPF CO-RE Reference Guide](https://nakryiko.com/posts/bpf-core-reference-guide/)** - **eBPF Tracing:** Brendan Gregg, **[Linux Extended BPF (eBPF) Tracing Tools](https://www.brendangregg.com/ebpf.html)** - **SHA256:** Cgminer (Bitcoin mining project), **[Fast SHA256 Implementation](https://github.com/fcicq/cgminer/)** - **MD5:** RSA Data Security, **[MD5 Message-Digest Algorithm](https://github.com/Zunawe/md5-c/)**

标签:AMSI绕过, API集成, DNS解析, Docker镜像, EDR, GPLv2, Homebrew安装, HTTP检测, IP 地址批量处理, SQLite数据库, Syslog, TCP监控, UDP监控, 内核态追踪, 内核监控, 可观测性, 威胁检测, 安全代理, 安全运营, 客户端加密, 客户端加密, 开源项目, 异常检测, 扫描框架, 文件系统监控, 端点安全, 网络信息收集, 网络安全, 网络安全审计, 脆弱性评估, 补丁管理, 请求响应过滤, 隐私保护