宝塔环境 Nginx sub_filter 广告注入 / LD_PRELOAD 劫持排查与清理

Nginx 服务器出现 nginx 总配置被注入 sub_filter(向 </head> 插脚本)或出现 LD_PRELOAD=/usr/local/lib/\*.so 这类劫持,可以实行先止血再找根源,以下是我的操作经验,以供参考。


宝塔环境 Nginx sub_filter 广告注入 / LD_PRELOAD 劫持排查与清理

0. 操作原则(非常重要)

  1. 先止血,再清理:先让“每分钟回写/注入”停下来,再做删除/改名/卸载。
  2. 先备份再改/etc/profile/etc/bash.bashrc、systemd unit 文件等,先 cp -a 备份。
  3. 尽量用“改名 .DISABLED”代替 rm:可回滚、也更利于留证取证。
  4. 遇到 Operation not permitted:root 也无法删除/改名,极大概率是被 chattr +i(immutable)锁住,先 lsattrchattr -i

1. 现象确认:Nginx 是否还有注入残留

1.1 全盘搜索注入特征(常见关键词)

grep -R "sub_filter '</head>'" -n /www/server/nginx/conf /www/server/panel/vhost/nginx /etc/nginx 2>/dev/null
grep -R "sub_filter_types" -n /www/server/nginx/conf /www/server/panel/vhost/nginx /etc/nginx 2>/dev/null
grep -R "sub_filter_once" -n /www/server/nginx/conf /www/server/panel/vhost/nginx /etc/nginx 2>/dev/null
grep -R "hasVisited" -n /www/server/nginx/conf /www/server/panel/vhost/nginx /etc/nginx 2>/dev/null
grep -R "atob(" -n /www/server/nginx/conf /www/server/panel/vhost/nginx /etc/nginx 2>/dev/null

3. 追溯“是谁改的”:从系统日志反推作案进程

这一步是关键:你需要找到“修改 nginx.conf 的进程名”。

3.1 在日志里反查 nginx.conf 相关记录

宝塔环境 Nginx sub_filter 广告注入 / LD_PRELOAD 劫持排查与清理
grep -R "nginx.conf" -n /var/log 2>/dev/null | tail -n 120

如果看到类似(示例):

  • employer[xxxx]: 配置文件: /www/server/nginx/conf/nginx.conf
  • ... nginx 劫持成功 / 流量劫持 / LD_PRELOAD (libemployer.so)

则基本可以判定:这是 systemd + LD_PRELOAD 的流量劫持程序 在回写并注入。


4. 定位恶意入口:systemd timer/service 与 LD_PRELOAD

4.1 找可疑 systemd 服务和定时器

#系统“安装了哪些单位文件/是否开机启用”
systemctl list-unit-files | grep -Ei 'employer|guard|tamper|protect|agent|watch|bt'
#这些服务当前“在不在跑”
systemctl list-units --type=service --all | grep -Ei 'employer|guard|tamper|protect|agent|watch|bt'
#定时器“有没有触发过/上次何时触发”
systemctl list-timers --all | grep -Ei 'employer|guard|tamper|protect|agent|watch|bt'

高危特征:timer 触发频率非常高(例如每 1 分钟)。

宝塔环境 Nginx sub_filter 广告注入 / LD_PRELOAD 劫持排查与清理

4.2 检查当前会话是否被 LD_PRELOAD 污染

echo "$LD_PRELOAD"

4.3 全盘搜 LD_PRELOAD 被写入在哪里(/etc 重点)

grep -R "LD_PRELOAD" -n /etc /www/server 2>/dev/null | head -n 200

4.4 检查“硬入口” /etc/ld.so.preload

cat /etc/ld.so.preload 2>/dev/null || echo "no /etc/ld.so.preload"

5. 止血:先停掉定时器/服务,再清掉 LD_PRELOAD(入口优先)

以下以你遇到的 employer 为例。其他名字同理替换。

5.1 先停止、禁用、mask

systemctl stop employer.service employer.timer 2>/dev/null || true
systemctl disable employer.timer 2>/dev/null || true
systemctl mask employer.service 2>/dev/null || true

验证是否真的停了:

systemctl status employer.service employer.timer --no-pager
systemctl list-timers --all | grep -i employer || echo "no employer timers"

5.2 清理 /etc/profile 中的 LD_PRELOAD(先备份)

