1. 项目概述为什么我们需要鉴别Zip文件真伪加密在CTFCapture The Flag竞赛、日常安全审计甚至是处理一些来路不明的压缩包时我们经常会遇到一个经典问题这个Zip文件是真的被密码保护了还是仅仅“伪装”成了加密状态这就是所谓的“Zip伪加密”与“真加密”鉴别。对于新手来说一个提示输入密码的Zip文件往往会让人下意识地去寻找密码或尝试爆破这可能会浪费大量时间甚至走入死胡同。而对于经验丰富的安全研究员或CTF选手快速识别加密真伪是高效解题的第一步。简单来说Zip文件的加密信息记录在其文件头的特定字段中。通过解析这些十六进制值我们可以像法医鉴定一样判断这个文件是否真的被加密以及使用了何种加密方式。掌握这项技能不仅能让你在CTF中快速破解“纸老虎”更能深入理解Zip文件格式的底层结构提升二进制文件分析能力。本指南将带你从最基础的Zip文件头结构讲起手把手教你如何用010 Editor、WinHex等工具进行手动分析并最终通过复现一道经典的BUUCTF题目来巩固实战技能。无论你是刚入门的安全爱好者还是想深化二进制知识的开发者这篇内容都能让你有所收获。2. Zip文件格式核心结构解析要鉴别加密必须先了解Zip文件的“骨架”。一个标准的Zip文件由三部分组成本地文件头Local File Header、文件数据File Data和中央目录文件头Central Directory File Header。对于加密分析我们最关心的是本地文件头和中央目录文件头中的特定标志位。2.1 关键文件头结构详解每个被压缩的文件在Zip包内都有一个对应的本地文件头它位于该文件数据的前面。而中央目录则位于Zip文件的末尾附近相当于整个压缩包的“总目录”。以下是涉及加密的关键字段偏移量相对于各个头结构的起始位置计算通用位标志General Purpose Bit Flag这是一个16位的字段2个字节它是判断加密真伪的核心。我们重点关注其中的第0位和第6位。位0Bit 0如果设置为1表示该文件是加密的。这是最直接的加密标志。位6Bit 6这个位具有双重含义也是造成“伪加密”的关键。对于传统PKZIP加密ZipCrypto如果位0加密位为1那么位6必须为0。对于强加密如AES位6会被设置为1同时会有一个额外的“扩展区”来描述加密算法。然而在“伪加密”的情况下攻击者会故意将位6设置为1但使用的却是传统的ZipCrypto。这种不符合规范的状态使得一些老旧或严格的解压软件如Windows资源管理器会认为文件已加密并索要密码而另一些软件如7-Zip、某些命令行工具则会忽略这个矛盾位直接解压。这就是“伪加密”的原理。加密方法Compression Method这个字段告诉我们使用了何种压缩和加密方法。0x0000 不压缩仅存储。0x0008 使用Deflate算法压缩最常见。0x0063 表示使用了非标准的、或受损的加密不这里需要特别注意对于AES加密这个值通常是0x0063或0x0065取决于AES强度但同时通用位标志的位6必须为1并且后面会跟着AES额外数据区。如果压缩方法是0x0008Deflate但通用位标志显示加密则通常是传统的ZipCrypto加密。CRC-32这是文件未压缩数据的循环冗余校验值。在传统ZipCrypto加密中CRC-32在加密前就已经计算并存储。这个特性催生了“已知明文攻击”Known Plaintext Attack。如果你拥有加密Zip包中的任意一个未加密文件或者知道某个加密文件的部分原始内容你就可以利用CRC和加密算法的弱点还原出加密密钥从而破解其他文件的密码。这在CTF中是一个重要考点。2.2 如何定位并查看这些字段我们通常使用二进制编辑器Hex Editor来查看。以010 Editor为例它甚至有现成的Zip文件格式模板Zip.bt可以自动解析结构对新手极其友好。手动分析步骤用010 Editor打开一个Zip文件。搜索Zip文件的魔术字头PK即十六进制50 4B。第一个PK开头后面跟03 04的就是本地文件头50 4B 03 04。从本地文件头起始位置开始偏移0x08处开始的2个字节是通用位标志。偏移0x00处开始的2个字节是压缩方法。在文件末尾附近搜索PK找到后面跟01 02的就是中央目录文件头50 4B 01 02。其中偏移0x08处同样是通用位标志。注意伪加密的“把戏”通常出现在中央目录文件头的通用位标志中。有些工具只检查这里而忽略了本地文件头的状态。因此一个完整的鉴别需要同时检查本地头和中央目录头。3. 真伪加密鉴别实战手册理论说再多不如动手看一眼。下面我们通过几种常见情况来实战演练鉴别流程。3.1 情况一无加密的正常文件现象使用任何解压软件都能直接解压。文件头分析本地文件头通用位标志例如00 00或08 00位0为0压缩方法为08 00Deflate。中央目录头通用位标志与本地头一致通常也是00 00。判断所有加密相关位均为0文件未加密。3.2 情况二真加密传统ZipCrypto现象所有解压软件均要求输入密码密码错误则无法解压。文件头分析本地文件头通用位标志为01 000000 0001仅位0为1。压缩方法为08 00。中央目录头通用位标志同样为01 00。判断本地头和中央目录头的位0均为1位6均为0符合传统加密规范是真加密。3.3 情况三伪加密经典手法这是CTF中最常见的套路。现象Windows自带压缩工具、部分在线解压网站提示需要密码但使用7-Zip“提取”而非“解压到”、unzip命令可能需加-P参数指定空密码或使用-P ‘’或binwalk -e命令可以直接解压出内容。文件头分析常见组合组合A本地无密中央伪密本地文件头通用位标志00 00未加密。中央目录头通用位标志09 000000 1001位0和位3为1。注意位3是“数据描述符”标志有时也会被设置但关键是位0为1。这种是最典型的伪加密因为本地实际数据没加密但中央目录却谎称加密了。组合B本地真密标志中央伪密标志本地文件头通用位标志01 00真加密标志。中央目录头通用位标志09 00位0和位3为1或更诡异的41 000100 0001位0和位6为1。这制造了矛盾。判断关键本地文件头与中央目录文件头的“通用位标志”关于加密的位位0不一致或者出现了传统ZipCrypto下不该出现的位6置1的情况。只要发现这种矛盾或违规基本可判定为伪加密。手工修复伪加密用010 Editor找到中央目录头PK0102中错误的通用位标志如09 00将其修改为与本地文件头一致的未加密状态如00 00保存后文件即可直接解压。这是一个非常实用的技巧。3.4 情况四AES强加密现象现代压缩软件如7-Zip、WinRAR新版创建的高强度加密Zip。文件头分析压缩方法通常为63 00AES-256或65 00等。通用位标志中位0加密位和位6强加密位同时为1例如41 000100 0001。在文件头后会跟有一个AES额外数据区其中包含了加密强度、盐值等信息。判断压缩方法为AES标识且通用位标志的位0和位6均为1。这是规范的真强加密暴力破解难度极大。4. BUUCTF真题复现[ACTF新生赛2020]usualCrypt这道题完美融合了文件头分析、伪加密判断和编码转换是一个绝佳的学习案例。我们一步步来复现。4.1 题目初探与伪加密破解下载题目附件得到一个usualCrypt.zip。尝试解压用Windows资源管理器或默认软件打开提示需要密码。这立刻引起了我们的警惕——可能是伪加密。文件头分析使用010 Editor打开zip文件搜索50 4B 01 02找到中央目录头。查看其通用位标志偏移8发现是09 00二进制00001001位0和位3为1。再搜索50 4B 03 04找到本地文件头查看其通用位标志发现是00 00未加密。结论典型的“本地无密中央伪密”。中央目录谎称文件加密了。修复并解压在010 Editor中将中央目录头PK0102的通用位标志从09 00修改为00 00。保存文件。再次双击zip发现不再索要密码可以直接解压了。我们得到了一个usualCrypt.txt文件。4.2 逆向分析与代码审计打开usualCrypt.txt发现是一段C代码。核心逻辑如下已简化并注释int main() { char v6[100]; // 存储输入的字符串 scanf(%s, v6); // 用户输入 // 1. 对输入字符串进行base64编码 base64_encode(v6); // 2. 对base64编码后的字符串进行“换表”操作 // 将标准Base64码表ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789/ // 替换为自定义码表ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789/ 的特定乱序 swap_table(v6); // 3. 将换表后的字符串与一个已知的字符串 zMXHz3TIgnxLxJhFAdtZn2fFk3lYCrtPC2l9 进行比较 if ( !strcmp(v6, zMXHz3TIgnxLxJhFAdtZn2fFk3lYCrtPC2l9) ) { puts(Correct!); } return 0; }题目的目标很明确我们已知最终的比较字符串zMXHz3TIgnxLxJhFAdtZn2fFk3lYCrtPC2l9需要逆向推出原始的输入v6。逆向思路逆向换表操作我们需要找到代码中自定义的码表是什么。在给出的代码中通常会有两个字符串标准码表ABCDEF.../和一个打乱顺序的码表比如XYZABC...。swap_table函数的功能就是将字符串中的每个字符根据它在自定义码表中的位置映射回标准码表中相同位置的字符。所以要逆向我们需要找到这个自定义码表然后进行反向映射。逆向Base64解码将反向换表后得到的字符串进行标准的Base64解码即可得到原始输入也就是Flag。4.3 编写解密脚本假设我们在代码中找到了自定义码表为ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789/的某种特定排列例如可能是循环移位或完全重排。这里为了演示我们假设自定义码表是标准码表循环左移了4位实际题目需要从源码中提取自定义码表EFGHIJKLMNOPQRSTUVWXYZABCDefghijklmnopqrstuvwxyzabcd0123456789/0123 标准码表 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789/那么解密脚本Python如下import base64 # 题目最终给我们的字符串 encoded_str zMXHz3TIgnxLxJhFAdtZn2fFk3lYCrtPC2l9 # 假设从源代码中提取的自定义码表和标准码表 std_table ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789/ custom_table EFGHIJKLMNOPQRSTUVWXYZABCDefghijklmnopqrstuvwxyzabcd0123456789/0123 # 示例需替换 # 1. 逆向换表将encoded_str中的字符根据custom_table找到位置用std_table对应位置的字符替换 # 构建一个从自定义字符到标准字符的映射字典 reverse_map {custom_table[i]: std_table[i] for i in range(len(std_table))} # 进行映射转换 after_swap .join([reverse_map.get(c, c) for c in encoded_str]) # get(c,c)防止字符不在表中 print(f换表还原后: {after_swap}) # 2. 对还原后的字符串进行标准base64解码 try: # Base64解码需要处理可能的填充 flag base64.b64decode(after_swap.encode()).decode(ascii) print(fFlag: {flag}) except Exception as e: print(f解码出错: {e}) # 有时解码后可能是二进制可以尝试直接输出字节 try: flag_bytes base64.b64decode(after_swap.encode()) print(fFlag (bytes): {flag_bytes}) except: print(无法解码。请检查码表是否正确。)实际操作中你需要在题目给的C源码中找到确切的custom_table字符串定义。将其替换到Python脚本的custom_table变量中。运行脚本即可得到Flag格式通常为actf{...}或flag{...}。4.4 解题总结与技巧这道题串联了多个知识点伪加密识别与修复通过文件头分析快速绕过第一道障碍避免在密码爆破上浪费时间。静态代码分析从逆向代码中理解加密编码流程Base64 - 换表。逆向思维加密流程是输入 - Base64 - 换表那么解密就是换表结果 - 反向换表 - Base64解码。脚本编写用Python快速实现逆向算法得到Flag。重要心得在CTF中遇到加密的Zip第一步永远是先扔到010 Editor或binwalk里看一眼文件头或者用7z l -slt [zipfile]命令查看文件属性7z会显示“Encrypted ”或“-”。这能帮你节省大量不必要的爆破时间。5. 扩展已知明文攻击与CRC碰撞除了伪加密Zip在CTF中另一个高频考点是已知明文攻击Known Plaintext Attack, KPA。这利用了传统ZipCryptoPKZIP加密算法的弱点。5.1 攻击原理简述在ZipCrypto加密中文件的CRC-32校验和在加密前就已计算并明文存储。加密密钥由用户密码初始化。由于CRC和加密算法的特性如果攻击者拥有加密Zip包中的任意一个完整未加密文件或者知道某个加密文件的部分连续明文至少12字节以上越多越好及其在压缩包中的偏移他就可以利用这些信息计算出加密密钥流进而解密其他文件。5.2 实战工具pkcrackpkcrack是实现Zip已知明文攻击的经典工具。攻击前提一个加密的Zip文件encrypted.zip。一个已知的明文文件plain.txt。这个文件必须与加密Zip中某个文件的未压缩原始数据完全相同。知道这个明文文件对应加密Zip中的哪个文件。基本命令# 1. 将已知的明文文件 plain.txt用与目标加密zip相同的压缩方式压缩成一个zip包。 zip -r plain.zip plain.txt # 2. 使用pkcrack进行攻击 pkcrack -C encrypted.zip -c “secret.txt” -P plain.zip -p plain.txt -d decrypted.zip -a-C: 加密的Zip文件。-c: 加密Zip中你想要破解的那个文件路径在Zip内的路径。-P: 你创建的包含明文文件的Zip包。-p: 明文文件在-P指定Zip包内的路径。-d: 输出解密后的Zip文件名。-a: 如果解密后的文件还需要解压可以加这个参数自动解压。操作难点与技巧获取明文在CTF中明文可能来自网站图片、常见文件头如PK\x03\x04、PNG、GIF89a、协议格式或题目提示。有时需要猜测或尝试。压缩方式一致plain.zip的压缩方式必须与encrypted.zip中对应文件一致通常都是Deflate-9。使用zip -r -9 plain.zip plain.txt来最大化匹配。CRC匹配攻击成功的核心是CRC匹配。可以用unzip -v encrypted.zip查看加密文件的CRC值用crc32 plain.txt计算明文文件的CRC两者必须一致否则攻击必然失败。5.3 CRC32碰撞与暴力破解如果连部分明文都没有只有CRC值有时会出CRC32碰撞的题目。题目可能给一个加密Zip告诉你其中某个文件的CRC32值让你找到一个能通过CRC校验的密码。由于CRC32只有32位4字节理论上存在大量碰撞。你可以编写脚本暴力生成一些内容比如短字符串计算其CRC直到与目标CRC匹配。这个匹配上的内容就可以作为“已知明文”来尝试进行已知明文攻击。但这通常只适用于非常小的文件或特定场景。6. 常用工具链与命令速查工欲善其事必先利其器。这里整理一份Zip分析破解的常用工具清单工具名用途关键命令/操作010 Editor二进制文件分析可视化解析Zip头使用Zip.bt模板自动解析手动搜索PK标记。WinHex轻量级十六进制编辑器类似010搜索和修改功能强大。7-Zip压缩/解压查看文件属性7z l -slt archive.zip查看详细属性加密状态。binwalk文件分析自动提取binwalk -e archive.zip尝试自动提取可破伪加密。unzipLinux下解压工具unzip -P archive.zip尝试空密码解压unzip -l列表。zipdetails详细分析Zip结构zipdetails -v archive.zip输出非常详尽的格式信息。pkcrack已知明文攻击pkcrack -C enc.zip -c file -P plain.zip -p plain.txt -d out.zipfcrackzipZip密码爆破字典/暴力fcrackzip -v -D -p rockyou.txt archive.zip使用字典爆破。hashcat高性能密码恢复支持Zip2传统PKZIP哈希模式-m 13600需用zip2john提取哈希。John the Ripper密码破解使用zip2john archive.zip hash.txt提取哈希再用john hash.txt破解。避坑指南伪加密判断优先遇到加密Zip先用7-Zip或binwalk -e试试再用010 Editor看文件头。这能解决至少50%的“假”密码题。已知明文攻击条件苛刻必须要有未压缩的原始明文文件且压缩方式一致。从网页、图片中提取的明文要注意是否经过编码或修改。AES加密是硬骨头遇到AES加密的Zip通用位标志位6为1已知明文攻击无效常规爆破是主要手段但难度极大通常需要强密码字典或题目有弱密码提示。注意编码问题在CTF中解压出的文件名或文件内容可能是GBK、UTF-8等不同编码中文乱码时记得用iconv或支持编码切换的编辑器查看。从文件头的几个字节到复杂的加密算法逆向Zip文件分析就像一场数字侦探游戏。掌握文件结构这把“钥匙”你就能快速看穿许多伪装直击问题核心。下次再遇到那个索要密码的压缩包别急着找字典先打开十六进制编辑器看一眼吧说不定惊喜就在那里。