幽灵在/proc:Linux进程隐藏与时间线篡改技术剖析

本文深入探讨了攻击者如何通过操纵Linux虚拟文件系统/proc来隐藏恶意进程并扭曲取证时间线。内容包括命令替换、启动时间篡改的具体示例,以及为事件响应者和安全分析师提供的检测与防御策略。

引言

在我们之前的博客《藏在眼皮底下:Linux中/proc文件系统操纵技术与防御》中,我们探讨了如何将恶意进程从取证审查工具中隐藏的技术。取证分析师通常依赖Linux虚拟文件系统/proc来枚举进程、重建时间线并将活动归因于特定的可执行文件。诸如pstop和各种审查脚本之类的工具从/proc/<pid>/下的文件中提取进程元数据,包括cmdlinestat。因此,这些文件的完整性对许多事件响应工作流程至关重要。

我们的研究表明,拥有特权访问权限的威胁行为者或某些类型的恶意代码如何操纵/proc视图,以制造误导性的取证伪影。通过改变这个内核接口,威胁行为者可以通过替换显示的命令行参数来混淆进程身份,并破坏诸如记录的进程启动时间等时间数据,从而破坏时间线分析。

关键发现

  • /proc/<pid>/cmdline可以被替换或编辑以显示任意命令字符串,使进程识别复杂化。
  • /proc/<pid>/stat中的starttime字段可以被修改以产生时间线差异,包括破坏事件关联的未来时间戳。
  • 由于操纵需要提升的权限或内核修改,成功的篡改是主机严重被入侵的强烈指标。
  • 单独依赖/proc会增加审查假阴性和归因错误的风险;必须与内核和远程遥测数据进行交叉验证。

技术演练

环境与目标

实验在Linux主机上进行,使用了一个从交互式shell运行的最小测试脚本(“evasion”脚本)。目标有两个:

  1. 演示替换/proc/<pid>/cmdline如何改变ps/top显示的命令字符串。
  2. 强调编辑/proc/<pid>/stat中的starttime字段如何能在转换为人类可读形式时产生时间不一致(包括“未来”)的进程启动时间。

测试过程:小型交互式脚本

目标进程是一个名为evasion的最小脚本:

1
2
3
4
#!/bin/bash
while true; do
    sleep 5
done

启动脚本后,该进程出现在进程列表中(ps aux的示例摘录):

1
2
3
4
USER       PID  %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
...
ubuntu   18316  0.0  0.1  20048  3540 pts/0    S+   22:06   0:00 /usr/bin/bash ./evasion
...

克隆目标进程的/proc数据

我们创建了一个工作区,并将实时的/proc/<pid>字段复制到该工作区:

1
2
3
mkdir /tmp/evil
cp /proc/18316/cmdline /tmp/evil/
cp /proc/18316/stat /tmp/evil/

复制后,工作区的内容为空,直到工件被放置在那里。我们的意图是稍后将该文件夹用作绑定挂载的目标。

通过绑定挂载将克隆的数据覆盖到/proc/

通过将/tmp/evil绑定挂载到/proc/18316上,用户空间工具的内核导出视图可以被重定向到被替换的文件:

1
mount --bind /tmp/evil /proc/18316

绑定后,ps aux不再报告原始的./evasion字符串,因为进程视图已被挂载的工件替换。例如,初始的ps aux显示了该进程,但在挂载工作区后,ps输出不再显示evasion,只出现grep进程。

将编辑后的工件放入挂载的文件夹

接下来,将先前复制的文件写入挂载的文件夹并进行编辑。以下是我们调查期间执行的命令示例。

1
# 此时,读取/proc/18316/cmdline和/proc/18316/stat的用户空间工具将读取存储在/tmp/evil中的版本。evasion进程现在由这些被替换的工件支持。

演示:替换命令字符串

/tmp/evil中的cmdline文件被编辑为包含一个单独的标记safeprocess

1
echo -n 'safeprocess' > /tmp/evil/cmdline

经过此替换后,ps aux显示PID 18316的新命令字符串:

1
2
3
4
USER       PID  %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
...
ubuntu   18316  0.0  0.1  20048  3540 pts/0    S+   22:06   0:00 safeprocess
...

因此,进程名称的实时显示从/usr/bin/bash ./evasion更改为safeprocess,这纯粹是通过替换/proc/18316/cmdline处暴露的cmdline内容实现的。这演示了当攻击者控制导出文件时,基于/proc的识别如何能被轻易欺骗。

Stat工件:原始与解析

stat文件包含许多数字字段。在本实验中,捕获的进程stat行如下:

1
18316 (bash) S 18295 18316 18295 34818 18316 4210944 1047 0 0 0 0 0 0 0 20 0 1 0 48156368 20537344 886 18446744073709551615 94714507956224 94714507958112 140724688591728 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 94714507966880 94714507967952 94714509352960 140724688594835 140724688594850 140724688594850 140724688597224 0

根据proc_pid_stat(5),我们可以将这些数字字段转换为更易理解的顺序:

字段编号 字段名 格式 字段编号 字段名 格式
(1) pid %d (8) tpgid %d
(2) comm %s (9) flags %u
(3) state %c (10) minflt %lu
(4) ppid %d (11) cminflt %lu
(5) pgrp %d (12) majflt %lu
(6) session %d (13) cmajflt %lu
(7) tty_nr %d (14) utime %lu
(15) stime %lu (22) starttime %llu
(16) cutime %ld (23) vsize %lu
(17) cstime %ld (24) rss %ld
(18) priority %ld (25) rsslim %lu
(19) nice %ld (26) startcode %lu [PT]
(20) num_threads %ld (27) endcode %lu [PT]
(21) itrealvalue %ld (28) startstack %lu [PT]

