背景
WebShell 排查是应急响应里比较常见、也比较容易被低估的一类工作。很多站点被入侵后,最先看到的不是漏洞利用过程,而是异常文件、异常进程、可疑访问日志或者主机告警。真正难的地方在于:如何判断 WebShell 是否仍然可用、攻击入口在哪里、是否存在持久化和横向扩散。
这篇文章整理的是一次较典型的内网 Web 服务器排查思路,重点放在文件分析、日志关联、代码审计和处置闭环上。内容尽量偏方法论,不涉及攻击利用引导,适合做日常排查清单参考。
场景描述
某业务系统部署在 Linux 主机上,技术栈为 Nginx + PHP-FPM,应用目录存在历史遗留代码和多个上传功能。安全设备告警显示:某 PHP 文件存在高危木马特征,同时 Web 访问日志中出现少量异常 POST 请求。
初步信息如下:
- 异常文件位于业务上传目录下,扩展名为
.php。 - 文件修改时间集中在凌晨低峰期。
- 访问来源 IP 较少,但 User-Agent 不稳定。
- 业务目录中存在多个可写目录,权限管理较粗。
排查目标
这类事件不建议只删除单个可疑文件就结束。比较稳妥的目标应该包括:
- 确认 WebShell 的数量、位置和影响范围。
- 判断是否存在同类变种、隐藏文件或后门逻辑。
- 定位可能的上传入口或代码缺陷。
- 确认是否有命令执行、文件写入、数据库访问等后续行为。
- 完成修复、加固和复盘,避免再次落地。
第一步:保护现场与基础取证
发现可疑文件后,建议先不要直接编辑或删除。可以先做副本留存,并记录文件元信息。这样后续关联时间线、确认入侵窗口时会更可靠。
cd /var/www/html
# 记录可疑文件信息
stat uploads/avatar/2024/xx.php
sha256sum uploads/avatar/2024/xx.php
ls -alh uploads/avatar/2024/xx.php
# 只读方式备份
mkdir -p /root/ir_backup/webshell_sample
cp -a uploads/avatar/2024/xx.php /root/ir_backup/webshell_sample/如果环境允许,建议同时备份相关日志,避免日志轮转导致证据丢失。
mkdir -p /root/ir_backup/logs
cp -a /var/log/nginx/access.log* /root/ir_backup/logs/
cp -a /var/log/nginx/error.log* /root/ir_backup/logs/
cp -a /var/log/php-fpm/*.log /root/ir_backup/logs/ 2>/dev/null注意:线上业务环境处理时要控制动作范围。大规模递归扫描、压缩全站文件、直接重启服务,都可能影响业务或破坏现场。
第二步:文件层面排查
WebShell 常见特征包括混淆函数、动态执行、异常编码、短变量名、非业务路径 PHP 文件等。但不能只依赖关键字判断,因为很多正常框架也会使用反射、回调或序列化相关能力。
可以从可写目录开始查找异常 PHP 文件:
# 查找最近 7 天变更的 PHP 文件
find /var/www/html -type f -name "*.php" -mtime -7 -print
# 查找上传目录中的 PHP 文件
find /var/www/html/uploads -type f \( -name "*.php" -o -name "*.phtml" -o -name "*.phar" \) -print
# 查找隐藏文件和非常规扩展
find /var/www/html/uploads -type f -name ".*" -print再结合关键函数做初筛:
grep -RIn --include='*.php' -E "eval\s*\(|assert\s*\(|system\s*\(|shell_exec\s*\(|passthru\s*\(|proc_open\s*\(|popen\s*\(|base64_decode\s*\(|gzinflate\s*\(" /var/www/html 2>/dev/null这里需要注意两点:
base64_decode、gzinflate并不天然等于恶意代码,需要结合上下文。- 有些 WebShell 会用字符串拼接、变量函数、字符编码等方式规避简单 grep,需要人工复核。
第三步:样本代码分析要点
分析可疑 PHP 文件时,可以先不执行代码,优先静态阅读。常见关注点如下:
- 是否读取了请求参数,例如
$_POST、$_GET、$_REQUEST、php://input。 - 是否存在动态函数调用,例如
$func($arg)。 - 是否存在解码、解压、拼接后再执行的逻辑。
- 是否有文件写入、删除、目录遍历、命令执行相关调用。
- 是否伪装成图片、缓存、模板、日志文件。
例如某些后门会把关键函数拆开拼接,静态特征不明显:
$a = 'ba' . 'se64' . '_decode';
$b = 'cre' . 'ate' . '_function';
$c = $a($_POST['x']);
$b('', $c);这类代码的核心风险不在于某个单独函数,而在于“外部输入经过处理后进入动态执行路径”。代码审计时应重点标记这条数据流。
第四步:日志关联分析
文件确认后,需要反查访问日志。可以从文件名、目录名、修改时间附近入手。
# 根据可疑文件名定位访问记录
grep "xx.php" /var/log/nginx/access.log*
# 查看某时间段附近的访问情况
zgrep "12/Mar/2024:02:" /var/log/nginx/access.log* | head -n 50
# 统计访问可疑文件的来源 IP
zgrep "xx.php" /var/log/nginx/access.log* | awk '{print $1}' | sort | uniq -c | sort -nr分析日志时建议关注这些字段:
- 首次访问时间:可能接近文件上传或验证时间。
- 请求方法:异常文件如果大量接收 POST,风险较高。
- 状态码:200、500、403 都有意义,500 可能是执行失败或环境不匹配。
- Referer:若来自上传接口或后台页面,可能指向入口。
- User-Agent:脚本化访问通常较杂乱,但不能单独作为判断依据。
如果 Nginx 日志没有记录请求体,可以结合 PHP-FPM slowlog、应用日志、安全设备日志进一步确认是否发生过命令执行或文件操作。
第五步:定位入口漏洞
WebShell 落地通常离不开文件写入能力。常见入口包括上传校验缺陷、后台编辑模板、任意文件写入、解压缩目录穿越、插件漏洞、弱口令后台等。
以上传功能为例,审计时可以检查:
- 是否只依赖前端校验文件类型。
- 后端是否只检查扩展名,未验证 MIME 和文件内容。
- 是否允许上传到 Web 可执行目录。
- 是否存在双扩展名、大小写扩展、特殊后缀解析问题。
- 文件名是否由用户完全控制。
- 是否存在历史兼容配置导致上传目录可执行 PHP。
Nginx + PHP-FPM 场景下,还要检查 PHP 解析范围是否过宽。例如不应让上传目录中的脚本被 PHP-FPM 处理。可以通过 location 策略限制:
location ^~ /uploads/ {
types { }
default_type application/octet-stream;
add_header X-Content-Type-Options nosniff;
location ~ \.php$ {
return 403;
}
}如果业务允许,更推荐上传文件使用对象存储或独立静态域名,并确保该位置没有脚本执行能力。
第六步:主机侧检查
确认 WebShell 后,还需要判断攻击者是否进一步操作主机。可以检查进程、计划任务、启动项、临时目录和账号变化。
# 查看异常进程
ps auxf
# 查看网络连接
ss -tunap
# 检查计划任务
crontab -l
ls -al /var/spool/cron/ /etc/cron.* 2>/dev/null
# 检查近期修改文件
find /tmp /var/tmp /dev/shm -type f -mtime -7 -ls 2>/dev/null
# 检查登录记录
last -a | head
lastlog | head如果发现异常下载器、反连进程、挖矿程序或陌生账号,需要扩大响应范围。单纯清理 Web 目录已经不够,应考虑主机隔离、凭据轮换和镜像级取证。
第七步:清理与加固
处置阶段建议按顺序进行,避免清理了文件但入口还在,导致短时间内再次被写入。
- 先确认入口漏洞,临时下线或限制对应功能。
- 备份样本和日志后清理 WebShell 及同类文件。
- 修复上传、文件写入、模板编辑等危险功能。
- 调整上传目录权限,禁止脚本执行。
- 检查 Web 目录属主属组,避免 Web 用户拥有不必要写权限。
- 轮换后台账号、数据库账号、服务器账号等敏感凭据。
- 补充监控规则,覆盖新增 PHP 文件、异常 POST、可写目录变更。
权限收敛示例:
# 示例:代码目录只读,上传目录单独可写
chown -R root:root /var/www/html
find /var/www/html -type d -exec chmod 755 {} \;
find /var/www/html -type f -exec chmod 644 {} \;
chown -R www-data:www-data /var/www/html/uploads
find /var/www/html/uploads -type d -exec chmod 750 {} \;
find /var/www/html/uploads -type f -exec chmod 640 {} \;权限配置需要结合实际部署用户调整。不要机械复制命令到生产环境,尤其是多应用共用目录的老环境。
常见误区
- 只删文件不修入口:这是最常见的复发原因。
- 只看 WebShell,不看日志时间线:容易漏掉横向移动和二次投放。
- 完全依赖特征扫描:混淆样本、业务混杂代码会带来漏报和误报。
- 没有保留样本和日志:后续复盘、定责、规则沉淀都会受影响。
- 把上传目录放在可执行路径:这是 WebShell 落地后可用的关键条件之一。
建议的长期监控点
| 监控项 | 价值 | 建议 |
|---|---|---|
| Web 目录新增脚本 | 发现异常落地文件 | 重点监控 uploads、cache、tmp、template |
| 异常 POST 请求 | 识别后门交互行为 | 关注低频但固定路径的 POST |
| PHP 危险函数调用 | 辅助发现命令执行 | 结合 EDR、审计日志分析 |
| 可写目录权限变化 | 发现持久化准备动作 | 对 Web 用户可写范围做基线 |
| 计划任务变化 | 发现主机持久化 | 记录 crontab 和系统 cron 变更 |
总结
WebShell 排查不是“找到一个可疑文件并删除”这么简单。比较可靠的处理方式,是把文件样本、访问日志、代码入口、主机行为串成一条时间线,再围绕入口修复和权限收敛做闭环。
实际工作中,建议沉淀三类东西:一是可写目录和脚本执行权限基线,二是上传和文件写入功能的审计清单,三是适合自身业务的日志检索规则。这样下次遇到类似事件时,排查效率会高很多,也更容易判断影响范围。
推荐意见