网站突然多了几个莫名其妙的php文件,流量异常飙升、后台密码被改、百度快照被劫持,到底怎么排查webshell?用哪几个工具组合能把藏得最深的后门揪出来?
年初一个做企业站群的朋友发现不对劲:谷歌搜索他的几个站点,标题全变成了"XX娱乐城"。打开百度快照更离谱,页面底部多了一堆隐藏的博彩链接。登录服务器一看,uploads目录下多了三个文件——x.php、favicon.ico.php、wp-config.bak.php。其中favicon.ico.php被伪装成图标文件,实际是个大马,攻击者用它批量改了他名下11个站的首页标题和meta标签,赚了整整三个月的黑帽SEO流量,他一无所知。
webshell不像病毒那样有明显的破坏症状。它安静地躺在服务器目录里,不删文件、不弹窗、不加密数据——攻击者用它批量改快照、挂暗链、发垃圾页面、做黑链买卖。等站长发现的时候,站已经被搜索引擎降权至少一个月了。问题是怎么查?
webshell查杀的四个层次,从快扫到深度溯源
| 1 | 工具快扫 —— D盾/河马一键全盘,5分钟出结果,拦截80%的常见webshell变种 |
| 2 | 命令手工排查 —— find+grep定位时间异常、特征函数、隐藏文件,发现工具漏掉的伪装马 |
| 3 | 日志溯源 —— 通过访问日志反查webshell的上传路径、攻击者IP、执行时间线 |
| 4 | 防御加固 —— 堵上传漏洞、禁目录执行权限、定时监控文件变更,不让同一个坑掉两次 |
一、先搞清楚webshell是怎么进来的,不然杀了还会再生

