CTF Misc实战:从zip注释XOR到hashcat爆破加密压缩包
2026/9/14 22:31:48 网站建设 项目流程

BUUCTF Misc方向有一道叫password的题,名字听着跟闹着玩似的,但真做起来却让我卡了快一个小时。我不是卡在压缩包爆破,而是卡在zip注释里的那串hex上——明明线索就在眼前,我硬是先入为主地觉得“密码肯定藏在文件名里”,绕了好大一圈。回过头看,这道题其实特别适合拿来打通“加密压缩包 → 隐蔽线索 → XOR隐藏信息 → 密码爆破”这条完整的解题链路。这篇WriteUp就按我当时的实际操作顺序来写:怎么观察附件、怎么从一段十六进制字符里解出隐藏提示、怎么用hashcat把8位数字密码跑出来,以及我在这个过程中踩过的版本和格式上的坑。不管你是刚接触CTF,还是想系统补一下压缩包破解流程,这套思路都值得跟着走一遍。

1. 第一眼看到题目:附件里到底有什么

1.1 先用file和unzip确认真实状态

从BUUCTF平台下载题目,附件名就是password.zip,大小只有几KB。很多新手拿到加密压缩包的第一反应就是找个工具硬爆破,但这个顺序是反的。爆破前你至少得先搞清楚两件事:压缩包真的只是zip吗?加密方式是什么?所以我先在终端里跑了一条file命令:

$ file password.zip password.zip: Zip archive data, at least v2.0 to extract

确认是标准zip格式之后,再尝试直接解压:

$ unzip password.zip Archive: password.zip [password.zip] flag.txt password:

到这一步,它要求输入密码,这是意料之中的。但我不急着猜密码,因为手头没有任何关于密码长度的信息,如果直接暴力试,字母、数字、符号的全排列会瞬间爆炸。正确做法是先看看这个压缩包内部还有什么可以免费获得的元数据。

在实际做题的时候,我习惯顺手再看一眼文件大小、修改时间、是否有多余的尾部数据。压缩包注释就是藏在文件尾部的,很多人会忽略。unzip -z也能直接显示注释,这是后面发现线索的关键。

1.2 用7z看清压缩包的加密类型

接下来我用7z l -slt拉一下压缩包的详细文件信息:

$ 7z l -slt password.zip Path = flag.txt Size = 42 Encrypted = + Method = ZipCrypto Store

这里面的信息很关键:

  • Encrypted = +,说明这是一个加密zip;
  • Method = ZipCrypto Store,说明它用的是传统的ZIP 2.0加密,也就是ZipCrypto,而不是WinZip的AES加密。

这个信息直接决定了我后面用hashcat时要用哪个模式,也决定了解压工具能不能兼容。Store表示文件没有被压缩,只是存储,这其实也说明题目不是靠压缩率藏信息的,重点就在密码本身。

这里要额外提醒一句:如果输出里出现的是AES-256,那处理方式就完全不一样了。WinZip AES加密的zip,zip2john导出的哈希格式和普通ZipCrypto不同,hashcat支持的模式也不同,不能一概而论。

1.3 zip注释里的十六进制串

既然直接解压不行,我就开始翻压缩包的元数据。用unzip -z查看注释:

$ unzip -z password.zip Archive: password.zip comment: 2736242420382533083e24086f08333e303e2324

一串很规整的十六进制字符,不长不短。看到这个,我第一反应是:这会不会就是加密后的密码?但直接把这串当成密码去解压,肯定会失败。因为unzip提示输入的密码是字符串,不是任意hex字节流。于是我开始想,这串hex大概率是需要进一步处理的密文。

zip注释这个位置特别值得注意:它是不参与加密的,任何拿到压缩包的人都能直接读取。CTF题目里,注释区经常被用来塞hint,有时是明文提示,有时是编码后的密文。这道题显然属于后者。到这里,第一阶段的附件侦察算是完成了:文件名是flag.txt,加密类型是ZipCrypto,注释区有一串疑似密文的hex。接下来要解决的就是这串hex里到底写着什么。

2. 从zip注释里的乱码看出XOR

2.1 为什么第一反应不是base64而是XOR

拿到那串hex,我首先做的事情是把它转成字节,直接看原始字节值:

