[渗透笔记][文件上传] upload-labs通关

知识框图

[渗透笔记][文件上传] upload-labs通关_第1张图片

Pass-01——本pass在客户端使用js对不合法图片进行检查!

看下js源码,设置了白名单,必须为三种格式中的一种,可以用burp抓包修改一下后缀名。
可以上传一句话木马,然后菜刀连接。

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

可以通过burp改包绕过js检测的原因是,js是在本地进行检测(也就是数据包还没发送之间检测),等检测过了之后要发给服务器的时候会被burp拦截下来,这个时候改包已经过了js的检测,所以上传会成功。

—————————————————————————————————————
Pass-02——本pass在服务端对数据包的MIME进行检查!(只验证Content-type)

MIME(Multipurpose Internet Mail Extensions) 多用途互联网邮件扩展类型。是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式。

后端php代码,服务器端检测,MIME必须是image/jpeg、image/png、image/gif。

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    if (file_exists($UPLOAD_ADDR)) {
        if (($_FILES['upload_file']['type'] == 'image/jpeg') || ($_FILES['upload_file']['type'] == 'image/png') || ($_FILES['upload_file']['type'] == 'image/gif')) {
            if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name'])) {
                $img_path = $UPLOAD_ADDR . $_FILES['upload_file']['name'];
                $is_upload = true;

            }
        } else {
            $msg = '文件类型不正确,请重新上传!';
        }
    } else {
        $msg = $UPLOAD_ADDR.'文件夹不存在,请手工创建!';
    }
}

在这里插入图片描述
MIME存放在Content-Type上,把.php的MIME修改成image/jpeg就可以上传成功。

—————————————————————————————————————
Pass-03——本pass禁止上传.asp|.aspx|.php|.jsp后缀文件!(黑名单绕过)

设置了黑名单,不允许上传’.asp’,’.aspx’,’.php’,’.jsp’类型的文件。

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    if (file_exists($UPLOAD_ADDR)) {
        $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)) {
            if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR. '/' . $_FILES['upload_file']['name'])) {
                 $img_path = $UPLOAD_ADDR .'/'. $_FILES['upload_file']['name'];
                 $is_upload = true;
            }
        } else {
            $msg = '不允许上传.asp,.aspx,.php,.jsp后缀文件!';
        }
    } else {
        $msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
    }
}

这种情况下,如果apache的httpd.conf中有如下配置代码

AddType application/x-httpd-php .php .phtml .phps .php5 .pht

意思是添加这几种应用的MIME。
就可以使用..phtml、.phps、.php5、.pht类型的文件上传。现在想起来之前做过一道题就是用的.php5后缀来绕过。
在这里插入图片描述

—————————————————————————————————————
Pass04——.htaccess绕过

.htaccess基础知识
.htaccess文件,全称是Hypertext Access(超文本入口)。提供了针对目录改变配置的方法, 即,在一个特定的文档目录中放置一个包含一个或多个指令的文件, 以作用于此目录及其所有子目录。作为用户,所能使用的命令受到限制。管理员可以通过Apache的AllowOverride指令来设置。
启用.htaccess,需要修改httpd.conf,启用AllowOverride,并可以用AllowOverride限制特定命令的使用。如果需要使用.htaccess以外的其他文件名,可以用AccessFileName指令来改变。例如,需要使用.config ,则可以在服务器配置文件中按以下方法配置:AccessFileName .config 。

先上传一个.htaccess文件,内容如下。意思是让所有文件都会当成php来解析。

SetHandler application/x-httpd-php 

这样就可以上传一个.jpg文件,但是解析的时候就会按照.php文件解析了。

—————————————————————————————————————
Pass-05——大小写绕过

过滤了.htaccess但是没有将后缀转换为小写,也就是说可以进行大小写绕过了。

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    if (file_exists($UPLOAD_ADDR)) {
        $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".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)) {
            if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name'])) {
                $img_path = $UPLOAD_ADDR . '/' . $file_name;
                $is_upload = true;
            }
        } else {
            $msg = '此文件不允许上传';
        }
    } else {
        $msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
    }
}

上传1.Php的文件,成功。

