Upload-Labs (Pass-01 ~ Pass-21) 完全通关指南

🛠️ 环境前置准备(避坑必看)

在开始打靶前,请务必确认你的 phpStudy (小皮面板) 或 XAMPP 满足以下配置,否则部分关卡将无法复现:

配置项 具体要求
Apache 解析权限 打开 httpd.conf​,将所有的 AllowOverride None​ 改为 AllowOverride All​
等价后缀解析 在 httpd.conf​ 末尾添加:AddType application/x-httpd-php .php .phtml .php3 .php5​
PHP 版本 Pass 01-11:建议 PHP 7.x;Pass 12-13:必须切换到 PHP 5.2.17,并在 php.ini​ 中关闭魔术引号 magic_quotes_gpc = Off​
工具准备 Burp Suite、蚁剑 (AntSword) 或哥斯拉 (Godzilla)

💡 提示:练习 Pass-14 以后的关卡时,如果蚁剑连不上,检查 php.ini​ 里的 short_open_tag​。如果为 Off​,图片马使用 <?​ 简写将无法解析,建议统一使用 <?php​ 标准写法。


第一类:前端验证与 MIME 绕过 (Pass-01, Pass-02)

核心逻辑:服务器将验证逻辑放在客户端或信任了可伪造的 HTTP 头部。

Pass-01:前端 JS 验证

  • 原理:仅在浏览器端使用 JavaScript 检查后缀,非 .jpg/.png/.gif​ 则弹窗阻止。

  • 绕过手法:

    1. 直接禁用:浏览器 F12 → 设置 → 禁用 JavaScript。
    2. 抓包改名(推荐):先将木马改名为 shell.jpg,上传时用 Burp 抓包,在报文中将文件名改回 shell.php。

Pass-02:MIME 类型绕过

  • 原理:后端检查 $_FILES['upload_file']['type'],即 HTTP 请求头中的 Content-Type 字段。
  • 绕过手法:抓包后,将 Content-Type: application/octet-stream 修改为 image/png 或 image/jpeg 即可欺骗后端。

🛡️ 防御方案:绝对不能依赖前端 JS 和 HTTP 头部的 MIME 类型进行安全验证,必须在后端对真实后缀和内容进行校验。


第二类:黑名单过滤不严与特性绕过 (Pass-03 ~ Pass-11)

核心逻辑:服务器定义了"不允许上传"的后缀列表(黑名单)。只要找到不在列表里、但又能被服务器当作脚本执行的后缀,就能绕过。

Pass-03:特殊解析后缀(等价扩展名)

  • 原理:黑名单漏掉了 .php3, .phtml, .php5 等。在配置了 AddType 的 Apache 环境下,这些后缀会被当作 PHP 解析。
  • 绕过手法:将文件改名为 shell.php3 上传。
  • 注意:若访问显示源码,请检查 Apache httpd.conf 是否添加了对应解析规则。

Pass-04:.htaccess 绕过

  • 原理:黑名单屏蔽了几乎所有脚本后缀,但漏掉了 .htaccess​(Apache 分布式配置文件)。

  • 绕过手法:

    1. 上传一个名为 .htaccess 的文件,内容为:SetHandler application/x-httpd-php(让当前目录下所有文件都按 PHP 解析)。
    2. 再上传一个 shell.jpg(内含木马代码),访问该图片即可执行。

Pass-05:.user.ini 绕过

  • 原理:利用 PHP 自有的配置文件特性(类似 .htaccess​)。

  • 绕过手法:

    1. 上传 .user.ini,内容为:auto_prepend_file=shell.jpg。
    2. 上传 shell.jpg。此时访问同目录下的任意正常 PHP 文件(如 readme.php),会自动包含并执行 shell.jpg。

Pass-06:大小写绕过

  • 原理:Windows 系统对文件名大小写不敏感,但后端 PHP 黑名单检查往往区分大小写。
  • 绕过手法:上传 .PhP 或 .pHp。

Pass-07:空格绕过

  • 原理:Windows 在保存文件时,会自动去除文件名末尾的空格。
  • 绕过手法:抓包,将文件名改为 shell.php (注意末尾有空格)。绕过了 === '.php' 的验证,保存到系统时变成了 shell.php。

Pass-08:点号绕过

  • 原理:与空格同理,Windows 系统会自动去除文件名末尾的点 .。
  • 绕过手法:上传 shell.php.。

