1. 项目概述从一张“损坏”的图片到压缩包的秘密最近在Bugku的CTF赛题里又遇到一个挺有意思的Misc杂项题题目通常就一句话“请攻击这个压缩包”然后给一个加密的ZIP文件。很多新手朋友一看到加密压缩包第一反应就是爆破密码但往往字典跑穿了也一无所获白白浪费时间和算力。这道题的巧妙之处在于它引导我们关注压缩包里的内容本身——一张看似损坏的PNG图片。这其实是一个经典的“已知明文攻击”场景。简单来说我们虽然不知道压缩包的密码但我们知道压缩包里某个文件的部分原始内容即明文。利用这个已知的片段配合强大的工具bkcrack我们就有机会逆向推导出加密密钥从而解开整个压缩包。今天我就来详细拆解这道题的完整解题思路和操作流程重点会放在bkcrack这个工具的原理和每一步的具体操作上让你不仅会“抄作业”更能理解背后的“所以然”。2. 核心原理ZIP加密与已知明文攻击的攻防逻辑2.1 ZIP的传统加密机制ZipCrypto为何脆弱我们常见的ZIP加密大多使用的是称为ZipCrypto的传统流加密算法。它并不是像AES-256那样牢不可破的现代加密。ZipCrypto的工作原理可以简单理解为它使用用户输入的密码生成一个密钥流这个密钥流会像一次性密码本一样与文件的原始数据明文进行异或XOR操作从而产生加密后的数据密文。它的一个致命弱点在于加密的头部。为了兼容性和快速校验ZIP文件在加密时会对每个文件的前12个字节使用一个固定的、已知的初始化向量进行加密。更重要的是在ZIP文件结构中紧跟在加密数据后面的是文件的CRC-32校验值。这个校验值是未加密的并且它是基于文件的原始明文计算得出的。这就埋下了一个伏笔如果我们能知道加密文件中任意一段12字节或更长的连续明文字节并且知道这段明文在加密文件中的确切位置我们就能利用这段“已知明文”和对应的密文结合CRC校验等机制去反推用于加密的密钥。这正是“已知明文攻击”能够成立的理论基础。2.2 PNG文件头为何是完美的“已知明文”PNG便携式网络图形是一种常用的无损压缩图片格式。它的文件结构有着非常严格和标准化的规范。每一个PNG文件的开头都有一个固定的8字节签名Signature89 50 4E 47 0D 0A 1A 0A这8个字节是雷打不动的。其中第一个字节0x89是一个超出ASCII范围的值用于检测文件传输是否被错误地转换为文本模式紧接着的PNG的ASCII码最后是DOS风格的换行符和文件结束符用于兼容性。在这8字节签名之后是第一个数据块ChunkIHDR图像头数据块。IHDR块的结构也是固定的4字节数据长度 4字节块类型“IHDR” 13字节实际数据 4字节CRC校验。因此一个标准的PNG文件其文件最开头的至少12个字节8字节签名“IHDR”的前4个字节是100%确定的。如果我们能确认ZIP包里的文件是一个标准的、未损坏的PNG那么我们就拥有了一个完美且足够长的已知明文片段。这正是本题目的核心突破口——压缩包里的“损坏的PNG”只是被加密了其原始结构完好无损。2.3 bkcrack工具的工作机制bkcrack正是利用上述原理自动化完成攻击的工具。它的工作流程可以概括为输入你需要提供加密的ZIP文件、至少一段已知的明文及其在原始未压缩文件中的准确偏移量从文件开头计算的字节位置。计算bkcrack会利用已知明文-密文对通过复杂的数学运算涉及ZipCrypto的密钥调度算法和CRC32的逆向特性尝试推导出加密时使用的三个内部密钥Key0, Key1, Key2。输出一旦成功计算出这三个密钥bkcrack就可以直接使用-k参数指定密钥来解密整个ZIP包。或者更进一步在已知密钥的情况下尝试爆破出原始的用户密码如果密码不是特别复杂。3. 实战环境准备与工具安装3.1 获取题目文件与初步分析首先你需要从Bugku平台下载题目附件通常是一个名为challenge.zip或类似名称的加密压缩包。拿到文件后不要急着运行工具先进行初步分析查看压缩包信息在Linux/macOS终端或Windows的PowerShell/CMD中使用unzip命令尝试解压会提示输入密码确认文件已加密。unzip challenge.zip列出压缩包内容使用unzip -l命令可以查看压缩包内包含的文件列表而不需要密码。这能让我们确认里面有一个PNG文件假设名为flag.png。unzip -l challenge.zip验证文件类型虽然文件在压缩包里但我们可以通过一些间接方式增强信心。有时题目描述或文件名本身已经强烈暗示。我们的所有后续操作都基于“该文件是一个标准PNG”的假设。3.2 安装bkcrack工具bkcrack是一个跨平台的开源命令行工具。安装方式如下Linux/macOS (推荐使用包管理器或编译):macOS (Homebrew): 最简单的方式brew install bkcrackUbuntu/Debian: 可以从项目Release页面下载预编译的.deb包安装或者使用apt从特定PPA安装需先添加PPA。通用方法编译确保已安装cmake和g。git clone https://github.com/kimci86/bkcrack.git cd bkcrack cmake -S . -B build -DCMAKE_BUILD_TYPERelease cmake --build build编译后可执行文件位于./build/src/bkcrack可以将其移动到系统路径如/usr/local/bin/或直接使用。Windows:访问bkcrack在 GitHub 的 Releases 页面。下载最新版本的bkcrack-x.x.x-win64.zipx.x.x为版本号。解压到一个目录例如C:\Tools\bkcrack\。为了方便使用可以将该目录添加到系统的PATH环境变量中。或者在命令行中直接切换到该目录下操作。验证安装打开终端或命令提示符输入bkcrack如果显示帮助信息说明安装成功。3.3 准备已知明文数据这是最关键的一步我们需要提取出加密ZIP中flag.png文件对应的密文头部并准备好与之匹配的明文。确定明文对于一个标准PNG其文件开头至少12字节的明文是固定的。我们可以用Python或十六进制编辑器来生成这段数据。使用Python生成# png_header.py png_header bytes([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]) bIHDR # 前8字节是签名接着是I,H,D,R四个字符共12字节 with open(plaintext.bin, wb) as f: f.write(png_header[:12]) # 我们取前12字节作为已知明文 print(f已知明文十六进制: {png_header[:12].hex()})运行后得到plaintext.bin文件和明文十六进制串89504e470d0a1a0a49484452。确定偏移量明文在原始未压缩文件中的偏移量Offset。对于我们准备的12字节明文它位于PNG文件的最开头所以偏移量是0。注意这里有一个极其重要的概念区分。偏移量指的是这段明文在“原始文件”中的位置而不是在“压缩后的ZIP数据块”或“加密数据块”中的位置。对于未压缩存储的ZIP条目偏移量计算相对直接。但对于压缩存储的条目情况更复杂因为ZIP是先压缩再加密。bkcrack内部会自动处理压缩流。我们通常只需要关心原始文件的偏移量。在本题场景下PNG文件很可能被“存储”即不压缩在ZIP中以简化题目此时偏移量就是0。4. 详细操作步骤使用bkcrack实施攻击假设我们的文件结构如下加密ZIP文件challenge.zip压缩包内加密文件flag.png我们准备好的12字节明文文件plaintext.bin(内容为89504e470d0a1a0a49484452)已知明文在flag.png中的偏移量04.1 步骤一发动已知明文攻击这是核心命令用于让bkcrack根据已知信息计算加密密钥。bkcrack -C challenge.zip -c flag.png -p plaintext.bin -o 0让我们拆解这个命令的每一个参数-C challenge.zip: 指定加密的ZIP归档文件C大写。-c flag.png: 指定ZIP归档内我们拥有已知明文的那个具体文件c小写。-p plaintext.bin: 指定包含已知明文片段的文件。-o 0: 指定已知明文在原始文件flag.png中的起始偏移量这里是0。执行过程与输出解读 当你运行上述命令后bkcrack会开始工作。它首先会读取ZIP文件结构定位到flag.png的加密数据部分然后提取出对应偏移量0开始的密文。接着它会利用已知的明文和提取的密文进行大量的计算尝试破解出那三个内部密钥Key0, Key1, Key2。如果一切顺利你会在几秒到几分钟内看到类似下面的成功输出[00:00:05] Keys d4a2c2f6 3e8d4b7a 914e6c8b这串十六进制数字就是破解成功的标志它表示找到了用于加密这个ZIP的密钥。如果长时间没有输出比如超过半小时或者输出“Could not find the keys”则可能意味着已知明文或偏移量错误。ZIP文件使用的不是传统的ZipCrypto加密可能是AES-256bkcrack对此无效。文件在ZIP中是以压缩模式存储的且我们的已知明文片段在压缩流中的位置发生了改变这种情况较少见通常CTF题会避免。4.2 步骤二使用获取的密钥解密文件成功获取密钥后我们不需要知道原始密码就可以直接解密并提取出flag.png文件。bkcrack -C challenge.zip -c flag.png -k d4a2c2f6 3e8d4b7a 914e6c8b -d decrypted_flag.png参数解释-k: 指定上一步骤破解得到的三个密钥用空格分隔。-d decrypted_flag.png: 指定解密后输出的文件名。运行这个命令后bkcrack会使用密钥对flag.png的加密数据进行解密并将结果写入decrypted_flag.png。现在你可以用任何图片查看器打开这个文件很可能就能看到包含Flag的图片了。4.3 步骤三可选根据密钥还原原始密码如果出于学习目的你想知道用户当初设置了什么密码bkcrack也提供了密码爆破功能。注意这只是在已知密钥的情况下对密码进行本地穷举速度很快。bkcrack -k d4a2c2f6 3e8d4b7a 914e6c8b -r 6 ?p参数解释-r 6 ?p: 这是一个密码恢复模式。6表示尝试密码最大长度为6。?p是一个掩码表示密码字符集为小写字母、大写字母和数字即a-zA-Z0-9。你可以根据需要调整长度和字符集例如?a表示所有可打印ASCII字符。执行后如果密码强度不高工具会很快输出找到的密码。5. 进阶技巧与疑难问题排查5.1 当已知明文不只在文件开头时有时题目可能不会那么直接。已知的明文片段可能隐藏在文件中间。例如PNG文件包含一些具有固定格式的数据块如tEXt文本信息、IEND结束块等。IEND块的12字节也是固定的数据长度00 00 00 00、块类型49 45 4E 44、CRCAE 42 60 82。假设我们通过其他方式推断出图片的尺寸或包含特定文本从而确定了tEXt块的内容和位置。这时你需要准确计算出这段明文在整个PNG文件中的起始偏移量。使用-o参数指定这个偏移量。bkcrack支持添加多段已知明文使用多个-p和-o参数组合可以增加攻击成功率并加快速度。bkcrack -C challenge.zip -c flag.png -p header.bin -o 0 -p iend.bin -o 123455.2 处理压缩模式存储的ZIP如果ZIP中的文件是“已压缩”的通过unzip -l查看方法列显示deflate情况会复杂一些。因为已知明文是针对原始文件的而工具需要处理的是压缩后的数据流。幸运的是bkcrack内置了对DEFLATE压缩算法的支持。你只需要像之前一样提供原始文件的明文和偏移量bkcrack会自动处理压缩层。这是它非常强大的一个功能。5.3 常见失败原因与排查表现象可能原因解决方案Could not find the keys1. 已知明文错误文件不是标准PNG或头损坏。2. 偏移量计算错误。3. 使用的加密算法是AES-256。1. 用十六进制编辑器查看解密出的文件头部验证猜测。2. 仔细计算偏移考虑ZIP可能包含的额外本地文件头。3. 使用7z l -slt challenge.zip查看加密方法确认是ZipCrypto而非AES-256。bkcrack长时间无输出计算量较大或明文长度不足。已知明文越长越好至少12字节。可以尝试增加明文片段如包含IHDR部分数据。耐心等待对于短密钥通常几分钟内会有结果。解密出的文件无法打开解密成功但文件本身可能仍有其他问题或不是预期格式。用file命令检查解密出的文件类型。或用十六进制编辑器查看文件头确认是否正确。可能还需要修复文件结构。命令参数错误参数顺序或格式错误。仔细检查-C,-c,-p,-o的对应关系。确保-c指定的文件名与ZIP内完全一致包括大小写。5.4 实操心得与效率提升优先验证文件类型在投入时间攻击前尽量用其他旁路信息确认ZIP内文件确实是PNG。有时unzip -l看到的文件名后缀可能是误导。利用文件结构除了PNG其他如BMP有固定文件头、GIF有固定签名“GIF89a”、PDF以“%PDF-”开头、ZIP本身以“PK”开头等格式都有固定的文件头可以作为已知明文来源。组合攻击如果有一段已知明文但长度不够可以尝试结合ZIP格式本身的特性。例如ZIP每个本地文件头后紧跟的加密数据其第一个字节对应原始压缩数据的第一个字节。如果文件是存储且未加密部分可分析有时能推断出更多信息。工具不是万能的bkcrack只针对传统的ZipCrypto。现在很多压缩软件如7-Zip、新版WinRAR默认使用AES-256加密这种加密方式目前没有已知明文攻击的公开有效方法只能依靠强密码爆破或字典攻击。自动化脚本在CTF比赛中可以提前编写一个小脚本自动提取ZIP内文件类型、生成对应的标准文件头明文并调用bkcrack能大大节省时间。通过这道题我们不仅学会了一个工具的使用更重要的是理解了ZIP传统加密机制的缺陷以及如何利用文件格式的规范性来发起攻击。这种“已知明文攻击”的思维在CTF的Misc和Forensics取证类题目中非常常见是信息安全从业人员需要掌握的基础密码分析思路之一。下次再遇到加密的ZIP不妨先看看里面藏了什么类型的文件也许突破口就在那固定的几个字节里。