这段时间看了一下文件上传漏洞的知识点,然后把upload的靶场打完了,记录了一下过关的路程。文章最后还有一张我对于文件上传漏洞的总结哦。

前言

我用的这个文件上传的靶场,是c0ny1的upload-labs。下载地址贴一下:https://github.com/c0ny1/upload-labs

听我学长的话,咱下载完成一个东西后,先看看它的readme文档或者其他要求的文档。

这个靶场的php环境推荐5.2.17,那我就乖乖把我的php调到这个版本,然后开始打靶场罗。

1、PASS-01——js绕过

上传php后缀文件时,弹出不允许上传,查看源代码,发现这是前端js拦截。

那就先上传一个正常的11.jpg,然后用burp抓包将11.jpg改成22.php,然后将图片的内容改成想要的PHP文件内容就可以啦。修改点击发送,发现已经上传成功啦。

2、PASS-02——content-type检测绕过

上传2.php时,提示文件类型不正确,查看源码,发现对content-type做了限制。

那就先上传2.php,然后用burp抓包,将content-type改成其中一个合法的就行。

抓包获取到的:

修改成合法的(image/jpeg或image/png或image/gif):

上传成功:

3、PASS-03——其他后缀名绕过

上传2.php,发现出现提示信息:

这很有可能是设置了黑名单,查看一下源代码。

既然源代码中只设置了这几种可执行后缀的黑名单,那就直接尝试上传其他可执行后缀的文件

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

上传2.php3文件,抓包,可显示图片路径,成功上传:

4、PASS-04——.htaccess解析绕过

上传php文件,查看源代码,发现还是设置了黑名单,只是这次好像把能禁用的后缀都禁用掉了:

1
$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");

发现它没有禁止上传.htaccess后缀,那就尝试上传这个,

.htaccess的内容为(.htaccess不能起名字,它就是.htaccess文件):

1
SetHandler application/x-httpd-php

(代码意思:无论上传哪种类型的文件,他就会被解析为.php)

所以,我们先上传.htaccess文件:

此时,再上传一张正常的jpg图片,利用Burp抓包,将1.jpg图片的内容替换成php代码,点击发送:

此时,访问1.jpg就会转换成php文件:

5、PASS-05——点空格点绕过

上传一个php代码,显示此文件类型不允许上传。查看源代码,黑名单限制,这题把.htaccess后缀也限制了。感觉都被限制了呀,但好像那些限制条件都只限制了一次,先去除文件后缀点再去除空格。若此时设置为文件名点空格点(即2.php. .),删掉一个点一个空格,还剩下2.php.

1
2
3
4
5
6
7
8
9
$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); //首尾去空

Burp抓包,修改2.php为2.php. .文件成功上传:

6、PASS-06——大小写绕过

上传php文件不被允许上传,查看源代码,仔细观察,发现这题居然没有设置大小写转换,那我就直接尝试大小写绕过啦。其实PASS-05的思路这题同样适用。

抓包,修改2.php为2.Php,成功上传:

7、PASS-07——空格绕过

php文件不允许上传,我们还是来看源代码吧,一看没有写去掉末尾空格的代码呀,那就直接空格绕过上传咯。Burp抓包,将2.php修改成2.php 发现成功上传

8、PASS-08——点绕过

直接上源代码,发现这题没有设置删除文件末尾的点的代码,那就在文件后面加点绕过啦。

这里点绕过的原理其实是利用windows的特性,在windows下,2.php.和2.php的效果是一样的。

Burp抓包,将2.php修改成2.php.成功上传。

9、PASS-09——::$DATA绕过上传

查看源代码,发现这里没有去除字符串::$DATA的代码,于是我们可以使用::$DATA绕过上传。

Burp抓包,将2.php修改成2.php::$DATA,发现成功上传

10、PASS-10——点空格点绕过

这关的源代码和第五关一样,所以采用点空格点就能绕过。

Burp抓包,将2.php修改为2.php. .成功上传

11、PASS-11——双写绕过

查看源代码,发现将图片的后缀用空白代替了。这时可以双写后缀名绕过。

