zip已知明文攻击

加密算法

ZIP的加密算法大致分为两种ZipCrypto和AES-256,各自又分Deflate和Store。

ZipCrypto Deflate

ZipCrypto Store

AES-256 Deflate

AES-256 Store

ZipCrypto算是传统的zip加密方式,只有使用ZipCrypto Deflate /Store才可以使用 ZIP已知明文攻击进行破解。

如何查看zip的详细信息呢?这里可以使用工具zipinfo:

zipinfo 是一个用于查看 ZIP 压缩包内部文件技术信息的命令行工具。它不需要解压文件,就可以列出压缩包内的文件名、文件大小、权限、压缩比率、时间戳等详细信息。

1
zipinfo [选项] 压缩包名.zip

进行深度取证分析(选项 -v)

也可以用7zip查看

1
7z l -slt sample.zip

其中的Method值就为加密算法(用软件打开也可以直接看到)

工具

Windows的ARCHPR

该工具通常需要一个完整的明文文件来进行明文攻击,要满足下面三个条件才能成功:

1
2
3
1.完整的明文文件
2.明文文件需要被相同的压缩算法标准压缩
3.明文对应文件的加密算法需要是ZipCrypto Store

添加文件即可

Linux的bkcrack

该工具只需要知道加密压缩包内容的12个字节

1
2
至少已知明文的12个字节及偏移,其中至少8字节需要连续。
明文对应的文件加密方式为ZipCrypto Store

该方法对于ZIP加密的算法有要求,明文对应的文件加密方式需要为ZipCrypto Store

而遇到ZipCrypto Deflate加密的,解密后(另外文件为ZipCrypto Store加密)需要bkcrack/tool内的inflate.py脚本再次处理

1
python3 inflate.py < file > fileoutput

工具安装

克隆仓库

1
2
git clone https://github.com/kimci86/bkcrack.git
cd bkcrack

创建构建目录并编译

1
2
3
4
mkdir build
cd build
cmake ..
make

确认是否成功

1
./bkcrack

不成功直接在build目录下(之后在任何地方直接输入 bkcrack 即可)

1
sudo make install

配置环境变量(在任意目录都可使用)

1
2
3
4
5
# 将 bkcrack 移动到 /usr/local/bin
sudo cp bkcrack /usr/local/bin/

# 赋予执行权限(通常默认已有,但为了保险)
sudo chmod +x /usr/local/bin/bkcrack

bkcrack常用参数:

-c 提取的密文部分
-p 提取的明文部分
-x 压缩包内目标文件的偏移地址 部分已知明文值
-C 加密压缩包
-o offset -p参数指定的明文在压缩包内目标文件的偏移量

得到内部密钥后使用bkcrack修改压缩包密码

破解出压缩包的三段密钥后,可以用 -U 参数修改压缩包密码并导出

1
bkcrack -C flag.zip -k 三段密钥 -U out.zip 111

攻击

这里只讲使用bkcrack的明文攻击手段

加密文本破解

文件准备:flag.zip

flag.txt内容为flag{16e371fa-0555-47fc-b343-74f6754f6c01}

可以看到压缩包为ZipCrypto Store加密,如果我们知道该文本部分明文,比如xxxxx16e371faxxxxxxxxxxxxxxxxx4f67xxxxxxxx

16e371fa转hex为3136653337316661

4f67转hex为34663637

1
bkcrack -C flag.zip -c flag.txt -x 5 3136653337316661 -x 30 34663637

得到内部密钥 b21e5df4 ab9a9430 8c336475

恢复flag.txt:

1
bkcrack -C flag.zip -c flag.txt -k b21e5df4 ab9a9430 8c336475 -d flag_decrypted.txt

得到flag{16e371fa-0555-47fc-b343-74f6754f6c01}

png文件破解

文件准备:png.zip

flag.txt

2.png

加密算法都为ZipCrypto Store,可以进行明文攻击

利用png文件头进行,标准PNG图片文件的文件头

89 50 4E 47 0D 0A 1A 0A 00 00 00 0D 49 48 44 52

1
bkcrack -C png.zip -c 2.png -x 0 89504E470D0A1A0A0000000D49484452

得到内部密钥 e0be8d5d 70bb3140 7e983fff

恢复flag.txt:

1
bkcrack -C png.zip -c flag.txt -k e0be8d5d 70bb3140 7e983fff -d flag.txt

得到flag{2f09f201dc590e0ecd71a90272996666}

利用压缩包格式破解

将一个名为sample.txt的文件打包成zip压缩包后,你会发现文件名称会出现在压缩包文件头中,且偏移固定为30。且默认情况下,sample.zip也会作为该压缩包的名称

所以,当一个加密压缩包中存在另一个ZIP压缩包时,且能够知道或猜测该压缩包内的文件名称时,可以尝试进行已知明文攻击

文件准备:test.zip

2.png

flag.zip

2.png为ZipCrypto Deflate加密,flag.zip为ZipCrypto Store加密

已知明文:

