本仓库包含用于收集内核函数时间测量值的代码,这些函数在隐藏文件时会被rootkit操纵,同时还提供了一种半监督检测方法,用于分析内核函数执行时间的偏移。此实现依赖于开源rootkit CARAXES,它包装了filldir函数以操纵文件枚举的结果,例如在执行ls命令时。我们通过eBPF探针从getdents系统调用中的多个函数(包括filldir)获取时间测量值。对于检测,我们应用了一个基于统计检验的简单机器学习模型。关于数据收集和异常检测机制的详细解释,请参考以下出版物。如果您使用了本仓库提供的任何资源,请引用该出版物:
以下步骤设置rootkit并说明如何从内核函数收集时间测量值。如果您只对异常检测感兴趣,并希望使用我们的公开数据集,可以跳过此部分。
rootkit和探测已在Linux内核5.15-6.11和Python 3.10上测试通过。要运行这些工具,请下载本仓库并安装运行rootkit和探测机制所需的以下依赖。
ubuntu@ubuntu:~$ git clone https://github.com/ait-aecid/rootkit-detection-ebpf-time-trace.git
ubuntu@ubuntu:~$ cd rootkit-detection-ebpf-time-trace
ubuntu@ubuntu:~/rootkit-detection-ebpf-time-trace$ sudo apt update
ubuntu@ubuntu:~/rootkit-detection-ebpf-time-trace$ sudo apt install python3-bpfcc make gcc flex bison python3-pip linux-headers-$(uname -r)
ubuntu@ubuntu:~/rootkit-detection-ebpf-time-trace$ pip install -r requirements.txt
某些场景需要额外资源。具体来说,ls-basic场景需要编译ls-basic脚本,系统负载场景需要安装stress-ng。如果您不想使用这些场景,可以跳过以下依赖。
ubuntu@ubuntu:~/rootkit-detection-ebpf-time-trace$ gcc -o ls-basic ls-basic.c
ubuntu@ubuntu:~/rootkit-detection-ebpf-time-trace$ sudo apt install stress-ng
以下命令是必须的,因为rootkit默认操纵getdents系统调用,但目前只支持对filldir的探测。下载rootkit,将hooks.h替换为本仓库提供的文件(这样确保挂接的是filldir而不是getdents),并编译rootkit。
ubuntu@ubuntu:~/rootkit-detection-ebpf-time-trace$ cd ..
ubuntu@ubuntu:~$ git clone https://github.com/ait-aecid/caraxes.git
ubuntu@ubuntu:~$ cd caraxes/
ubuntu@ubuntu:~/caraxes$ cp ../rootkit-detection-ebpf-time-trace/hooks.h .
ubuntu@ubuntu:~/caraxes$ sudo make
如果您在安装rootkit时遇到问题,或者想测试它是否按预期工作,请查看CARAXES GitHub页面上的ReadMe。
之后,返回本仓库,打开linux.py并修改变量KERNEL_OBJECT_PATH,使其指向您刚刚克隆的caraxes文件夹;默认路径是"/home/ubuntu/caraxes/"。
ubuntu@ubuntu:~/caraxes$ cd ../rootkit-detection-ebpf-time-trace
ubuntu@ubuntu:~/rootkit-detection-ebpf-time-trace$ vim linux.py
现在您可以运行探测机制了,它会自动向内核注入探针,启动rootkit,将时间测量数据存储到文件中,并停止rootkit。为了触发系统调用,脚本会创建一个包含待隐藏文件的目录,并执行ls 100次(可通过-i标志修改),同时轮询探针。该脚本支持在启用rootkit(--rootkit标志)和未启用rootkit(--normal标志)的情况下收集测量值,或两者都收集,并支持多种场景。使用以下命令运行默认场景:
ubuntu@ubuntu:~/rootkit-detection-ebpf-time-trace$ sudo python3 probing.py --normal --rootkit
compiling eBPF probes...
probes compiled!
attached bpf probes:
iterate_dir-enter
iterate_dir-return
dcache_readdir-enter
dcache_readdir-return
filldir64-enter
filldir64-return
verify_dirent_name-enter
verify_dirent_name-return
touch_atime-enter
touch_atime-return
Running experiment with ls for 100 times.
Iteration 0...
detection_PID: 70133
Iteration 1...
detection_PID: 70134
...
Iteration 99...
detection_PID: 70338
polled 40 times!
done with the "rootkit version"
Experiment finished, saving output.
Saved data to events/events_2025-01-17T09:59:52.183801_rootkit.json.gz
412K events/events_2025-01-17T09:59:52.183801_rootkit.json.gz
测量值存储在events目录中。使用python3 probing.py -h查看帮助页面,了解其他参数(例如,使用ls-basic代替ls或模拟系统负载)以及为不同运行指定名称(--description)。查看repeat_seq.sh了解参数化命令;事实上,我们使用此脚本收集了公开数据集。请注意,我们只考虑了getdents系统调用中的部分可用内核函数。要指定探测机制应挂接哪些函数,请打开probing.py,在文件开头的probe_points列表中添加或删除函数名称。
运行异常检测算法只需要安装Python依赖。如果您在之前的步骤中没有安装,请运行以下命令通过pip安装依赖。
ubuntu@ubuntu:~$ git clone https://github.com/ait-aecid/rootkit-detection-ebpf-time-trace.git
ubuntu@ubuntu:~$ cd rootkit-detection-ebpf-time-trace
ubuntu@ubuntu:~/rootkit-detection-ebpf-time-trace$ pip install -r requirements.txt
然后,下载并解压我们在Zenodo上提供的数据集。如果您在之前的步骤中生成了自己的数据并想使用它,请跳过此步骤。
ubuntu@ubuntu:~/rootkit-detection-ebpf-time-trace$ wget https://zenodo.org/records/14679675/files/events.zip
ubuntu@ubuntu:~/rootkit-detection-ebpf-time-trace$ unzip events.zip
现在您可以使用以下命令运行异常检测。指定包含测量数据的目录(-d)、用于训练的正常数据比例(-t)、运行模式(-m)和分组函数(-g)。脚本将加载指定目录中的所有文件,将它们分成训练和测试数据(在输出中总结),计算并打印检测指标,并绘制混淆矩阵。
ubuntu@ubuntu:~/rootkit-detection-ebpf-time-trace$ python3 evaluate.py -d events -t 0.333 -m offline -g fun
100%|█████████████████████████████████████████████| 1250/1250 [02:47<00:00, 7.45it/s]
Processed all files from events
Normal batches: 750
Normal batches for training: 250
default: 50
file_count: 50
system_load: 50
ls_basic: 50
filename_length: 50
Normal batches for testing: 500
default: 100
file_count: 100
system_load: 100
ls_basic: 100
filename_length: 100
Anomalous batches: 500
default: 100
file_count: 100
system_load: 100
ls_basic: 100
filename_length: 100
Results (Run 1)
Threshold=3.5111917342151415e-16
Time=0.0027740001678466797
TP=499
FP=9
TN=491
FN=1
TPR=R=0.998
FPR=0.018
TNR=0.982
P=0.9822834645669292
F1=0.9900793650793651
ACC=0.99
MCC=0.9801254640896192
Confusion Matrix (Run 1)
Predicted
default file_count system_load ls_basic filename_length
Pos Neg Pos Neg Pos Neg Pos Neg Pos Neg
100 0 100 0 100 0 100 0 100 0 Pos - Actual default
3 97 100 0 99 1 100 0 2 98 Neg - Actual default
100 0 100 0 100 0 100 0 100 0 Pos - Actual file_count
100 0 0 100 100 0 100 0 100 0 Neg - Actual file_count
100 0 100 0 100 0 100 0 100 0 Pos - Actual system_load
100 0 100 0 4 96 100 0 100 0 Neg - Actual system_load
100 0 100 0 100 0 99 1 100 0 Pos - Actual ls_basic
100 0 100 0 100 0 2 98 100 0 Neg - Actual ls_basic
99 1 100 0 100 0 100 0 100 0 Pos - Actual filename_length
3 97 100 0 99 1 100 0 0 100 Neg - Actual filename_length
使用python3 evaluate.py -h查看手册,了解此脚本的更多可用参数。另外,请查看demo.sh,了解我们在论文中用于评估的参数化命令。
如果您使用了本仓库提供的任何资源,请引用以下出版物: