TT Lab
开始
学习 学习路径 课程

cron 在凌晨三点执行了 curl

分清哪些留得下、哪些留不下

在 TT Lab 中继续学习

本实验在 VM 中运行

一台 Ubuntu 24.04 VM。以 root 身份运行并拥有内核权限,所以可以真正加载审计规则。实验 Pod 中没有任何 capability,auditctl 根本无法工作,所以只有本实验在 VM 中运行。首次启动需要 1–2 分钟。

目标

亲手设置内核审计规则,故意制造事件,并取出记录来阅读。在 journal 一侧重新找到同一个事件,查看两份记录各自包含什么,最后找出没有被监视的位置并把它覆盖起来。

为什么重要

在编写检测规则之前,有一个必须回答的问题——这个事件最初有没有被记录在某个地方。在 Linux 上,内核审计默认几乎什么也不记录。它只看设置了规则的路径和系统调用。所以才会出现“日志都收集了,却没有答案”的情况。

这里要学的不是命令,而是范围感。如果能说清自己的规则看什么、不看什么,事件发生时就能区分“没有记录”和“一直没在看那个位置”。这两者会导向完全不同的处方。

步骤

  1. 把 auditctl -s 和服务状态保存到 /root/det/01-status.txt。
  2. 在 /etc/audit/rules.d/labhub.rules 中写入以键 cron_change 监视 /etc/cron.d 的写入和属性变更的规则,并加载到内核。
  3. 用键 outbound_exec 把只捕获 64 位 execve 中可执行文件为 /usr/bin/curl 的规则加到同一个文件中,并加载。
  4. 创建 /etc/cron.d/nightly-report 并让它调用 curl,手动执行一次 curl 之后,把做了什么写到 /root/det/04-trigger.txt。
  5. 把 ausearch -k outbound_exec -i 的最后一个事件保存到 /root/det/05-evidence.txt,并在其下写出 pid=、exe=、key= 三个值。
  6. 从 journal 中以 JSON 导出 cron 的执行记录,保存到 /root/det/06-cron.json。其中必须包含这台 VM 上每分钟运行的作业(labhub-metrics)的执行行。
  7. 创建 /usr/local/bin/labhub-helper.sh 并赋予执行位,确认 cron_change 这个键不会留下它的记录,把命令、结果和原因写到 /root/det/07-blindspot.txt。
  8. 添加并加载以键 persistence 监视 /usr/local/bin 的规则,再修改一次文件,并在 /root/det/08-closed.txt 中确认记录已经留下。
  9. 把这台主机的检测范围写到 /root/det/09-report.md,分为 ## 무엇이 남는가、## 무엇이 남지 않는가、## 규칙 목록、## 다음에 할 일(韩文,依次意为“留下了什么”“没有留下什么”“规则列表”“接下来要做什么”)四节。

参考

什么处于开启状态

把 auditctl -s 的输出和 systemctl is-active auditd 的结果保存到 /root/det/01-status.txt。其中必须原样包含 enabled 和 backlog_limit 的值。

auditctl -s 会逐行输出内核审计子系统的当前状态。把两条命令的输出接到同一个文件里即可。

监视计划任务目录

在 /etc/audit/rules.d/labhub.rules 中写入一条规则:监视 /etc/cron.d 的写入(w)和属性变更(a),并附上键 cron_change,然后加载到内核。

文件监视规则的形式是 -w <경로> -p <권한> -k <키>(占位符依次为路径、权限、键)。把写在 rules.d 中的内容加载到内核的命令是 augenrules --load,已加载的规则用 auditctl -l 确认。

什么被执行了

用键 outbound_exec 把只捕获 64 位 execve 中可执行文件为 /usr/bin/curl 的规则加到 /etc/audit/rules.d/labhub.rules 中,并加载到内核。

系统调用规则的形式是 -a always,exit -F arch=b64 -S <시스콜> -F <필터> -k <키>(占位符依次为系统调用、过滤条件、键)。按可执行文件路径收窄的过滤字段名是 exe。仅靠文件监视,看不到“什么被执行了”。

制造事件

创建 /etc/cron.d/nightly-report,让它在凌晨三点调用 curl,然后再手动执行一次 curl。并把做了什么用两行以上写到 /root/det/04-trigger.txt。

必须在加载规则之后创建文件,才会留下记录。curl 不需要真的连到任何地方——它被执行过这件事会以 execve 的形式留下来。

取出记录来阅读

把 ausearch -k outbound_exec -i 的最后一个事件保存到 /root/det/05-evidence.txt,并在其下把 pid=、exe=、key= 三个值各写一行。

不加 -i,uid 和系统调用号会以数字显示。只看最后一个事件的话,可以用 awk/sed 只保留 ausearch 结果中最后一个 ---- 分隔符之后的内容,或者用 tail 截取。

在 journal 中找同一个事件

从 journal 中以 JSON 导出 cron 留下的执行记录,保存到 /root/det/06-cron.json。其中必须包含这台 VM 上每分钟运行的作业(labhub-metrics)的 CMD 行。

用 journalctl -t CRON -o json --since "-30 min",每行会输出一个 JSON。如果还没运行,请等 1 分钟后重新导出。

没有监视的位置

创建 /usr/local/bin/labhub-helper.sh 并赋予执行位,确认 ausearch -k cron_change 中不会出现该路径,并把命令、结果和为什么不留记录,用 120 个字符以上写到 /root/det/07-blindspot.txt。

审计规则只看写下的路径。攻击者不需要新建计划任务,只要修改已预约脚本的内容即可。这一步是要亲自确认,那个位置现在处于监视范围之外。

把空缺的位置覆盖起来

把监视 /usr/local/bin 的写入和属性变更、并附上键 persistence 的规则加到 /etc/audit/rules.d/labhub.rules 并加载,再修改一次 labhub-helper.sh,并在 /root/det/08-closed.txt 中确认记录已经留下。

如果把键设为 cron_change,第 7 步中确认的“不会留下”就会被推翻,前面的步骤也会被破坏。新的位置用新的键来覆盖。必须在规则加载之后修改文件,才会留下记录。

把检测范围写成文档

把这台主机现在留下什么、没有留下什么,写到 /root/det/09-report.md,分为 ## 무엇이 남는가、## 무엇이 남지 않는가、## 규칙 목록、## 다음에 할 일(韩文,依次意为“留下了什么”“没有留下什么”“规则列表”“接下来要做什么”)四节。正文中必须出现三个键名和规则文件路径。

在规则列表一节中贴上 auditctl -l 的结果即可。“没有留下什么”是这份文档中最有价值的一节——它能让下一个人不会相信“什么都会留下”。