Pass-09:::$DATA 绕过

  • 原理:利用 Windows NTFS 文件系统的备用数据流特性。
  • 绕过手法:上传 shell.php::$DATA,Windows 会把它当成 shell.php 的数据流保存,从而绕过黑名单且不影响执行。

Pass-10:组合拳(点空格点)

  • 原理:后端代码使用 str_replace 等函数过滤危险后缀,但对末尾的空格和点处理不彻底。
  • 绕过手法:构造 shell.php. .(点 + 空格 + 点),利用 Windows 特性最终保存为 shell.php。

Pass-11:双写替换绕过

  • 原理:后端将黑名单后缀替换为空,但只替换一次。
  • 绕过手法:将文件名改为 shell.pphphp,中间的 php 被替换为空后,前后拼接成 shell.php。

🛡️ 防御方案:

  1. 废弃黑名单,使用白名单:只允许 .jpg, .png, .gif 等明确安全的后缀。
  2. 严格的文件名清洗:判断后缀前,统一转小写,并使用 trim() 彻底去除末尾空格、点号和特殊字符。

第三类:白名单与路径截断 (Pass-12, Pass-13)

核心逻辑:开发者使用了白名单(只允许图片后缀),但拼接保存路径时出现了漏洞。

底层语言(如 C)在处理字符串时,遇到 \0​(空字符/0x00)会认为字符串结束。若 PHP 版本 < 5.3.4​ 且 magic_quotes_gpc = Off​,就会产生截断漏洞。

Pass-12:GET 型 %00 截断

  • 原理:保存路径由 GET 参数控制。%00 后的内容被系统底层截断。
  • 绕过手法:将上传路径修改为 save_path=../upload/shell.php%00,上传的文件名为 1.jpg。最终拼接结果是 ../upload/shell.php%00/1.jpg,系统保存时由于 %00 截断,文件被保存为 shell.php。

Pass-13:POST 型 0x00 截断

  • 原理:保存路径由 POST 参数控制。POST 数据不会像 URL 那样自动解码 %00。
  • 绕过手法:在 save_path 的 shell.php 后加一个空格作为占位,在 Burp 的 Hex 视图中找到那个空格的十六进制 20,手动修改为 00。

🛡️ 防御方案:升级 PHP 至 5.3.4 以上;不要将用户可控的变量直接用于构建文件保存路径。


第四类:文件内容检测与图片马 (Pass-14 ~ Pass-17)

核心逻辑:服务器不仅检查后缀,还开始检查文件内部的数据。

Pass-14 ~ Pass-16:图片马 (Magic Bytes)

  • 原理:

    • 14-15 关:读取文件前两个字节(魔术头),如 JPEG 是 FF D8,GIF 是 GIF89a;或使用 getimagesize() / exif_imagetype() 验证是否为真实图像。
    • 16 关(二次渲染):服务器使用 imagecreatefromjpeg() 等函数,把上传的图片重新在内存里画一遍再生成新图,这会破坏附加在图片末尾的恶意代码。
  • 绕过手法:

    • 14-15 关(制作图片马):在 CMD 中使用命令:

      复制代码
      copy normal.jpg /b + shell.php /a webshell.jpg

      将 PHP 代码追加到正常图片尾部。配合靶场自带的文件包含漏洞(include.php​)即可执行。

    • 16 关(二次渲染绕过):GIF 最容易绕过。先上传一个正常 GIF,下载经过服务器渲染后的 GIF,使用十六进制工具(如 010 Editor)对比两份文件,找到未发生变化的数据块,将一小段 PHP 代码(如 <?php phpinfo(); ?>​)插入该区段。

🛡️ 防御方案:二次渲染是非常优秀的防御手段,配合单独的文件服务器(如阿里云 OSS、腾讯云 COS)效果最佳。


第五类:条件竞争 (Race Condition) (Pass-18)

核心逻辑:代码逻辑为"先上传,后检测"。服务器先把文件保存到网站目录,然后再检查后缀和内容,不合法则用 unlink()​ 删除。

Pass-18:条件竞争

  • 原理:利用从"保存"到"删除"之间极短的时间差。

  • 绕过手法:

    1. 使用 Burp Suite 的 Intruder 模块并发发送大量上传请求(上传 wshell.php,内容是一个会生成另一个木马的脚本)。
    2. 同时用另一个工具或线程疯狂访问该文件。
    3. 只要访问请求在删除前"抢占"成功,wshell.php 就会被执行,通常利用 file_put_contents 在当前目录生成一个不会被删除的后门文件(如 shell_b.php)。

