跳转到帖子

背景

最近整理了一次 Web 服务器可疑文件告警的排查过程,场景并不复杂:业务侧反馈某台 PHP 应用服务器被安全设备提示存在疑似 WebShell 文件,但没有明确说明入口点。类似事件在日常应急里很常见,难点通常不在于“删掉一个可疑文件”,而是要判断它从哪里来、是否被执行过、是否还有持久化或横向痕迹。

这篇文章按一次相对完整的排查链路来写,重点放在防守视角的取证、日志关联、代码审计和加固建议上,不涉及攻击利用细节。

问题场景

已知信息比较有限:

  • 服务器为 Linux,运行 Nginx + PHP-FPM。
  • 业务目录存在近期新增的可疑 PHP 文件。
  • 安全设备提示文件具有 WebShell 特征。
  • 业务方不确定是否存在异常登录或数据泄露。

这类场景建议先不要急着删除文件。直接删除会破坏时间戳、文件内容和权限等取证信息,也可能漏掉其他关联文件。更稳妥的做法是先隔离访问、保全证据,再做关联分析。

初始处置:先控风险,再保全

如果业务允许,优先在网关、WAF 或 Nginx 层面临时限制该站点的外部访问,避免可疑文件继续被触发。对于生产环境,通常不建议立即关机,因为关机会丢失部分内存态和进程信息。可以先做以下保全:

mkdir -p /root/incident-$(date +%F)
cd /root/incident-$(date +%F)

# 记录基本系统信息
date > basic.txt
hostname >> basic.txt
whoami >> basic.txt
uname -a >> basic.txt

# 记录进程、网络连接、登录情况
ps auxww > ps_auxww.txt
ss -antup > ss_antup.txt
last -a > last_login.txt
lastb -a > lastb_login.txt 2>/dev/null
w > w.txt

# 记录计划任务
crontab -l > crontab_current_user.txt 2>/dev/null
ls -lah /etc/cron* > cron_dirs.txt 2>/dev/null

同时对可疑文件做只读复制,保留哈希:

cp -a /var/www/html/path/suspect.php ./suspect.php.copy
sha256sum /var/www/html/path/suspect.php ./suspect.php.copy > suspect_hash.txt
stat /var/www/html/path/suspect.php > suspect_stat.txt

注意不要在原文件上直接使用编辑器打开并保存,避免改变元数据。

技术分析一:确认可疑文件特征

对 WebShell 的初步识别,一般从代码结构、敏感函数、混淆方式和输入来源几方面入手。防守分析中重点不是复现控制效果,而是确认它是否具备远程执行、文件操作、命令执行、信息回显等能力。

常见风险点包括:

  • 动态执行:如 eval、assert、preg_replace 的历史危险用法、create_function 等。
  • 系统调用:如 system、exec、shell_exec、passthru、popen、proc_open。
  • 文件操作:如 file_put_contents、fwrite、unlink、copy、move_uploaded_file。
  • 输入来源:如 $_POST、$_GET、$_COOKIE、php://input。
  • 混淆痕迹:如 base64_decode、gzinflate、str_rot13、chr 拼接、大量不可读变量名。
# 在业务目录内做敏感函数检索,仅用于排查
cd /var/www/html
grep -RIn --exclude-dir=vendor --exclude-dir=node_modules \
  -E "eval\s*\(|assert\s*\(|system\s*\(|exec\s*\(|shell_exec\s*\(|passthru\s*\(|proc_open\s*\(|popen\s*\(|base64_decode\s*\(|gzinflate\s*\(" . > /root/incident-grep.txt

检索结果不能直接等同于木马。很多框架、依赖包或运维脚本也可能使用类似函数。因此要结合文件路径、修改时间、代码风格、提交记录和访问日志判断。比如一个位于 uploads 目录下的 PHP 文件,风险通常高于框架核心目录里的正常代码。

技术分析二:从时间线找入口

入侵排查里,时间线非常关键。先看可疑文件的创建、修改时间,再回溯这一时间点前后的访问日志、错误日志和上传目录变化。