1
2
3
4
1. 8字节
偏移为30的flag.txt,转为hex得到666c61672e747874
2. 4字节
flag.zip本身的文件头(hex):504B0304

进行明文攻击:

1
bkcrack -C test.zip -c flag.zip -x 0 504B0304 -x 30 666c61672e747874

得到内部密钥 b21e5df4 ab9a9430 8c336475

1
bkcrack -C test.zip -c flag.zip -k b21e5df4 ab9a9430 8c336475 -d flag.zip

flag.zip可以直接成功解密,得到flag{16e371fa-0555-47fc-b343-74f6754f6c01}

但是若想解密2.png,由于是ZipCrypto deflate加密的,所以解密后需要bkcrack/tool内的inflate.py脚本再次处理

1
2
3
bkcrack -C test.zip -c 2.png -k b21e5df4 ab9a9430 8c336475 -d 2.png

python3 ~/ctf/bkcrack-1.7.0-Linux/tools/inflate.py < 2.png > 2_out.png

之后就能得到完整可看的图像

exe文件格式破解

EXE文件默认加密情况下,不太会以store方式被加密,但它文件格式中的的明文及其明显,长度足够。如果加密ZIP压缩包出现以store算法存储的EXE格式文件,很容易进行破解

大部分exe中都有这相同一段,且偏移固定为64

1
0E1FBA0E00B409CD21B8014CCD21546869732070726F6772616D2063616E6E6F742062652072756E20696E20444F53206D6F64652E0D0D0A2400000000000000

文件准备:nc.zip

nc64.exe

该程序为ZipCrypto Store加密,可以进行明文攻击

1
bkcrack -C nc.zip -c nc64.exe -x 64 0E1FBA0E00B409CD21B8014CCD21546869732070726F6772616D2063616E6E6F742062652072756E20696E20444F53206D6F64652E0D0D0A2400000000000000

已知明文越多,攻击成功的速度越快,该内部密钥还是很快得到的: b21e5df4 ab9a9430 8c336475

恢复:

1
bkcrack -C nc.zip -c nc64.exe -k b21e5df4 ab9a9430 8c336475 -d nc64.exe

流量包pcapng格式解密

利用pcapng文件头进行明文攻击

红色部分是固定的:BlockType始终为0A0D0D0A;BlockTotalLength是小端存储的Header长度,显然不会超过64KB,所以高两位都是00;Byte-Order Magic在小端机器上始终为4D3C2B1A;Major Version目前只有0100;Minor Version目前只有0000。

这样可以知道文件中的4+10字节内容,满足明文攻击的要求

其实蓝色部分也是可以猜出来的:SectionLength是可选字段,大多数软件(比如WireShark)在保存pcapng时会写入-1(即8个字节的FF)

因此,把蓝色部分也算上的话,我们知道文件中的4+18字节内容,对明文攻击绰绰有余了

1
2
3
4
5
6
1. 4字节
偏移为0
0A 0D 0D 0A
2. 18字节
偏移为6
00 00 4D 3C 2B 1A 01 00 00 00 FF FF FF FF FF FF FF FF

因此可以构造明文攻击

1
bkcrack -C file.zip -c file -x 0 0A0D0D0A -x 6 00004D3C2B1A01000000FFFFFFFFFFFFFFFF

网站相关文件破解

网站目录中充斥着大量类型的文件,哪怕被打包成加密ZIP,也很容易找到突破口

例如

robots.txt的文件开头内容通常是User-agent: *
html文件开头通常是 <!DOCTYPE html>
xml文件开头通常是<?xml version="1.0" encoding="UTF-8"?>

文件准备:xml.zip

网站目录肯定会涉及到多级目录,进行模拟。在文件夹中创建一个二级目录“123”,并将一个web.xml放入该二级目录中,然后打包成加密ZIP

123/web.xml

555.jpg

是ZipCrypto Store加密,可以进行明文攻击

常见xml文件头为:

1
<?xml version="1.0" encoding="UTF-8"?>

hex:

1
3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d38223f3e

构造明文攻击:

1
bkcrack -C xml.zip -c 123/web.xml -x 0 3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d38223f3e

得到内部密钥: e0be8d5d 70bb3140 7e983fff

恢复web.xml:

1
bkcrack -C xml.zip -c 123/web.xml -k e0be8d5d 70bb3140 7e983fff -d web.xml

SVG文件格式破解

xml格式的文件除了.xml以外,也包括.svg文件。SVG是一种基于XML的图像文件格式

文件头:

1
<?xml version="1.0"

转hex为:

1
3c 3f 78 6d 6c 20 76 65 72 73 69 6f 6e 3d 22 31 2e 30 22

文件准备:secrets.zip

spiral.svg

advice.jpg

spiral.svg为ZipCrypto Store加密,可以明文攻击

构造明文攻击:

1
bkcrack -C secrets.zip -c spiral.svg -x 0 3c3f786d6c2076657273696f6e3d22312e3022

得到内部密钥: c4038591 d5ff449d d3b0c696

