文件上传__常用bypass小结

文件上传是常用getshell的路径之一,因为可以通过上传一句话木马实现控制主机

这里从uploads-lab靶场的实验下,用文字总结并讲述一些常用的上传及bypass。顺便拓展一丢丢东西

这里借用uploads-lab的图片一用
在这里插入图片描述

首先针对前端 (也就是客户端) 的绕过

js绕过

在F12下,在js添加文件后缀删除方法
在这里插入图片描述

抓包修改文件后缀绕过

可以将要上传的php文件改后缀名为jpg|png|gif上传,绕过js验证后,再用burp抓包修改文件后缀
 

首先针对后端 (也就是服务端) 的绕过

检查后缀

一、黑名单
  1. 上传特殊可解析后缀
    服务器端做了一个黑名单过滤,过滤了 asp、aspx、php、jsp
    但是可以其他后缀名上传,例如phps、php3、phtml、php5等等
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    if (file_exists(UPLOAD_PATH)) {
        $deny_ext = array('.asp','.aspx','.php','.jsp');
        $file_name = trim($_FILES['upload_file']['name']);
        $file_name = deldot($file_name);//删除文件名末尾的点
        $file_ext = strrchr($file_name, '.');
        $file_ext = strtolower($file_ext); //转换为小写
        $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
        $file_ext = trim($file_ext); //收尾去空

        if(!in_array($file_ext, $deny_ext)) {
            $temp_file = $_FILES['upload_file']['tmp_name'];
            $img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;            
            if (move_uploaded_file($temp_file,$img_path)) {
                 $is_upload = true;
            } else {
                $msg = '上传出错!';
            }
        } else {
            $msg = '不允许上传.asp,.aspx,.php,.jsp后缀文件!';
        }
    } else {
        $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
    }
}
  1. 上传.htaccess
    黑名单里php、php5等奇葩后缀全部不允许上传时。可尝试上传.htaccsess文件绕过
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    if (file_exists(UPLOAD_PATH)) {
        $deny_ext = array(".php",".php5",".php4",".php3",".php2","php1",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2","pHp1",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf");
        $file_name = trim($_FILES['upload_file']['name']);
        $file_name = deldot($file_name);//删除文件名末尾的点
        $file_ext = strrchr($file_name, '.');
        $file_ext = strtolower($file_ext); //转换为小写
        $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
        $file_ext = trim($file_ext); //收尾去空

        if (!in_array($file_ext, $deny_ext)) {
            $temp_file = $_FILES['upload_file']['tmp_name'];
            $img_path = UPLOAD_PATH.'/'.$file_name;
            if (move_uploaded_file($temp_file, $img_path)) {
                $is_upload = true;
            } else {
                $msg = '上传出错!';
            }
        } else {
            $msg = '此文件不允许上传!';
        }
    } else {
        $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
    }
}

首先上传一个.htaccess内容如下的文件:
类似于把文件名包含 1 的解析成php
<FilesMatch "1"> SetHandler application/x-httpd-php </FilesMatch>

htaccess文件是Apache服务器中的一个配置文件,它负责相关目录下的网页配置。在这里,可以通过htaccess文件,可以帮我们将所有文件都会以php进行解析,包括上传的图片马等…
 
3. 后缀大小写绕过
用burp将后缀改为大写PHP即可
 
4. 空格、点后缀绕过
可以利用windows系统的命名规则进行绕过
Windows下xx.jpg[空格]xx.jpg. 这两类文件都是不允许存在的,若这样命名,windows会默认除去空格或点
此处会删除末尾的点,但是没有去掉末尾的空格,因此上传一个.php[空格]或者.php.文件即可
 
5. 双写后缀绕过

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    if (file_exists(UPLOAD_PATH)) {
        $deny_ext = array("php","php5","php4","php3","php2","html","htm","phtml","pht","jsp","jspa","jspx","jsw","jsv","jspf","jtml","asp","aspx","asa","asax","ascx","ashx","asmx","cer","swf","htaccess");

        $file_name = trim($_FILES['upload_file']['name']);
        $file_name = str_ireplace($deny_ext,"", $file_name);
        $temp_file = $_FILES['upload_file']['tmp_name'];
        $img_path = UPLOAD_PATH.'/'.$file_name;        
        if (move_uploaded_file($temp_file, $img_path)) {
            $is_upload = true;
        } else {
            $msg = '上传出错!';
        }
    } else {
        $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
    }
}

利用str_ireplace对黑名单里的文件后缀名进行了替换,换成空字符,使用了str_ireplace函数,即不区分大小写,故大小写绕过不适用。但是这里替换是替换成了空字符,于是我们可以双写后缀名,如xxx.pphphp,使得替换后的后缀名为php。
 
6. ::$DATA绕过
这里还是利用windows的一个特性。
NTFS文件系统包括对备用数据流的支持。这不是众所周知的功能,主要包括提供与Macintosh文件系统中的文件的兼容性。备用数据流允许文件包含多个数据流。每个文件至少有一个数据流。在Windows中,此默认数据流称为:$ DATA

简单讲就是在php+windows的情况下:如果文件名+"::$DATA"会把::$DATA之后的数据当成文件流处理,不会检测后缀名,且保持"::$DATA"之前的文件名。例如:xx.php::$DATA
 