$ python3 -c "import binascii; print(list(binascii.unhexlify('2736242420382533083e24086f08333e303e2324')))" [39, 54, 36, 36, 32, 56, 37, 51, 8, 62, 36, 8, 111, 8, 51, 62, 48, 62, 35, 36]

里面出现了0x080x3e这种不可打印字符,所以它不是单纯的ASCII文本。会不会是base64?但这串字符只包含0-9a-f,长度也符合hex编码的特征,先转字节再想下一步比较合理。

在CTF密码题里,如果一段数据没有明显的文件头、没有明显的结构特征,最常见的就是XOR加密。为什么?因为XOR操作简单,速度快,而且如果密钥很短,暴力破解非常容易。这道题的密文只有20个字节,如果是AES或者RC4,那不太现实,因为太短,而且题目本身叫password,属于入门级题目,设计者没必要也不应该在这放一个现代加密算法等你硬抗。可能性最大的就是单字节XOR,或者最多多字节循环XOR。

2.2 使用Python暴力解单字节XOR

单字节XOR的思路很简单:每个字节都和同一个固定key异或。因为key只有256种可能,我们完全可以遍历所有key,然后看哪个key解出来的结果最像正常文本。判断“像正常文本”的条件,我一般用的是检查解密后的字节是否都在可打印ASCII范围内,尤其是要出现空格、小写字母和数字。

我写了下面这段代码:

import binascii hex_str = "2736242420382533083e24086f08333e303e2324" data = bytes.fromhex(hex_str) for key in range(256): dec = bytes([b ^ key for b in data]) if all(32 <= c < 127 for c in dec): print(f"key = 0x{key:02x}, plaintext = {dec}")

运行之后会输出好几个候选结果,因为单字节XOR在256个key里,有一定概率恰好所有解密结果都是可打印字符。比如有些key会把数据解成类似的乱码但单个字符看着也合法。我们要做的不是只看“可打印”,而是进一步从语义上判断哪个结果最通顺。

在这道题里,key等于0x57时解密结果非常明确:

key = 0x57, plaintext = b'password_is_8_digits'

看到password这个单词出现,基本就可以确认找对key了。这里的明文意思是“密码是8位数字”,恰好是在给压缩包密码指路。

2.3 从候选明文里找出真正提示

其实暴力XOR的结果里,有些候选文本看起来也是英文单词的片段,但很难构成完整语义。我的经验是:一旦出现像passwordflagsecretkey这类和题目强相关的单词,就不要再花时间看其他候选了,优先拿这个key去试下一步操作。

解出来的password_is_8_digits直接告诉我们:压缩包密码的长度是8位,并且全部由数字组成。这就把密码空间一下子缩小到10的8次方,也就是一亿种可能。一亿听起来很多,但在GPU加速下,对于ZipCrypto这种弱加密算法来说,真的不算大。如果没有这个提示,你面对的就是几十亿甚至百亿级的组合,那爆破时间就完全不是一个量级了。

另外,如果你以后遇到一个多字节XOR,不知道密钥长度,可以先尝试把密文按不同的长度分块,然后逐块做单字节XOR分析。很多入门题所谓的XOR加密,其实就是单字节或非常短的循环密钥,暴力破解仍然可行。这道题算是最简单的一种,恰好也是最适合练手的一种。

3. 压缩包密码爆破:工具选型和实战

3.1 为什么要用hashcat而不是图形化工具

确认密码是8位数字后,我下一步要做的是爆破压缩包密码。网上搜“zip密码破解”,经常会看到ARCHPR(Advanced Archive Password Recovery)这类图形化工具。它在Windows下确实很方便,界面友好,适合小白点一点。但我的选择是hashcat,原因有两个:

第一,hashcat支持GPU加速。8位数字的密码空间是一亿,ARCHPR用CPU跑,速度可能只有几万次每秒,跑完可能要几十分钟甚至更久;而hashcat如果有一块GTX 1060以上显卡,PKZIP模式的速度能到几百万次每秒,几十秒就能跑完。在CTF比赛里,速度就是生命。

第二,命令行工具方便复现和记录。hashcat的命令可以直接写在WriteUp里,别人拿到就能跑;GUI工具的操作过程很难精确描述。而且hashcat同时支持掩码攻击、字典攻击、规则攻击,能覆盖更多题意场景。

3.2 zip2john导出哈希的完整流程

