言零的博客

一次 Nginx Lua 木马应急响应实录:从移动端跳转博彩站到 root 级入侵溯源

2026 年 06 月 21 日 17:00

事件等级:严重 — 已确认 root 级入侵
攻击链:root SSH 认证登录 → Nginx Lua 木马植入 → 服务脚本持久化 → 日志清洗
持久化方式:init.d 服务脚本回灌 + chattr +i 文件锁定 + 时间戳伪造
处置结果:活跃链路已切断,已知残留已隔离,证据已归档


一、事件概述

某电商站点运维人员收到用户反馈:移动端访问站点时偶发跳转到博彩风格的外部页面,桌面端访问正常。同时该站点通过 CDN 访问时频繁出现 520 错误。

初步排查后确认,这是一次已经落证的服务器侧入侵事件,前端和应用层均无异常。攻击者通过已认证的 root SSH 会话进入系统,在 Nginx 层植入 Lua 恶意模块实现流量劫持,并配合了服务脚本持久化、文件不可变属性锁定和日志清洗等全套反取证手段。

本文脱敏后完整记录此次应急响应的全流程,包括排查思路、取证方法、处置步骤和经验教训。


二、事件影响


三、核心时间线

3.1 首次入侵(约一个月前)

HIDS 记录到一条真实的 root SSH 会话,该会话执行了以下操作:

动作 说明
修改 Nginx 配置文件 操作 proxy.conf 等反向代理配置
植入恶意 Lua 文件 将恶意 WAF 脚本写入 Nginx 相关目录
锁定文件 对植入文件执行 chattr +i 使其不可变
伪造时间戳 修改文件修改时间,掩盖植入时间点
重启 Nginx 执行 nginx -t && /etc/init.d/nginx restart 使木马生效
清洗日志 清空 /var/log/auth.logwtmpbtmp、审计日志
清除痕迹 执行 history -clastlog 清除命令历史和登录记录

从 HIDS 记录判断,这属于「已认证」的入侵行为,攻击者拥有合法的 root 凭据,不存在爆破痕迹。

3.2 第二次落地(事发当天凌晨)

系统出现第二段落地行为:

这已经构成服务重启级的持久化链路:即使当前恶意文件被删除,重启 Nginx 后木马会自动复活。

3.3 应急响应窗口

从用户反馈到完整处置,应急响应推进路径如下:

  1. 复现移动端 UA 与桌面端访问表现差异
  2. 对比应用层日志和 Nginx 访问日志
  3. 确认异常 302 重定向出现在 Nginx 层而非 PHP 应用层
  4. 通过 nginx -T 导出全量配置,顺 Lua 加载路径定位恶意模块
  5. 先备份证据,再替换为 no-op 空壳
  6. 深挖持久化点,确认 init.d 脚本回灌逻辑
  7. 清理认证面、隔离残留样本、打包证据并记录哈希
  8. 复测移动端、桌面端、支付接口和关键服务状态

四、排查分析过程

4.1 区分问题层级

用户报障后,首先要判断异常发生在哪一层:

层级 如果是这层的问题 实际表现
前端 / CDN 缓存 服务端日志仍返回正常 HTML 排除,服务端日志存在异常 302
PHP 应用层 应用代码、路由或日志中能找到跳转逻辑 排除,应用层无异常
Nginx 请求入口层 访问日志出现应用无感知的 302 命中

本次通过移动端 UA 请求复现了 302,并发现跳转参数中包含原始域名和设备类型,说明跳转逻辑在 HTTP 请求入口层,即 Nginx 层被劫持。

4.2 访问日志分析

访问日志中出现了关键特征:

正常路径如 /、/item/1、/products → 间歇性 302,与正常 200 混杂

这个特征非常关键:

4.3 定位 Nginx Lua 加载链

审计 nginx -T 全量配置后,重点排查以下位置:

最终确认活跃恶意模块是一个伪装成正常模块名的 .lua 文件,内容包含:

与线上表现完全一致。

4.4 先取证再处置

本次没有直接删除任何可疑文件。原因:

  1. 直接删除会破坏法证链,无法回溯入侵过程
  2. 直接删除 Lua 文件可能导致仍存在的调用点把 Nginx 打挂
  3. 攻击者使用了 chattr +i、时间戳伪造和重启回灌,单点删除不能解决持久化

处置策略:

4.5 追踪持久化机制

仅替换当前活跃恶意模块后,不能认为修复完成。后续检查发现 init.d 服务脚本已被改造:

这就是木马的复活机制。只要 Nginx 服务重启,远程载荷会重新落地,配置会被重新注入。清理当前文件而不处理服务脚本,等于什么都没修。

4.6 用 HIDS 建立根因证据链

系统日志和 shell history 被清空后,常规取证手段失效。本次的关键证据来自 HIDS(主机入侵检测系统)的日志:

教训:HIDS 日志是日志清洗后唯一可信的证据源,必须保证不被同机单点覆盖,最好外送或异地备份。

