upload labs 通关笔记

整理的知识点

1.jpg

pass-01

前端js验证,改一下html的函数为空就行.

QQ截图20190819152515.png

pass-02

MIME TYPE 验证,修改文件类型为image/jpeg即可,更多在下方的链接查找

http://tool.oschina.net/commons/

QQ截图20190819152833.png

pass-03

特殊文件名绕过,如php3,phps,phtml
前提是web服务器能解析这些后缀名,如果没有设置解析,是不会当作php解析的
如果使用的是apache没有的话可以在配置文件中添加如下字段:

AddType application/x-httpd-php .php
AddType application/x-httpd-php .php .phtml .php3
AddType application/x-httpd-php-source .phps

pass-04

黑名单把基本上把所有脚本后缀都过滤了,除了.htaccess

我们先在htaccess文件中写入一下内容,随后上传即可.在windows下不能直接编写名字为.htaccess,但是我们可以在burp上修改(FilesMatch 后面可以写正则的哈,我们直接指定文件就行)

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

例如下方语句能解析以ph(p3|p4|p5|s|tml|ps)为后缀的文件

<FilesMatch "^\.ph(p[345]?|t|tml|ps)$">
    Order Deny,Allow
    Deny from all
</FilesMatch>

QQ截图20190819153314.png

上传后,我们在上传一个以图片格式结尾的木马文件即可

QQ截图20190819153357.png

可以看到已经把jpg按照php解析了

关于htaccess

.htaccess文件提供了一种目录级别的修改配置的方式。一个文件,包含一条或多条配置指令,放置于目录下,这些配置指令对当前目录和其所有子目录生效。.htaccess与httpd.conf配置文件不同的是,它只作用于当前目录.所以这个东西按照我的理解就是起到一个控制的配置文件
当你不能修改apache的配置文件的时候,htaccess是一个很好的办法,但是仅限在apache配置文件中AllowOverride为 All的时候,None就没用了哈

pass-05

后缀的畸形绕过,后缀改为phP就能绕过.

pass-06

源码中,发现没有首尾去空处理,所以在burp修改文件名即可绕过黑名单.

pass-07

没有去点处理,修改为php.即可

pass-08

没有过滤::$DATA后缀,我们可以在burp修改为文件名为1.php::$DATA,即可直接上传成功

关于::$DATA

Windows ::DATA alternate data stream
主要是利用window下的ntfs文件格式,NTFS交换数据流(Alternate Data Streams,简称ADS)是NTFS磁盘格式的一个特性,在NTFS文件系统下,每个文件都可以存在多个数据流。

pass-09

没有递归处理后缀,即只处理了一次,所以构造文件名1.php. .

pass-10

这个是替换脚本后缀为空,双写即可1.pphphp

$file_name = str_ireplace($deny_ext,"", $file_name);

pass-11

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

可见,程序采用白名单的方式,只有以图片后缀的格式才行,所以想绕过上传检测几乎不可能.
但是发现save_path是可控的

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

对此我们采用%00截断的方式,则path变为../upload/2.php%00/rand(10, 99).date("YmdHis").".".$file_ext;
这个漏洞条件是在版本小于5.3.4,且php.ini 中 magic_quotes_gpc为off.但是现在php版本也大多都在5.4以上,基本凉凉了.
本人没有复现成功,一直提示上传错误,应该是权限不足导致的无法创建目录的原因造成的.(环境xampp,php=5.2)

pass-12

post版的%00截断,在修改hex值即可

pass-13

上传图片马,制作方法,在cmd环境即可,上传后利用文件包含漏洞才能将其生效.

copy normal.jpg /b + shell.php /a webshell.jpg

因为在源码中显示仅依靠文件开头是否为图片格式进行判断,所以我们在一个脚本文件前面加上图片文件头也是可以的.但依然需要其他漏洞配合才行

QQ截图20190819165642.png

pass-14

采用getimagesize()进行验证,上一个真正的图片马即可

 $info = getimagesize($filename);

pass-15

exif_imagetype() 读取一个图像的第一个字节并检查其签名.所以同上...

pass-16

考察的是二次渲染,再源码中这一处可以看到

