0x00 概述

文件上传漏洞是Web安全漏洞中严重性最高的漏洞之一,通过攻击者通过文件上传漏洞就可以上传WebShell,从而控制整台Web服务器。

这里对文件上传漏洞进行归纳分类,将典型的检测机制和绕过方法,以及一些通用的攻击框架进行梳理。

0x01 客户端-JavaScript检测

检测方法

JavaScript检测即前端检测,通常是当前上传页面含有专门检测上传文件的JavaScript代码,一般是对文件后缀名进行检测。

绕过方法

通常有两种方法。

第一种是使用Burp代理,上传WebShell文件时页面弹框显示文件不合法,但Burp中没有任何请求报文,说明只是前端JS进行检测,此时可以修改为正常文件的后缀名后再页面上传、然后再通过Burp拦截修改后缀名即可绕过。

第二种是直接在浏览器中直接对页面HTML代码进行修改,将调用的相关的JS检测代码去掉即可正常上传WebShell文件。

案例参考

Upload-Labs Pass-01

0x02 服务端-MIME类型检测

检测方法

MIME类型检测,即服务端对请求报文Content-Type头的检测,一般采取白名单的方式来进行检测,如只能上传图像文件的话就Content-Type头就必须为image/jpeg或image/png或image/gif。

绕过方法

使用Burp代理,在上传WebShell的时候截断修改请求头Content-Type头的值为白名单限定的MIME类型即可绕过。

案例参考

Upload Labs Pass-02

0x03 服务端-目录路径检测

检测方法

一般是检测上传的目录路径是否合法。

绕过方法

若路径可控,则可以使用0x00或%00截断来绕过。

%00截断是用于GET方式中的,而0x00截断则是用于非GET的需要在二进制代码上直接修改的方式如POST。

其实00截断的根源是在于move_uploaded_file(file,newloc)函数的第二个参数newloc可被00截断攻击,而该函数的限制条件为:

  • PHP版本 < 5.3.4;
  • PHP的魔术引号即magic_quotes_gpc为Off关闭状态;

案例参考

Upload Labs Pass-11 利用%00截断绕过

Upload Labs Pass-12 利用0x00截断绕过

0x04 服务端-文件扩展名检测

检测方法

对于文件扩展名即后缀名的检测,一般有两种方式,黑名单和白名单。一般来说,白名单的方式更安全、更能难被攻击者绕过。

常见黑名单:

文件类型 扩展名
HTML html、htm、sthml、shtm
PHP php、php2、php3、php4、php5、phtml、pwml
ASP asp、aspx、ascx、ashx、asa、cer、cdx
JSP jsp、jspx、jspf
其他 xml、ini、htaccess、cgi、pl、js、exe、bat、swf

常见白名单:

文件类型 扩展名
图像 png、jpeg、jpg、gif、bmp
文档 doc、docx、xls、xlsx、csv、ppt、pptx、zip、rar、7z、gz、bz2、md
Flash swf、fla
Media swf、flv、mp3、mp4、wav、wma

绕过方法

针对黑名单的绕过方法:特殊可解析后缀、大小写、.$::DATA、空格、嵌套、/.、.htaccess、解析漏洞。

针对白名单的绕过方法:00截断、解析漏洞。

案例参考

Upload Labs Pass-4 利用.htaccess绕过

Upload Labs Pass-19 多种方法绕过

Upload Labs Pass-20 数组+/.绕过

0x05 服务端-文件内容检测

检测方法

包括3个以下方面。

文件幻数检测

即文件头检测,主要是检测文件内容开始处的文件幻数,比如图片类型的文件幻数如下:

JPG文件:Value = FF D8 FF E0 00 10 4A 46 49 46

GIF文件:Value = 47 49 46 38 39 61

PNG文件:Value = 89 50 4E 47

文件相关信息检测

图像文件相关信息检测常用的就是getimagesize()函数和exif_imagetype()函数等。

getimagesize()函数的返回结果类型是个数字,其中索引2表示的是图像的类型,返回的是数字,其中1 = GIF,2 = JPG,3 = PNG,4 = SWF,5 = PSD,6 = BMP,7 = TIFF(intel byte order),8 = TIFF(motorola byte order),9 = JPC,10 = JP2,11 = JPX,12 = JB2,13 = SWC,14 = IFF,15 = WBMP,16 = XBM。

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