查杀之前得先想一个问题:这个webshell是怎么传到服务器上的?如果不堵住入口,今天杀一个明天又传一个。常见的入口就那么几条路:
文件上传漏洞
头像上传、附件上传、编辑器上传没做后缀白名单校验,攻击者直接把.php改成.php.jpg绕过前端校验,后端没二次检查就存了。这是最常见的入口,占了入侵事件的六成以上。
后台弱口令 + 模板编辑
WordPress后台密码是admin/123456,攻击者登录后直接在主题编辑器中往functions.php里插入一句话木马。或者利用后台的数据库备份功能,把备份文件名改成.php然后执行。
插件/主题漏洞
安装了来路不明的破解版主题或插件,里面预埋了后门。或者是用了一个两年前就没更新的插件,存在已知的文件包含漏洞,攻击者直接远程写文件。
服务器漏洞/弱口令
SSH/RDP弱口令被爆破,FTP密码泄露,Redis未授权访问写SSH公钥,SQL注入写文件到web目录。这些不是应用层问题,是运维层面没做好。
排查webshell之前,先根据上面的入口逐条自查一遍。把漏洞堵了再去杀马,逻辑才对。经常有人用D盾扫完杀了5个webshell,一周后又冒出3个——就是因为上传漏洞没修,攻击者手里还捏着入口。
二、第一层:工具快扫,5分钟覆盖80%的常见webshell
别一上来就手动翻文件,效率太低。先用工具扫一遍,把明显的一波揪出来,剩下的再手工细查。市面上主流的webshell检测工具按技术路线分三类:特征库匹配、机器学习模型、云端沙箱动态分析。没有哪一类能全覆盖,组合使用才是正解。
| 工具 | 技术路线 | 核心优势 | 主要短板 | 适用阶段 |
|---|---|---|---|---|
| D盾 WebShellKill | 静态特征码 + 危险函数匹配 | 扫描速度极快,对已知变种检出率高,结果按红/黄/蓝三级标注 | 误报多,正常用了eval的业务代码容易被标红;对加密混淆后的马识别率低 | 第一轮快扫 |
| 河马 (Hema) | 机器学习 + 静态分析 | 误报率低,对混淆/加密型webshell检出率明显优于特征库方案;支持自定义模型训练 | 对最新变种响应慢,模型更新有滞后;需要一定专业知识做模型调优 | 第二轮复核 |
| 牧云 (CloudWalker) | 云端沙箱 + 动态行为分析 | 不被静态混淆欺骗,基于恶意行为判定,能发现未知威胁 | 需上传文件到云端(隐私风险),有网络延迟;商业产品需付费 | 深度分析 |
| 安全狗 | 特征库 + 语义分析 + RASP实时防护 | 集扫描与实时防护于一体,能拦截webshell执行;部分版本可检测内存马 | 占用服务器资源,可能影响业务性能;实时防护存在兼容性问题 | 持续防护 |
| WebShellKill (PHP扩展) | PHP扩展层实时拦截 | 在文件被执行瞬间拦截,实时性最高;性能开销相对低 | 部署复杂,需编译PHP扩展;扩展出错可能导致PHP服务崩溃 | PHP专项防护 |
实操顺序建议:先用D盾全盘扫一遍,把标红的文件逐个看——大量是误报(比如用了base64_decode的业务代码),但一定有真正的webshell。然后把D盾标黄和标蓝的文件用河马再跑一遍复核。最后如果还有高度可疑但无法确认的文件,上传牧云做沙箱动态分析。
三、第二层:手工排查,工具扫不出来的用命令挖
工具不是万能的。攻击者把webshell做了base64编码+自定义密钥解密、或者把恶意代码拆成多段分别写在不同的include文件里、或者用图片马配合.htaccess解析——这些情况D盾和河马都可能漏。工具扫完一轮后,必须手工再过一遍。
Linux服务器上这几条命令挨个跑一遍:
# 1. 找近3天内被修改过的php文件(排除缓存目录)find /var/www -path "*/cache" -prune -o -name "*.php" -type f -mtime -3 -exec ls -lh {} \;# 2. 找包含危险函数的php文件find /var/www -name "*.php" | xargs grep -l "eval\|assert\|system\|exec\|shell_exec\|passthru\|popen\|proc_open\|base64_decode\|gzinflate\|str_rot13" 2>/dev/null# 3. 找777权限的可疑文件(webshell常被设为全权限)find /var/www -name "*.php" -perm 0777# 4. 找隐藏文件(.开头的文件,常见伪装手法)find /var/www -name ".*.php" -type f# 5. 找图片目录里的php文件(正常情况不该有)find /var/www/wp-content/uploads -name "*.php" -type f# 6. 按文件修改时间倒序排列,看最新的文件ls -alt /var/www | head -n 30跑完这几条,一般能定位到可疑文件。重点看三种:时间戳异常的(其他文件都是两年前,就这一个昨天刚改的)、位置不对的(uploads目录下冒出来的php文件)、名字伪装的(favicon.ico.php、wp-config.bak.php、index.php.bak这类)。
注意:grep搜危险函数会有大量误报。像WordPress本身就用到了base64_decode、file_get_contents等函数。grep只是帮你缩小范围,搜出来的结果要逐个人工确认,不要直接删。
四、webshell常见的五种伪装手法,看懂了手工排查效率翻倍
知道了webshell怎么伪装,看代码的时候一眼就能分辨。以下五种是实战中最常见的:
| 伪装手法 | 典型特征 | 怎么看穿 |
|---|---|---|
| 一句话木马 | 单行代码,如<?php @eval($_POST['cmd']);?> | 搜eval、assert、$_POST、$_GET关键字,找到后看上下文——正常业务代码里eval不会直接执行POST参数 |
| 图片马 | 恶意代码藏在图片EXIF信息或二进制尾部,配合.htaccess把.jpg解析为.php | 检查.htaccess是否有AddType application/x-httpd-php .jpg这类异常配置;用file命令检查图片文件头是否正常 |
| 加密混淆马 | 一大段乱码字符串,通过base64_decode/gzinflate/str_rot13层层解码后执行 | 看到巨长的base64字符串后面跟着eval,基本确定是webshell。可以手动把base64字符串解码看明文 |
| 内存马 | 不落盘,直接注入到PHP-FPM/Apache/Tomcat进程内存中 | 普通文件扫描查不到。检查进程内存、看是否有异常加载的PHP扩展/Java Filter、用专业内存马检测工具 |
| 日志注入马 | 通过User-Agent或请求URL注入PHP代码到access.log,再包含日志文件执行 | 检查日志文件里是否有<?php开头的行,检查access.log和error.log的访问权限 |
警惕内存马:如果你的站用的是Java(Tomcat/Spring Boot)或PHP-FPM,工具扫完目录没发现可疑文件,但服务器还是有异常流量,要考虑内存马的可能性。内存马通过Java Agent、Filter动态注册、PHP扩展注入等方式实现,不写文件、不落盘,D盾和河马都扫不到。这种情况需要用到专业的内存马检测工具如arthas、jstack配合排查,或者直接重启服务进程(重启后内存马消失,但要同时堵住注入入口)。
五、第三层:日志溯源,找到webshell是什么时候、从哪个IP传进来的

