现代 webshell 的形态
现代 PHP webshell 很少直接写一句 eval($_POST[x]):更常见的是拼接、编码与动态函数调用,把高危函数名拆开或隐藏,绕过关键字检测。因此排查必须结合文件位置、修改时间与访问行为,而不是只搜函数名。
排查的三条线
第一条是内容特征:动态执行、编码解码、变量函数;第二条是位置与时间:新增或修改的 php 文件集中在哪些目录;第三条是行为:access.log 中针对同一文件的规律性 POST 请求与响应体量。
基本信息
| 高危函数 | eval、assert、create_function、system、popen、shell_exec |
|---|---|
| 常见混淆 | base64_decode、gzinflate、str_rot13、变量函数、拼接字符串 |
| 易落位置 | 上传目录、缓存目录、图片目录、站点根目录 |
| 行为线索 | 规律性 POST 请求、响应长度异常、单一 UA |
| 排查范围 | 站点根目录及各虚拟主机目录 |
| 适用平台 | PHP 站点(Nginx/Apache 均可) |
典型使用场景
- 站点被植入后门后定位可疑文件
- 确认入侵者是否保留了多个持久 webshell
- 配合访问日志还原 webshell 的使用时间与来源
- 清理后做复扫验证
- 评估是否需要重装网站或更换框架版本
特征与时间双路排查
特征与时间双路排查
grep -RnE 'call_user_func|create_function|str_rot13|gzinflate' /www/wwwroot --include='*.php' -l 2>/dev/null | head -n 20
find /www/wwwroot -type f -name '*.php' -mtime -30 -ls | head -n 40
find /www/wwwroot -type f -name '*.php' -newermt '2026-10-01' ! -newermt '2026-10-12' | head -n 40
grep -RniE '\$_(POST|GET|REQUEST)\s*\[' /www/wwwroot --include='*.php' -l 2>/dev/null | head -n 20
ls -la /www/wwwroot/*/upload* /www/wwwroot/*/cache* 2>/dev/null | head -n 30输出逐列读法
| 线索 | 含义 | 正常/异常 |
|---|---|---|
| 文件修改时间 | 文件最后写入时间 | 与入侵时间窗重合的新增 php 文件优先核查 |
| 高危函数命中 | 动态执行能力 | 命中不等于恶意,需结合上下文与文件用途判断 |
| 上传目录内的 php | 本不该存在的可执行脚本 | 上传目录出现可直接访问的 php 基本可判定 |
| 访问日志中的 POST | 外部交互入口 | 单一文件的高频 POST 是 webshell 的典型特征 |
免杀样本可能不含任何高危函数名:「文件出现在不该出现的位置与时间」本身就是信号,先按位置与时间收敛范围,再做内容核查。
结合访问日志定位使用时刻
结合访问日志定位使用时刻
awk '$6 ~ /POST/ {print $1, $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -n 20
find /www/wwwroot -name '*.php' -newermt '2026-10-01' -printf '%TY-%Tm-%Td %TH:%TM %p\n' | sort | head -n 30清理前后的核对项
- 清理前先复制可疑文件到证据目录并计算哈希
- 记录文件的属主、权限与时间戳
- 检查同目录是否有伴随的 .htaccess 改写
- 清理后重新跑一遍位置与时间维度扫描确认无残留