跳转到帖子

背景

这篇整理来自一次站点被植入 WebShell 的应急复盘。目标不是讨论“如何利用”,而是把排查过程、常见痕迹、日志关联方式和后续加固点记录下来,方便以后遇到类似事件时少走弯路。

受影响环境大致是常见的 Java Web 应用,前面有 Nginx 反向代理,后端 Tomcat,业务目录存在文件上传功能。事件表现为:服务器 CPU 偶发升高,站点目录出现异常 JSP 文件,Nginx 访问日志里有少量非常规请求。

建议在授权范围内做排查和复现。本文只覆盖取证、分析和防护,不提供未授权入侵、持久化控制或规避检测的操作。

问题场景

初始告警来自主机侧文件完整性监控:Web 根目录下新增了几个 JSP 文件,文件名看起来像随机字符串,例如 update_2024.jsp、test1.jsp 这类容易混入日常维护文件的命名。

管理员反馈近期没有发布这些文件,也没有临时调试需求。结合访问日志查看,发现这些 JSP 文件被少量外部 IP 请求过,请求时间和文件创建时间接近。

这类事件排查重点一般有几个:

  • 确认异常文件的写入时间、属主、权限和内容特征。
  • 从 Web 日志还原首次访问、上传入口、可疑参数。
  • 确认是否存在命令执行、横向移动、敏感文件读取等后续行为。
  • 清理落点后,定位根因并做长期加固,避免只删文件不修洞。

技术分析

先从文件层面看。Linux 下可以用 stat 查看文件时间,结合应用发布记录判断是否异常:

stat /data/www/app/upload/update_2024.jsp
ls -al --time-style=full-iso /data/www/app/upload/
find /data/www/app -type f -name "*.jsp" -mtime -7 -ls

需要注意,文件的 mtime、ctime 只能作为线索,不能作为绝对证据。攻击者或者异常程序可能修改时间戳;另一方面,运维备份、解压覆盖也会改变时间。更可靠的方式是同时关联 Web 日志、系统审计日志、应用日志。

在 Nginx 场景中,可以先按异常文件名反查请求:

grep -n "update_2024.jsp" /var/log/nginx/access.log*
grep -n "test1.jsp" /var/log/nginx/access.log*

如果日志量比较大,建议按时间窗口筛选。比如文件创建时间在 10:20 左右,可以取前后 30 分钟:

awk '$4 >= "[12/Mar/2024:09:50:00" && $4 <= "[12/Mar/2024:10:50:00" {print}' /var/log/nginx/access.log

不同日志格式下,awk 条件需要调整。实战里我更倾向先用 grep 粗筛 URI、状态码、IP,再导入本地做结构化分析。

日志时间线还原

一次比较完整的时间线通常包含三类请求:

  • 上传入口请求:可能是 /upload、/file/save、/editor/upload 等。
  • 落点访问请求:直接访问新写入的 JSP、PHP、ASP 文件。
  • 后续探测请求:访问系统信息、配置文件、管理接口、压缩包、备份文件等。

可以先统计异常时间窗口内状态码和 URI:

awk '{print $7, $9}' /var/log/nginx/access.log | sort | uniq -c | sort -nr | head -50

如果 Nginx 日志记录了请求体长度、User-Agent、Referer,会更好关联。比如上传请求一般 body_bytes_sent 或 request_length 会明显偏大;落点访问可能返回 200 且响应体较小。

常见可疑特征包括:

  • 上传接口返回 200 或 302 后,很快访问上传目录下的脚本文件。
  • 同一 IP 在短时间内访问多个敏感路径,例如 /WEB-INF/、/actuator/、/.env。
  • User-Agent 异常固定,或者为空,和正常浏览器请求差异明显。
  • URL 参数包含长字符串、编码后的片段、疑似命令关键字。

如果是 Tomcat,可以继续看 catalina.out、应用日志和访问日志。很多上传失败、类型校验异常、业务报错会留在应用日志里,这些信息对定位入口很有用。