文件加载检测

一般是调用API或函数去进行文件加载检测。常见的是图像渲染和二次渲染。

二次渲染的原理是调用imagecreatefromjpeg()函数对图像进行二次编译即进行了二次渲染。

imagecreatefromjpeg():由文件或URL创建一个新图象。

绕过方法

针对文件幻数检测的绕过

只需在后门代码前面插入如前面列的文件幻数的内容即可。

当然,用图片马的方法可以通杀,更方便(只校验文件幻数的话,图片马可以不用正常显示都OK)。

Windows中可通过如下命令生成图片马:

1
copy normal.jpg /b + shell.php /a webshell.jpg

更多的可参考Upload Labs靶场作者的博客:图片木马制作大法

针对文件相关信息检测的绕过

基本的绕过原理就是,先把文件头部分伪造好,再在幻数加上了一些文件信息,比如GIF文件中添加的信息:

1
2
3
4
GIF89a
(...some binary data for image...)
<?php phpinfo(); ?>
(... skipping the rest of binary data ...)

当然,用图片马的方法可以通杀,但是是需要能够正常显示的图片马。

针对文件加载检测的绕过

对于图像渲染,直接用正常显示的图片马就能绕过;

对于二次渲染,同样用图片马可成功绕过上传,但需要对经过二次渲染后的图像中未进行二次编译的位置进行分析,再往该位置插入恶意PHP代码。GIF文件直接手工即可插入、操作较为简单,JPG和PNG都有工具脚本直接实现后门代码的插入实现图片马绕过。

案例参考

Upload Labs Pass-13 利用图片马绕过文件头检测

Upload Labs Pass-14 利用图片马绕过getimagesize()和image_type_to_extension()

Upload Labs Pass-15 利用图片马绕过exif_imagetype()

Upload Labs Pass-16 二次渲染绕过

0x06 解析漏洞

Web应用程序解析漏洞

Apache解析漏洞

未知扩展名解析漏洞

其实该漏洞是由于用户配置不当产生的,与具体Apache版本无关。

通过module方式部署的Apache+PHP的环境存在如下解析问题。

解析:test.php.abc(其中abc为任意不属于黑名单且也不属于Apache解析白名单的名称)

描述:一个文件名为x1.x2.x3的文件,Apache 会从x3的位置往x1的位置开始尝试解析,如果x3不属于Apache能解析的扩展名,那么Apache会尝试去解析x2的位置,这样 一直往前尝试,直到遇到一个能解析的扩展名为止。

与其说这是漏洞,不如说是Apache的特性,就是我们平常所说的从右向左解析是一样的。

通常,该用户配置实在php.conf文件中配置的,我本地phpStudy环境是C:\phpStudy\Apache\conf\extra\httpd-php.conf文件:

1
2
3
4
5
6
7
8
9
10
11
LoadFile "C:/phpStudy/php/php-5.2.17/php5ts.dll"
LoadModule php5_module "C:/phpStudy/php/php-5.2.17/php5apache2_4.dll"
<IfModule php5_module>
PHPIniDir "C:/phpStudy/php/php-5.2.17/"
</IfModule>
LoadFile "C:/phpStudy/php/php-5.2.17/libmysql.dll"
LoadFile "C:/phpStudy/php/php-5.2.17/libmcrypt.dll"

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

上面的配置是没问题的,但如果用户将\.php$修改为如\.php时就会存在解析漏洞。

换行解析漏洞(CVE-2017-15715)

Apache通过mod_php来运行脚本,其2.4.0-2.4.29中存在Apache换行解析漏洞,在解析php时xxx.php\x0A将被按照PHP后缀进行解析,导致绕过一些服务器的安全策略。

本地Apache的版本为2.4.23,可通过httpd -v命令查看:

具体可参考P神的文章:《利用最新Apache解析漏洞(CVE-2017-15715)绕过上传黑名单》

.htaccess解析漏洞

.htaccess文件是Apache服务器中的一个配置文件,它负责相关目录下的网页配置。通过htaccess文件,可以帮我们实现:网页301重定向、自定义404错误页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能。