cp -a /etc/profile /root/profile.bak.$(date +%F_%H%M%S)
sed -i '/LD_PRELOAD/d;/libemployer\.so/d' /etc/profile
grep -n "LD_PRELOAD" /etc/profile || echo "LD_PRELOAD cleared in /etc/profile"

注意:改 /etc/profile 只影响“新会话”,当前会话要立刻解除:

unset LD_PRELOAD
echo "$LD_PRELOAD"

6. 取证与隔离:找到二进制与 so,把它们“改名禁用”

6.1 定位二进制(例:/usr/sbin/employer)

sudo find / -xdev -type f -name "employer" 2>/dev/null | head -n 50

6.2 备份到隔离目录

mkdir -p /root/quarantine_employer
cp -a /usr/sbin/employer /root/quarantine_employer/employer.bin 2>/dev/null || true
cp -a /usr/local/lib/libemployer.so /root/quarantine_employer/libemployer.so 2>/dev/null || true

6.3 改名禁用(如遇禁止操作先解 immutable)

尝试改名:

mv /usr/sbin/employer /usr/sbin/employer.DISABLED
mv /usr/local/lib/libemployer.so /usr/local/lib/libemployer.so.DISABLED

如果报错 Operation not permitted(极常见),先查锁并解锁:

lsattr /usr/sbin/employer /usr/local/lib/libemployer.so
chattr -i /usr/sbin/employer /usr/local/lib/libemployer.so

再重试改名。

验证:

ls -lah /usr/sbin/employer /usr/local/lib/libemployer.so 2>/dev/null || echo "original paths are gone"
ls -lah /usr/sbin/employer.DISABLED /usr/local/lib/libemployer.so.DISABLED 2>/dev/null || true

7. 断根:彻底移除 systemd 的 unit/timer(注意 mask 与 immutable)

7.1 找 unit 文件位置

ls -lah /lib/systemd/system/employer.* /etc/systemd/system/employer.* 2>/dev/null || true
systemctl list-unit-files | grep -i employer || true

常见情况:

  • /etc/systemd/system/employer.service -> /dev/null:这是 mask 的黑洞软链
  • 真正 unit 在 /lib/systemd/system/employer.service.timer

7.2 备份 unit 文件留证

mkdir -p /root/quarantine_employer/systemd
cp -a /lib/systemd/system/employer.service /root/quarantine_employer/systemd/employer.service 2>/dev/null || true
cp -a /lib/systemd/system/employer.timer   /root/quarantine_employer/systemd/employer.timer 2>/dev/null || true

7.3 删除 mask 软链 + 删除 unit(如删不了先 chattr -i)

# 停止并解除 mask
systemctl stop employer.timer employer.service 2>/dev/null || true
systemctl disable employer.timer 2>/dev/null || true
systemctl unmask employer.service 2>/dev/null || true

# 删除 mask 软链(如果存在)
rm -f /etc/systemd/system/employer.service 2>/dev/null || true

# 若 unit 文件删除报 Operation not permitted,先解锁
lsattr /lib/systemd/system/employer.service /lib/systemd/system/employer.timer 2>/dev/null
chattr -i /lib/systemd/system/employer.service /lib/systemd/system/employer.timer 2>/dev/null || true

# 删除 unit 文件
rm -f /lib/systemd/system/employer.service /lib/systemd/system/employer.timer 2>/dev/null || true

# 刷新 systemd
systemctl daemon-reload
systemctl reset-failed

验证彻底消失:

systemctl list-unit-files | grep -i employer || echo "no employer unit files"
systemctl list-timers --all | grep -i employer || echo "no employer timers"

8. 清掉第二入口:/etc/bash.bashrc 与伪造文件 /etc/profilefile + libintegrity.so

即使 /etc/profile 清了,也可能在 /etc/bash.bashrc 残留 preload。

8.1 清理 /etc/bash.bashrc(先备份)

# 先看看相关区段
nl -ba /etc/bash.bashrc | sed -n '60,90p'

# 备份并删除 LD_PRELOAD 行
cp -a /etc/bash.bashrc /root/bash.bashrc.bak.$(date +%F_%H%M%S)
sed -i '/LD_PRELOAD/d;/libemployer\.so/d' /etc/bash.bashrc

# 验证
grep -n "LD_PRELOAD" /etc/bash.bashrc || echo "LD_PRELOAD cleared in bash.bashrc"

验证新 shell 环境:

bash -lc 'echo "LD_PRELOAD=$LD_PRELOAD"'