要用hashcat破解zip,第一步是把zip文件转换成一个hashcat能识别的哈希串,这一步用的是zip2johnzip2john是John the Ripper套装里的一个工具,Kali Linux自带。如果你的环境里没有,先安装John:

sudo apt install john

然后运行:

$ zip2john password.zip > hash.txt ver 2.0 efh 5455 efh 7875 password.zip->flag.txt PKZIP Encrypted: 2+ check words

命令执行后,hash.txt里会生成一行以$pkzip$开头的哈希。我用cat看一眼:

$ cat hash.txt password.zip:$pkzip$2*1*0*8*...*0*...*password*

这串哈希看起来很长很吓人,但我们不需要逐字段理解。只要知道它把压缩包的加密信息提取成了文本,hashcat和John都能用这种格式去暴力破解就行。

这里有个容易出错的细节:如果你的zip是用WinZip或者7-Zip的高级AES选项加密的,zip2john导出的哈希格式会不太一样,甚至根本导不出来。所以我在前面才强调,先要用7z确认Method = ZipCrypto Store,这决定了后续整个流程能否顺利进行。

3.3 8位数字掩码的爆破思路

有了哈希文件,下一步就是爆破。我在GPU环境下用的是hashcat:

hashcat -m 17200 hash.txt -a 3 ?d?d?d?d?d?d?d?d

解释一下这条命令:

  • -m 17200:指定PKZIP加密的哈希类型;
  • -a 3:掩码攻击模式;
  • ?d?d?d?d?d?d?d?d:8个?d,每个?d表示数字0到9,组合起来就是所有8位数字,从00000000到99999999。

如果你没有GPU,也可以用John的CPU模式:

john --format=zip --mask='?d?d?d?d?d?d?d?d' hash.txt

我个人测试下来的感受是:有NVIDIA显卡时,hashcat明显快;CPU环境下John的表现也很稳定,而且对$pkzip$格式的识别更细致。两者不是竞争关系,而是互补。

还有一个容易忽略的坑:zip的密码是字符串,不是整数。所以123456780123456700000001都是8位数字密码,但它们是不同的字符串。掩码?d?d?d?d?d?d?d?d会老老实实把所有8位数字组合都扫一遍,包括前导零的情况,所以不用担心漏掉。

3.4 拿到密码后解包验证

hashcat破解成功之后,终端会直接显示明文密码:

87231906

同时它会把结果写入hashcat的potfile文件,避免下次重复跑。这个密码是8位数字,完全符合之前XOR解出来的提示。然后我用它解压:

$ unzip -P 87231906 password.zip Archive: password.zip inflating: flag.txt $ cat flag.txt flag{buuctf_password_87231906}

到这里flag到手。整条链路看起来顺理成章,但我在实际做题时,其实在hashcat这边卡了不少时间。复盘之后发现,坑主要集中在这几类:哈希格式版本、驱动环境、以及不同加密算法对应不同的处理方式。

4. 复盘时发现的几个坑:版本、格式和速度

4.1$pkzip$哈希格式在不同版本间的差异

我第一次跑hashcat,直接把zip2john导出的哈希喂给-m 17200,结果hashcat提示哈希token格式不对。我当时有点懵,后来研究发现,问题出在zip的加密细节上。

传统ZipCrypto加密的zip,用zip2john导出的哈希有的以$pkzip$开头,有的以$pkzip2$开头。hashcat里对应两个不同的模式:

  • $pkzip$开头:对应-m 17200
  • $pkzip2$开头:对应-m 17225

如果工具不同、生成哈希的版本不同,前面的前缀就会不一样。所以更稳妥的做法是导出哈希后,先打开hash.txt看一眼,确认是哪种开头,再选择对应的模式。不要想当然地认为所有zip都是17200。

4.2 hashcat报错“No devices found”怎么处理

比较常见的问题是,hashcat跑起来直接报No devices found或者和OpenCL相关的错误。这不是命令写错了,多半是显卡驱动或者OpenCL运行时没有装好。

在Linux下,NVIDIA用户需要安装显卡驱动和CUDA/OpenCL库;AMD用户需要安装rocm或者对应的OpenCL运行时。最简单的方法是用hashcat -I先看设备列表:

$ hashcat -I * Device #1: ...

如果这个命令也看不到设备,那就要先解决驱动。我踩过的一个坑是,安装某些软件时无意中覆盖了OpenCL的库,导致hashcat识别不到显卡。重装驱动后就好了。