在文件上传中若未限制上传.htaccess文件且开启了.htaccess,那么就可以在.htaccess文件中重新定义可被执行的文件类型。

具体的在后面的小结中讲到。

案例参考

Upload Labs Pass-18 利用条件竞争+解析漏洞绕过

Upload Labs Pass-04 利用.htaccess绕过

Nginx解析漏洞

未知PHP文件解析漏洞

该漏洞同一与Nginx版本无关,属于用户配置不当造成的解析漏洞。

解析:abc/def.php(其中abc、def都为任意文件名)

描述:对任意文件名,在后面添加/abc.php的解析漏洞,如原本文件名是test.jpg则可以添加为test.jpg/x.php进行解析攻击。

%00截断解析漏洞

对于低版本的Nginx(0.5.*, 0.6.*, 0.7 <= 0.7.65, 0.8 <= 0.8.37),可以在任意文件名后面添加%00.php进行解析攻击。

如:1.jpg%00.php就会将前面1.jpg文件当成PHP文件进行解析执行。

IIS解析漏洞

IIS 5.x/6.0解析漏洞

解析:test.asp/abc 或 test.asp;abc(其中abc为任意文件名)

描述:IIS 5.x/6.0在解析asp格式的时候有两个解析漏洞,一个是如果目录名包含”.asp”字符串,那么这个目录下所有的文件都会按照asp去解析,另一个是只要文件名中含有”.asp;”会优先按asp来解析。

IIS 7.0/7.5解析漏洞

在默认Fast-CGI开启的情况下,IIS 7.0/7.5是对php解析时有一个类似于Nginx的解析漏洞,对任意文件名只要在URL 后面追加上字符串”/任意文件名.php”就会按照php的方式去解析。

如上传一个图片马shell.jpg,访问shell.jpg/xx.php可成功触发WebShell。

文件包含解析

这里指的是PHP的本地文件包含漏洞。

前面说到的一些如利用图片马绕过的方法中,由于上传图片马本身就是个图像类型的文件,直接在浏览器访问时不能触发其中的恶意代码的。此时就需要结合文件包含漏洞来触发如图片马中的代码。

简单地说,PHP文件包含漏洞的原理是:只要包含进来的文件,该文件中的内容都会被当成PHP代码来执行。

PHP文件包含的几个函数:include、include_once、require、require_once。

案例参考

看图片马那几个案例就ok。

.htaccess解析

.htaccess(Hypertext Access)文件,又称分布式配置文件,提供了针对目录改变配置的方法, 即在一个特定的文档目录中放置一个包含一个或多个指令的文件, 以作用于此目录及其所有子目录。作为用户,所能使用的命令受到限制。管理员可以通过Apache的AllowOverride指令来设置。

.htaccess文件是Apache服务器中的一个配置文件,它负责相关目录下的网页配置。通过.htaccess文件,可以帮我们实现:网页301重定向、自定义404错误页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能。

启用.htaccess,需要修改httpd.conf,启用AllowOverride,并可以用AllowOverride限制特定命令的使用,另外还需要加载mod_rewrite模块。

即启用.htaccess文件的两个条件:

  • 在httpd.conf配置文件中启用AllowOverride:AllowOverride All
  • 在httpd.conf配置文件中启用mod_rewrite模块:LoadModule rewrite_module modules/mod_rewrite.so

如果需要使用.htaccess以外的其他文件名,可以用AccessFileName指令来改变。例如,需要使用.config ,则可以在服务器配置文件中按以下方法配置:AccessFileName .config 。

通常,在文件上传有严格的后缀名黑名单限制但除了.htaccess外,我们可以利用上传.htaccess文件修改上传文件所在目录的配置、令其解析任意后缀名文件为目标后缀名文件如php,从而绕过黑名单过滤。其中该上传的.htaccess文件内容如下:

1
AddType application/x-httpd-php .jpg

1
2
3
4
5
SetHandler application/x-httpd-php

<FilesMatch "filename">
SetHandler application/x-httpd-php
</FilesMatch>

案例参考

Upload Labs Pass-04 利用.htaccess绕过

.user.ini解析

自 PHP 5.3.0 起,PHP 支持基于每个目录的 .htaccess 风格的 INI 文件。此类文件被 CGI/FastCGI SAPI 处理。此功能使得 PECL 的 htscanner 扩展作废。如果使用 Apache,则用 .htaccess 文件有同样效果。