🛡️ 防御方案:先检测,后保存。文件应先存放在系统临时目录,所有安全检测通过后再使用 move_uploaded_file()​ 移动到 Web 目录。


第六类:CVE 及框架/逻辑缺陷 (Pass-19 ~ Pass-21)

Pass-19:Apache 解析漏洞 + CVE-2015-2348

  • Apache 解析漏洞:Apache 会从右向左解析后缀,直到认识为止。上传 shell.php.7z,Apache 不认识 .7z,会将其解析为 .php。
  • CVE-2015-2348:move_uploaded_file() 函数内部的 \x00 截断,原理类似于 12 和 13 关。

Pass-20:自定义文件名过滤疏忽

  • 原理:用户可以输入自定义文件名。代码将文件名以点 . 分割为数组进行黑名单检测,但对特定构造处理不当。
  • 绕过手法:构造 shell.php/. 或利用空格/点组合绕过验证。

Pass-21:数组指针逻辑漏洞(代码审计)

  • 原理:开发者使用 explode()​ 拆分文件名,并用 end()​ 取最后一个元素作后缀检查,但对数组形式的输入处理不当。

  • 绕过手法:抓包修改 save_name​ 为数组形式:

    • save_name[0] = shell.php/
    • save_name[2] = jpg
    • 最终拼接结果会绕过白名单检测并保存为 shell.php。

🛡️ 终极防御指南(The Golden Rules)

在真实业务开发中,防止上传漏洞不需要写几百行的过滤正则,只要遵循以下三大黄金法则,就能从根本上解决 99% 的问题:

法则 具体措施
1. 强制文件重命名(最重要) 坚决不使用用户上传的原文件名。后端使用随机哈希(如 md5(uniqid())​ + 时间戳)强制重命名。shell.php​ 会变成 8a2b...91f.jpg​,即使上传成功也无法预测文件名。
2. 严格的白名单检测 利用 PHP 的 finfo_file()​ 结合文件扩展名白名单(只允许 .jpg​, .png​, .pdf​ 等),拒绝任何未知类型。
3. 目录权限分离(降维打击) 存放上传文件的目录(如 /uploads/​)绝对不能有脚本执行权限。在 Nginx/Apache 中限制该目录无法解析 .php​。更好的做法是使用第三方对象存储(OSS/S3),彻底将文件存储与 Web 应用服务器物理隔离。

📋 快速参考:验证环节 vs 攻击手段 vs 防御方案

验证环节 攻击手段 最强防御方案
前端验证 禁用 JS、Burp 抓包 后端验证是唯一准则
后缀验证 特殊后缀、大小写、00 截断 白名单限制后缀 + 统一转小写
文件名验证 空格、点、::$DATA 强制重命名(UUID / 时间戳)
MIME 验证 伪造 Content-Type 获取文件流真实内容,不信任请求头
内容验证 图片马、二次渲染 彻底二次渲染 + 禁用执行目录权限
解析环境 .htaccess、解析漏洞 关闭目录执行权限、Web 服务器加固
相关推荐
其实防守也摸鱼3 天前
Upload-labs:部署靶场及Pass-01实战解析
服务器·网络·安全·web安全·教程·文件上传·工具
探索者0112 天前
Upoad靶场--文件上传
安全·文件上传·upload靶场
探索者0112 天前
文件上传漏洞指南:原理+绕过手法与靶场实战
安全·web安全·文件上传
探索宇宙真理.17 天前
Vvveb CMS 任意文件上传导致RCE | CVE-2026-6257原理分析&研究
经验分享·开源·文件上传·安全漏洞·vvveb
~ rainbow~22 天前
前端转型全栈(六)——深入浅出:文件上传的原理与进阶
前端·http·文件上传
阿飞不想努力1 个月前
文件上传原理与实操
java·spring boot·vue·文件上传
Cxiaomu1 个月前
Flutter 录制视频+大文件上传 MinIO + NodeJS落库
flutter·音视频·文件上传
叫我一声阿雷吧1 个月前
原生 JS 实现图片预览上传组件:多图上传 + 拖拽上传 + 裁剪预览 + 进度显示(附完整源码)
图片上传·canvas·文件上传·响应式布局·拖拽上传·原生javascript·filereader api
abigale032 个月前
【浏览器 API / 网络请求 / 文件处理】前端文件上传全流程:从基础上传到断点续传
前端·typescript·文件上传·vue cli