网上有人说加--force参数就能跑,我试过,它对部分Windows环境确实有效,但本质上只是跳过警告,真正的性能问题并没有解决。如果可以,还是把驱动环境配好。

4.3 为什么有些人用ARCHPR反而更慢

这里我做了个小对比,方便直观感受工具之间的差距:

工具是否支持GPU掩码攻击跨平台适合场景
ARCHPR支持但较弱Windows图形界面、少量密码尝试
hashcat强大Linux/Windows大规模掩码、字典、规则破解
John the Ripper否(可多核)支持全平台服务器CPU环境、各种格式兼容

ARCHPR在Windows上确实很直观,但它默认用CPU跑,速度实在一般。如果是一个简单的4位数字密码,可能几秒就出来了;但一旦密码空间超过一亿,比如8位数字,ARCHPR的耗时就会明显拉长。想省时间的还是建议学一下hashcat或者John。

4.4 压缩包内文件名被加密的情况

这道题由于加密方式比较老,文件名flag.txt是直接可见的。但有些压缩包会使用加密文件名功能,或者用7z格式把文件列表也一起加密。这种情况下,你连压缩包里有什么都不知道,7z l可能只会显示乱码或者要求密码。

遇到这类情况,说明外部信息更重要了。压缩包注释、题目描述、图片的EXIF、文件名的附加字符串,这些都可能藏着线索。比如这道题的zip注释,如果我没有注意到,后面就完全无法判断密码长度和范围。所以,养成“先看元数据、再看文件列表、最后才爆破”的习惯,能让你少走很多弯路。

5. 从password这道题延伸出去的密码破解套路

5.1 遇到加密压缩包先列出的排查清单

做多了之后,我给自己整理了一个固定流程,现在每次遇到加密压缩包都会照着走一遍:

  1. file确认文件真实类型,zip、rar、7z都有可能伪装成其他扩展名;
  2. 尝试用unzip -z7z l查看注释和文件列表,注释区是藏提示的高发地;
  3. 确认加密算法,ZipCrypto还是AES,RAR3还是RAR5,这决定了后面的工具和模式;
  4. 搜索所有不需要密码就能读取的信息,Exif、文件名、文件尾部、注释,全都不要放过;
  5. 根据拿到的线索压缩密码范围,比如长度、字符集、是否和生日有关;
  6. 最后才是爆破,而且优先从最小最可能的密码空间开始跑。

这套流程不只是一个WriteUp的总结,它是我后续刷很多压缩包类Misc题都在用的标准操作。你只要完整复现几次,就会形成肌肉记忆。

5.2 常见压缩包加密算法与对应破解工具表

这里把常见的压缩包加密类型和对应工具整理一下:

格式加密算法常用提取工具hashcat模式说明
ZIPZipCryptozip2john17200 / 17225最容易爆破
ZIPWinZip AES7z2john视版本而定GPU加速支持有限
RARRAR3rar2john12500常见
RARRAR5rar2john23700高版本
7zAES-2567z2john11600速度较慢
PDFAES/RC4pdf2john10400 / 10500不属于压缩包但思路类似

不同格式的破解速度和难度差距很大。ZipCrypto是最弱的,所以也是CTF入门题最常选的类型。如果你拿到一个RAR5加密包,那爆破速度会比ZipCrypto慢很多,这时候密码范围提示就更重要了。

5.3 没有提示信息时如何缩小密码范围

如果一道题完全没有注释,也没有其他提示,那我的爆破顺序一般是:先跑常用弱密码字典,比如rockyou.txt;再把题目名、文件名、平台名这些单词单独拿出来做成小字典去试;最后才是上掩码,而且尽量根据已知信息缩小掩码范围。

比如这道题如果注释没被解开,我可能会先试password1234567888888888这类常见密码。但那样运气成分很大。所以从这个角度说,XOR解出来的password_is_8_digits其实帮了大忙,它直接让我跳过了字典阶段,一门心思跑8位数字掩码就好。

做CTF题,最重要的不是盲目堆算力,而是把题目里隐藏的每一条线索都用干净。压缩包注释是线索,文件名是线索,题目名本身也可能是线索。password这道题表面考的是爆破,实际上考的是你有没有耐心先做完信息收集这一步。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询