4.7 扩展扫描残留

切断已知攻击链后,继续检查:

检查项 内容
进程 当前进程列表、高 CPU 进程
端口 监听端口和对应进程
服务 systemd 启用服务和 timer
定时任务 root 与系统级 crontab
预加载 /etc/ld.so.preload
启动脚本 shell profile、自启动脚本
认证文件 authorized_keys、uid=0 账户
SUID SUID 提权文件
Nginx worker 当前加载的动态库映射
近期变更 最近修改的系统文件
IOC 搜索 恶意模块名、可疑域名、隐藏标记文件

最终确认并隔离了三个残留工件:隐藏标记文件、恶意动态库、异常数据文件。

4.8 认证面收敛(避免自锁)

发现 root 已泄露后,凭据轮换必须做,但不能为了「看起来更安全」直接关闭当前唯一的远程入口。

本次策略:

  1. 清空 root 的 authorized_keys
  2. 隔离未确认但仍需使用的 SSH 密钥
  3. 确认没有其他 uid=0 账户或异常用户的认证文件
  4. 暂时保留 root 密码登录,等待新管理员入口就绪后再关闭

这是安全和可运维之间的必要取舍。没有替代入口时直接关闭 root 登录,只会把正常运维锁在外面。

4.9 四层验证

验证层次 检查内容 结论
配置层 nginx -tnginx -T 全量导出 通过,无语法错误,无恶意 include
运行层 进程、端口、worker 映射库、内核日志 通过,无崩溃,无异常动态库加载
业务层 移动端 UA / 桌面端 UA 访问核心页面 通过,200 正常,无跳转
支付层 支付配置接口、支付回调日志 通过,200 正常

只看服务状态 active 不等于业务可用;只看页面返回 200 也不等于木马已清理。必须四层同时验证。


五、处置措施总结

已执行操作

后续动作

24 小时内:

1-3 天内:

中期:


六、经验教训

1. 偶发跳转必须优先怀疑请求入口层

移动端跳转博彩站、桌面端偶发正常,这是典型的按 UA 或比例触发的流量劫持特征。不能只从前端缓存或应用路由找原因,必须第一时间查 Nginx 层的异常。

2. CDN 520 可能是源站进程崩溃

CDN 的 520 错误表示源站连接异常。本次 520 与恶意 .so 文件导致的 Nginx worker 进程崩溃直接相关。排查 CDN 错误时必须同时看源站内核日志和 worker 状态。

3. 单点删除木马不等于修复

攻击者使用了:

只替换一个恶意文件会留下重启复活的风险,必须深挖持久化链。

4. 证据保存必须早于清理

先打包证据、记录哈希、保留备份,再清理生产路径。否则后续无法解释完整的入侵链,也无法判断是否存在第二阶段攻击。

5. 安全加固不能盲目锁死

关闭 root 密码登录是正确方向,但前提是有可验证的新管理员入口。没有替代入口就直接关闭,等于把自己也锁在门外。

6. HIDS 是日志清洗后唯一的可信证据源

系统日志被清空后,HIDS 日志成为了唯一能证明入侵时间点和攻击行为的关键证据。后续必须保证 HIDS 日志异地存储,不能被同机攻击者一并清理。

7. 运行态问题要和入侵事件分层处理

本次排查中发现的支付反代超时问题,经分析是 Docker 网络配置问题,与 Lua 木马无关。应急响应中必须严格区分:

混为一谈会误导排查方向,浪费时间。


七、应急响应检查清单

以下模板可直接复用于类似事件的排查:

1. 复现用户侧异常
 记录 UA、URL、时间、响应码、跳转目标

2. 分层对比日志
 CDN → Nginx → 应用 → 系统日志,定位异常发生层级

3. 审计 Web 服务器配置
 导出全量配置,检查 Lua/WAF/include/proxy/rewrite/动态模块

4. 搜索 IOC
 关键词搜索,但不要在取证前删除任何文件

5. 取证归档
 对可疑文件做 stat、lsattr、sha256sum、备份归档

6. 检查持久化点
 systemd、init.d、cron、profile、ld.so.preload、Docker entrypoint

7. 检查认证面
 uid=0 账户、authorized_keys、私钥、面板用户、API key

8. 检查运行态
 进程、端口、worker 映射库、内核崩溃日志

9. 最小化清理
 先切断活跃链路,再处理持久化机制和残留文件

10. 重新验证
 配置层 → 运行层 → 业务层 → 支付层,四层全部验证

11. 归档与复盘
 归档证据和哈希,记录回滚点与剩余风险

八、判断边界

可以确认的:

不能百分百确认的:

因此后续安全策略不能停留在「已清理木马」这一步,要按「已发生 root 级入侵后的恢复流程」推进,最终闭环仍是重装系统、重建凭据、重新部署业务。


本文由真实应急响应案例脱敏整理,涉及域名、IP、路径等信息已做匿名化处理。