文件上传漏洞小结
基本概念
文件上传漏洞一般都是指上传Web脚本能够被服务器解析的问题,也就是通常所说的webshell的问题。
产生条件:
-
上传的文件能够被解析执行
-
用户能够访问这个文件
-
上传文件的内容不可以被改变
文件上传绕过姿势概述:
客户端bypass
文件上传功能的安全检测通常分为前端检测和后端检测。
一些常见的前端校验方法:
-
文件类型校验:前端可以限制用户只能选择特定类型的文件进行上传,例如只允许图片、文档等。
-
文件大小限制:设置文件大小的限制,防止上传过大的文件,这可以减少服务器的负担,并且可以防止某些类型的拒绝服务攻击。
-
文件格式检查:除了文件扩展名,还可以检查文件的实际格式,确保上传的文件不是伪装的恶意文件。
前端的校验功能大多数都是通过Javascript来实现的,通过Burp抓包修改绕过,或者禁用指定js文件,很轻松就可以绕过,所以前端bypass不是重点。
文件上传漏洞绕过主要是在后端的校验,后端的校验方法主要是这几种:文件扩展名,文件内容和代码逻辑。
黑名单bypass
特殊后缀名绕过
可以尝试使用服务器黑名单中未列出的文件扩展名,在某些特定的环境中,某些特殊的后缀名仍然会被当做php文件解析。
在某些httpd.conf中,默认对于文件的解析规则可能如下:
<FilesMatch "+\.ph(p[3457]?|t|tml)$">
SetHandler application/x-httpd-php
</FilesMatch>
由于黑名单规则不严谨,可以通过如下扩展名绕过:
Php|php2|php3|php4|php5|php6|php7|pht|phtm|phtml
又比如配置文件中:
AddType application/x-httpd-php .php .php3 .phtml
所以上传.php|.php3|.phtml
后缀的文件都可以当做php文件来执行。
大小写绕过
大小写绕过利用了文件系统或web服务器对文件名大小写的不敏感性。或者没有将文件后缀统一转换为大写或者是小写,而黑名单不严谨。
在某些操作系统中,比如windows对大小写就不敏感,所以上传大小写混写的php进行绕过,所以.PhP
文件被当成php文件解析。
又比如禁止上传如下后缀的文件:
.php|.php5|.php4|.php3|.php2|php1|.html|.htm|.phtml|.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|.htaccess
但是没有使用strtolower()函数等类似函数进行转换。
.htaccess绕过
在apache中,该文件作为一个配置文件,可以用来控制所在目录的访问权限以及解析设置。
黑名单没有禁止.htaccess
文件上传,并且允许用户使用自定义.htaccess
文件。那么上传一个.htaccess
文件,就可以改变当前目录以及子目录的apache配置信息,将其他后缀的文件作为php文件解析。
若要启动.htaccess
配置文件,需要在服务器的主配置文件将 AllowOverride 设置为 All。
在.htaccess
文件中重新写规则:
<FilesMatch "eval.gif">
SetHandler application/x-httpd-php
</FilesMatch>
在当前目录下,如果匹配到evil.gif文件,则被解析成php代码执行。上传覆盖.htaccess
文件后,将上传的带有脚本马的图片以脚本方式解析。
.user.ini绕过
.user.ini
文件是php的一个特性,允许位特定的php文件或目录设置特定的ini配置,而无需更改全局的php.ini
文件。(.user.ini实际上就是一个可以由用户自定义的php.ini)
条件:只有在 php>=5.3.0 版本中,并且以fastcgi运行的php才可以使.user.ini
生效。
.user.ini
比.htaccess
用的更广泛,不管是Nginx/Apache/IIS只要是以fastcgi运行的php就可以。在Apache中.user.ini
和.htaccess
有同样的效果,但.htaccess
只可以用于Apache。
.user.ini
中的两个配置:
auto_append_file ; 指定一个文件,自动包含在要执行的文件前
auto_prepend_file ; 指定一个文件,自动包含在要执行的文件后
可以上传一个这样的.user.ini
文件:
auto_prepend_file = eval.gif
然后再上传一个文件名为eval.gif
图片马,再访问上传目录下的一个可执行的php文件,那么eval.gif
图片马就会被正常执行。
系统特性绕过
空格绕过
在Windows平台,在对用户上传的文件名进行处理时,没有使用trim()
函数去除字符串首尾处的空白字符。
当用户上传图片马时,用Burp拦截在文件尾部加入空格。带有空格的后缀可以绕过黑名单的检测,但文件存在Windows服务器上时,会自动去除后缀中的空格。
点绕过
在Windows平台,在对用户上传的文件名进行处理时,没有使用deldot()
函数删除文件名末尾的点。
上传文件名末尾的点的文件。在Windows服务器中,后缀名之后的点在保存时,会被自动忽略。
NTFS文件流(::$DATA)绕过
::$DATA
流是Windows NTFS文件系统中的一个功能,它允许一个文件拥有多个数据流。创建一个数据交换流文件的方法:宿主文件:准备与宿主文件关联的数据流文件
。
文件名为文件名+::DATA
,则会把::DATA
之后的数据当成文件流处理,并不会检测后缀名,且保持::DATA
之前的文件名。
上传一个名为eval.php::$DATA
的木马,可以绕过黑名单的检测,并且通过eval.php
就可以访问。
配合解析漏洞
Apache Httpd多后缀解析漏洞
Apache默认一个文件可以有多个以点.
分割的后缀,当右边的后缀名无法识别,则继续向左识别。
如果服务器的php文件处理程序时配置不当,那么所以只要文件含有.php
后缀的文件会被识别成php文件,没必要是最后一个后缀。
上所以上传eval.php.jpg
就可以被解析为php文件,并且上传后的文件名并不会被修改。
Apache Httpd换行解析漏洞
Apache会使用正则表达式中的$
用来匹配字符串结位置,但在设置了对象的Multiline属性的条件下,$
还会匹配到字符串结尾的换行符。
也就是说 $
会去匹配换行符(LF),\x0A
转义序列代表的就是换行符,所以在php文件后面加上 \x0A
可以进行绕过。在解析php时1.php\x0A
将被按照php文件进行解析。
Nginx配置不当解析漏洞
当配置项cgi.fix_pathinfo开启并且security.limit_extensions没有限制解析文件类型时,在上传的文件名后面加上/.php
,被解析为php文件。
上传/eval.jpg/a.php
,配置文件中的配置项cgi.fix_pathinfo=1默认开启(路径修复:如果当前路径不存在则采用上级路径)如果a.php
不存在,FastCGI就会把上一级的eval.jpg
作为php文件解析。
IIS7.5解析漏洞
在FastCGI运行模式下,php.ini里配置项cgi.fix_pathinfo=1,并且取消勾选php-cgi.exe程序的模块映射中的请求限制。
在上传的文件名后面加上/.php
,可以被作为php文件解析,和Nginx配置不当解析漏洞非常类似。
IIS6.0解析漏洞
路径解析:在.asp|.asa
目录下的任意文件都会以asp格式解析。
分号截断:IIS6.0默认不解析;
后面的内容,上传eval.asp;.jpg
会被解析为asp。
解析文件类型:IIS 6.0默认的可执行文件除了asp还包含asa|cer|cdx
,会将这三种扩展名文件解析为asp文件。
双后缀名绕过
黑名单使用str_ireplace()
函数将匹配到的黑名单中的内容替换为空。但是它只会将黑名单中的内容替换为空一次,可以通过双写后缀名.phpphp
进行绕过。
白名单bypass
相比于黑名单,白名单的绕过要困难很多。
MIME类型绕过
浏览器通常使用MIME类型(而不是文件扩展名)来确定如何处理URL。大部分Web应用系统判定文件类型是通过content-type
字段。
只需要将MIME类型修改为白名单中允许的类型即可。上传对文件类型做了白名单限制,通过Burp将其他类文件类型修改为如content-type: image/png
等常见的的文件类型进行绕过。
00截断
%00
是字符串的结束标识符,可以利用手动添加字符串结束标识符的方式来将后面的内容进行截断,而后面正常的扩展名又可以帮助我们绕过黑白名单检测。
注意:0x00
和%00
都表示字节值为零的字符,%00
是0x00
字节的URL编码形式。
当上传路径可控,php.ini
中的magic_quotes_gpc
为off
时,可以使用00截断来绕过白名单:
如果上传文件的路径为:可控的上传路径/随机数.白名单中的后缀
正常情况下,服务器拼接得到的上传路径为:$img_path = ../upload/5920201223231032.gif;
而在可控的上传路径中,使用%00
截断后,拼接得到的上传路径为:$img_path = ../upload/eval.php%00/5920201223231032.gif
对后缀进行白名单检测时.gif
可以很好绕过。但是保存在服务器上的文件却是eval.php
,因为%00
之后的内容被截断了。
00截断应该在什么时候使用呢?
数据包中必须含有上传后文件的目录情况才可以用,比如数据包中存在path: uploads/
,那么攻击者可以通过修改path的值来构造paylod: uploads/aa.php%00
。为什么修改path才可以,因为程序中检测的是文件的后缀名,如果后缀合法则拼接路径和文件名,那么攻击者修改了path以后的拼接结果为:uploads/aaa.php%00/2018051413370000.php
,移动文件的时候会将文件保存为uploads/aaa.php
,从而达到getshell效果。
文件内容bypass
文件头检测
在每一个文件(包括图片,视频或其他的非ASCII文件)的开头都有一片区域来显示这个文件的实际用法,这就是文件头标志。添加服务器允许的文件头以绕过检测。
常见的文件头:
GIF: 47 49 46 38 39 61
PNG: 89 50 4E 47 0D 0A 1A 0A
JPG: FF D8 FF E0 00 10 4A 46 49 46
只能上传图片格式的后缀,在进行文件头绕过时可以把上面的文件头添加到一句话木马内容最前面,达到绕过文件头检测的目的。
图片马绕过
绕过getimagesize函数
php一般使用 getimagesize()
函数检测文件头内容检测,getimagesize()函数会返回一个数组,其中下标2是图像的类型,其中1=GIF|2=JPG|3=PNG
。上传一个正常图像后缀的图片马即可绕过。
绕过exif_imagetype函数
exif_imagetype()
函数会判断一个图像的类型。检查图像的第一个字节。可能返回的常量有IMAGETYPE_GIF=1|IMAGETYPE_JPEG=2|MAGETYPE_PNG=3
文件头不正确返回false,上传具有正常文件头的图片马即可绕过。
图片马需要结合解析漏洞或者文件包含漏洞才能解析图片木马。
二次渲染
在上传文件后,网站会对图片进行二次处理(格式、尺寸要求等),服务器会把里面的内容进行替换更新,处理完成后,我们原有的图片生成一个新的图片并放到网站对应的标签进行显示。
如何判断图片是否进行了二次处理?
对比要上传图片与上传后的图片大小,使用16进制编辑器打开图片查看上传后保留了哪些数据,查看那些数据被改变。
绕过方法:
文件包含漏洞:将一句话木马插入到网站二次处理后的图片中,也就是把一句话插入图片在二次渲染后会保留的那部分数据里,确保不会在二次处理时删除掉。这样二次渲染后的图片中就存在了一句话,在配合文件包含漏洞获webshell。
条件竞争:这里二次渲染的逻辑存在漏洞,先将文件上传,之后再判断,符合就保存,不符合删除,可利用条件竞争来进行爆破上传。
条件竞争
由于服务器端在处理不同用户的请求时是并发进行的,因此,如果并发处理不当或相关操作逻辑顺序设计的不合理时,将会导致条件竞争漏洞的发生。
如果文件可以直接上传,上传成功后才进行判断:如果文件格式符合要求,则重命名;如果文件格式不符合要求,将文件删除。
由于服务器并发处理多个请求,假如a用户上传了木马文件,由于代码执行需要时间,在此过程中b用户访问了a用户上传的文件,会有以下三种情况:
-
访问时间点在上传成功之前,没有此文件。
-
访问时间点在刚上传成功但还没有进行判断,该文件存在。
-
访问时间点在判断之后,文件被删除,没有此文件。
参考文章:
http://www.admintony.com/关于上传中的00截断分析.html
https://www.freebuf.com/articles/web/265245.html
https://blog.csdn.net/qq_43665434/article/details/115013915
若有错误,欢迎指正!o( ̄▽ ̄)ブ