8.2 处理可疑伪造入口 /etc/profilefile(如存在)

检查内容:

ls -lah --time-style=full-iso /etc/profilefile 2>/dev/null || true
sed -n '1,120p' /etc/profilefile 2>/dev/null || true

如果里面是重复 export LD_PRELOAD=/usr/local/lib/libintegrity.so(你遇到的情况),按下面清理:

cp -a /etc/profilefile /root/profilefile.bak.$(date +%F_%H%M%S)
sed -i '/LD_PRELOAD/d' /etc/profilefile
wc -l /etc/profilefile
cat -n /etc/profilefile

再隔离 libintegrity.so(同 employer 处理方式):

mkdir -p /root/quarantine_employer
cp -a /usr/local/lib/libintegrity.so /root/quarantine_employer/libintegrity.so 2>/dev/null || true
chattr -i /usr/local/lib/libintegrity.so 2>/dev/null || true
mv /usr/local/lib/libintegrity.so /usr/local/lib/libintegrity.so.DISABLED
ls -lah /usr/local/lib/libintegrity.so 2>/dev/null || echo "libintegrity.so original path is gone"

验证新 shell:

bash -lc 'echo "LD_PRELOAD=$LD_PRELOAD"'

备注:你当时 grep -R "/etc/profilefile" -n /etc 是空的,这说明它可能是“残留后门文件”(入口曾存在但后来改动/被清理),这类文件仍建议清空与隔离对应 so。


9. 最终验证(必须做)

9.1 Nginx 配置不再被回写(mtime 不变)

stat /www/server/nginx/conf/nginx.conf
sleep 90
stat /www/server/nginx/conf/nginx.conf

两次 Modify/Change 完全一致 → 回写链路断。

9.2 全局不存在 sub_filter 注入

grep -R "sub_filter" -n /www/server/nginx/conf /www/server/panel/vhost/nginx /etc/nginx 2>/dev/null || echo "no sub_filter found"

9.3 新 shell 不再出现 LD_PRELOAD

bash -lc 'echo "LD_PRELOAD=$LD_PRELOAD"'

9.4 systemd 中不再存在 employer unit/timer

systemctl list-unit-files | grep -i employer || echo "no employer unit files"
systemctl list-timers --all | grep -i employer || echo "no employer timers"
ls -lah /etc/systemd/system/employer.service 2>/dev/null || echo "no masked symlink"

10. 复发防护(建议你下一轮立刻做)

你清掉的是“作案工具链”,但对方能放进来说明入口未修补。

10.1 宝塔面板(强烈建议)

  • 改宝塔登录密码(强复杂度)
  • 改面板端口
  • 面板端口仅放行你的固定 IP(云安全组 + 防火墙)

10.2 SSH(强烈建议)

  • 禁用密码登录改密钥(或至少 fail2ban)
  • 检查成功登录记录(Ubuntu/Debian)
last -a | head -n 50
grep "Accepted" /var/log/auth.log | tail -n 100

(CentOS/Rocky/Alma)

last -a | head -n 50
grep "Accepted" /var/log/secure | tail -n 100

10.3 最小化权限与 include 风险

  • 确保网站运行用户(www/nginx/www-data)没有/www/server/nginx/ 的权限
  • 检查 nginx.conf 是否 include 了任何“可被 web 写”的目录(危险)

附:一键快速排查脚本块(手动执行版)

A. 查注入

grep -R "sub_filter" -n /www/server/nginx/conf /www/server/panel/vhost/nginx /etc/nginx 2>/dev/null

B. 查 LD_PRELOAD

echo "Current LD_PRELOAD=$LD_PRELOAD"
grep -R "LD_PRELOAD" -n /etc /www/server 2>/dev/null | head -n 200
cat /etc/ld.so.preload 2>/dev/null || echo "no /etc/ld.so.preload"
bash -lc 'echo "New shell LD_PRELOAD=$LD_PRELOAD"'

C. 查 systemd 高频定时器

systemctl list-timers --all | head -n 120

D. 查 nginx.conf 是否仍被回写

stat /www/server/nginx/conf/nginx.conf
sleep 90
stat /www/server/nginx/conf/nginx.conf
Linux运维

Linux系统盘被塞满如何快速删除垃圾文件恢复系统

2025-11-17 16:24:42

Linux运维

Linux源码安装ab压测工具

2025-12-14 13:57:58

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索