一文简单入门文件上传

文件上传

随着Web应用发展和广泛应用,很多的应用都允许用户上传自己的文件,以此提升用户体验。但是,这也就造成了一个web应用安全中很著名的漏洞,它就是文件上传漏洞。由于Web应用的上传功能的代码实现没有对用户上传文件的格式和后缀以及文件类型进行过滤,从而导致大家都可以任意上传文件到服务器中,那么攻击者就会通过web访问的目录上传任意的PHP文件,并且能够将这些文件在PHP解释器上运行,从而可以远程控制服务器。这种方式很直接,没有说明门槛,就是上传控制。一般都会上传木马,然后利用木马来读/写服务器上的文件。不过好在,现在很多的程序员都已经意识到这个问题了,上传漏洞现在也比较少了,毕竟大家都开始做过滤了。但是作为安全学习者,必须知道这个漏洞,并且了解其原理。

1、上传漏洞原理

文件上传漏洞一般是指上传Web脚本能够被服务器解析的问题。大多数情况下,攻击者想要完成整个文件上传漏洞攻击时需要满足一定条件的。

首先,上传的文件能够被Web容器解析执行,所以文件上传后的目录要是Web容器所覆盖的路径。其次,Web 服务器要能访问到该文件,如果上传成功了,但是攻击者不能通过Web途径进行访问,那么就废了,攻击是无法形成的。最后,如果上传的文件被Web安全检测格式化、图片压缩等改变其内容, 导致无法解析的话,攻击也是无法形成的。
接下来我会通过DVWA上的上传漏洞实例,学习整个漏洞攻击的过程。
首先将DVWA的安全程度调至low,,不然开启默认为impossible,安全级别太高。

然后在自己本地编写一句话PHP文件,代码如下。

1<?php 2 phpinfo(); 3?> 4 5

然后把这个文件在DVWA中进行上传

在这里插入图片描述

上传后可以看到上传路径,那么就可以根据这个路径目录去访问上传的文件,我的路径是:http://127.0.0.1/DVWA/hackable/uploads/1.php

访问之后就可以看到:

在这里插入图片描述

这个页面就是文件中编写的那句phpinfo()在Web服务器里执行的效果。

如果上传的脚本是一个Webshell的话,就可以直接获取服务器的控制权限。

之前说到上传后的文件会被Web容器解析,其实在文件解析过程中也会产生一些问题。下面就来说一说由哪些问题。

2、IIS文件解析问题

IIS是互联网信息服务,使用IIS 5.x-6.x版本服务器,大多为Windows Service 2003,网站比较古老,开发语句一般为asp;该解析漏洞也只能解析asp文件,而不能解析aspx文件。

(1)目录解析(IIS6.0)

形式:www.xxx.com/xx.asp/xx.jpg

原理:服务器默认会把.asp和.asp目录下的文件都解析成asp文件。

(2)文件解析

形式:www.xxx.com/xx.asp;.jpg

原理:服务器默认不解析;后面的内容,因此,xx.asp;.jpg便会被解析为asp文件。

(3)解析文件类型

IIS6.0默认的可执行文件除了asp还包含一下3种:/test.asa、/test.cer、/test.cdx

这样的话可能做了一些过滤,但是攻击者把修改后缀名,绕过一些限制后,依旧可以上传成功,这个假的jpg或其他文件还是成功地被执行了其中的asp代码。

3、Apache文件解析问题

Apache解析文件的规则就是从由到左进行判断解析,如果后缀名为不可识别文件解析,就再往左判断。例如test.php.qwe.rar,.qwe和.rar这两种后缀是Apache不可识别解析的,Apache就会把wooyun.php.qwe.rar解析为PHP文件。

例如有一个网站www.xxxx.xxx.com/test.php.php123,其余配置问题导致如下漏洞。

1、如果在Apache的conf里有一行AddHandler php5-script.php,这时只要文件名里包含了.php,即使文件名是test2.php.jpg也会按照PHP来执行。

2、如果在Apache的conf里有这样一行配置AddType application/x-http-php.jpg,即使拓展名是.jpg,一样能以PHP方式执行。

4、PHP的CGI路径解析问题

Nginx默认以CGI方式支持PHP解析,普通的做法是在Nginx配置文件中通过正则匹配设置SCRIPT_FILENAME。当访问www.xx.com/phpinfo.jpg/1.php时,$fastcgi_script_name会被设置为”phpinfo.jpg/1.php”,然后构成SCRIPT_FILENAME传递给PHP CGI。但是大家应该都会有一个疑问,PHP为什么会接受这样的参数,并将phpinfo.jpg作为PHP文件解析?我也时很纳闷,原来是和fix_pathinfo这个选项有关。如果开启了这个选项,就会触发PHP的某些逻辑。

PHP会以为SCRIPT_FILENAME是phpinfo.jpg,而1.php是PATH_INFO,所以就会自然地把phpinfo.jpg作为PHP来进行解析。

在举几个例子:

1www.xxx.com/uploadfile/image/1.jpg/1.php 2www.xxx.com/uploadfile/image/1.jpg%00.php 3www.xxx.com/uploadfiel/image/1.jpg/%20\0.php 4 5

这些例子和上面说的那个原理是一样的,都是x.php作为PAT_INFO,所以以PHP来解析。

另一种是上传一个名字为test.jpg的文件,文件里是写好的php代码,只要上传成功后访问test.jpg/.php ,就可以在当前目录下生成一个一句话shell木马shell.php。代码如下:

1<?PHP fputs(fopen('shell.php','w'),'<?php eval($_POST[cmd]) ?>'); ?> 2 3

