背景
这篇整理来自几次应急排查中的共性经验:业务站点突然出现异常文件、可疑进程或被搜索引擎标记风险,最后追溯到上传点、后台弱口令、插件漏洞或历史遗留接口。很多复盘文章会直接给 IOC 或处置结论,但真正有长期价值的是把排查路径沉淀下来,方便下次遇到类似情况时能快速缩小范围。
本文只讨论防守视角下的日志分析、样本识别、代码审计和加固方法,不涉及攻击利用细节。示例命令也以本地自查和取证为主。
问题场景
常见的 WebShell 入侵现场通常会有几个信号:
- Web 目录下出现异常 PHP、JSP、ASPX 文件,文件名看似正常,例如 cache.php、config_old.php、upload_tmp.php。
- 访问日志中存在少量 POST 请求,响应码为 200,User-Agent 非常规,访问路径集中在上传目录或插件目录。
- 服务器上出现可疑外连、异常计划任务、临时目录中的脚本文件。
- 业务代码近期没有发布,但文件修改时间集中在某个时间窗口。
复盘时建议先明确三个问题:入口在哪里、落地文件是什么、后续动作有哪些。不要一开始就急着删除文件,否则容易丢失时间线和证据。
第一步:保护现场与划定时间窗口
如果条件允许,先做磁盘快照或至少备份 Web 目录、日志目录、系统任务配置。对线上服务压力较大时,可以先导出关键文件,不建议直接在原文件上操作。
常用的第一轮时间线排查:
find /var/www -type f -mtime -7 -printf '%TY-%Tm-%Td %TT %p\n' | sort
find /var/www -type f -newermt '2024-01-01 00:00:00' ! -newermt '2024-01-02 00:00:00' -ls
stat /var/www/html/uploads/cache.php这里重点看两类文件:一是上传目录中的可执行脚本,二是业务代码目录中最近被改动的核心文件。很多后门不会新建文件,而是追加到已有文件末尾,尤其是入口文件、配置文件、模板缓存文件。
第二步:从访问日志反推落点
WebShell 的访问通常有一些特征:请求频率不一定高,但路径稳定;方法以 POST 为主;参数名可能很短;响应体大小相对固定。可以先按时间窗口过滤访问日志。
grep '01/Jan/2024' /var/log/nginx/access.log | grep 'POST' > /tmp/post.log
awk '{print $1,$4,$6,$7,$9,$10,$12}' /tmp/post.log | sort | uniq -c | sort -nr | head -50如果是 Nginx,默认日志不记录 POST body,所以不能指望仅靠 access.log 还原所有细节,但足够定位路径、IP、时间和状态码。可进一步聚合可疑路径:
awk '{print $7}' /tmp/post.log | sort | uniq -c | sort -nr | head -30排查时不要只盯 200,部分探测、上传失败、目录扫描会落在 403、404、500。它们对确认入口同样有价值。
第三步:识别 WebShell 与变形痕迹
简单的关键字搜索仍然有用,但不要只依赖单个特征。建议结合文件位置、修改时间、代码风格和危险函数使用情况综合判断。
grep -RIn --include='*.php' -E 'eval\s*\(|assert\s*\(|base64_decode\s*\(|gzinflate\s*\(|shell_exec\s*\(|passthru\s*\(|proc_open\s*\(' /var/www 2>/dev/nullPHP 场景中,经常看到的风险点包括:
- 动态执行:eval、assert、preg_replace /e、create_function。
- 命令执行:system、exec、shell_exec、passthru、proc_open、popen。
- 编码混淆:base64_decode、str_rot13、gzinflate、gzuncompress 多层嵌套。
- 文件操作:file_put_contents、fopen、fwrite 配合外部输入。
但需要注意,很多正常框架也会使用反射、缓存、序列化和文件写入,不能看到关键字就直接判定后门。比较可靠的判断方式是:外部输入是否未经约束进入动态执行或文件写入链路。
例如下面这种模式就需要重点关注:
// 风险模式示意:不要在业务中使用
$action = $_POST['action'] ?? '';
$data = $_POST['data'] ?? '';
if ($action === 'run') {
eval($data);
}实际样本通常不会这么直白,可能通过变量拼接、函数名拆分、编码还原等方式隐藏。审计时可以先格式化代码,再追踪输入源和危险汇点。
第四步:定位入口而不是只清理后门
只删除 WebShell 不解决问题。入口没有修复,文件很快会再次出现。常见入口可以按优先级排查:
- 上传功能:是否允许上传脚本后缀,是否只做前端校验,是否存在双后缀、MIME 信任、解析配置错误。
- 后台入口:是否存在弱口令、默认账号、暴露在公网的管理面板。
- 第三方组件:CMS 插件、编辑器、文件管理器、历史版本框架。
- 任意文件写入:模板编辑、日志写入、缓存生成、导入导出功能。
- 反序列化链路:外部可控数据进入 unserialize、readObject 等危险流程。
上传场景建议检查 Web 服务器解析配置。很多事故不是上传校验单点失效,而是上传目录被错误配置为可执行。
# Nginx 示例:上传目录禁止脚本执行
location ^~ /uploads/ {
location ~* \.(php|phtml|phar|jsp|asp|aspx)$ {
return 403;
}
}同时建议把上传文件存储到非 WebRoot 路径,通过受控接口读取,或者至少使用对象存储并关闭脚本解析能力。
第五步:系统层面排查后续动作
WebShell 只是入口,后续可能会有持久化、横向移动或数据打包行为。Linux 主机可以重点看以下位置:
crontab -l
ls -al /etc/cron* /var/spool/cron 2>/dev/null
ps aux --sort=-%cpu | head
ss -antp
last -a | head
find /tmp /var/tmp /dev/shm -type f -mtime -7 -ls 2>/dev/null如果发现可疑进程,不建议立即 kill 后就结束排查。先记录进程路径、启动参数、父进程、网络连接和文件句柄:
pid=12345
pwdx $pid
ls -al /proc/$pid/exe
tr '\0' ' ' < /proc/$pid/cmdline
ls -al /proc/$pid/fd | head这些信息有助于判断攻击者是否已经从 Web 权限进入系统权限,以及是否存在其他落地文件。
第六步:代码审计中的几个高频误区
复盘代码时,比较容易踩以下几个坑:
- 只查上传接口,不查文件解压、远程下载、模板编辑等“间接写文件”功能。
- 只看新增文件,不看被追加的一句话代码或被替换的依赖包文件。
- 只修业务代码,不检查 Nginx、Apache、PHP-FPM 的解析和权限配置。
- 只封 IP,不修漏洞。攻击源经常变化,封禁只能作为临时措施。
- 只升级主程序,不升级插件、主题、编辑器和历史遗留目录。
代码审计建议从输入源到危险操作建立链路。例如 PHP 项目里可以先找 $_GET、$_POST、$_FILES、php://input,再看数据是否进入文件写入、命令执行、SQL 拼接、模板渲染等位置。
加固建议
- 上传目录禁止脚本执行,上传文件重命名为随机文件名,文件类型以白名单校验为主。
- 后台管理入口增加访问控制和多因素认证,避免默认路径长期暴露公网。
- Web 进程使用低权限账号运行,业务目录按最小权限设置,代码目录尽量只读。
- 关闭不必要的危险函数,结合业务实际评估 disable_functions,不要盲目配置导致业务异常。
- 建立文件完整性监控,对核心目录新增、修改、权限变化进行告警。
- 日志集中化保存,避免攻击者取得单机权限后直接清理本地日志。
- 定期清理历史测试文件、备份压缩包、旧版本插件和未使用的管理工具。
一个相对实用的权限基线是:代码发布目录由发布用户写入,运行时 Web 用户只读;需要写入的目录单独划分,例如 uploads、cache、logs,并对这些目录限制脚本执行。
事件复盘模板
建议每次事件结束后沉淀一份简短报告,至少包含以下内容:
| 项目 | 说明 |
| 发现时间 | 告警、用户反馈或人工巡检发现的时间 |
| 影响范围 | 受影响域名、主机、目录、账号和数据范围 |
| 入侵入口 | 漏洞点、弱口令、组件缺陷或配置问题 |
| 攻击时间线 | 关键请求、文件落地、进程启动、外连行为 |
| 处置动作 | 隔离、备份、清理、修复、升级、密钥轮换 |
| 长期改进 | 监控、权限、发布流程、组件治理、审计规则 |
复盘报告不需要写得很花,关键是能回答“为什么发生、怎么发现、如何避免再次发生”。
注意点
- 清理前先备份样本和日志,后续确认入口时经常需要回看。
- 不要把文件修改时间作为唯一依据,时间戳可能被修改。
- 不要忽略内网机器访问 WebShell 的情况,可能是跳板或自动化扫描器。
- 涉及敏感数据时,优先确认是否存在读取、打包、导出痕迹。
- 修复后要做回归验证,包括上传限制、目录解析、权限边界和告警触发。
总结
WebShell 事件的处理重点不是“找到一个可疑文件然后删除”,而是围绕时间线把入口、落地、执行、持久化和影响范围串起来。日志分析负责还原路径,样本识别负责确认行为,代码审计负责修漏洞,权限和监控负责降低下一次事件的影响。
长期看,最有效的办法不是堆更多工具,而是把上传目录不可执行、最小权限、组件治理、日志留存、文件完整性监控这些基础项做扎实。很多入侵事件之所以反复发生,问题往往不在某个单点漏洞,而在基础安全边界长期缺位。
推荐意见