Upload Labs

Upload Labs做题记录

记录一下,让自己了解上传的一些常见姿势,同时学习学习php代码,增加自己代码审计的能力。

pass-01   js前端验证

只是在前端进行验证,这时候可以使用firefox的Noscript插件,来禁用JS,达到上传目的。

 前端判断代码为:

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

可以直接F12,在文件上传类型中添加.php就可以上传php文件了。

我这里是进行BP抓包:

然后访问,蚁剑链接

pass-02  Content-Type

 文件类型绕过

BP抓包,将文件类型改为图片即可

源码审计:

$is_upload = false; //初始的上传状态
$msg = null;
if (isset($_POST['submit'])) { //判断是否是点了submit传过来的
    if (file_exists(UPLOAD_PATH)) {    //判断上传路径是否存在,也就是说在根目录下,是否存在upload这么一个文件夹,如果自己本地搭建的话,需要创建这么一个文件夹
        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'];  //判断允许上传的文件类型,BP抓包可以看到,他的文件类型是application/octet-stream,将其改为上面三个中的一个就行了
            $img_path = UPLOAD_PATH . '/' . $_FILES['upload_file']['name']    //上传的路径  upload/你上传文件的名字   我这里就是:upload/test.php        
            if (move_uploaded_file($temp_file, $img_path)) {
                $is_upload = true;
            } else {
                $msg = '上传出错!';
            }
        } else {
            $msg = '文件类型不正确,请重新上传!';
        }
    } else {
        $msg = UPLOAD_PATH.'文件夹不存在,请手工创建!';
    }
}

pass-03   文件后缀的判断

 上传文件可以看到,他不允许上传以下后缀的文件,那么我们用其他php别名就行了,常见的别名有:pht,phpt,phtml,php3,php4,php5,php6

这里使用的是php3后缀

蚁剑访问成功

源码审计:

$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']);   //使用trim函数去掉文件名前后的字符
        $file_name = deldot($file_name);//删除文件名末尾的点
        $file_ext = strrchr($file_name, '.');   //strchr函数是strstr函数的别名,这里返回 .后缀名。
        $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 . '文件夹不存在,请手工创建!';
    }
}

pass-04   .htaccess解析

 上传之后,发现文件不允许,应该在第三题的基础上加了其他别名到黑名单了,基本上是都过滤掉了,不过没有过滤 .htaccess。.htaccess文件可以实现重写文件解析的规则。

创建一个.htaccess的文件,里面写的内容为:SetHandler application/x-httpd-php,然后上传,这样就可以实现把锁上传的文件当成php来执行了。

在上传一个图片马,或者是将一句话文件改为图片形式上传就行了

蚁剑连接成功

