深入理解zip伪加密

深入理解zip伪加密

前言: 之前一直认为,zip的伪加密也就是判断奇偶,改一改加密标志位那么简单,甚至可以直接上手拿工具去梭,感谢经过C3ngH师傅指正后,才意识到其中原理的重要性. 对其深入研究后, 记录下这篇文章。

zip伪加密原理

了解伪加密之前,我们需要深入理解zip的文件结构。

一个zip通常由三部分组成,即: 压缩源文件数据区 压缩源文件目录区 压缩源文件目录结束标志

如图:

image-20251031165119300

压缩源文件数据区:

HEX 含义
50 4B 03 04 这是zip的头文件标记(0x04034b50),对应文本PK
14 00 解压文件所需的 pkware 版本
00 00 全局方式位标记(有无加密)
08 00 压缩方式 (0x0008,对应Deflated)
AA 84 最后修改文件时间 (遵循MS-DOS时间格式)
5F 5B 最后修改文件日期 (遵循MS-DOS时间格式)
6A B1 EC C9 CRC-32校验和(0xC9ECB16A)
19 00 00 00 压缩后尺寸
18 00 00 00 未压缩尺寸
08 00 文件名长度
00 00 扩展记录长度
66 6C 61 67 2E 74 78 74 文件名(对应flag.txt)

压缩源文件目录区

HEX 含义
50 4B 01 02 目录中文件文件头标记
1F 00 压缩使用的 pkware 版本
14 00 解压文件所需 pkware 版本
00 00 全局方式位标记(有无加密)
08 00 压缩方式
AA 84 最后修改文件时间
5F 5B 最后修改文件日期
6A B1 EC C9 CRC-32校验和
16 00 00 00 压缩后尺寸
18 00 00 00 未压缩尺寸
08 00 文件名长度
24 00 扩展字段长度
00 00 文件注释长度(0 字节,表示没有注释)
00 00 磁盘开始号(0,表示文件不跨磁盘)
00 00 内部文件属性
20 00 00 00 外部文件属性
00 00 00 00 局部头部偏移量
66 6C 61 67 2E 74 78 74 文件名(对应flag.txt)
0A 00 20 00 … DC 01 扩展字段(长度为36字节,这是由上面的扩展字段长度24 00决定的。这是ZIP64、NTFS时间戳等扩展信息的存放位置)

压缩源文件目录结束标志

HEX 含义
50 4B 05 06 目录结束标记
00 00 当前磁盘编号(因为该ZIP文件没有分卷,不跨越多张磁盘,所以从0开始)
00 00 目录区开始磁盘编号 (同上,表示中央目录也位于第一个磁盘上)
01 00 本磁盘上纪录总数 (表示当前磁盘上有1条中央目录记录)
01 00 目录区中纪录总数 (这是整个ZIP文件中最重要的计数之一,它表明这个ZIP文件中总共包含1个文件)
5A 00 00 00 目录区尺寸大小 (十进制90字节。这指的是从50 4B 01 02开始到中央目录记录结束的所有字节长度)
3C 00 00 00 目录区对第一张磁盘的偏移量 (中央目录相对于存档起始位置的偏移量。小端序,0x0000003C = 十进制 60 字节。这意味着,解压软件需要从ZIP文件开头跳过60个字节,就能找到中央目录(即 PK\x01\x02 签名)
00 00 ZIP 文件注释长度(0表示ZIP文件没有全局注释)
ZIP文件注释内容(因为注释长度为0,所以这里没有数据)

伪加密原理

在一个正常、健康的ZIP文件中,对于同一个文件条目,其压缩源文件数据区和压缩源文件目录区中的“全局方式位标记”(即加密标志)必须完全一致

如:

image-20251031173026383

而解压软件处理ZIP文件通常分两步:

步骤一:列出文件列表

软件首先读取ZIP文件末尾的中央目录(目录区),这里包含了所有文件的索引信息(文件名、加密标志等),软件根据这里的信息向用户展示文件列表,并给加密文件打上“*”的图标。

步骤二:解压具体文件

当用户选择解压一个文件时,软件根据中央目录记录的指针,找到文件对应的本地文件头(数据区),软件依据数据区中的标志位来执行实际的解压操作。

伪加密,则是在一个正常未加密的zip文件上进行修改:将压缩源文件目录区的全局方式位标记改为加密的状态,这样,压缩软件首先读取目录区,就会认为“这是一个加密文件”,从而向用户索要密码。(但实际上,文件根本没有加密,这也是“伪加密”叫法的由来。)

例如:

image-20251031174523805

这里将00 00改为09 00,压缩软件就会显示加密:

image-20251031174631352

经过实测,7-Zip检测的是数据区的全局方式位标记,其他解压软件,例如BandZip和WinRAR检测目录区的全局方式位标记,这三种软件都只检测一位,并不会检测另一个位置,同时也不会进行报错。

你可能会好奇,为什么这里非得改成09而不是其它数字呢?

这与压缩软件判断通过全局方式位标记判定加密的逻辑有关:

全局方式位标记是一个16位的二进制数(在ZIP文件中以2个字节表示),在这16个位中,最低位(Least Significant Bit, 也称之为第0位)是加密的总开关

在ZIP文件中,这2个字节是小端序存储的。例如,你看到 00 00,实际值应为 0x0000

对应的二进制数为:0000 0000 0000 0000,最低位为0,因此判定为未加密,压缩软件会直接解压。

09 00,对应二进制数:0000 0000 0000 1001,最低位为1,因此会判定为加密。

不同的加密算法也具有不同的详细特征:

加密算法 全局方式位标记 (二进制) 典型十六进制值 原理与特点
未加密 xxxx xxxx xxxx xxx0 00 00, 08 00 第0位 = 0。总开关关闭,文件未加密。
PKWARE 传统加密 xxxx xxxx xxxx xxx1 01 00, 09 00 第0位 = 1,且第6位和第11位均为0。这是ZIP格式最初定义的弱加密算法。
AES 加密 xxxx xxx1 xxxx 1xx1 01 09, 01 41, 01 63 第0位=1(加密),且第6位=1,第11位=1。这是WinZip开发并标准化的强加密。

但是总的来说,不管哪种加密,第0位都是决定加密的总开关,当第0位为0时,对应的十六进制值为偶数值,当第0为为1时,对应的十六进制值为奇数值,因此,我们才有了通过判定奇偶值来判断加密的说法。

解题思路

在CTF 比赛题目中,涉及到伪加密类型,我们需要同时分析zip的压缩源文件数据区和压缩源文件目录区,判定其是否为伪加密,再通过修改目录区的全局方式位标记来破解伪加密。