# 查看近期变更的 PHP 文件
find /var/www/html -type f -name "*.php" -mtime -15 -printf "%TY-%Tm-%Td %TH:%TM:%TS %p\n" | sort > recent_php_files.txt

# 查看近期上传目录文件
find /var/www/html -type f -mtime -15 -printf "%TY-%Tm-%Td %TH:%TM:%TS %s %p\n" | sort > recent_all_files.txt

如果文件系统支持,可以进一步查看 ctime。ctime 不是创建时间,而是 inode 元数据变化时间,但在排查中很有参考价值:

stat /var/www/html/path/suspect.php

随后关联 Nginx access log。假设可疑文件修改时间在 10:20 左右,可以提取前后半小时日志:

grep "10/Oct/2026:10:" /var/log/nginx/access.log > access_10h.txt

重点关注以下特征:

  • 是否有上传接口在可疑时间点被访问。
  • 是否有管理后台、插件安装、模板编辑等高风险功能被调用。
  • 是否出现异常 User-Agent、非常规 HTTP 方法或大量 4xx/5xx。
  • 是否从同一 IP 连续访问上传接口和可疑 PHP 文件。
  • 是否存在对配置文件、备份文件、接口文档的探测请求。

如果日志量较大,可以先按状态码、路径、IP 聚合:

# 按 IP 统计访问量
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -nr | head

# 按 URL 聚合,适合先看异常路径
awk '{print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -nr | head -50

# 查看 4xx/5xx 请求
awk '$9 ~ /^[45]/ {print $0}' /var/log/nginx/access.log | head -200

技术分析三:排查上传与文件写入链路

WebShell 落地常见原因包括上传校验不足、后台弱口令、组件漏洞、部署目录权限过大、历史测试脚本遗留等。排查时不建议只盯着一个可疑文件,而要把“文件如何写入”作为核心问题。

可以从以下几个方向检查:

  • 上传接口是否只校验前端或 Content-Type,而没有服务端白名单。
  • 上传后的文件是否保存在 Web 可执行目录下。
  • Nginx 是否错误地将 uploads、attachment、public 等目录交给 PHP 解析。
  • 后台是否存在文件管理、模板编辑、插件安装等功能。
  • 应用日志中是否记录了文件上传、用户登录、后台操作。

一个比较稳妥的 Nginx 加固方式,是禁止上传目录内 PHP 解析:

location ~* ^/(uploads|attachment|static)/.*\.php$ {
    return 403;
}

如果业务允许,更推荐让上传文件使用对象存储或独立静态域名,并确保该域名不具备脚本解析能力。即使上传校验出现疏漏,也能降低直接执行风险。

技术分析四:检查 PHP-FPM 与权限边界

很多服务器被入侵后影响扩大,并不是单个漏洞本身多严重,而是运行权限过大。例如 PHP-FPM 使用高权限用户运行、业务目录整体可写、配置文件包含数据库明文密码且权限过宽。

建议检查 PHP-FPM 运行用户:

ps aux | grep php-fpm | grep -v grep
cat /etc/php-fpm.d/ 2>/dev/null | grep -E "^(user|group)\s*="

再检查 Web 目录权限:

find /var/www/html -type d -perm -0002 -ls > world_writable_dirs.txt
find /var/www/html -type f -perm -0002 -ls > world_writable_files.txt
find /var/www/html -type f -name "*.php" -perm -0200 -ls | head -100

原则上,代码目录不应该被 Web 运行用户随意写入。确实需要写入的目录,如缓存、日志、上传目录,应尽量单独隔离,并禁止脚本执行。

技术分析五:判断是否存在后续动作

确认 WebShell 后,还需要判断是否被访问过、是否执行过异常命令、是否留下持久化。可以从以下位置排查:

  • Nginx access/error log:是否请求过可疑文件。
  • PHP-FPM slow log/error log:是否有异常报错或慢请求。
  • 系统认证日志:是否有异常 SSH 登录、sudo 行为。
  • 计划任务:是否新增异常任务。
  • 启动项:systemd、rc.local、profile 等是否被修改。
  • 临时目录:/tmp、/var/tmp、/dev/shm 是否有异常文件。