除了主 php.ini 之外,PHP 还会在每个目录下扫描 INI 文件,从被执行的 PHP 文件所在目录开始一直上升到 web 根目录($_SERVER[‘DOCUMENT_ROOT’] 所指定的)。如果被执行的 PHP 文件在 web 根目录之外,则只扫描该目录。

在 .user.ini 风格的 INI 文件中只有具有 PHP_INI_PERDIRPHP_INI_USER 模式的 INI 设置可被识别。

实际上,除了PHP_INI_SYSTEM以外的模式(包括PHP_INI_ALL)都是可以通过.user.ini来设置的。

而且,和php.ini不同的是,.user.ini是一个能被动态加载的ini文件。也就是说我修改了.user.ini后,不需要重启服务器中间件,只需要等待user_ini.cache_ttl所设置的时间(默认为300秒),即可被重新加载。

查看PHP_INI_SYSTEM可以发现,大多数敏感配置项包括disable_functionsextension_direnable_dl等都在其中,我们无法直接通过.user.ini来直接设置了。

但是.user.ini可设置如下几项来实现构造后门:

这里只看auto_prepend_file项,在主文件解析之前会先解析该项设置的文件,效果和PHP文件包含一样。

案例参考

下面看个例子,环境是Apache+PHP,注意是以Fast-CGI的形式启动PHP的:

在upload目录中本身就存在hello.php文件:

1
<?php echo "HelloWorld!";?>

正常访问时输出指定字符串内容:

现在上传1.jpg文件,内容为一句话木马:

接着,由于服务端未过滤.ini扩展名,我们上传.user.ini文件,内容如下,指定刚刚上传后门jpg文件:

1
auto_prepend_file=1.jpg

此时再去访问hello.php,它已经加载1.jpg作为PHP文件执行了:

0x07 条件竞争

当后台程序先将文件上传后再进行相应的检测处理时,会存在个时间差,导致条件竞争漏洞的存在。

一般只能通过代码审计来发现此类问题。

绕过方法

通常,使用Burp重复发送上传报文或者自己编写脚本多线程发送上传报文,然后再浏览器中访问上传文件的页面,直至触发为止。

其中脚本用hackhttp模块和多线程模块即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import hackhttp
from multiprocessing.dummy import Pool as ThreadPool

url = 'http://a.com/upload.php'
raw = '''
POST上传的请求报文'''

def upload(lists):
hh = hackhttp.hackhttp()
code,head,html,redirect_url,log = hh.http(url=url,raw=raw)
print code

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

案例参考

Upload Labs Pass-17 利用条件竞争绕过

Upload Labs Pass-18 利用条件竞争+解析漏洞绕过

0x08 PUT上传漏洞

Web容器支持PUT、MOVE、COPY等不安全的HTTP方法,若权限配置不当、系统未禁用这些危险的HTTP方法时,攻击者就可以直接从客户端向服务器上传数据来取代指定文档的内容,即攻击者通过PUT、MOVE、COPY等HTTP方法上传恶意文件。

该漏洞很简单,直接向目标站点的某些接口发送HTTP OPTIONS请求,若正常返回响应,则查看返回响应中允许哪些HTTP方法,若允许PUT、MOVE、COPY等其中的某些方法,则可以发送这些HTTP方法请求进行利用。

具体的攻击利用参考网上的文章即可:HTTP PUT方法利用的几种方式

防御方法很多,比如Tomcat容器的防御是在web.xml中设置如下,这样就能禁用PUT、DELETE、HEAD、OPTIONS、TRACE等危险的HTTP方法了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"  
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">

<security-constraint>
<web-resource-collection>
<url-pattern>/*</url-pattern>
<http-method>PUT</http-method>
<http-method>DELETE</http-method>
<http-method>HEAD</http-method>
<http-method>OPTIONS</http-method>
<http-method>TRACE</http-method>
</web-resource-collection>
<auth-constraint>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
</login-config>

0x09 文件上传攻击框架

先看下前辈总结的整个文件上传攻击框架的核心图:

在此基础上,我将自己的理解和新绕过方法都整合到一个新的文件上传攻击框架:

0x0A 参考

Upload Attack Framework