—————————————————————————————————————
Pass-06——空格绕过

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    if (file_exists($UPLOAD_ADDR)) {
        $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".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
        
        if (!in_array($file_ext, $deny_ext)) {
            if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name'])) {
                $img_path = $UPLOAD_ADDR . '/' . $file_name;
                $is_upload = true;
            }
        } else {
            $msg = '此文件不允许上传';
        }
    } else {
        $msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
    }
}

相比于前两题, 这道题没有后缀名去空的处理$file_ext = trim($file_ext); //首尾去空
所以可以在后缀名里面加空格绕过。
在这里插入图片描述

—————————————————————————————————————
Pass-07——点绕过

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    if (file_exists($UPLOAD_ADDR)) {
        $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".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_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)) {
            if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name'])) {
                $img_path = $UPLOAD_ADDR . '/' . $file_name;
                $is_upload = true;
            }
        } else {
            $msg = '此文件不允许上传';
        }
    } else {
        $msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
    }
}

$file_ext = strtolower($file_ext); //转换为小写 过滤了大小写
$file_ext = trim($file_ext); //首尾去空 过滤了空格
$deny_ext = array(".htaccess"); 过滤了.htaccess文件以及.php5一类的文件。

没有$file_name = deldot($file_name);//删除文件名末尾的点
没有对后缀名末尾的点进行处理。
利用windows特性,会自动去掉后缀名中最后的.,可在后缀名中加.

在这里插入图片描述

—————————————————————————————————————
Pass-08——::$DATA绕过

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    if (file_exists($UPLOAD_ADDR)) {
        $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".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 = trim($file_ext); //首尾去空
        
        if (!in_array($file_ext, $deny_ext)) {
            if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name'])) {
                $img_path = $UPLOAD_ADDR . '/' . $file_name;
                $is_upload = true;
            }
        } else {
            $msg = '此文件不允许上传';
        }
    } else {
        $msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
    }
}

相比于前面的题,少了$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA

在php+windows的情况下:如果文件名+::$DATA会把::$DATA之后的数据当成文件流处理,不会检测后缀名.且保持::$DATA之前的文件名。利用windows特性,可在后缀名中加::$DATA绕过

在这里插入图片描述

—————————————————————————————————————
Pass-09——点+空格+点绕过

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    if (file_exists($UPLOAD_ADDR)) {
        $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".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)) {
            if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name'])) {
                $img_path = $UPLOAD_ADDR . '/' . $file_name;
                $is_upload = true;
            }
        } else {
            $msg = '此文件不允许上传';
        }
    } else {
        $msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
    }
}

首先去除文件名前后的空格,在删除最后的点,再转换为小写,在去除::$DATA,再把尾部去空。
但是存文件的时候没有重命名。导致可以利用1.php. .(点+空格+点)来绕过。
在这里插入图片描述

—————————————————————————————————————
Pass-10——双写绕过

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    if (file_exists($UPLOAD_ADDR)) {
        $deny_ext = array("php","php5","php4","php3","php2","html","htm","phtml","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);
        if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $file_name)) {
            $img_path = $UPLOAD_ADDR . '/' .$file_name;
            $is_upload = true;
        }
    } else {
        $msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
    }
}

$file_name = str_ireplace($deny_ext,"", $file_name); 把正则匹配到的结果替换成空,这里双写就可以绕过。

上传文件1.phphpp,成功绕过。

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

$img_path是直接拼接,因此可以利用%00截断绕过。
使用00截断的条件php版本小于5.3.4,php的magic_quotes_gpc为OFF状态)(这个很重要,一开始我的是ON状态,怎么传都不成功)
$img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;burp抓包,修改save_path,后面加上%00,这样即使会拼接,但是到%00就结束了。文件的内容也会存在那里。
[渗透笔记][文件上传] upload-labs通关_第2张图片

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

和上一题相似,不同的是上一题的保存路径时get传参,这一题是post传参。
在这里插入图片描述
POST不会像GET对%00进行自动解码,所以需要在二进制中进行修改。

在1.php后面加个空格,并且在十六进制改成空就好。
在这里插入图片描述
在这里插入图片描述

—————————————————————————————————————
Pass-13——图片马绕过

先举几个例子介绍一下copy命令。

将当前目录下的 1.txt 文件复制到root目录下,就输入 copy 1.txt root\

将当前目录下的 1.txt 这个文件复制到 root目录下,并且更名为 2.txt,就输入 copy 1.txt root\2.txt