解释这些字段需要参考proc(5);特别是,字段(22)是starttime,即进程在系统启动后开始的时间,以时钟滴答数表示。 为了简化解释,实验使用了一个小型辅助程序procstat将数字字段转换为人类可读的形式。以下是一个示例输出:

1
start_time: 10.12 22:06 (698.43s)

将starttime转换为绝对时间

starttime值必须相对于系统启动时间来解释。在本实验中,系统的正常运行时间捕获如下:

1
2
$ uptime
 22:07:43 up 11 min,  1 user,  load average: 0.00, 0.00, 0.00

使用原始stat文件中存在的starttime数值(48156368),报告显示该进程在观察点之前大约85秒启动(实验室通过_SC_CLK_TCK将时钟滴答转换为秒,并与正常运行时间进行比较的计算)。procstat工具随后报告start_time: 10.12 22:06 (698.43s),说明了原始stat数据如何转换为人类可解释的形式。

篡改starttime以制造时间假情报

为了说明时间线是如何被操纵的,/tmp/evil/stat中的starttime字段从48156368被编辑为98156368

1
2
# 修改 /tmp/evil/stat 中的第22个字段(starttime)
sed -i 's/^\([^ ]*\) [^ ]* [^ ]* [^ ]* [^ ]* [^ ]* [^ ]* [^ ]* [^ ]* [^ ]* [^ ]* [^ ]* [^ ]* [^ ]* [^ ]* [^ ]* [^ ]* [^ ]* [^ ]* [^ ]* [^ ]*\) [^ ]*/\1 98156368/22' /tmp/evil/stat

修改starttime并保持cmdline替换后,ps aux现在报告该PID的日历日期相对于实际系统时间而言是未来的。在我们的测试期间,系统日期/时间为:Sun Oct 12 10:24:07 PM +07 2025。更改starttime后,ps输出为PID 18316显示的进程开始日期为Oct18(即未来的日期)。 这演示了编辑stat记录中的starttime数字字段如何导致工具显示误导性的日历时间戳——有效地将进程“移动”到未来并破坏时间线关联。

结论

/proc伪文件系统是进程自省的一个便捷通道,但在对抗性环境中并非不可变的证据存储。特权参与者可以操纵/proc条目以隐藏身份并破坏时间线重建所依赖的时间数据。有效的检测需要将/proc视为众多证据来源之一,并根据源自内核的遥测数据和远程不可变日志验证进程事件。

检测与防御建议

  • 监控挂载和卸载系统调用:使用auditd或eBPF等工具检测可疑的挂载活动。
  • 对异常的/proc挂载发出警报:如果/proc/[pid]被挂载到tmpfs或任何外部文件系统,则生成警报。
  • 交叉验证/proc数据:将/proc条目与内核和远程遥测源(如auditd、EDR内核事件流、systemd日志时间戳和远程日志)进行比较,以维护可信的时间线。
  • 限制特权访问:应用最小权限原则,强制执行RBAC,并且只允许加载经过签名或授权的内核模块。
  • 实施不可变审计转发:将关键审计日志转发到远程的、一次性写入的存储,以在主机被篡改时保留证据。
  • 启用内核完整性控制:在可能的情况下启用安全启动、内核模块签名和主机证明以确保完整性。
  • 增强审查工具:更新审查脚本,以标记/proc与独立遥测源之间的不一致,并默认将/proc条目视为“不可信”。

常见问题

什么是Linux中的/proc文件系统? `/proc`文件系统是一个虚拟接口,提供关于运行进程和内核参数的详细、实时信息。它被诸如`ps`、`top`和取证脚本等系统工具广泛使用,以从`/proc//`下的文件(包括`cmdline`和`stat`)检索进程元数据。
为什么/proc在数字取证和事件响应中很重要? 在取证调查中,`/proc`是识别运行进程、重建执行时间线以及将活动归因于特定可执行文件的基础来源。分析人员依赖它提供的数据来建立事件期间进程行为和系统状态的上下文。
攻击者如何操纵/proc数据? 拥有提升权限的攻击者可以改变`/proc`视图以隐藏或伪造信息。这可以通过替换`/proc//cmdline`文件来显示任意命令字符串,从而有效地重命名或伪装恶意进程来实现。他们还可以编辑`/proc//stat`文件以修改记录的进程启动时间,甚至将其设置为未来时间戳。这些更改通常通过将备用目录绑定挂载到原始`/proc`路径上来实现,从而重定向用户空间工具所看到的内容。
/proc操纵对调查有何影响? 操纵`/proc`可以通过掩盖进程的真实身份或伪造其执行时间来误导取证工具和分析人员。这种欺骗可能产生不正确或误导性的取证时间线,导致分析人员忽略恶意活动,并导致假阴性或归因错误。
进行这种操纵需要什么级别的访问权限? 编辑`/proc`条目需要root或内核级权限。这意味着成功的操纵是系统严重被入侵的强烈指标,因为普通用户无法修改`/proc`内核导出的数据。
防御者如何检测/proc操纵? 检测需要监控异常系统行为并在多个来源之间验证进程数据。系统管理员应使用`auditd`或eBPF等工具监控挂载和卸载系统调用,并在`/proc/[pid]`被挂载到像`tmpfs`这样的非标准文件系统时生成警报。`/proc`数据与独立遥测(如内核日志、审计记录、EDR事件和systemd日志时间戳)之间的交叉验证可以揭示表明篡改的不一致。
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计