1
$file_name = str_ireplace($deny_ext,"", $file_name);

用burp抓包,将2.php修改成2.pphphp成功上传

12、PASS-12——目录可控%00截断绕过(GET)

上传一个php文件,出现提示信息:

说明可能设置了白名单,查看源代码:

1
$ext_arr = array('jpg','png','gif');

看到的确是设置了白名单,可以采用%00截断。

满足%00截断的两个条件:

1
2
3
条件1:php版本小于5.3.4

条件2:要将magic_quotes_gpc关闭

上传1.jpg,burp抓包,将save_path=../upload/修改为save_path=../upload/2.php%00,并且将jpg图片内容改为php内容,这样就相当于上传了2.php,并对后面的图片1.jpg进行了截断,成功上传

13、PASS-13——目录可控%00截断绕过(POST)

上传一个php文件,也显示只允许上传.jpg|.png|.gif类型文件。应该也是设置了白名单,查看源代码。这题的代码好像跟PASS-12差不多耶,先抓包看看,发现明显不同,上一题中的save_path路径以GET方式直接显示出来了,这里的save_path明显是POST方式。所以我们可以用POST方式的%00截断绕过。

两者的区别就是GET会自行解码,POST不会自行解码,所以POST方式的需要我们手动将%00经过decoode进行解码。

上传正常的jpg图片,Burp抓包,将../upload/修改为../upload/2.php%00,将jpg图片内容改为php内容,

然后选中%00按如下方式进行decode,解码成功之后%00会看不见,实际存在。

修改完成之后,点击发送,文件上传成功:

14、PASS-14——图片马绕过

本题要求:

1
2
3
4
5
6
7
8
9
上传图片马到服务器。

注意:

1.保证上传后的图片马中仍然包含完整的一句话或webshell代码。

2.使用文件包含漏洞能运行图片马中的恶意代码。

3.图片马要.jpg,.png,.gif三种后缀都上传成功才算过关!

首先,制作图片马,在cmd中输入:

1
copy 1.jpg/b+2.php/a 3.jpg

生成包含webshell的3.jpg,直接上传3.jpg。

本题直接说明存在文件上传漏洞:

于是,上传之后,抓包,查看文件路径,

访问:

.png和.gif的后缀按照同样的方法制作图片马,并上传,能够成功访问:

15、PASS-15——getimagesize()图片马绕过

本关卡要求和上一关一样,首先查看源代码,发现有:

1
$info = getimagesize($filename);

getimagesize()函数会对目标文件的16进制去进行一个读取,去读取头几个字符串是不是符合图片的要求的。还是制作图片马上传即可。

制作图片马:

1
2
3
4
5
copy 1.jpg/b+2.php/a 3.jpg

copy 1.png/b+2.php/a 3.png

copy 1.gif/b+2.php/a 3.gif

分别上传,使用文件包含漏洞访问上传的图片马中的恶意代码:

16、PASS-16——exif_imagetype()图片马绕过

查看源码,exif_imagetype() 读取一个图像的第一个字节并检查其签名。

1
$image_type = exif_imagetype($filename);

本题需要开启php_exif模块

解题过程跟PASS-14和PASS-15一样,利用图片马上传绕过。

使用文件包含漏洞访问上传的图片马中的恶意代码:

17、PASS-17——图片二次渲染绕过

查看源码,发现图片经过了二次渲染。

1
$im = imagecreatefromjpeg($target_path);

imagecreatefromjpeg()函数,二次渲染是会创建一个新图像,导致图片马的数据丢失,上传图片马失败。所以要绕过imagecreatefromjpeg()函数进行上传。

关于gif的图片比较简单:

1
原理大致就是先上传一张正常的gif图片,将经过二次渲染的图片下载下来。然后利用工具找到两张图片渲染前后相同的部分,在相同部分写入webshell,再上传,即可成功绕过二次渲染。

具体步骤,首先,先上传一张正常的图片2.gif,将生成的32421.gif与原来的2.gif进行对比,查找渲染前后没有变化的部分。用一个可以查看十六进制的工具,我用的是winhex,将两张图片放进去,然后在查看处选择同步和比较。