源码审计:

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    if (file_exists(UPLOAD_PATH)) {
     //这里可以看到,他几乎是把所有的php别名都给ban了,其他地方和之前的都一样,就不审了。 $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.'/'.$file_name; if (move_uploaded_file($temp_file, $img_path)) { $is_upload = true; } else { $msg = '上传出错!'; } } else { $msg = '此文件不允许上传!'; } } else { $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!'; } }

pass-05  大小写绕过

 这里和上面一个题一样都,把.htaccess添加进去了。但是没有进行小写的转换,所以说可以使用大小写绕过

蚁剑连接成功

源码审计:

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    if (file_exists(UPLOAD_PATH)) {
     //可以看到,在最后面,他把.htaccess加进去了,但是在下面的变量里,没有像之前那样,使用strtolower函数将分离出来的后缀,都改为小写。 $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 . '文件夹不存在,请手工创建!'; } }

pass-06  trim

 相较与上一题的没有进行小写转换,这一题是对文件名没有进行严格的检查,没有使用trim函数将文件名前后的字符去点,所以说可以BP抓包之后,在php后面加一个空格就行了

然后访问,蚁剑连接,这里只是没有时候trim函数进行首尾去空而已,就不审了。

pass-07  deldot,windows特性

 在这一关,去掉了,也就是说,可以在文件名末尾加上点进行绕过,根据windows的特性,test.php.这样,最后执行的时候会把php.后面的点去掉。

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

蚁剑连接成功

pass-08   ::$DATA文件流

 由于之前burp suite一直抓不到本地包,所以上面做的几个题都是在 https://buuoj.cn/ 做的,现在终于可以本地复现了,开心,之前抓不到包,好像 是8080端口的锅

将端口改为8081,终于可以抓本地包,可以更加清楚的知道上传文件的变化了。

在这一关,缺少了这个函数对文件后缀的限定,

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

::$DATA是windows上的一个文件流特性,必须在windows上,且是php文件,源文件的时候加上::$DATA,windows会把::$DATA之后的数据当作文件流来处理

不会检测后缀名.且保持"::$DATA"之前的文件名。

这里上传成功之后,在upload下的文件名自动的去掉了::$data,之后直接访问php就行了,然后蚁剑连接

pass-09  代码逻辑漏洞

 这一关,其实和第四关差不多,只不过,第四关没有过滤掉.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); //首尾去空

访问shell.php,蚁剑连接

pass-10   后缀名双写绕过

 看一下这一关关键的源代码

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

可以看到,直接去掉了黑名单里面存在的文件名后缀,不过只是进行了一次,所以说可以后缀名双写绕过

可以看到上传之后又两个文件,访问php文件,蚁剑连接即可

pass-11 00截断

 来看一下源码

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

从代码上可以看出,设置了一个白名单,只允许jpg/png/gif后缀的文件上传,但是在后面的保存的时候,文件名是拼接的,其中前面是可控的

$img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;   //save_path是可控的部分

这时候就可以使用00截断进行尝试,00截断使用的条件:

PHP版本小于5.3.4
php.ini配置文件里magic_quotes_gpc=Off

 这样就可以上传成功了,然后访问upload/13.php,蚁剑连接

pass-12 00截断

 还是和上面一样,不过将save_path的传参方式变成了POST,GET传参的时候,会自动进行URL解码,POST不会,

 访问,连接即可。

pass-13  图片马文件包含

 根据关卡要求,需要上传图片马,以及使用文件包含

来看一下源代码

function getReailFileType($filename){
    $file = fopen($filename, "rb");
    $bin = fread($file, 2); //只读2字节
    fclose($file);
    $strInfo = @unpack("C2chars", $bin);    
   //pcak函数是将对应参数打包成二进制字符串,uppack($format,$data)就是进行解包,format是解包时使用的数据格式,C是无符号字符 $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 = "上传出错!"; } } }

pack函数例子:

test.php

<?php
echo pack('C3',80,72,80);
?>

 test.php里面的C表示无符号的字符,3就是后面对应的参数个数,前面的数字必须小于等于后面的参数个数。

从源码可以知道,后端是对上传文件进行了文件头的的检测。图片马上传成功之后,还不能直接访问到

还需要文件包含才能成功执行php代码

包含之后还是出错了

 网上查了发现,发现是我自己phpstudey使用的php版本低了,做上面的00截断的题的时候,用了5.2版本的php,没改过来,所以这里报了这样的错误

将php改为5.4.45之后就可以成功了

pass-14 图片马/getimagesize

 核心源代码

 $types = '.jpeg|.png|.gif';
    if(file_exists($filename)){
        $info = getimagesize($filename);  //判断文件,如果是图片,就返回一个数组,数组里面有图片大小和后缀
        $ext = image_type_to_extension($info[2]);   //$info[2]=后缀名

这里使用getimagesize函数来判断文件,用来获取图像的大小及后缀名,成功的话,返回一个数组,失败返回false

也是只检查了文件头,绕过的话,只需要制造一个图片马,或者是上传一个一句话木马,抓包,然后在一句话内容前面加上图片的文件头就行了

 然后访问,蚁剑连接

pass-15 图片马/exif_imagetype

 这题也是一样,和上面两个图片马,也是检查了文件的文件头格式

这里使用的是exif_imagetype函数来判断

方法个上面一样,就不多说了。

pass-16 

pass-17

pass-18

pass-19

pass-20

原文地址:https://www.cnblogs.com/mortals-tx/p/11373979.html