Webshell 到底是什么:从后门原理、发现方法到防守策略
很多人第一次听到 webshell,会把它理解成“黑客上传了一个脚本文件”。这个理解不算错,但还是太轻了。
更准确一点说,webshell 是攻击者放进 Web 服务器上的一个持久化入口。它通常长得像普通脚本、普通页面,甚至普通插件的一部分,但作用不是提供业务功能,而是让攻击者能继续执行命令、读写文件、横向移动,或者重新拉起其他后门。MITRE ATT&CK 也把它归到 T1505.003 Web Shell,本质上就是把服务器软件组件当成持久化载体。
这类东西之所以麻烦,不在于“神秘”,而在于它非常贴近正常 Web 运行环境。它借的是现成的 HTTP/HTTPS 流量、现成的脚本解释器、现成的站点目录和权限模型。Microsoft 在 IIS 检测文章里提到,Web exploitation 和 web shell 仍然是现实环境里很常见的初始入侵点与持久化手段;而且恶意 IIS 模块甚至可以把通信藏进参数、请求头、请求体里,让日志和常规文件扫描都更难看出来。
所以这篇文章不打算讲“怎么做一个 webshell”,而是讲三件更实际的事:
- webshell 后门通常是什么样
- 你怎么在服务器上发现它
- 真正有效的防御优先级应该怎么排
一、webshell 后门通常长什么样
先说结论:webshell 不一定像一个单独的 shell.php 文件那样显眼。
最常见的几种形态,大概有这些:
1)伪装成正常业务脚本
比如一个看上去很普通的 PHP、JSP、ASPX 文件,文件名叫:
login.phpdb-old.phpcache.aspglobal.aspxerror.jsp
它们可能混在上传目录、临时目录、主题目录、插件目录里,表面看只是“功能文件”,实际会在收到某个特定参数后执行系统命令。
2)被注入到现有文件里
这比单独放一个文件更常见,也更难查。
攻击者未必新建文件,而是把几行恶意逻辑塞进已有入口文件、模板文件、公共 include 文件,或者某个你平时根本不会打开的 helper 文件里。这样做的好处很明显:不容易触发“新文件告警”,也更像正常代码变更。
3)伪装成插件、模块、扩展
在 IIS、CMS、WordPress、Exchange、SharePoint 一类系统里,后门未必只是脚本文件,也可能是模块、扩展、主题文件,或者站点运行时会自动加载的组件。Microsoft 提到的恶意 IIS 模块就是这一类:它不一定表现成“某个可疑页面”,而可能挂在请求处理链路上,直接拦截和改写请求、响应。
4)功能极简,但足够维持入口
别把 webshell 想得太“全功能后台化”。很多 webshell 的实现很短,可能只干一件事:
- 执行命令
- 写入第二阶段载荷
- 回显文件内容
- 接收参数后解码执行
攻击者不一定需要一个华丽控制面板,只要能保持可重复进入就够了。
二、webshell 一般是怎么进来的
从防守角度看,webshell 很少是“凭空出现”的,它通常是前面某个安全问题的结果。
最常见的入口包括:
1)文件上传点失守
这是最经典的一类。OWASP 在文件上传安全指南里强调,上传功能如果只检查扩展名、信任 Content-Type、把文件直接放进 webroot,风险会非常高;更稳妥的做法是扩展名白名单、类型校验、重命名、权限控制、存储到 webroot 之外,并在可能时接入 AV 或沙箱扫描。
这背后的现实逻辑很简单: “可上传” + “可被 Web 解释执行”,基本就是 webshell 最舒服的落点。
2)已知漏洞未修补
很多真实事件不是因为对方“技术特别高”,而是因为目标站点还挂着已知 RCE、任意文件写入、认证绕过或组件漏洞。打进去以后,再落一个 webshell 维持入口,就是非常常见的后续动作。MITRE 的过程样例里也反复能看到,攻击者在 Exchange、OWA、ERP、IIS 等暴露服务上放 webshell 作为持续访问手段。
3)后台口令弱、权限过大
CMS、面板、部署工具、文件管理器被撞库或弱口令拿下后,攻击者未必要立刻做复杂动作,最直接的就是写一个后门进去。 这类场景在中小团队、自建站点、历史项目里并不少见。
4)供应链和插件生态问题
特别是 CMS、主题、低质量插件、历史扩展,常见问题不是“主程序很脆”,而是外围生态很脆。对个人站长和小团队来说,这比 APT 叙事更现实。
三、怎么发现 webshell:别只盯着“可疑文件名”
发现 webshell,最容易踩的坑,是把排查理解成“全盘搜 eval”。
这当然有用,但远远不够。更靠谱的做法是把排查拆成四层:文件、时间线、行为、流量/日志。
四、第一层:查文件异常
1)先找最近新增或最近改动的脚本文件
Linux 上可以先看近几天被修改过的 Web 目录文件:
find /var/www -type f \( -name "*.php" -o -name "*.jsp" -o -name "*.aspx" -o -name "*.asp" \) -mtime -7 -printf "%TY-%Tm-%Td %TT %p\n" | sort
如果站点路径不止一个,也可以把 Nginx/Apache 虚拟主机目录一起扫。
Windows / IIS 环境可以用 PowerShell 看最近改动的脚本文件:
Get-ChildItem -Path "C:\inetpub\wwwroot" -Recurse -Include *.aspx,*.ashx,*.asmx,*.php `
| Where-Object { $_.LastWriteTime -gt (Get-Date).AddDays(-7) } `
| Sort-Object LastWriteTime `
| Select-Object LastWriteTime, FullName
这一步的目的不是“直接命中 webshell”,而是先把调查范围缩小。 很多时候,异常点不是文件名,而是修改时间和业务发布时间对不上。
2)搜索高风险执行函数
以 PHP 为例,先做一轮关键字扫描:
grep -RInE "eval\s*\(|assert\s*\(|system\s*\(|exec\s*\(|shell_exec\s*\(|passthru\s*\(|base64_decode\s*\(|gzinflate\s*\(|preg_replace\s*\(.*\/e" /var/www
这条命令不是判定规则,只是筛查入口。因为这些函数本身并不等于恶意,但它们和混淆、动态执行、命令调用组合在一起时,值得重点看。
3)关注“看起来不像业务代码”的痕迹
例如:
- 一大段不可读的 Base64
- 很短但高度混淆的单行脚本
- 文件头部或尾部突然多出一段解码执行逻辑
- 上传目录里出现可执行脚本
- 图片、日志、缓存目录里出现脚本扩展名
- 正常前端模板里突然调用系统命令
这些都不一定百分百是 webshell,但都值得拉高优先级。
五、第二层:对时间线做交叉验证
单看文件内容,误报会很多。 更有效的办法是把文件改动时间和访问日志、漏洞利用时间、发布记录放在一起看。
建议你交叉核对:
- 文件最后修改时间
- Nginx / Apache / IIS 访问日志
- WAF 告警时间
- CI/CD 发布时间
- 管理员登录日志
- 系统补丁变更记录
例如你发现一个 cache.php 是凌晨 03:12 被改的,而那天没有发布;同一时间段访问日志里还有异常 POST 请求、非常规 User-Agent、404 页面触发大量参数提交,那就比“grep 出了 eval”更像真实线索。
六、第三层:看进程和父子关系
真正有价值的告警,往往不是“文件里有危险函数”,而是 Web 服务进程拉起了不该拉起的系统命令。
MITRE 2025 年新增的检测策略就明确强调,可以通过“Web 服务器行为 + 文件执行链”来识别 webshell,重点看 Web 服务进程是否触发了脚本解释器、shell、系统工具等异常子进程。
Linux 上可以先看由 Web 用户拉起的可疑进程:
ps -ef | egrep 'www-data|nginx|apache|httpd|tomcat'
再重点盯这些异常行为:
nginx/apache/php-fpm拉起sh、bash- Web 进程拉起
curl、wget - Web 进程调用
python、perl、nc - Tomcat / Java Web 进程突然执行系统命令
- 短时间内频繁创建临时文件或压缩包
如果你的环境有 EDR / Sysmon / auditd,这层的价值会比静态扫文件高很多。
七、第四层:查访问模式和请求特征
webshell 通信经常藏在正常 HTTP 请求里,所以建议重点看这些模式:
- 某个很少访问的脚本持续被请求
- 请求参数极短但高频
- POST 请求体里出现明显编码串
- 某个 404/500 页面也能稳定返回 200 或固定长度响应
- 非浏览器 User-Agent 长时间访问后台脚本
- 来自单一 IP 的周期性探测与命令回连
Nginx 上可以先做最基础的日志聚合:
awk '{print $1, $7, $9}' /var/log/nginx/access.log | sort | uniq -c | sort -nr | head -50
如果怀疑某个后门文件:
grep "suspicious.php" /var/log/nginx/access.log
IIS 环境则要重点关注:
w3wp.exe的异常子进程- 非常规请求头
- 针对不存在页面却能触发不同响应的请求
- 模块、处理程序、站点配置的异常变动
Microsoft 也特别指出,恶意 IIS 模块可以把通信藏在参数、Body、Header 甚至 HTTP Method 中,还能篡改日志可见性,这也是为什么只看 URL 维度经常不够。
八、一个更靠谱的排查顺序
如果你怀疑站点已经有 webshell,我更建议按这个顺序处理:
第一步:先保留证据,不要急着删文件
这是很多团队最容易犯的错。 看到可疑文件,第一反应就是删。结果文件是删了,真正的入侵路径、横向痕迹、二阶段载荷全没了。
更稳妥的做法是:
- 先备份可疑文件
- 记录 hash、权限、时间戳
- 导出相关访问日志
- 记录当前进程、网络连接、计划任务
- 再进入隔离和清理
Linux 示例:
sha256sum /var/www/html/suspicious.php
stat /var/www/html/suspicious.php
cp /var/www/html/suspicious.php /root/forensics/
第二步:判断它是不是“单点文件”,还是“已取得持续控制”
真正要回答的问题不是“这是不是 webshell”,而是:
- 攻击者是只写了一个文件?
- 还是已经拿到后台账号?
- 还是已经写入计划任务、systemd、启动项、计划任务、IIS 模块、SSH key?
- 还是已经把数据库、对象存储、CI 凭据一起拿走了?
如果只删掉前端看到的那个脚本,而不处理初始漏洞、账户、密钥、扩展模块,通常还会再回来。
第三步:修入口,再清后门
顺序非常重要。 比如问题来自文件上传绕过,那你应该先关闭上传点或切断对外服务,再清理落地文件。否则你删一次,对方再传一次,等于白做。
九、怎么防 webshell:优先级比“堆产品”更重要
讲防护时,最怕写成一串口号。 实际上,对大多数团队来说,真正有价值的是下面这几个优先级。
1)把“上传后可执行”这件事先堵死
这是收益最高的一项。
按照 OWASP 的建议,上传安全至少做到这些:扩展名白名单、不要信任 Content-Type、服务端重命名、限制大小、只给授权用户上传、文件尽量放到 webroot 之外,必要时再走杀毒或沙箱。
如果你的网站确实要让用户上传文件,一个很实用的原则是:
上传目录只允许存储,不允许解释执行。
比如 Nginx 可以显式禁止上传目录中的脚本执行:
location /uploads/ {
autoindex off;
}
location ~* ^/uploads/.*.(php|php5|phtml|jsp|jspx|asp|aspx)$ {
deny all;
}
Apache 也可以在上传目录关闭脚本执行能力:
location /uploads/ {
autoindex off;
}
location ~* ^/uploads/.*\.(php|php5|phtml|jsp|jspx|asp|aspx)$ {
deny all;
}
注意,这些配置是否生效取决于你的部署模式,但核心思路不变: 让上传目录成为“纯文件区”,而不是“可执行区”。
2)最小权限,不给 Web 进程多余写权限
很多 webshell 能持久化,不是因为它太高级,而是因为 Web 服务账号写权限太大。
至少要检查:
- Web 进程是否能写整个站点目录
- 是否能写配置文件
- 是否能写插件/主题目录
- 是否能写 system 目录、计划任务目录、启动目录
- 容器是否挂了过大的宿主机卷权限
一个很朴素但有效的原则是:
- 需要运行的目录给读权限
- 必须写的目录单独隔离
- 代码目录默认只读
- 配置和密钥分离存放
3)补丁管理别掉队
这听起来老生常谈,但现实里 webshell 落地最常见的前提,还是暴露组件有漏洞。 Web 服务器、中间件、CMS、插件、主题、管理后台、文件管理器,这些都应该纳入补丁节奏,而不是只盯操作系统。
4)为“Web 进程拉起系统命令”建立告警
对检测成熟度稍微高一点的团队,这条很值。
因为静态特征会变,文件名会伪装,编码方式会变,但下面这些行为很难说得过去:
w3wp.exe->cmd.exe/powershell.exeapache2/nginx/php-fpm->sh/bashtomcat->/bin/sh- Web 进程调用下载器和压缩工具
这类父子进程链,比“关键字搜到了 eval”更接近真实入侵行为。MITRE 的检测策略和 Microsoft 的 IIS 调查建议,本质上也都在强调这一层。
5)保留日志,而且别只保留三天
如果没有访问日志、进程日志、认证日志,很多 webshell 事件最后只能停留在“好像被挂马了”。
最少建议保留:
- Web 访问日志
- 错误日志
- 反向代理/WAF 日志
- 后台登录日志
- 文件完整性变更记录
- 关键系统进程创建日志
对于个人站长和小团队来说,不一定一开始就上很重的 SIEM,但至少别把基础日志全关掉。
十、给个人开发者和小团队的现实建议
如果你不是大厂安全团队,而是自己管服务器、自己发版本、自己装插件,我会更建议你把精力放在这四件事上:
1)减少暴露面
不用的后台、测试目录、旧入口、历史面板、演示站点,能关就关。 很多 webshell 不是从主业务入口进来的,而是从你忘了的旧系统进来的。
2)少装来源不明的插件和主题
对 CMS 用户来说,这条经常比“上更强的 WAF”更实际。 很多问题压根不在你主程序,而在第三方生态。
3)把上传目录和代码目录彻底分开
这是非常值得做的工程化改动。哪怕麻烦一点,也比事后清后门便宜。
4)给服务器做最基础的完整性巡检
哪怕没有高级安全平台,也应该至少有:
- 定期列出最近变更文件
- 定期核对关键目录 hash
- 定期检查异常计划任务/启动项
- 定期看一次访问日志热点
这不性感,但非常有用。
十一、最后的判断
webshell 不是一个“神秘黑客名词”,它本质上是攻击者把 Web 运行环境变成自己的遥控入口。
真正难的地方也不在于理解这个概念,而在于两点:
- 它很像正常 Web 代码和正常 HTTP 流量
- 它往往不是根因,而只是入侵完成后的一个结果
所以如果你只把注意力放在“删掉那个可疑文件”,通常不够。更合理的做法是:
- 从上传、漏洞、弱口令、插件生态里找真正入口
- 从文件、时间线、进程链、访问模式四层交叉排查
- 从“上传不可执行、最小权限、及时补丁、行为告警、日志保留”几个优先级先做起
对于开发者来说,这件事最值得关注的点不是恐慌,而是工程常识: 只要一个系统允许“不可信内容进入 Web 可执行路径”,webshell 风险就一直存在。
这不是玄学问题,而是架构和运维纪律问题。