0%

upload-labs之文件上传

继续来学习owasp top10之一的文件上传,使用的靶场是upload-labs

pass-01(前端js绕过)

直接右键查看源码:

发现前端有js拦截,只允许上传.jpg,.png和.gif文件,不确定后端有没有校验,先尝试抓包绕过:

图片

把文件后缀改成png,点击上传:

图片

修改后缀为php,然后放包

图片

在后台可以看到一句话木马成功上传

图片

但如果我们作为攻击者,我们是看不到后台的,我们需要在前端找到上传的路径:

图片

发现上传的文件在上一级目录下upload下,然后蚁剑连接:

图片

pass-02(MIME绕过)

常见MIME类型:

text/plain (纯文本)
text/html (HTML文档)
text/javascript (js代码)
application/xhtml+xml (XHTML文档)
image/gif (GIF图像)
image/jpeg (JPEG图像)
image/png (PNG图像)
video/mpeg (MPEG动画)
application/octet-stream (二进制数据)
application/pdf (PDF文档)

绕过方法:

修改Content-Type头

  • 将恶意文件(如PHP)的Content-Type改为无害类型(如image/jpeg)
  • 示例:Content-Type: image/jpeg(实际是PHP文件)

双扩展名绕过

  • 例如:malicious.php.jpg
  • Content-Type: image/jpeg,但删掉.jpg,就又变成了php文件

这里直接上传php木马文件,会上传失败,观察前端源码并没有过滤,也就是后端进行了校验,那依旧是上传jpg后缀的木马,然后抓包把文件后缀名改成php;也可以上传muma.php.jpg,抓包的结果Content-Type: image/jpeg,所以只需要把.jpg给删掉即可,两个方法对应上面的修改Content-Type头双扩展名绕过,但本质没什么区别

图片

图片

看下后端源码:

图片

getshell的方法同第一关

pass-03(黑名单绕过)

先尝试上传muma.php,提示:不允许上传.asp,.aspx,.php,.jsp后缀文件!原来有黑名单,我们如果继续按照前两关的方式,抓包修改文件后缀为php,Content-Type: image/jpeg依旧不行,因为后端专门检验你的文件后缀是不是php

图片

虽然php被禁,但我们还可以尝试php3, .php4, .php5, .php7, .php8(旧版 PHP 遗留支持),.phtml(PHP + HTML 混合文件),.phps(PHP 源代码显示,但某些配置仍可执行)

图片

根据返回信息可见这些都被上传成功了(除了php后缀,不是看状态码),但是其中存在未被解析的文件,我们只能根据响应数据包里的上传路径一个一个测试:如果说显示空白页面,那么就是被解析了,如果显示一句话木马,那就是没被解析,前提是我们需要在Apache的httpd.conf配置文件中设置AddType application/x-httpd-php,才可以解析php3, .php4, .php5, .php7, .php8.phtml.phps

