当前位置:首页 > 网络安全 > web渗透 > 正文内容

文件上传漏洞详讲

6个月前 (01-31)523

一.漏洞原理


成因

文件上传漏洞起因于,上传程序没有对上传文件格式进行正确判断,导致可执行程序上传到网站目录。

危害

文件上传漏洞的后果很多样,包括完全的系统控制、使文件系统或数据库超载、后端系统攻击、钓鱼攻击、客户端攻击或单纯的破坏。这取决于应用程序如何处理上传的文件,特别是存储的位置。

利用条件

在大多数情况下,文件上传漏洞一般是指上传web脚本能够被服务器解析的问题,也就是通常说的web shell的问题,要完成这个攻击,需要满足以下几个条件:

首先上传的文件能够被web容器解释执行,所以文件上传后的目录要是web容器所覆盖的路径。

其次,web服务器能够访问这个文件,如果文件上传了,但用户无法通过web访问,那攻击者即使上传了这个文件也是访问不到这个文件的,这样的话,上传也就不能被利用。

最后用户上传的文件被安全监测格式化,图片压缩等改变了内容,就有可能导致这个文件解析失败。

二.漏洞检测/代码审计



目前大多Web应用都是基于框架来写,上传的点都是调用的同一个上传类,上传函数又只有move_uploaded_file()这一个

所以文件上传漏洞在代码审计的时候,最快的方法就是直接去搜索move_uploaded_file()函数,再去看调用这个函数上传文件的代码存不存在未限制上传格式或者可以绕过的情况。

未过滤或本地过滤

未过滤和本地过滤共同点是在服务器端都未过滤,这个未过滤指的是没限制任何格式的文件上传,就是一个最简单的文件上传功能,上传的时候直接上传PHP格式的文件即可利用,它的代码简化之后就直接是下面这样:

<?php    move_uploaded_file($_FILES["file"]["tmp_name"], $_FILES["file"]["name"]);//move_uploaded_file(file,newloc)?>

move_uploaded_file函数直接把上传的临时文件copy到了新文件。

黑名单扩展名过滤

黑名单扩展名是前几年用得比较多的验证方式,后来因为绕过多了,就慢慢改用了白名单。

黑名单的缺点有以下几个:

1)限制的扩展名不够全

上传文件格式不可预测的性质导致了可能会有漏网之鱼。PHP能够在大多数的WebServer上配置解析,不同的WebServer默认有不同的可以解析的扩展名,典型的IIS默认是支持解析ASP语言的,不过在IIS下执行ASP的代码可不止.asp这个扩展名,还有cdx、asa、cer等,如果代码里面没有把这些写全,一旦漏掉一个就相当于没做限制。

我们来看看PHPCMSv9里面限制的:

$savefile = preg_replace("/(php|phtml|php3|php4|jsp|exe|dll|asp|cer|asa|shtml|shtm |aspx|asax|cgi|fcgi|pl)(\.|$)/i","_\\1\\2", $savefile);

很明显我们上面说的cdx不在这个列表里面。

2)验证扩展名的方式存在问题可以直接绕过

另外是结合PHP和系统的特性,导致了可以截断文件名来绕过黑名单限制。下面先看一段代码:

<?phpfunction getExt($filename){     return substr($filename,strripos($filename,'.')+1);//substr() 方法可在字符串中抽取从start下标开始的指定数目的字符//strripos() 函数查找字符串在另一字符串中最后一次出现的位置}$disallowed_types = array("php","asp","aspx");//获取文件扩展名$FilenameExt = strtolower(getExt($_FILES["file"]["name"]));//判断是否在被允许的扩展名里in_array($FilenameExt, $disallowed_types)){die("disallowed type");}else{      $Filename = time().".".$FilenameExt;//移动文件      move_uploaded_file($_FILES["file"]["tmp_name"],"upload/".$FileName);}

这段代码的问题在获取文件扩展名与验证扩展名,如果我们上传文件的时候文件名为

“1.php”

注意后面有一个空格,则这里$FilenameExt的值为“php”,后面有一个空格,这时候in_array($FilenameExt,$disallowed_types)是返回false的,最终成功上传文件。

另外一种情况是正确的黑名单方式验证了扩展名,但是文件名没有修改,导致可以在上传时使用“%00”来截断写入,如“1.php%00.jpg”,验证扩展名时拿到的扩展名是jpg,写入的时候被%00截断,最终写入文件1.php,这里不再给出案例。

文件头、content-type验证绕过

这两种方式也是早期出现得比较多的,早期搞过渗透的人可能遇到过,上传文件的时候,

如果直接上传一个非图片文件会被提示不是图片文件,但是在文件头里面加上“GIF89a”后上传,则验证通过,这是因为程序用了一些不可靠的函数去判断是不是图片文件

比如getimagesize()函数,只要文件头是“GIF89a”,它就会正常返回一个图片的尺寸数组。

content-type是在http request的请求头里面,所以这个值是可以由请求者自定义修改的,而早期的一些程序只是单纯验证了这个值,找了一段存在这个漏洞的代码如下:

<?php$type = $_FILES['img']['type'];if(($type =="image/pjpeg")||($type =="image/jpg")||($type =="image/jpeg")||($type =="image/gif")||($type =="image/bmp")||($type =="image/png")||($type =="image/x-png")){//uploading}?>

phpcms任意文件上传分析

这里我们以PHPCMSv9在2014年公开的一个会员投稿处文件上传漏洞,漏洞作者felixk3y,漏洞乌云编号:wooyun-2014-062881

漏洞在文件/phpcms/libs/classes/attachment.class.php的upload()函数,为了易于理解,这里省略部分代码,代码如下:

function upload($field, $alowexts ='', $maxsize =0, $overwrite =0,$thumb_setting = array(), $watermark_enable =1){/***省略***/      $this->alowexts = $alowexts;//获取允许上传的类型/***省略***/foreach($uploadfiles as $k=>$file){//多文件上传,循环读取文件上传表单        $fileext = fileext($file['name']);//获取文件扩展名/***省略***///检查上传格式,不过$alowexts是从表单提交的,可绕过      if(!preg_match("/^(".$this->alowexts.")$/", $fileext)) {          $this->error ='10';returnfalse;}/***省略***/       $temp_filename = $this->getname($fileext);       $savefile = $this->savepath.$temp_filename;       $savefile = preg_replace("/(php|phtml|php3|php4|jsp|exe|dll|asp|cer|asa|shtml|shtm|aspx|asax|cgi|fcgi|pl)(\.|$)/i","_\\1\\2", $savefile);//最需要绕过的地方在这里/***保存文件***/if(@$upload_func($file['tmp_name'], $savefile)){

从上面的代码我们可以看出,这个漏洞最有意思的地方在:

$savefile = preg_replace("/(php|phtml|php3|php4|jsp|exe|dll|asp|cer|asa| shtml|shtm |aspx|asax|cgi|fcgi|pl)(\.|$)/i","_\\1\\2", $savefile);

而获取文件扩展名的函数内容为:

function fileext($filename){return strtolower(trim(substr(strrchr($filename,'.'),1,10)));//strrchr() 函数(在php中)查找字符在指定字符串中从右面开始的第一次出现的位置,如果成功,返回该字符以及其后面的字符,如果失败,则返回 NULL。//substr() 方法可在字符串中抽取从start下标开始的指定数目的字符}

这里用了trim()函数去掉了空格,我们之前举例用空格绕过的方式在这里就不好使了。那有没有其他字符一样可以达到空格的效果呢,即“1.phpX”,X代表某个字符?

作者利用fuzz的方式找到了%81-%99是可行的,仅在Windows下。

利用时修改文件上传表单里的filename,在文件名后面利用十六进制修改原预留的空格20为81~99中的一个。

三.常见检测及绕过方式



客户端校验

JavaScript检测

有的站点仅仅在前端检测了文件类型,这种类型的检测可以直接修改网络请求绕过。同样的,有的站点在后端仅检查了HTTP Header中的信息,比如 Content-Type 等,这种检查同样可以通过修改网络请求绕过。

服务端校验


MIME类型检测

绕过方法:找一个正常的可上传的MIME类型(jpg、mp4、mp3等),然后将文件的MIME改成合法的MIME即可。

目录路径检测

此检测一般是检测路径是否合理。

burp抓包如果能看见上传文件路径,可以使用空字符截断目录路径来绕过
1.get方法传送文件路径,利用%00截断

1.png

那么我们上传一个jpg图片后就会存为以下格式,空格后的内容会被截断

2.png2.若是post方法传送路径,需要在hex中修改二进制将空格20改为00,这样服务器端保留的文件为11.php(.php%00.jpg)


文件扩展名检测(黑白名单)


黑名单

部分服务仅根据后缀、上传时的信息或Magic Header来判断⽂件类 型,此时可以绕过。php由于历史原因,部分解释器可能⽀持符合正则 /ph(p[2-7]? |t(ml)?)/的后缀,

如 php / php5 / pht / phtml / shtml / pwml / phtm等 可在禁⽌上传php⽂件时测试该类型。

jsp引擎则可能会解析jspx / jspf / jspa / jsw / jsv / jtml等后缀,

asp ⽀持asa / asax / cer / cdx / aspx / ascx / ashx / asmx / asp{80-90}等后 缀。

除了这些绕过,其他的后缀同样可能带来问题

vbs / asis / sh / reg / cgi / exe / dll / com / bat / pl / cfc / cfm / ini等。

白名单

除了结合各种服务器解析特性,较常用的是Null Byte Injection空字节注入,插入空字节值的原因是某些应用程序服务器脚本语言使用c/c++库来检查文件名和内容。

在C/C ++中,一行以/00结尾或称为NullByte。

因此,只要解释器在字符串的末尾看到一个空字节,就会停止读取,认为它已经到达字符串的末尾。

如,我们将要上传的Happy.jpg的名称更改为Happy.phpA.jpg,然后上传文件,在Burp中捕获请求,切换到Hex视图。在字符串视图中找到文件名。

查看相应的Hex表,并将41(’A’)替换为00(为空字节)。

结果字符串变为Happy.php(空).jpeg。

由于php解释器在内部使用C语言库,它将停止读取Happy.php后的文件名,文件将保存为Happy.php。

另一种绕过白名单的方法是使用双后缀:shell.php.jpg。

WAF设备校验


安全狗绕过


1.绕过思路:对文件的内容,数据。数据包进行处理。

关键点在这里Content-Disposition: form-data; name="file"; filename="ian.php"将form-data;修改为~form-data;

2.通过替换大小写来进行绕过

Content-Disposition: form-data; name="file"; filename="yjh.php"Content-Type: application/octet-stream将Content-Disposition修改为content-Disposition将 form-data 修改为Form-data将Content-Type修改为content-Type

3.通过删减空格来进行绕过

Content-Disposition: form-data; name="file"; filename="yjh.php"Content-Type: application/octet-stream将Content-Disposition: form-data 冒号后面增加或减少一个空格将form-data; name="file";分号后面增加或减少一个空格将Content-Type: application/octet-stream 冒号后面增加一个空格

4.通过字符串拼接绕过

看Content-Disposition: form-data; name="file"; filename="yjh3.php"将 form-data 修改为 f+orm-data将from-data 修改为 form-d+ata

5.双文件上传绕过

<formaction="https://www.xxx.com/xxx.asp(php)"method="post"name="form1"enctype="multipart/form‐data"><inputname="FileName1"type="FILE"class="tx1"size="40"><inputname="FileName2"type="FILE"class="tx1"size="40"><inputtype="submit"name="Submit"value="上传"></form>

6.HTTP header 属性值绕过

Content-Disposition: form-data; name="file"; filename="yjh.php"我们通过替换form-data 为*来绕过Content-Disposition:*; name="file"; filename="yjh.php"

7.HTTP header 属性名称绕过

源代码:Content-Disposition: form-data; name="image"; filename="085733uykwusqcs8vw8wky.png"Content-Type: image/png绕过内容如下:Content-Disposition: form-data; name="image"; filename="085733uykwusqcs8vw8wky.pngC.php"删除掉ontent-Type: image/jpeg只留下c,将.php加c后面即可,但是要注意额,双引号要跟着c.php".

8.等效替换绕过

原内容:Content-Type: multipart/form-data; boundary=---------------------------471463142114修改后:Content-Type: multipart/form-data; boundary =---------------------------471463142114boundary后面加入空格。

9.修改编码绕过

使用UTF-16、Unicode、双URL编码等等

WTS-WAF 绕过上传

原内容:Content-Disposition: form-data; name="up_picture"; filename="xss.php"添加回车Content-Disposition: form-data; name="up_picture"; filename="xss.php"

百度云上传绕过


百度云绕过就简单的很多很多,在对文件名大小写上面没有检测php是过了的,Php就能过(注意一点:nginx会解析Php但是apache不能),或者PHP,一句话自己合成图片马用Xise连接即可。Content-Disposition: form-data; name="up_picture"; filename="xss.jpg .Php"

阿里云上传绕过


源代码:Content-Disposition: form-data; name="img_crop_file"; filename="1.jpg .Php"Content-Type: image/jpeg修改如下:Content-Disposition: form-data; name="img_crop_file"; filename="1.php"没错,将=号这里回车删除掉Content-Type: image/jpeg即可绕过。ps:阿里云也可通过修改boundary格式来绕过,查看上方的“等效替换绕过”

360主机上传绕过


源代码:Content-Disposition: form-data; name="image"; filename="085733uykwusqcs8vw8wky.png"Content-Type: image/png绕过内容如下:Content-Disposition: form-data; name="image"; filename="085733uykwusqcs8vw8wky.pngContent-Disposition 修改为 Content-空格Disposition

系统命名绕过


在Windows系统中,上传 index.php. 会重命名为 . ,可以绕过后缀检查。

也可尝试index.php%20 , index.php:1.jpg index.php::$DATA等。

在Linux系统中,可以尝试上传名为 index.php/. 或 ./aa/../index.php/. 的⽂件。

竞争上传绕过


有的服务器采⽤了先保存,再删除不合法⽂件的⽅式,在这种服务器 中,可以反复上传⼀个会⽣成Web Shell的⽂件并尝试访问,多次之后 即可获得Shell。

.user.ini上传利用

.user.ini

.user.ini是php的一种配置文件,众所周知php.ini是php的配置文件,它可以做到显示报错,导入扩展,文件解析,web站点路径等等设置

利用条件:

(1)服务器脚本语言为PHP
(2)对应目录下面有可执行的php文件
(3)服务器使用CGI/FastCGI模式

auto_prepend_file/auto_append_file

auto_prepend_file配置项,可以指定一个文件,自动包含在要执行的文件前,类似于在文件前调用了require()函数。

而auto_append_file类似,只是在文件后面包含。

使用方法很简单,直接写在.user.ini中:

auto_prepend_file=01.gif

01.gif是要包含的文件。

所以,我们可以借助.user.ini轻松让所有php文件都“自动”包含某个文件,而这个文件可以是一个正常php文件,也可以是一个包含一句话的webshell。

.htaccess漏洞利用


.htaccess文件是Apache服务器中的一个配置文件,它负责相关目录下的网页配置,

通过.htaccess文件可以实现网页301重定向、自定义404页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能。

需要用到的代码如下,当匹配到名称含test的文件,服务器会以php文件的形式来解析:

<FilesMatch"test">Sethandler application/x-httpd-php</Eilesmatch>

利用条件

1、如果存在可以上传 .htaccess 文件,就可以直接利用此规则解析;

2、如果存在修改文件权限,就直接修改解析规则。



扫描二维码推送至手机访问。

版权声明:本文由零零博客发布,如需转载请注明出处。

分享给朋友:

相关文章

新手怎么学习web渗透

新手怎么学习web渗透

因为web安全这一块范围实在太大,哪些先学,哪些后学,如果没有系统的路线会降低大家效率,对于刚入门的同学们来说简直就是“噩梦”。所以,这篇类似学习路线的文章,希望可以帮助刚入门的萌新们少走弯路。1,H...

网络渗透方向怎么学呢?

网络渗透方向怎么学呢?

很多朋友问我,想搞网络安全,编程重要吗,选什么语言呢?国内其实正经开设网络安全专业的学校很少,大部分同学是来自计算机科学、网络工程、软件工程专业的,甚至很多非计算机专业自学的。因此不像这三个专业,有系...

优秀渗透工具资源整理

优秀渗透工具资源整理

在进行渗透测试的过程中,会用到大量的开源工具,每次在各种网站、论坛看到很多很好的工具,所以使用该文章将每次碰到的优秀工具记录下来,然后在后期在进行归纳整理,既方便他人,也方便自己。好用工具1、B-XS...

字典生成工具pydictor使用教程

字典生成工具pydictor使用教程

在渗透测试前期,信息收集时非常重要的工作,需要对目标的各种信息进行分析,拆分和融合,目的是对目标进行全方位的了解,其中一个直接产出的就是生成账号密码的字典,后续的鱼叉,水抗攻击做好准备。很多时候的成功...

漏洞挖掘 | 记一次越权登录

漏洞挖掘 | 记一次越权登录

http://xxxxx/index.html?userNo=xxxx可以直接登录学生用户(女朋友给的)fofa收集了一波4个站点。。。,由于没扫到备份,只能黑盒测了然后发现一处接口 杂七杂八测试了下...

后台getshell常用技巧总结

后台getshell常用技巧总结

1.利用文件上传漏洞,找文件上传处想办法上传php文件。一些网站在设置可以允许修改上传的文件类型则直接添加php有时候会还有检测是否为php文件,可以通过文件名变形,大小写,双写等形式绕过,只要是黑名...