7. 配合解析漏洞

(一)IIS 6.0解析漏洞
IIS 6.0解析利用方法有两种
1.目录解析
将木马图片上传至asp文件夹下,其目录内的任何扩展名的文件都被IIS当作asp文件来解析并执行
/xx.asp/xx.jpg

2.文件解析
分号后面的不被解析,也就是说xxx.asp;.jpg会被服务器看成是xxx.asp
xxx.asp;.jpg

(二)IIS 7.0解析漏洞
在php.ini里设置cgi.fix_pathinfo=1
使得访问任意文件URL时,在URL后面添加“/x.php”等字符时,该文件被iis当php文件代码解析
默认Fast-CGI开启状况下,上传一个木马文件为xxx.jpg,然后访问xxx.jpg/x.php,这个文件将以php进行解析

(三)Nginx <8.03畸形解析漏洞
默认Fast-CGI开启状况下,上传一个木马文件为xxx.jpg,然后访问xxx.jpg/x.php,这个文件将以php进行解析

(四)Nginx 空字节代码执行漏洞
影响版本0.5.,0.6, 0.7 <= 0.7.65, 0.8 <= 0.8.37
Ngnix在遇到%00空字节时与后端FastCGI处理不一致,导致可以在图片中嵌入PHP代码然后通过访问xxx.jpg%00.php来执行其中的代码

(五)Apache解析漏洞(只能是黑名单)
上传的文件命名为:xxx.php.x1.x2.x3,Apache是从右往左判断后缀,直到遇到可解析后缀为止

 

二、白名单
  1. MIME绕过

后端只对Content-Type进行了检查。在burp中更改Content-Type进行绕过即可
以白名单方式更换:image/jpg
更多content-type格式

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    if (file_exists(UPLOAD_PATH)) {
        if (($_FILES['upload_file']['type'] == 'image/jpeg') || ($_FILES['upload_file']['type'] == 'image/png') || ($_FILES['upload_file']['type'] == 'image/gif')) {
            $temp_file = $_FILES['upload_file']['tmp_name'];
            $img_path = UPLOAD_PATH . '/' . $_FILES['upload_file']['name']            
            if (move_uploaded_file($temp_file, $img_path)) {
                $is_upload = true;
            } else {
                $msg = '上传出错!';
            }
        } else {
            $msg = '文件类型不正确,请重新上传!';
        }
    } else {
        $msg = UPLOAD_PATH.'文件夹不存在,请手工创建!';
    }
}

 
2. 00截断

Get路径传入

$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
    $ext_arr = array('jpg','png','gif');
    $file_ext = substr($_FILES['upload_file']['name'],strrpos($_FILES['upload_file']['name'],".")+1);
    if(in_array($file_ext,$ext_arr)){
        $temp_file = $_FILES['upload_file']['tmp_name'];
        $img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;

        if(move_uploaded_file($temp_file,$img_path)){
            $is_upload = true;
        } else {
            $msg = '上传出错!';
        }
    } else{
        $msg = "只允许上传.jpg|.png|.gif类型文件!";
    }
}
截断条件:
1、php版本小于5.3.4
2、php.ini的magic_quotes_gpc为OFF状态

可在get请求路径构造sava_path=/upload/xxx.php%00绕过

Post路径传入

$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
    $ext_arr = array('jpg','png','gif');
    $file_ext = substr($_FILES['upload_file']['name'],strrpos($_FILES['upload_file']['name'],".")+1);
    if(in_array($file_ext,$ext_arr)){
        $temp_file = $_FILES['upload_file']['tmp_name'];
        $img_path = $_POST['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;

        if(move_uploaded_file($temp_file,$img_path)){
            $is_upload = true;
        } else {
            $msg = "上传失败";
        }
    } else {
        $msg = "只允许上传.jpg|.png|.gif类型文件!";
    }
}

点击上传抓包后
对路径:sava_path=/upload/xxx.php%00
或者
对文件:xxx.php%00.jpg
我们需要对%00做一个URL编码,也就是URL-decode

为什么两者用法不同?
这是因为 %00 截断在 GET 中被 url 解码之后是空字符。但是在 POST 中 %00 不会被 url 解码,所以只能通过 burpsuite 修改成 hex 值为 0x00 (URL decode)进行截断。
 

检查内容

一、图片马

利用windows的cmd命令制作copy制作图片马。制作完图片马后直接上传,然后利用文件包含即可

copy /b 11.jpg + yijuhua.php yijuhua.jpg
在这里插入图片描述
 

二、二次渲染

过程有点复杂。等实际场景用到了再细细研究
参考这个?

条件竞争(代码逻辑问题)

(这种方式还是不建议的,容易被管理员发现,还是算了)

$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函数将上传文件临时保存,再进行判断,如果不在白名单里则unlink删除,在的话就rename重命名,所以这里存在条件竞争

先用burp开启两个intruder模块,一个用于重复上传,另一个用于重复访问。设置上传请求,记住此处的文件名,等下要用来拼接访问请求的url

因为此处没有什么参数需要爆破,只是需要重复发起请求
 

总结

总结就是,慢慢测试,根据测试选择适合的路线

 
GOT IT!

 
******************************************************
小实验小结,具体测试利用方式需根据具体实践场景~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章