1
bkcrack -C secrets.zip -c spiral.svg -k c4038591 d5ff449d d3b0c696 -d spiral.svg

针对deflate算法:

1
2
3
bkcrack -C secrets.zip -c advice.jpg -k c4038591 d5ff449d d3b0c696 -d advice.jpg

python3 ~/ctf/bkcrack-1.7.0-Linux/tools/inflate.py < advice.jpg > advice_out.jpg

pyc文件格式破解

例题:minivnctf的D u know Pyc?

满足明文攻击,很明显是想对pyc文件进行攻击,且注释有

1
2
3
python 3.12.12
Bit Field为00 00 00 00
hash 字段非置空

明文攻击的条件为:至少已知明文的12个字节及偏移,其中至少8字节需要连续

让我们先来了解一下pyc文件的结构

分别来看,最开始的4个字节是魔数,与python版本信息有关,是CB 0D 0D 0A

1
2
3
4
5
6
7
8
9
10
import importlib.util

# 获取魔数(bytes类型)
magic = importlib.util.MAGIC_NUMBER

# 打印十六进制表示
print(f"Hex: {magic.hex(' ').upper()}")

# 打印字节数组表示
print(f"Bytes: {list(magic)}")

Bit Field为00 00 00 00

因此到这里,我们已经知道了八个字节CB0D0D0A00000000

同时有一个注意的点:

1
pyc产生的时间,事实上是py文件最后修改的时间,大小也是指py文件的大小

那么我们可以从文件大小入手,flag.py原始大小是1411字节,转为4字节的16进制表示为:83050000

我们已经具备明文攻击的条件了:

1
2
3
4
5
偏移量为0(共8字节):
CB0D0D0A00000000

偏移量为12(共4字节):
83050000

因此可以构造明文攻击的语句:

1
bkcrack -C flag.zip -c attack_it.pyc -x 0 CB0D0D0A00000000 -x 12 83050000

使用内部密钥恢复:

1
bkcrack -C flag.zip -c flag.py -k d7fe0787 b3af2704 99fa95dc -d flag.py

tar文件格式破解

例题:LilCTF的提前放出附件

可以进行明文攻击

根据tar文件结构:https://docs.fileformat.com/zh/compression/tar/ 有多处可以用于构造明文攻击的已知明文。

且tar文件头内未使用的字段用 NUL 字节填充。标头由 257 个字节组成,用 NUL 字节填充以使其填充到 512 个字节的记录。例如:magic字段有固定的.ustar6个字节、文件名字段有100个字节,一般情况是用不满的,剩余部分将会填充为0。

因此使用文件名字段剩余字节尝试明文攻击,成功获得三段密钥。

1
bkcrack -C flagtest.zip -c flag.tar -x 40 000000000000000000000000

这里偏移也可为其他的数值

VMDK文件格式破解

可利用文件头进行攻击

1
4B444D560100000003000000

构造明文攻击

1
bkcrack -C flag.zip -c flag.vmdk -x 0 4B444D560100000003000000

得到内部密钥解密即可破解压缩包

.git/HEAD文件格式破解

在Git版本控制系统中,HEAD 文件是一个极其重要的符号引用

HEAD 就像一个指针,指向你当前所在的各种分支或提交。当你执行 git checkoutgit switch 时,Git 就会更新 HEAD 文件的内容

在绝大多数情况下(即你处于某个分支时),HEAD 是一个纯文本文件,内容只有一行。其标准格式为: ref: refs/heads/<分支名>

验证

1
2
3
4
5
6
7
mkdir git_test && cd git_test

git init

ls -a .git

cat .git/HEAD

1
2
3
4
5
# 创建并切换到新分支 dev
git checkout -b dev

# 再次查看 HEAD
cat .git/HEAD

因此我们可以利用这个思路来进行明文攻击

已知明文且偏移量为0

1
ref: refs/heads/master
1
bkcrack -C deflated.zip -c .git/HEAD -p Deflate.txt

特殊状态–游离头指针

游离状态是指:HEAD 直接指向了一个特定的 **提交哈希值 (SHA-1 ID)**,而不是指向任何分支名

当你不再检出(checkout)分支,而是检出某个具体的提交 ID远程分支时,就会进入这个状态

验证

1
2
3
echo "test content" > file.txt
git add file.txt
git commit -m "first commit"

查看当前的提交ID:

1
git log --oneline

你会看到一行输出,比如:7b2a1c4 (HEAD -> dev) first commit。前面的 7b2a1c4 就是你的短提交 ID

切换到该ID(进入游离状态): 将下面的 xxxxxxx 替换成你刚才看到的那个ID

1
2
3
git checkout xxxxxxx

cat .git/HEAD

此时是一个长达40位的哈希字符串

结语

当然还有其他文件格式可以破解,我们做题的时候要去仔细分析文件的数据,查找可利用的明文

本文参考于

https://www.freebuf.com/articles/network/255145.html

https://ctf-wiki.org/misc/archive/zip/#_6

https://g3rling.top/583