这种白色的都是相同的,黑色部分则是不相同的。

只需要在2.gif的白色部分,即相同部分,插入恶意代码即可。

将其另存为22.gif,然后上传到服务器。利用文件包含漏洞即可绕过二次渲染。

至于jpg和png的,用上面这种方法是不行的,你会发现当你在比较渲染前后图片相同位置时,都是一些断断速速的点,根本插不进去的。这里具体的实现还是要利用一些写的脚本,将webshell插入进去。具体实现可以参考[这篇文章](upload-labs之pass 16详细分析 - 先知社区 (aliyun.com))

18、PASS-18——条件竞争绕过

查看源代码,发现本关卡是先将图片上传到服务器,再判断文件后缀是否在白名单,在则重命名,不在则删除。

1
2
3
4
5
6
7
8
9
10
$upload_file = UPLOAD_PATH . '/' . $file_name;
if(move_uploaded_file($temp_file, $upload_file)){
if(in_array($file_ext,$ext_arr)){
$img_path = UPLOAD_PATH . '/'. rand(10, 99).date("YmdHis").".".$file_ext;
rename($upload_file, $img_path);
$is_upload = true;
}else{
$msg = "只允许上传.jpg|.png|.gif类型文件!";
unlink($upload_file);
}

那我们就可以利用条件竞争来绕过。看看谁比谁快(bushi)。如果我们在上传上去的一瞬间访问这个文件,那他就不能对这个文件删除。这就相当于我们打开了一个文件,然后再去删除这个文件,就会提示这个文件在另一程序中打开无法删除。

上传一个2.php文件,burp抓包,将其发送给测试器Intruder,在position处清除负载。在payloads选择没有负载(Null payloads),有效载荷选项(payload options)选择无限期地重复(continue indefinitely)。在options处将线程数调高一点,如20。

点击攻击,这边在不停的上传:

我们打开另一个浏览器,访问2.php的路径,找不到我就一直访问,总有你还没来得及删掉的时候吧,然后我第二次就直接访问到啦:

19、PASS-19——条件竞争绕过

查看源代码,这关是检查了后缀名,然后上传,然后再进行二次渲染。所以我们只能上传图片马,然后配合解析漏洞(即访问地址加上include.php?file)即可成功绕过。

这题的上传路径有点问题,没有上传到upload/upload目录下,所以我们先打开PASS-19的myupload.php修改一下路径:

先制作一张包含恶意代码的图片马:

1
copy 1.jpg/b+2/php/a 3.jpg

然后上传3.jpg,并用burp抓包,其他操作跟PASS-18一样,发送到测试器,对它不断进行上传。

然后打开另一浏览器,不断访问图片地址(http://192.168.56.1:8099/upload/include.php?file=upload/3.jpg)

20、PASS-20——/.绕过

查看源代码,本题是设置了一个黑名单,然后发现有一个move_uploaded_file()函数。这个函数有个特性,就是会忽略文件末尾的 /. (或者用.也可以)

也就是说,我们先上传一张正常的图片1.jpg,然后用burp抓包,将upload-19.jpg改为2.php/.此时会上传2.php文件,并自动忽略/.后面的内容,即忽略1.jpg

还有一个方法。这个函数的img_path是由post参数的save_name控制的。所以可以利用POST方式的%00截断。

先上传一张正常的图片1.jpg,并用burp抓包,找到save_name,将upload-19.jpg改为2.php%00,并将%00进行url的decode,上传成功

21、PASS-21——数组绕过

查看源码,如果是数组的话就不会检查后缀。

1
2
3
if (!in_array($ext, $allow_suffix)) {
$msg = "禁止上传该后缀文件!";
}

采用第一个数组和第二个数组拼接

1
$file_name = reset($file) . '.' . $file[count($file) - 1];

那就可以利用数组绕过。

在这里,数组的下标不能相邻就行,比如第一个数组下标为0,第二个就要大于1,才不会被拼接起来。

首先,构造表单,能够数组上传,然后上传一张正常的照片1.jpg

Burp抓包,点击发送,成功上传

22、总结

最后,放上一张关于文件上传漏洞的总结图