因为我是高版本phpstudy,于是想手动添加该字段,但即便添加后,在web中访问该文件会将该文件下载(这挺让人懵逼的,按道理不应该是这样啊),未添加前,在web中访问该文件只是空白(但并未解析),两种共同点都是未被解析(因为我上传phpinfo内容依旧是空白),我看别的博主说要将php的版本改为ts(参考:https://blog.csdn.net/mooyuan/article/details/147541272),但我的phpstudy里面没有ts版本,遂放弃。

不过本关的重点在于知道当php被后端校验时应该如何绕过:尝试上传php3, .php4, .php5, .php7, .php8.phtml.phps

pass-04(黑名单,.htaccess绕过)

源码:

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
$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-03能上传的文件也校验了,所以pass-03的方法也行不通

但是这里没有禁止上传.htaccess文件,介绍下该文件:.htaccess(Hypertext Access)是 Apache Web 服务器的一个配置文件,主要用于目录级配置,允许在不修改主服务器配置(httpd.conf)的情况下,对特定目录进行权限、重定向、URL 重写等设置。

而且其可以修改 PHP 解析规则,攻击者可上传 .htaccess 文件,使 .jpg 等文件被当作 PHP 执行:

1
AddType application/x-httpd-php .jpg

使用htaccess文件前提:

  • 黑名单中未过滤 .htaccess
  • apache配置文件httpd.conf中启用了AllowOverride All
  • 服务端未处理文件名(否则上传到htaccess到目录下成为其它文件名则不奏效)

上传.htaccess文件成功:

图片

图片

然后上传phpinfo.php文件,抓包将文件后缀改成jpg(htaccess中可以将jpg文件解析成php文件)

图片

图片

访问时又出错了,又变成下载了,和pass-03遇到的情况一样,这里还是php的版本问题,不过知道原理就可以了

有个师傅把版本改成ts后做得:https://blog.csdn.net/mooyuan/article/details/147542111

pass-05(黑名单,.user.ini绕过)

提示说:上传目录存在php文件(readme.php),本次使用配置文件.uer.ini,该配置文件的效果是在.user.ini相同的目录下,所有的php文件都包含pass5.jpg这个文件。如果我们上传.uer.ini,而且该目录下存在readme.php,我们再上传一个修改为jpg后缀的phpinfo,虽然jpg不能解析为php,但该文件被写入readme.php,这样就可以解析了

.user.ini重要配置项:auto_prepend_file=文件名:在页面头部加载的文件,auto_append_file=文件名:在页面尾部加载的文件,写入一个就行

1
auto_prepend_file=phpinfo.jpg

依次上传文件,然后访问readme.php

图片图片图片

看下后台上传的文件:

图片

注:本次上传禁止了.htaccess

pass-06(黑名单,大小写绕过)

通过源码可知,这里把.htaccess和.user.ini都给禁用了,但不同的是这里并没有转换成小写再校验:

图片

图片

我们只需要把后缀改成没有校验的大写即可,但如果你使用的是高版本的phpstudy,还用的是apach服务器,那么当访问文件的上传路径时,大概率会遇到500的报错,这里使用nginx即可:

图片图片

pass-07(黑名单,后空格绕过)

依旧是把所有后缀都给禁用了,与pass 05不同的是,校验的代码又少了一行:

图片

图片

这里少了首尾去空这个过滤,我们通过抓包在文件尾处添加一个空格:

图片

图片

如果在.后面加空格呢???

图片

图片

可见能上传,回显空白页面说明存在该文件,但不能被解析

pass-08(黑名单,加点绕过)

与上面相比,过滤少了删除文件名末尾的点,既然如此,那我们主动构造一个点

图片

图片

访问该文件时,最后加不加点都可以成功

图片图片

原理:在 Windows 系统 中,文件名末尾的点(.)会被自动忽略,导致 phpinfo.php. 实际保存为 phpinfo.php,从而绕过某些文件上传检查。

pass-09(黑名单,::$DATA绕过)

过滤又少了$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA,我们继续再文件尾处加上::$DATA:

图片

访问时不用加::$DATA:

图片

原理:在 Windows 系统 中,文件名::$DATA 是一种特殊写法,用来直接访问文件的原始数据流,常用于绕过文件上传限制或隐藏恶意代码。

  • NTFS 文件系统特性
    Windows 的 NTFS 格式允许文件附带“数据流”(Alternate Data Streams, ADS),比如文件可以有隐藏的额外内容。
  • ::$DATA 的作用
    加在文件名后,表示直接操作文件的主数据流(默认存储内容的部分)。

上传名为 phpinfo.php::$DATA 的文件,Windows 会自动忽略 ::$DATA,最终保存为 phpinfo.php

pass-10(黑名单,点空格点绕过)

查看源码,这次将所有该过滤的都过滤了,我们观察它的逻辑,它是先去除文件名末尾的点,然后转换为小写,去掉::$DATA,然后再去除空格,如何我们在文件名后面加上一个点,再加上空格,再加上一个点,第二个点按照代码的逻辑是不会被过滤的,所以当进行in_array匹配时,可以成功绕过

抓包修改文件后缀为. .

图片

图片

顺便提一嘴,我们上面所有的绕过,都可以采用这种点空格点的方式

pass-11(黑名单,双写绕过)

直接看源码,与上面都不一样,这里的str_ireplace的第一个参数设置为黑名单,str_ireplace不区分大小写,所以无法通过大写绕过,如何我们后缀设置为pphphp,str_ireplace会匹配到php并将其删除,然后左边剩下的p和右边的hp可以合并再次生成php后缀,因为该函数是通过递归进行匹配,所以就绕过了前面的p,当执行到最后一个p,结束匹配,成功绕过;

图片

这里文件名phpinfo中的php也被删掉了

图片

pass-12(白名单,前提:上传路径可控,get,%00截断绕过)

我们先上传一个符合要求的图片:

图片

发现上面有save_path的参数,我们再看下源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$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类型文件!";
}
}

只允许上传'jpg','png','gif',上传.jpg.php这样是不行的,看下最终的图片保存路径,文件名是save_path加上一个rand随机数和一个date日期,和默认的文件后缀,我们刚才上传正常图片时观察到图片的save_path是/upload/,也就是我们最终上传的文件路径是/upload/rand+date.jpg,但如果我们能主动在/upload/后面加上个文件名,再使用%00截断后面的rand+date.jpg,即/upload/自定义文件名+%00+rand+date.jpg,当我们自定义的文件名是phpinfo.php,那我们上传的phpinfo.jpg,最终在服务中生成的名字是不是变成了/upload/phpinfo.php???

还有两个前置条件:

配置文件php.ini中的magic_quotes_gpc = off

php的版本要求是5.2.x

图片

因为我是8.1.1.3的phpstudy,上面最低的php版本是5.2.17,可死活下载不下来,下载高版本的就可以,也是离了个大谱,不过还是重在知道方法

最终也是上传失败,只要我在upload/后面拼接任何路径,上传都是失败的,大概率是因为php版本过高的问题

pass-13(白名单,post,%00截断绕过)

与上一关设计方法一样,区别就是这里是post控制上传路径,遇到的问题也一样

图片

pass-14