$im = imagecreatefromjpeg($target_path);

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

imagecreatefrom 系列函数用于从文件或 URL 载入一幅图像,成功返回图像资源,失败则返回一个空字符串.随后再生成一个新的图像,中间可能会丢失不属于图像的一些资源,但是从这篇文章https://xz.aliyun.com/t/2657#toc-3 看有一些区块是不变的.写的很详细,我们可以看出再每一个格式都是不一样的,在此我们选择上传gif的方式(别人的图)

QQ截图20190820140854.png

gif :https://github.com/LandGrey/upload-labs-writeup/blob/master/webshell/bypass-imagecreatefromgif-pass-00.gif
png :https://raw.githubusercontent.com/LandGrey/upload-labs-writeup/master/webshell/bypass-imagecreatefrompng-pass-LandGrey.png
jpg :https://raw.githubusercontent.com/LandGrey/upload-labs-writeup/master/webshell/bypass-imagecreatefromjpeg-pass-LandGrey.jpg

pass-17

可以看到源码中,它先是上传文件,然后再检查文件格式,所以我们可以采用条件竞争漏洞,采用burp批量发包.

QQ截图20190820141741.png

QQ截图20190820141529.png

pass-18

本体考察的是apache的解析漏洞和代码审计,利用到的技巧是条件竞争.主要是因为程序会修改文件名.

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

可以看到rename在move的后面,所以我们可以保存我们自定义的文件名,但是完全复现的话要配合文件解析漏洞才能解析为php.

QQ截图20190820150143.png

pass-19

这里是采用黑名单的方式进行检查的,还是自定义保存文件名,所以filename我们是可控制的.想一想也只有在save_name做文章了,经过查阅资料发现move_uploaded_file会忽略掉文件末尾的/.Pass9中的文件名是从$_FILES'upload_file'中获取的,但是这里是用户可控的.所以我们保存为1.php/.即可绕过黑名单且保存为php

QQ截图20190820153135.png

关于/.绕过

php中file_put_content函数与move_uploaded_file在p总的小密圈中提到在底层都会调用一个叫tsrm_realpath的函数来将filename标准化为一个绝对路径,所以最后都会递归地删除/.,所以能绕过黑名单检测,但是这种方法无法覆盖现有文件.详细查看下方博客
http://wonderkun.cc/index.html/?p=626

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 = "请选择要上传的文件!";
}

第一步发现mime检测,绕过就好.第二步发现程序如果file不是数组就把文件名通过explode转为了数组,$ext被赋值了最后一个元素的值.

 $ext = end($file);

然后采用了白名单的方式检查了后缀名.

 if (!in_array($ext, $allow_suffix))

我们看到如下语句:

$file_name = reset($file) . '.' . $file[count($file) - 1];

当我们上传1.php.jpg,$ext即$file[count($file) - 1]将等于jpg,reset($file)为1,中间的php则会直接丢弃.
于是思考...怎么变形都会检测第一个和最后一个元素,而且采用白名单,绕过更不可能了,而且最后组合的时候还是始终使用的最后一个元素.
但是我们注意到,最后文件名组合的时候为什么不用$ext而用$file[count($file) - 1],虽然是同一个意思,但这其中一定有蹊跷.
此外还注意到savename是我们完全可控的,对此我们上传一个数组可否?

我们上传一个save_name为数组的时候,则会跳过$file = explode('.', strtolower($file));
随后将最后一个元素赋值为jpg,第一个元素即reset($file)赋值为1.php,那么在赋值文件名的时候则会将倒数第二个元素作为后缀,因为数组只有两个元素,此时count($file)为2,所以此时$file[count($file) - 1]为空.

QQ截图20190822102826.png

$file_name = reset($file) . '.' . $file[count($file) - 1];

再回到这个语句,此时reset($file)为1.php/与.合并为1.php/.再与空字符串合并,最后为1.php/.然后上传但是会递归删除/.所以最后能直接上传成功webshell

QQ截图20190822101907.png

(php是世界上最好的语言)

地址

https://github.com/c0ny1/upload-labs

本文链接:

http://chrisyy.top:2000/index.php/archives/6/
1 + 6 =
快来做第一个评论的人吧~