异常文件内容分析

拿到 WebShell 或疑似脚本后,不建议直接在生产环境打开执行。可以先复制到隔离环境,使用文本工具和静态分析方式查看。

file update_2024.jsp
sha256sum update_2024.jsp
strings update_2024.jsp | head -50
sed -n '1,120p' update_2024.jsp

分析时关注几个点:

  • 是否包含动态执行相关逻辑,例如反射、脚本引擎调用、进程创建、类加载等。
  • 是否读取请求参数、请求头、Cookie,并将其传入危险函数。
  • 是否对内容做 Base64、URL 编码、字符拼接等混淆。
  • 是否落地其他文件,或连接外部地址下载内容。

以 Java Web 为例,风险点通常集中在:

  • Runtime.getRuntime().exec、ProcessBuilder 这类进程调用。
  • 反射调用 ClassLoader、defineClass 等动态加载逻辑。
  • 使用 javax.script.ScriptEngine 执行脚本。
  • 读写 Web 根目录、临时目录、用户家目录下的文件。

这里不建议把样本直接拿去公网沙箱提交,尤其是业务系统路径、内网地址、密钥片段可能会泄露。可以先本地脱敏,或只提取 hash 和关键行为特征。

根因定位:上传链路是重点

很多 WebShell 事件的根因是文件上传校验不完整。常见问题有:

  • 只校验前端扩展名,后端未校验。
  • 只判断 Content-Type,信任客户端传入的 MIME。
  • 允许上传目录被 Web 容器解析脚本。
  • 上传后文件名可控,路径拼接缺少规范化处理。
  • 富文本编辑器、老旧组件存在已知文件上传漏洞。

代码审计时,可以搜索上传相关入口和危险写文件逻辑:

grep -R "MultipartFile" -n src/main/java
grep -R "transferTo" -n src/main/java
grep -R "FileOutputStream" -n src/main/java
grep -R "getOriginalFilename" -n src/main/java

重点看文件扩展名白名单是否严格,是否使用服务端生成文件名,是否限制保存目录,是否对路径做规范化校验。

一个更稳妥的后端处理思路是:

  • 服务端生成随机文件名,不使用用户原始文件名作为最终路径。
  • 扩展名采用白名单,例如只允许 jpg、png、pdf 等业务必需类型。
  • 结合文件头魔数做二次校验,但不要只依赖魔数。
  • 上传目录不放在 Web 可执行目录下,最好通过对象存储或静态文件服务提供访问。
  • 对上传大小、频率、用户权限做限制。

关键处置步骤

现场处置建议按“保全证据、隔离风险、定位根因、清理恢复、加固验证”的顺序做。不要一上来就直接删除文件,否则时间线和样本证据容易丢。

1. 保全样本和日志

mkdir -p /root/incident-20240312/samples
cp -a /data/www/app/upload/update_2024.jsp /root/incident-20240312/samples/
sha256sum /root/incident-20240312/samples/update_2024.jsp > /root/incident-20240312/hash.txt
cp -a /var/log/nginx/access.log* /root/incident-20240312/
cp -a /var/log/nginx/error.log* /root/incident-20240312/

如果主机上有审计系统或 EDR,也应导出同一时间窗口内的进程、网络连接、文件变更记录。

2. 临时隔离可疑入口

如果确认上传入口存在风险,可以先临时关闭上传功能,或通过网关限制对应接口访问来源。对于已经落地的脚本文件,建议先阻断执行,而不是直接删除。

Nginx 可临时禁止上传目录解析脚本,示例:

location ^~ /upload/ {
    location ~* \.(jsp|jspx|php|asp|aspx)$ {
        return 403;
    }
}

实际配置要结合业务路径调整。Java Web 下更推荐从 Tomcat 或应用部署层面确保上传目录不在可执行路径内。

3. 排查进程和网络连接

WebShell 被访问后,可能触发系统命令、下载工具或反连行为。可以查看异常进程树和网络连接:

ps aux --forest
ss -tunap
lsof -i -P -n
last -a
lastb -a

关注 Web 服务用户启动的异常进程,例如 tomcat、www-data、nginx 用户下出现 shell、下载器、压缩工具、扫描工具等。这里只是排查方向,不建议仅凭进程名判断,需要结合启动时间、父进程、命令行和文件路径。

4. 清理落点与持久化项

清理时除了 Web 根目录,还要看临时目录、计划任务、启动项、SSH 授权密钥等常见持久化位置:

find /data/www/app -type f -mtime -14 -ls
find /tmp /var/tmp -type f -mtime -14 -ls
crontab -l
ls -al /etc/cron.*
ls -al ~/.ssh/authorized_keys

如果存在多台节点,注意不要只清理一台。负载均衡后面的应用节点、共享存储、备份目录都要检查。

5. 修复代码和配置

根因如果是上传校验问题,需要修代码,而不是靠 WAF 规则长期兜底。WAF 可以作为缓解措施,但上传目录可执行、后端校验缺失这类问题必须从应用和部署层解决。

典型配置加固包括:

  • 上传文件存储目录与应用执行目录分离。
  • Web 容器禁止上传目录内脚本解析。
  • 应用进程最小权限运行,不使用 root 启动。
  • 文件写权限按目录收敛,不给整个站点目录写权限。
  • 关闭不必要的管理端口和调试接口。

检测规则和持续监控

事件结束后,建议沉淀一些可复用的检测规则。比如对 Web 根目录新增脚本文件做监控,对上传目录出现可执行扩展名做告警。

find /data/www/app/upload -type f \( -name "*.jsp" -o -name "*.jspx" -o -name "*.php" -o -name "*.asp" -o -name "*.aspx" \) -print

如果使用 auditd,可以对关键目录写入做审计:

auditctl -w /data/www/app/upload -p wa -k web_upload_write
aureport -f -k | grep web_upload_write

生产环境中 auditd 规则要评估性能影响,尤其是高频写目录。更稳妥的方式是结合文件完整性监控、日志平台和主机安全基线统一处理。

代码审计关注点

从长期治理角度,建议把以下点纳入代码审计清单:

审计点风险说明建议
文件名处理使用用户原始文件名可能导致覆盖、路径穿越服务端生成文件名,路径规范化
类型校验仅依赖扩展名或 Content-Type 容易失效白名单、魔数、业务侧多重校验
存储位置上传目录可执行会放大风险放到非 Web 执行目录或对象存储
权限控制任意用户可上传敏感类型文件按角色限制上传能力和频率
异常日志上传失败和拦截缺少记录记录用户、IP、文件名、大小、原因

注意点

  • 不要只看单个 WebShell 文件。一次入侵里可能有多个落点,甚至不同目录下存在备份木马。
  • 不要只依赖文件名判断。很多异常文件会伪装成业务脚本、图片缓存、临时文件。
  • 不要在生产环境直接执行样本。静态分析优先,必要时放到隔离环境。
  • 不要只删文件不修根因。上传链路、组件版本、权限模型都要检查。
  • 不要忽略时间同步。多台服务器时间不一致会影响日志关联。

总结

WebShell 事件的处理核心不是“找到一个文件然后删除”,而是建立完整证据链:异常文件什么时候写入、通过哪个入口写入、被谁访问、执行了什么行为、是否还有其他落点。

从防护角度看,上传目录不可执行、后端严格白名单校验、应用最小权限、关键目录文件监控,是比较基础但有效的措施。应急结束后,把排查命令、时间线、样本 hash、根因代码位置和修复记录沉淀下来,下一次响应效率会高很多。

代码审计与漏洞定位示意图
代码审计、调用链与关键函数定位示意

0篇意见

推荐意见

没有意见。

游客
抱歉,你的帖子内容包括我们不允许的字词。请编辑你的帖子,删除下面高亮的屏蔽字。
添加意见…