# 查找临时目录近期文件
find /tmp /var/tmp /dev/shm -type f -mtime -15 -printf "%TY-%Tm-%Td %TH:%TM:%TS %s %p\n" 2>/dev/null | sort

# 查看系统登录与认证日志,路径按发行版不同可能有差异
grep -Ei "Accepted|Failed|sudo|session" /var/log/auth.log 2>/dev/null | tail -300
grep -Ei "Accepted|Failed|sudo|session" /var/log/secure 2>/dev/null | tail -300

# systemd 服务变更排查
find /etc/systemd/system /usr/lib/systemd/system -type f -mtime -30 -ls 2>/dev/null

如果发现 Web 运行用户发起异常外连,也需要结合 ss 结果、进程启动时间、父子进程关系进一步确认。对于仍在运行的可疑进程,先记录命令行、环境变量、打开文件,再考虑处置:

# 假设 PID 为 1234
cat /proc/1234/cmdline | tr '\0' ' '
ls -lah /proc/1234/cwd /proc/1234/exe
ls -lah /proc/1234/fd | head
cat /proc/1234/environ | tr '\0' '\n' | head

代码审计关注点

如果初步判断入口在业务代码,建议围绕可疑时间点访问过的接口做定向审计,而不是全站盲扫。以文件上传为例,审计重点包括:

  • 扩展名校验是否使用服务端白名单,例如仅允许 jpg、png、pdf 等。
  • 是否校验真实文件内容,避免只看后缀或 MIME。
  • 上传后的文件名是否随机化,是否保留用户原始文件名。
  • 是否允许双后缀、大小写绕过、特殊字符路径。
  • 上传目录是否与代码目录混放。
  • 是否存在任意路径写入、目录穿越或解压缩覆盖问题。

一个更安全的上传处理思路是:服务端白名单扩展名、重新生成文件名、固定存储目录、关闭脚本解析、记录上传审计日志。对于图片类文件,可使用图像库重新编码后再存储,减少夹带非预期内容的风险。

处置与恢复建议

完成证据保全和影响面判断后,再做处置。常见动作包括:

  • 删除或隔离确认恶意的文件,并记录哈希和路径。
  • 修复入口漏洞,例如上传校验、后台弱口令、组件漏洞。
  • 调整目录权限,禁止上传目录脚本执行。
  • 轮换数据库、后台、服务器账号等敏感凭据。
  • 检查同集群、同镜像、同代码仓库是否存在相同问题。
  • 补齐日志留存,避免后续无法追溯。

如果无法确认攻击者是否获得系统权限,建议不要只在原机上“清理一下继续跑”。更稳妥的方式是基于可信镜像重建环境,回滚干净代码和数据,再将修复后的配置上线。

常见误区

  • 只删除 WebShell,不找入口。这样很容易复发。
  • 只看文件修改时间,不关联访问日志。时间线会断。
  • 把 grep 到敏感函数的文件都当木马。容易误判业务代码。
  • 让上传目录继续支持 PHP 解析。修复上传校验也不能替代执行隔离。
  • 忽略凭据轮换。配置文件、环境变量、日志中都可能暴露敏感信息。

总结

WebShell 告警的排查重点不是单点文件识别,而是围绕“落地、执行、扩展、持久化”建立证据链。实际工作中,可以按这条线推进:先隔离和保全,再确认文件特征,随后用时间线关联访问日志和业务日志,最后修复入口并加固权限边界。

长期看,减少这类事件的关键不只是上设备告警,而是把基础防线做好:上传目录不可执行、代码目录最小权限、后台强认证、组件及时更新、日志可追溯。很多入侵并不依赖复杂技巧,往往是几个基础配置同时失守后被放大。

网络流量与边界分析示意图
网络请求、日志与边界流量分析示意

0篇意见

推荐意见

没有意见。

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