首页/安全/应急响应速查/自定义 systemd 服务排查

自定义 systemd 服务排查

systemd 单元是现役 Linux 最主流的持久化点:列出启用中的单元与 /etc/systemd/system 下的新增文件,逐个确认来源。

应急响应速查安全更新于 2026-10-13

systemd 单元是什么

systemd 是现役主流 Linux 发行版的初始化与服务管理器,所有服务、定时器、socket 都由单元文件描述。排查持久化时必须看它,原因是:单元改动只需一个文件,重启永久生效,而且 systemctl 输出的名字看起来非常「官方」。systemd 按固定优先级读取单元目录,越靠前的目录优先级越高,攻击者通常把文件写进优先级最高的目录,用来覆盖发行版自带的同名单元。

基本信息

搜索优先级/etc/systemd/system 高于 /run/systemd/system 高于 /usr/lib/systemd/system
enable 的本质在目标 target 的 .wants 目录里创建符号链接,文件仍在原目录
修改后必须执行systemctl daemon-reload,否则运行中的实例仍用旧定义
查看单元内容systemctl cat 单元名(含各 drop-in 片段)
单元类型.service 常驻服务、.timer 定时、.socket 套接字激活、.path 路径监控
彻底禁用systemctl mask 会链接到 /dev/null,效果强于 disable

典型使用场景

  • 木马反复被拉起时确认是哪条服务单元在起作用
  • 核对 /etc/systemd/system 下近期新增或修改的单元文件
  • 确认某个服务的实际启动命令与运行账号,判断是否被替换
  • 排查异常监听端口是否为 socket 激活或新增长驻服务
  • 做主机基线时留存启用中的单元清单,便于差异比对

找新增与非包管理单元

找新增与非包管理单元
systemctl list-unit-files --type=service --state=enabled | head -n 50   # 启用中的服务
ls -lt /etc/systemd/system/*.service | head -n 20                        # 按修改时间排,看最新落地的
systemctl cat suspicious.service                                         # 含 drop-in 覆盖片段
systemctl status suspicious.service --no-pager | head -n 20              # 状态与最近日志
systemctl list-timers --all | head -n 20                                 # 定时器是另一条时间线
sudo dpkg -S /etc/systemd/system/xxx.service 2>/dev/null || echo 非包管理文件   # Debian 系反查归属
sudo rpm -qf /usr/lib/systemd/system/xxx.service 2>/dev/null             # RHEL 系反查归属

单元内容重点字段

字段含义异常信号
ExecStart服务启动的实际命令指向 /tmp、/dev/shm、/var/tmp 或随机文件名
User / Group运行身份系统服务以 nobody、www 之外的低权限账号运行并请求高权限行为
Restart退出后的重启策略always 或 on-failure 配合短 RestartSec 形成保活
WantedBy被哪个 target 拉起指向 multi-user.target 之外的非常规 target
Environment / EnvironmentFile环境变量来源从 /tmp 或用户目录加载配置文件
After / Requires依赖关系依赖被替换或被篡改的单元,形成隐蔽的启动链
排查不要只看 enable 状态:run 状态、failed 状态与由 socket 或 timer 触发的单元同样会执行代码。另外 drop-in 覆盖片段(/etc/systemd/system/<单元>.d/*.conf)能在不改原始文件的情况下替换 ExecStart,只看主单元文件会漏掉它。
区分自建单元与包管理单元是判断可疑的高效手段:dpkg -S 或 rpm -qf 能查文件属于哪个包,反查不到归属的单元文件基本都是人工投放的,需要逐个解释来源。

处置与留证

处置与留证
sudo cp -a /etc/systemd/system /evidence/systemd_$(date +%F)/     # 先整目录留证
systemctl cat suspicious.service > /evidence/suspicious_unit.txt   # 单元内容单独存档
sudo systemctl stop suspicious.service                              # 先停再禁,观察业务影响
sudo systemctl disable suspicious.service                           # 解除自启链接
sudo systemctl daemon-reload                                        # 变更后重载管理器
systemctl is-enabled suspicious.service; systemctl is-active suspicious.service   # 验收
禁用之后要复查同名单元是否在 /usr/lib/systemd/system 里还有一份:如果只删了 /etc 下的覆盖文件,重启后会回落到发行版原定义,行为与攻击者的版本完全不同。

清理顺序

  • 复制 /etc/systemd/system 整个目录与可疑单元内容到证据目录,先留证
  • systemctl stop 停止服务,记录停止前后连接与进程的差异,确认它确实是元凶
  • systemctl disable 解除自启链接,避免重启后被重新拉起
  • 删除或清空单元文件与对应的 .d 覆盖片段,随后执行 daemon-reload
  • 复查 list-unit-files、list-timers 与 /etc/systemd/system 下的时间戳,确认没有残留
  • 观察至少一个业务周期,确认没有其他入口把它重新创建出来
用户级单元常被忽略:普通用户用 systemctl --user 也能管理自己的服务与定时器,目录在 ~/.config/systemd/user。以 root 身份执行 systemctl 看不到它们,需要逐用户检查。

复查与验收

复查与验收
systemctl list-unit-files --state=enabled | grep -i suspicious    # 是否还处于启用
systemctl status suspicious.service --no-pager | head -n 5        # 单元是否已消失
ls -lt --time-style=full-iso /etc/systemd/system/ | head -n 10    # 目录时间戳有无新变化
sudo find /etc/systemd /usr/lib/systemd -name '*suspicious*' 2>/dev/null   # 全路径搜残留
systemctl --user list-unit-files 2>/dev/null | head -n 20         # 逐用户检查用户级单元

易错点

  • 只看 running 状态:失败后被反复重启的单元同样在持续执行代码,failed 与 inactive 都要看一遍
  • 漏掉 drop-in 覆盖片段:ExecStart 可以在 .d 目录里被替换,只读主单元文件会得出错误结论
  • 改完单元不 daemon-reload:管理器仍按旧定义运行,清理看起来生效、重启后又回来
  • 用 rm 直接删单元文件:应先 stop 与 disable,并保存内容与时间戳,删除后还要 daemon-reload
  • 把 systemd 当成唯一持久化点:timer、socket、path 单元与用户级单元(systemctl --user)都能触发执行

数据来源与参考

  • systemd.service(5) 手册
  • MITRE ATT&CK T1543.002 Systemd 服务

相关工具

​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