查杀完webshell不是终点。你得知道攻击者是什么时候进来的、从哪个IP、利用了什么漏洞。不知道这些,补丁就打不对,下次还从同一个口子进来。
溯源第一步:找到webshell文件的时间戳。stat x.php看一下Access/Modify/Change三个时间。Modify时间就是文件最后被修改写入的时间——这个时间点大概率就是webshell被上传的时间。Change时间是文件属性变更时间,如果攻击者用touch改了时间戳,Access和Modify可能被伪造,但Change时间在大多数情况下更可靠。
拿到时间点后,去Web服务器日志里搜这个时间点前后的请求。以Nginx为例:
# 搜webshell文件名在日志中的首次出现(就是上传或首次访问的时间点)grep "x.php" /var/log/nginx/access.log# 搜webshell被创建时间点前后1小时的POST请求(POST比GET更可能是上传操作)grep "POST" /var/log/nginx/access.log | grep "2026-03-15T14:"# 搜所有对uploads目录的POST请求grep "POST.*uploads" /var/log/nginx/access.log日志中如果能找到攻击者的IP,再反查这个IP在webshell创建时间前后还访问了哪些URL——大概率能定位到攻击者利用的漏洞入口(某个上传接口、某个插件路径、某个后台页面)。
一个容易被忽略的点:攻击者上传webshell后通常会马上访问一次确认是否成功。日志里x.php第一次被GET/POST的时间,和它被上传的时间通常只差几秒到几分钟。如果日志里webshell的第一次请求和某个POST上传请求的IP一致,基本就锁定了攻击者。
六、三个翻车坑,每个都有人反复踩
查杀webshell这事,工具用对了只是第一步。真正的差距在执行细节上。
坑1:只杀文件,不堵漏洞
D盾扫出3个webshell,删了,以为安全了。一周后同样的目录又冒出来2个——因为上传漏洞根本没修。查杀的第一件事是关上传入口:检查所有上传接口有没有做后缀白名单、临时把uploads目录的执行权限去掉。
坑2:只信工具,不手工复核
用了一个工具扫完显示"未发现威胁",就觉得没问题了。实际上加密混淆马、内存马、日志注入马这几种,大部分免费工具检测率不到50%。工具扫完必须手工再过一遍文件时间线和可疑目录。
坑3:查完不建立持续监控
杀完webshell就当完事了。下次被入侵又要从头排查一遍。正确做法是:杀完后部署文件完整性监控(如Tripwire、AIDE、或简单的md5sum定时比对),新文件/文件变更第一时间告警。
七、多站场景下的webshell查杀怎么批量做
如果你只有一两个站,手工操作上面这套流程完全可行。但如果有二三十个站甚至更多,一台台登录服务器跑D盾、手工grep日志,时间和人力都扛不住。
批量化的思路分三步:
· 统一扫描脚本:在每台服务器上部署定时任务,每天凌晨用find+grep组合跑一遍关键目录,结果汇总到一个中心日志服务器。发现异常文件自动发钉钉/飞书告警。
· 文件完整性基线:每次网站代码部署完成后,生成一份全站文件的md5清单作为基线。之后每天用md5sum比对,任何文件变更(新增/修改/删除)都会触发告警。webshell本质上就是"不该存在的文件",文件完整性监控是最底层的防线。
· 目录权限自动化:用脚本统一管理所有站点的目录权限——uploads目录批量去掉执行权限,wp-content/themes去掉写权限,wp-config.php设为400只读。权限收紧之后,即使攻击者找到了上传漏洞,文件也执行不了。
如果你用UC建站系统管理的站群,这些批量操作可以更省心——内容中台统一管理所有站点的代码部署和文件基线,每次发布自动生成md5清单。多站看板里可以统一监控各站的文件变更状态,某个站的文件系统出现异常变化第一时间就能看到,不用一台台登录查。目录权限也能在部署时通过配置模板统一设置,uploads禁执行、关键文件设只读,一次配置所有站生效。
webshell查杀不是一次性动作。今天杀了不代表明天不会再有。真正有效的安全策略是三层:入口防御(上传白名单、目录禁执行、弱口令整改)+ 持续检测(工具定期扫描 + 文件完整性监控 + 日志异常分析)+ 快速响应(告警→定位→溯源→修复漏洞,形成闭环)。缺了任何一层,webshell都会在你不知道的时候悄悄回来。