将 1.txt 和 2.txt 这两个文件合并成一个文件 3.txt,就输入 copy 1.txt+2.txt 3.txt。

\A表示ascii码的文件

\B表示二进制文件

function getReailFileType($filename){
    $file = fopen($filename, "rb");
    $bin = fread($file, 2); //只读2字节
    fclose($file);
    $strInfo = @unpack("C2chars", $bin);    
    $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_ADDR."/".rand(10, 99).date("YmdHis").".".$file_type;
        if(move_uploaded_file($temp_file,$img_path)){
            $is_upload = true;
        }
        else{
            $msg = "上传失败";
        }
    }
}

绕过方式
(1)只读文件的前两个字节,在文件的开端添加gif的标志文件头GIF89a(其实也可以只加一个GI,因为只读两个字节),可进行绕过;
(2)使用命令copy 1.jpg /b + shell.php /a webshell.jpg将一句话木马添加到图片中也可以。

这两种方法上传后都会被存为.jpg.gif.png格式,所以如果要利用的话还需要配合其他方式。

—————————————————————————————————————
Pass-14——getimagesize()-图片马

getimagesize() 函数用于获取图像大小及相关信息,成功返回一个数组,失败则返回 FALSE 并产生一条 E_WARNING 级的错误信息。

示例
list($width, $height, $type, $attr) = getimagesize("runoob-logo.png");
echo "宽度为:" . $width;
echo "高度为:" . $height;
echo "类型为:" . $attr;

image_type_to_extension — 根据指定的图像类型返回对应的后缀名。


绕过方法同十三题。

—————————————————————————————————————
Pass-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_ADDR."/".rand(10, 99).date("YmdHis").".".$res;
        if(move_uploaded_file($temp_file,$img_path)){
            $is_upload = true;
        }
        else{
            $msg = "上传失败";
        }
    }
}

exif_imagetype() 读取一个图像的第一个字节并检查其签名。

绕过方法也是把小马写在图片里,或者把图像的头写在前面,同十三题。

—————————————————————————————————————
Pass-16——二次渲染绕过

插入到图片尾部,上传后16进制打开,发现已经被更改了,对比上传前后两张图片,找出相同的部分,再将其插入,上传成功后,发现php代码没有被更改。

—————————————————————————————————————
Pass-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_ADDR . '/' . $file_name;

    if(move_uploaded_file($temp_file, $upload_file)){
        if(in_array($file_ext,$ext_arr)){
             $img_path = $UPLOAD_ADDR . '/'. rand(10, 99).date("YmdHis").".".$file_ext;
             rename($upload_file, $img_path);
             unlink($upload_file);
             $is_upload = true;
        }else{
            $msg = "只允许上传.jpg|.png|.gif类型文件!";
            unlink($upload_file);
        }
    }else{
        $msg = '上传失败!';
    }
}

代码审计后发现,先是把文件搬移到那个目录之后检查,判断是否在白名单,
如果在则重命名,否则删除,因此我们可以上传1.php只需要在它删除之前访问即可。
可以利用burp的intruder模块不断上传,然后我们不断的访问刷新该地址即可。

可以把上传的php文件内容改为如下。

 fputs(fopen('shell.php','w'), 'cmd']); ?>') ?>

然后用burp发包,不断刷新访问这个文件。
[渗透笔记][文件上传] upload-labs通关_第3张图片

—————————————————————————————————————
Pass-18——条件竞争

上传图片马时也存在条件竞争,有可能会未重命名

条件竞争没太弄明白。。。

—————————————————————————————————————
Pass-19-00截断

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    if (file_exists($UPLOAD_ADDR)) {
        $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)) {
            $img_path = $UPLOAD_ADDR . '/' .$file_name;
            if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $img_path)) { 
                $is_upload = true;
            }else{
                $msg = '上传失败!';
            }
        }else{
            $msg = '禁止保存为该类型文件!';
        }

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

move_uploaded_file() 函数将上传的文件移动到新位置。

move_uploaded_file()函数中的img_path是由post参数save_name控制的,因此可以在save_name利用00截断绕过

[渗透笔记][文件上传] upload-labs通关_第4张图片

在这里插入图片描述

你可能感兴趣的:(渗透笔记)