文件上传 uploadlabs

BUUCTF=>Basci=>Upload-Labs-Linux 1

思维导图

客户端 检查

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

1.浏览器(FireFox)禁用js

about:config

2.F12删除掉检查函数

服务端 黑名单

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

这关只对Content-Type:进行了验证

if (($_FILES['upload_file']['type'] == 'image/jpeg') || ($_FILES['upload_file']['type'] == 'image/png') || ($_FILES['upload_file']['type'] == 'image/gif')) {
           ......
        } else {
            $msg = '文件类型不正确,请重新上传!';
        }

1.修改Content-Type

MIME (Multipurpose Internet Mail Extensions) 是描述消息内容类型的因特网标准。
MIME 消息能包含文本、图像、音频、视频以及其他应用程序专用的数据。


2.Burp改包shell.png =>shell.php

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

上传特殊后缀文件,能被php解析,但文件名被改了

1.Proxy->Repater->raw记着改过后的文件名
2.直接就拖图片到搜索框(图片的href就是它保存的位置)

Pass-4 分布式配置文件 .htaccess

$is_upload = false;
$msg = null;
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");
        $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 . '文件夹不存在,请手工创建!';
    }
}
$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");

虽然没有过滤pphhpp但它解析出来是文本形式,怎么把它解析成php呢

.htaccess文件(或者"分布式配置文件"),全称是Hypertext Access(超文本入口)。
概述来说,htaccess文件是Apache服务器中的一个配置文件,它负责相关目录下的网页配置。通过htaccess文件,可以帮我们实现:网页301重定向、自定义404错误页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能。
Unix、Linux系统或者是任何版本的Apache Web服务器都是支持.htaccess的,但是有的主机服务商可能不允许你自定义自己的.htaccess文件。
启用.htaccess,需要修改httpd.conf,启用AllowOverride,并可以用AllowOverride限制特定命令的使用。如果需要使用.htaccess以外的其他文件名,可以用AccessFileName指令来改变。例如,需要使用.config ,则可以在服务器配置文件中按以下方法配置:AccessFileName .config 。
笼统地说,.htaccess可以帮我们实现包括:文件夹密码保护、用户自动重定向、自定义错误页面、改变你的文件扩展名、封禁特定IP地址的用户、只允许特定IP地址的用户、禁止目录列表,以及使用其他文件作为index文件等一些功能。

.htaccess

<FilesMatch "任意后缀木马文件名"
SetHandler application/x-httpd-php
</FilesMatch>

上传shell.hugboy马,蚁剑连接

Pass-5 大小写绕过

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

这关删去了此行代码

$file_ext = strtolower($file_ext); //转换为小写

Pass-6 空格绕过 (windows)

if (!in_array($file_ext, $deny_ext)) {
            ......
        } else {
            $msg = '此文件不允许上传';
        }

代码比较时会带上空格去和黑名单匹配,burp改包文件名shell.php windows会自动忽略后面的空格
识别为shell.php

Pass-7 点号绕过

这关删去了此行代码

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

Burp改包shell.php=>shell.php.

Pass-8 ::$DATA绕过 (windows)

这关删去了此行代码

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

在window的时候如果文件名+"::$DATA"会把::$DATA之后的数据当成文件流处理,不会检测后缀名,
且保持::$DATA之前的文件名,他的目的就是不检查后缀名
例如:"phpinfo.php::$DATA"Windows会自动去掉末尾的::$DATA变成"phpinfo.php"

Burp改包shell.php=>shell.php::$DATA

Pass-9 点+空格+点 (windows)

虽然有以下检查

        $file_name = deldot($file_name);//删除文件名末尾的点
        ......
        $file_ext = trim($file_ext); //首尾去空

但我们Burp改包shell.php=>shell.php. .相当于Pass-7 点号绕过

Pass-10 双写绕过

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

上传shell.pphphp,shell.phphpp。。。

服务端 白名单

Pass-11 白名单 Get%00 截断(PHP<php.534)

先上传shell.png
Burp改包修改保存目录save_path: shell.php=>shell.php%00

Pass-12 白名单 POST%00 截断(PHP<php.534)

服务端 图片马

图片马上传后,服务器不能解析,我们要结合文件包含漏洞才能利用。

Pass-13 图片马

这关是根据上传文件内容来判断图片类型,具体如下

$file = fopen($filename, "rb");
    $bin = fread($file, 2); //只读2字节
    fclose($file);
    $strInfo = @unpack("C2chars", $bin);//unpack方式解码    
    $typeCode = intval($strInfo['chars1'].$strInfo['chars2']);//用intval分别把2字节内容转换为10进制后拼接
    $fileType = '';    
    switch($typeCode){      //根据计算出的$typeCode判断图片类型
        case 255216:            
            $fileType = 'jpg';
            break;
        case 13780:            
            $fileType = 'png';
            break;        
        case 7173:            
            $fileType = 'gif';
            break;
        default:            
            $fileType = 'unknown';
        }    
        return $fileType;
}

我们构造图片类型正确,但包含shell内容的图片
pngjpg类型构造方式

copy image.png/b + phpinfo.php = pngphpinfo.png

gif类型构造方式(其实只是绕过,并未真正构造)

Pass-14 getimagesize()绕过

绕过方法同Pass-13,只不过换了一种验证图片类型的方式。

function isImage($filename){
    $types = '.jpeg|.png|.gif';
    if(file_exists($filename)){
        $info = getimagesize($filename);//获取图片参数
        $ext = image_type_to_extension($info[2]);//索引2代表图片的类型
        if(stripos($types,$ext)>=0){
            return $ext;
        }else{
            return false;
        }
    }else{
        return false;
    }
}

另:
getimagesize(string $filename [,array &$imageinfo])//获取图像信息,返回一个数组
/*
返回的数组中,索引0:图像宽度像素值
索引1:图像高度像素值
索引2:图像类型,1=GIF,2=JPG,3=PNG,4=SWF,5=PSD,6=BMP,7=TIFF_II,8=TIFF_MM,9=JPC,10=JP2,11=JPX,12=JB2,13=SWC,14=IFF,15=WBMP,16=XBM,17=ICO,18=COUNT
索引3:图像宽度和高度的字符串
索引bits:图像的每种颜色的位数,二进制格式
索引channels:图像的通道值
索引mime:图像的MIME信息
/
image_type_to_extension(int $imagetype [,bool $include_dot = TRUE])//获取图像类型的文件扩展名
/

include_dot是否在扩展名前加点。默认为TRUE
*/

Pass-15 exif_imagetype() 绕过

绕过方法同Pass-13,只不过换了一种验证图片类型的方式。

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

参考

Lnng
Cnblogs
知乎
先知社区
CSDN-1
CSDN-2

原文地址:https://www.cnblogs.com/hugboy/p/upload_labs.html