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 # 逐用户检查用户级单元