5、上传绕过漏洞

在上传漏洞出现后,程序员们当然都意识到这个问题,企业也会开始避免这样的风险,所以大多数网站现在对于上传的文件都有进行一定限制,例如说常见的后缀限制,它们会规定哪些后缀名文件时允许上传的,哪些时不允许的。比如有一个网站它只允许上传后缀为.jpg的图片文件,那么一个攻击者需要使用上面手段去绕过后缀的限制和检测,上传一个木马。这是一个值得思考的问题。

在很多CTF题里都有上传绕过的题目,更是让我对这个%00的截断方式印象深刻啊。%00似乎是最常用的方法,其实就是攻击者通过手动地去改上传过程中的POST数据报,在文件名的后面给添加一个%00,来达到截断的作用。因为函数在判断一个文件名称和后缀的时候遇到NULL就是代表结束了,而%00对应的正是NULL。(这里的函数指的是C、PHP等语言字符串处理时用到的)

既然Web应用只允许我们上传.jpg的文件,那么我就如其所愿,给他一个.jpg我们可以构造一个x.php[\0].jpg,其中,[\0]就是十六进制的0x00字符。这样就可以成功绕过客户端对于文件后缀的验证,但是在server端,在解析时会被0x00截断,就会解析为x.php,所以就是成功解析为我们想要达到的PHP文件了。这个就是前端绕过client端,后端截断,解析为PHP。

6、客户端绕过(前端绕过)

上面对上传绕过简单讲了一下,下面就详细说一下客户端绕过,我一般也叫它前端绕过。一些比较的CTF题目就会出现前端绕过就OK的情况。

既然要前端绕过,那就必须要稍微知道,前端时如何来判断过滤的。一般client端都是使用JavaScript来进行一个文件名的校验工作。对于这种方法,其实很简单,我们可以client端输入符合条件的后缀并上传文件,关键在于要使用一个抓包工具,抓包改包重放。抓包就是要抓client验证无误后发给server端的POST分组,改包就是要修改POST请求中的部分内容,重放就是抓了改了当然要放行了。

介绍一下我用的工具,我一般都是使用Burpsuit来进行抓包的,这是一个很不错的工具,推荐使用。对了专业版会比社区版用起来舒服很多,因为专业版可以修改线程。

不多说DVWA里演示一下:

工具:Firefox、burpsuit

环境:Windows(本机)、DVWA(靶场)

把安全级别设为low,上传一个后缀被改为了.jpg的文件1.jpg,抓包后结果如下所示:

在这里插入图片描述

可以看到filename处显示的时1.jpg我这个时候看到的是我上传的情况,我只要把1.jpg改为1.php就可以了。

在这里插入图片描述

然后再提交。结果会如下:

在这里插入图片描述

上传成功,这样就绕过了client端,也就是绕过前端了。我实际上传的时1.php

7、服务端绕过(后端绕过)

server端绕过和client端绕过一样,我们还是想了解一下,server端时如何来进行判断的。一般来说server端会通过3种东西来进行判断:content-type字段、文件头、拓展名。那么如果是单种方式,要想绕过验证还是很容易的。但是组合之后就要想办法去绕过每一个校验,当然这也是可以实现的。

我们一个一个来:

1.content-type

这个字段我记得在之前的博客里面有提到过,它其实就是表示上传文件的类型,其实就是MIME格式表示标识文件。我之前有写过一篇常见的MIME可以供大家查看,这里举几个常见的:imag/jpeg、application/x-php等。

对于这个还是简单事情我们是可以和client端一样,使用burpsuit抓包改一下就好了。
在这里插入图片描述

把原本的类型用图片的MIME来替换,这里换成了image/jpeg,提交就可以绕过验证了。

2.文件头

这种校验方法其实只需要在木马的前加上文件类型所对应的文件头就可以欺骗绕过了,比如把<?php phpinfo(); ?>变成GIF89A<? php phpinfo(); ?>服务器端就会认为你上传的是gif文件,也就绕过了。

3.拓展名

验证拓展名其实也是在验证MIME,MIME就是多用途互联网邮件拓展类型,相信学习过计算机网络的朋友应该都是知道的。它的作用很大的,比如我访问一个文件,浏览器就会为我寻找合适的应用去运行它,就是因为MIME。

MIME的作用就是区分不同种类的数据,文件到达服务器后,服务器本地进行MIME的分类 ,这种方式比较验证比较安全,要想绕过唯一方法就是去查找漏网之鱼了,要找有没有被黑名单漏掉的拓展名。这个比前两种都要安全。

关于修复的思考和总结

上传问题也算得上是老问题了。很多开发者也已经有了很多办法来修复这个洞。我自己有一些想法,上传漏洞传上木马后想要远程控制,是需要知道路径和文件可执行的。那么我们可以从此下手,断了他的路。一个是不要回显路径,这个目前基本都做到了,其次是之前在系统安全的博客里有提到我们要善于利用系统的权限控制,我们完全可以把用来存储上传文件的目录设置为不可执行。从而让攻击者无法连上他的木马。当然这是在木马已经上服务器的情况下的一个好办法,重点还是要避免木马轻易就被上传到服务器中。可以前端+后端多重验证,后端的话拓展名验证是个很好的选择,之前说拓展名的时候有说到黑名单拦截,其实我们不一定使用黑名单,更可以使用白名单,因为我们允许上传的文件类型可能远比不允许上传的文件类型要少,白名单就是一个很好的选择了。对了还有就是图片马,最好要使用图片压缩函数或resize函数,对图片文件进行处理,同时破坏图片中含有的恶意代码。

代码交流 2021