返回 AI 资讯
安全研究言零的博客

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

联系方式 & 交流群 QQ : 46333839 微信 : GOV-HACK 进微信群请联系博主,各位觉得文章对你有帮助的话可否打赏一些呀~ 事件等级:严重 — 已确认 root 级入侵 攻击链:root SSH 认证登录 → Nginx Lua 木马植入 → 服务脚本持久化 → 日志清洗 持久化方式:init.d 服务脚本回灌 + chattr +i 文件锁定 + 时间戳伪造 处置结果:活跃链路已切断,已知残留已隔离,证据已归档 一、事件概述 某电商站点运维人员收到用户反馈:移动端访问站点时偶发跳转到博彩风格的…

内容摘要

联系方式 & 交流群 QQ : 46333839 微信 : GOV-HACK 进微信群请联系博主,各位觉得文章对你有帮助的话可否打赏一些呀~ 事件等级:严重 — 已确认 root 级入侵 攻击链:root SSH 认证登录 → Nginx Lua 木马植入 → 服务脚本持久化 → 日志清洗 持久化方式:init.d 服务脚本回灌 + chattr +i 文件锁定 + 时间戳伪造 处置结果:活跃链路已切断,已知残留已隔离,证据已归档 一、事件概述 某电商站点运维人员收到用户反馈:移动端访问站点时偶发跳转到博彩风格的外部页面,桌面端访问正常。同时该站点通过 CDN 访问时频繁出现 520 错误。 初步排查后确认,这是一次已经落证的服务器侧入侵事件,前端和应用层均无异常。攻击者通过已认证的 root SSH 会话进入系统,在 Nginx 层植入 Lua 恶意模块实现流量劫持,并配合了服务脚本持久化、文件不可变属性锁定和日志清洗等全套反取证手段。 本文脱敏后完整记录此次应急响应的全流程,包括排查思路、取证方法、处置步骤和经验教训。 二、事件影响 业务层面:移动端用户访问站点时被服务端重定向到外部博彩风格域名,直接影响用户体验和业务信誉。 CDN 层面:CDN 出现间歇性 520 错误,实际叠加了 Nginx worker 进程崩溃风险。 支付链路:排查期间发现支付反代服务偶发超时,经分析属于 Docker 网络桥接配置问题,与 Lua 木马无直接关联。 运维安全:root 密码登录仍处于开放状态,且系统日志被清洗,导致部分入侵入口无法百分百回溯。 三、核心时间线 3.1 首次入侵(约一个月前) HIDS 记录到一条真实的 root SSH 会话,该会话执行了以下操作: 动作 说明 修改 Nginx 配置文件 操作 proxy.conf 等反向代理配置 植入恶意 Lua 文件 将恶意 WAF 脚本写入 Nginx 相关目录 锁定文件 对植入文件执行 chattr +i 使其不可变 伪造时间戳 修改文件修改时间,掩盖植入时间点 重启 Nginx 执行 nginx -t && /etc/init.d/nginx restart 使木马生效 清洗日志 清空 /var/log/auth.log 、 wtmp 、 btmp 、审计日志 清除痕迹 执行 history -c 和 lastlog 清除命令历史和登录记录 从 HIDS 记录判断,这属于「已认证」的入侵行为,攻击者拥有合法的 root 凭据,不存在爆破痕迹。 3.2 第二次落地(事发当天凌晨) 系统出现第二段落地行为: 服务启动脚本 /etc/init.d/nginx 被植入恶意回灌逻辑 出现可疑的 .so 动态库文件 出现隐藏标记文件,内容为木马版本标识 内核日志出现 Nginx worker 进程的段错误 这已经构成服务重启级的持久化链路:即使当前恶意文件被删除,重启 Nginx 后木马会自动复活。 3.3 应急响应窗口 从用户反馈到完整处置,应急响应推进路径如下: 复现移动端 UA 与桌面端访问表现差异 对比应用层日志和 Nginx 访问日志 确认异常 302 重定向出现在 Nginx 层而非 PHP 应用层 通过 nginx -T 导出全量配置,顺 Lua 加载路径定位恶意模块 先备份证据,再替换为 no-op 空壳 深挖持久化点,确认 init.d 脚本回灌逻辑 清理认证面、隔离残留样本、打包证据并记录哈希 复测移动端、桌面端、支付接口和关键服务状态 四、排查分析过程 4.1 区分问题层级 用户报障后,首先要判断异常发生在哪一层: 层级 如果是这层的问题 实际表现 前端 / CDN 缓存 服务端日志仍返回正常 HTML 排除,服务端日志存在异常 302 PHP 应用层 应用代码、路由或日志中能找到跳转逻辑 排除,应用层无异常 Nginx 请求入口层 访问日志出现应用无感知的 302 命中 本次通过移动端 UA 请求复现了 302 ,并发现跳转参数中包含原始域名和设备类型,说明跳转逻辑在 HTTP 请求入口层,即 Nginx 层被劫持。 4.2 访问日志分析 访问日志中出现了关键特征: 正常路径如 /、/item/1、/products → 间歇性 302,与正常 200 混杂 这个特征非常关键: 正常业务跳转通常有稳定规则(如未登录跳登录页) 恶意流量劫持常按设备类型、流量比例、来源 Referer 或时间随机触发 本次恶意 Lua 中确实存在移动端比例控制逻辑,只在部分移动端请求中触发跳转 4.3 定位 Nginx Lua 加载链 审计 nginx -T 全量配置后,重点排查以下位置: lua_package_path — Lua 模块搜索路径 rewrite_by_lua / access_by_lua — 请求阶段 Lua 钩子 include luawaf.conf — WAF 配置文件 Nginx Lua 库目录 WAF 脚本目录 反向代理配置文件 最终确认活跃恶意模块是一个伪装成正常模块名的 .lua 文件,内容包含: 外部博彩风格跳转域名 移动端 UA 识别和比例触发逻辑 远程配置拉取功能 ngx.redirect() 跳转实现 与线上表现完全一致。 4.4 先取证再处置 本次没有直接删除任何可疑文件。原因: 直接删除会破坏法证链,无法回溯入侵过程 直接删除 Lua 文件可能导致仍存在的调用点把 Nginx 打挂 攻击者使用了 chattr +i 、时间戳伪造和重启回灌,单点删除不能解决持久化 处置策略: 将恶意原件保留到证据备份目录 生产路径中的恶意 Lua 替换为同名 no-op 空壳模块 保留导出函数签名,避免隐藏调用点异常 执行 nginx -t 验证配置后再 reload 4.5 追踪持久化机制 仅替换当前活跃恶意模块后,不能认为修复完成。后续检查发现 init.d 服务脚本已被改造: 从外部 URL 拉取远程载荷 向 Nginx 配置文件写入 Lua 钩子 操作 lua_package_path 确保模块加载 操作 ld.so.preload 预加载共享库 配合 chattr +i 保护植入文件 这就是木马的复活机制。只要 Nginx 服务重启,远程载荷会重新落地,配置会被重新注入。清理当前文件而不处理服务脚本,等于什么都没修。 4.6 用 HIDS 建立根因证据链 系统日志和 shell history 被清空后,常规取证手段失效。本次的关键证据来自 HIDS(主机入侵检测系统)的日志: HIDS 中保留了 root SSH 会话记录及命令样本 能证明约一个月前已发生真实入侵 这个证据比猜测 IP 来源、猜测插件漏洞有价值得多 教训: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 已泄露后,凭据轮换必须做,但不能为了「看起来更安全」直接关闭当前唯一的远程入口。 本次策略: 清空 root 的 authorized_keys 隔离未确认但仍需使用的 SSH 密钥 确认没有其他 uid=0 账户或异常用户的认证文件 暂时保留 root 密码登录,等待新管理员入口就绪后再关闭 这是安全和可运维之间的必要取舍。没有替代入口时直接关闭 root 登录,只会把正常运维锁在外面。 4.9 四层验证 验证层次 检查内容 结论 配置层 nginx -t 、 nginx -T 全量导出 通过,无语法错误,无恶意 include 运行层 进程、端口、worker 映射库、内核日志 通过,无崩溃,无异常动态库加载 业务层 移动端 UA / 桌面端 UA 访问核心页面 通过,200 正常,无跳转 支付层 支付配置接口、支付回调日志 通过,200 正常 只看服务状态 active 不等于业务可用;只看页面返回 200 也不等于木马已清理。必须四层同时验证。 五、处置措施总结 已执行操作 将恶意 Lua 模块替换为 no-op 安全空壳 将恶意 WAF 脚本替换为安全空壳 移除 init.d 服务脚本中的恶意回灌逻辑 移除 Nginx 全局配置中的异常 lua_package_path 去除攻击者遗留在相关文件上的 immutable 属性 隔离隐藏标记文件、恶意动态库、异常数据文件 清理 root 本机 SSH 私钥驻留 归档完整事件证据并生成 SHA256 校验值 恢复 Docker bridge 网关,修复支付反代超时问题 后续动作 24 小时内: 持续观察 Nginx 访问日志中的异常状态码 持续观察内核日志中的 worker 崩溃 观察支付链路的稳定性 保存 CDN 安全事件和访问日志 1-3 天内: 新建非 root 管理员用户并配置公钥 验证新入口可用后,关闭 root 密码直接登录 轮换面板密码、API key、部署密钥和数据库密码 将关键日志外送或定时同步到异地 中期: 评估系统重装和业务迁移窗口 用干净系统重新部署服务栈 只迁移业务数据,不迁移旧系统脚本和二进制 建立上线后基线:端口清单、文件哈希、日志保留策略 六、经验教训 1. 偶发跳转必须优先怀疑请求入口层 移动端跳转博彩站、桌面端偶发正常,这是典型的按 UA 或比例触发的流量劫持特征。不能只从前端缓存或应用路由找原因,必须第一时间查 Nginx 层的异常。 2. CDN 520 可能是源站进程崩溃 CDN 的 520 错误表示源站连接异常。本次 520 与恶意 .so 文件导致的 Nginx worker 进程崩溃直接相关。排查 CDN 错误时必须同时看源站内核日志和 worker 状态。 3. 单点删除木马不等于修复 攻击者使用了: 服务脚本持久化(重启复活) chattr +i 文件不可变属性(防删除) 时间戳伪造(掩盖时间线) 日志清洗(销毁证据) 只替换一个恶意文件会留下重启复活的风险,必须深挖持久化链。 4. 证据保存必须早于清理 先打包证据、记录哈希、保留备份,再清理生产路径。否则后续无法解释完整的入侵链,也无法判断是否存在第二阶段攻击。 5. 安全加固不能盲目锁死 关闭 root 密码登录是正确方向,但前提是有可验证的新管理员入口。没有替代入口就直接关闭,等于把自己也锁在门外。 6. HIDS 是日志清洗后唯一的可信证据源 系统日志被清空后,HIDS 日志成为了唯一能证明入侵时间点和攻击行为的关键证据。后续必须保证 HIDS 日志异地存储,不能被同机攻击者一并清理。 7. 运行态问题要和入侵事件分层处理 本次排查中发现的支付反代超时问题,经分析是 Docker 网络配置问题,与 Lua 木马无关。应急响应中必须严格区分: 安全事件(入侵、木马、持久化) 运行态故障(网络、配置漂移、资源耗尽) 业务 Bug(代码逻辑、支付流程) 混为一谈会误导排查方向,浪费时间。 七、应急响应检查清单 以下模板可直接复用于类似事件的排查: 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 SSH 入侵行为 存在 Nginx 服务脚本级持久化机制 移动端博彩跳转来自服务端 Nginx Lua 恶意模块 恶意动态库与 Nginx worker 进程崩溃相关 已知活跃链路已切断,已知残留已隔离 不能百分百确认的: 最初 root 凭据是如何泄露的 是否还存在未知 rootkit 或内核级隐藏组件 不同时间点的两次操作是否完全同源 不重装系统的情况下机器是否永远可信 因此后续安全策略不能停留在「已清理木马」这一步,要按「已发生 root 级入侵后的恢复流程」推进,最终闭环仍是重装系统、重建凭据、重新部署业务。 本文由真实应急响应案例脱敏整理,涉及域名、IP、路径等信息已做匿名化处理。

资讯来源

言零的博客

原文链接

打开原文