资讯动态

CTF ZIP伪加密与CRC爆破实战:从二进制结构到自动化修复

发布时间:2026/9/14 5:39:41 来源:尧图企业网站定制
简介本资源为2021年中山市「香山杯」CTF网络安全竞赛的完整赛题压缩包面向CTF初学者、高校信息安全专业学生及CTF战队成员提供真实地方赛事的多方向实战题目与配套素材。包内共41个文件涵盖17张PNG与10张JPG格式的图片题含二维码、隐写线索、视觉密码等、5个嵌套ZIP压缩包含PWN、Crypto、Reverse等方向子题、3个Python脚本用于解密、自动化分析或环境搭建、2段WAV音频需频谱分析或音频隐写、2个TXT说明文件及1个RTF文档整体体积17.3MB结构典型适合作为多维度CTF训练样本。已有493人学习下载资源包含MISC、Crypto、PWN、Reverse四大类题目原始素材及部分题目命名线索如‘你悟了吗’‘BrokenPassword’‘ezrsa’等便于选手开展靶向练习、复现解题路径并积累常见题型处理经验。1. 中山市香山杯2021 CTF zip题不是解压就完事而是从伪加密、CRC爆破到结构篡改的完整链路“中山市香山杯2021 CTF zip”这道题在CTF新手圈里流传甚广但很多人卡在第一步——双击打不开、7-Zip报错“无法打开存档”或解压后得到一堆乱码文件。它根本不是一道“找密码”的题而是一套压缩包格式层数据层逻辑层三重嵌套的逆向工程zip文件头被手动篡改实现伪加密中央目录记录被刻意错位导致文件名乱码真实flag藏在被CRC校验掩盖的修改字节中。这类题目专为考察选手对ZIP文件二进制结构的理解深度而非工具调用熟练度。适合刚学完PKWARE APPNOTE v6.3.9规范、能手写hexdump定位local file header偏移的新手进阶也适合老手验证自己是否真正掌握zip -Z store与-Z deflated在文件头字段上的差异、以及extra field中如何植入自定义扩展标识。如果你还在用john --wordlistrockyou.txt硬扫zip密码这道题会直接告诉你真正的入口从来不在密码框里。2. 拆解ZIP二进制结构定位伪加密标志、修复中央目录偏移、识别被篡改的file name字段CTF中zip题的突破口永远在二进制层面。中山市香山杯2021这道题的原始zip文件假设名为challenge.zip表面看是标准zip但用xxd challenge.zip | head -n 20可发现异常第6字节即local file header中的general purpose bit flag本应为0x0000无加密却显示为0x0001——这就是伪加密标志。它不触发AES或ZipCrypto解密流程仅让解压工具误判需密码实际数据完全明文。更关键的是该zip的central directory header中offset of start of central directory字段偏移量0x14–0x17被设为一个非法值导致unzip -l列出的文件名全是不可见字符而zipinfo -v则暴露出central directory offset mismatch警告。2.1 用hexedit定位并清除伪加密位伪加密位位于每个local file header的第6–7字节little-endian对应general purpose bit flag的bit 0。标准值为00 00伪加密时被改为01 00。使用hexedit challenge.zip打开后按/搜索50 4b 03 04PK\003\004 magic bytes定位第一个文件头起始位置。跳转至该位置6字节处即第6–7字节将01 00手动改为00 00。保存退出后unzip -l challenge.zip即可正常列出文件名——此时你会看到一个名为flag.txt的文件但unzip challenge.zip flag.txt仍失败提示bad CRC。这是因为文件内容本身被故意篡改过CRC32校验值未同步更新。提示不要依赖zip -F或zip -FF自动修复它们会重写central directory可能覆盖题目预设的隐藏结构。所有修复必须手工定位偏移量操作。2.2 修正central directory offset并提取原始file datacentral directory offset错误会导致解压工具无法正确定位文件数据块。用binwalk challenge.zip可快速扫描结构binwalk -e challenge.zip输出中会显示DECIMAL HEXADECIMAL DESCRIPTION列表其中central directory项的HEXADECIMAL值如0x1A2B即为真实central directory起始地址。用dd命令提取该区域# 提取central directory部分假设长度为0x500字节 dd ifchallenge.zip ofcd.bin bs1 skip0x1A2B count0x500再用xxd cd.bin | head -n 10查看前几条central directory record。每条record固定46字节其中bytes 28–31为relative offset of local header。将该值如0x0000012C与实际local file header位置比对若偏差超过±10字节说明local header被移动过。此时需用xxd challenge.zip | grep -A5 50 4b 03 04找到所有local file header位置计算其与central directory record中记录的offset差值批量修正central directory record中的offset字段。2.3 手动提取flag.txt原始数据并绕过CRC校验即使修复了结构flag.txt解压仍报CRC错误。这是因为题目作者修改了flag.txt的原始字节如将flag{...}改为fl4g{...}但未更新local file header中的CRC32字段偏移量0x10–0x13。此时不能依赖unzip -p而应直接提取raw data# 获取flag.txt在zip中的start offset从central directory record中读取 # 假设其relative offset为0x0000012C且文件采用store压缩compression method 0 # 则data从local file header后42630字节开始filename length extra field length # 使用dd跳过header提取原始字节 dd ifchallenge.zip offlag_raw.bin bs1 skip$((0x0000012C 30)) count128提取出的flag_raw.bin即为篡改后的明文。用xxd flag_raw.bin查看可见开头为fl4g{...}。将4改为a保存为flag_fixed.bin即可得到正确flag。3. 用Python脚本自动化修复伪加密与CRC校验从hex解析到结构重写手动hex编辑适合单次调试但面对多文件zip或批量题目时效率低下。以下Python脚本基于struct和io.BytesIO实现全自动修复核心逻辑分三步解析local file header → 清除bit 0伪加密标志 → 重新计算并写入CRC32。3.1 解析ZIP local file header并定位伪加密位ZIP local file header固定结构为30字节其中general purpose bit flag占2字节offset 6–7。脚本需逐个扫描PK\x03\x04魔数并解析后续字段import struct import sys def parse_zip_headers(zip_path): with open(zip_path, rb) as f: data f.read() headers [] offset 0 while True: # 查找local file header magic pos data.find(bPK\x03\x04, offset) if pos -1: break offset pos # 解析header30字节 # [0:4] signature, [4:6] version, [6:8] gp_bit_flag, [8:10] compression... if len(data) pos 30: break header data[pos:pos30] sig, ver, gp_flag, comp_method, mod_time, mod_date, crc32, comp_size, uncom_size, fname_len, extra_len \ struct.unpack(4s2s2s2s2s2sI4s4s2s2s, header[:30]) # 检查gp_flag是否设置bit 0伪加密 if gp_flag 0x0001: print(fFound pseudo-encrypted file at offset {hex(pos)}) headers.append({ offset: pos, gp_flag: gp_flag, fname_len: struct.unpack(H, header[26:28])[0], extra_len: struct.unpack(H, header[28:30])[0], data_offset: pos 30 struct.unpack(H, header[26:28])[0] struct.unpack(H, header[28:30])[0] }) offset pos 30 return headers # 调用示例 headers parse_zip_headers(challenge.zip)此段代码输出每个伪加密文件的起始偏移、文件名长度、额外字段长度及数据块起始位置为后续修复提供精确坐标。3.2 自动清除伪加密位并重写header获取header位置后需将原gp_flag的bit 0清零并将新header写回文件def fix_pseudo_encryption(zip_path, headers): with open(zip_path, rb) as f: for h in headers: # 定位gp_flag字段offset 6 f.seek(h[offset] 6) # 读取原2字节 old_flag struct.unpack(H, f.read(2))[0] # 清除bit 0 new_flag old_flag 0xFFFE # 写回 f.seek(h[offset] 6) f.write(struct.pack(H, new_flag)) print(fCleared pseudo-encryption at {hex(h[offset])}, old{hex(old_flag)}, new{hex(new_flag)}) fix_pseudo_encryption(challenge.zip, headers)注意rb模式允许原地修改避免生成临时文件。struct.pack(H, new_flag)确保小端序写入与ZIP规范一致。3.3 提取并修复CRC校验失败的文件内容对于flag.txt这类CRC被篡改的文件脚本需跳过header直接读取raw data再用zlib.crc32()重新计算import zlib def extract_and_fix_crc(zip_path, header_info, output_path): with open(zip_path, rb) as f: f.seek(header_info[data_offset]) # 读取未压缩数据假设compression method 0 raw_data f.read(header_info[uncom_size]) # 需从central directory获取真实uncom_size # 修正数据示例将fl4g改为flag fixed_data raw_data.replace(bfl4g, bflag) # 计算新CRC32 new_crc zlib.crc32(fixed_data) 0xFFFFFFFF print(fOriginal CRC: {hex(header_info[crc32])}, Fixed CRC: {hex(new_crc)}) # 写入修复后文件 with open(output_path, wb) as out_f: out_f.write(fixed_data) # 注意header_info需补充uncom_size字段需从central directory解析此函数输出修正后的flag.txt且打印新旧CRC对比验证修复有效性。4. 破解ZIP密码的实战边界当伪加密失效时如何用hashcatrockyou精准爆破尽管中山市香山杯2021这道题本质是伪加密但CTF中大量zip题确实依赖真实密码保护。当binwalk未发现结构异常、unzip -t报password required时必须进入密码破解阶段。关键在于不要盲目用john跑全量rockyou.txt而要先提取hash并选择正确hash mode。4.1 从ZIP文件提取ZipCrypto或AES-256 hashZIP密码加密分两类传统ZipCryptolegacy和现代AES-256。二者hash提取方式不同ZipCrypto用zip2john challenge.zip hash.txt生成john格式hash以$zip2$开头AES-256zip2john无法直接提取需用python3 -m zipfile -l challenge.zip确认加密类型再用7z l -slt challenge.zip查看Method 99AES-256或Method 98ZipCrypto# 提取ZipCrypto hash zip2john challenge.zip | head -n 1 hash.txt # 若为AES-256需用7z导出key derivation参数 7z l -slt challenge.zip | grep -E (Method|Password)输出中若含Method 99则需用hashcat mode13600ZIP AES-256若为Method 98则用mode17200ZIP Legacy。4.2 用hashcat进行高效爆破参数选择与词典裁剪直接跑全量rockyou.txt耗时过长。应先用hashcat -m 17200 -a 0 hash.txt /usr/share/wordlists/rockyou.txt --force测试基础流程再优化# 步骤1统计hash长度排除超长密码ZIP密码通常≤8字符 hashcat -m 17200 -a 0 hash.txt /usr/share/wordlists/rockyou.txt --potfile-disable --stdout | wc -l # 步骤2裁剪rockyou.txt只保留1–8字符密码 awk length($1) 1 length($1) 8 /usr/share/wordlists/rockyou.txt rockyou_1to8.txt # 步骤3启用规则引擎增强如添加数字后缀 hashcat -m 17200 -a 0 hash.txt rockyou_1to8.txt -r /usr/share/hashcat/rules/best64.rule --forcebest64.rule包含常见变形大小写翻转、数字追加等可将破解成功率提升3倍以上。4.3 验证破解结果并提取flaghashcat成功后输出cracked.txt中含密码。用该密码解压unzip -P password_found challenge.zip # 若解压后flag.txt内容仍异常说明存在二次隐写如LSB、空格编码 # 此时需用steghide或binwalk进一步分析 binwalk -e flag.txt若binwalk发现flag.txt内嵌PNG则用foremost -i flag.txt提取再用zsteg检查LSB隐写。5. 进阶技巧用zipdetails深度解析ZIP结构差异快速识别中山市香山杯类题目的篡改痕迹zipdetails是PKWARE官方推荐的ZIP结构分析工具比unzip -l或zipinfo更底层能直接显示每个字段的十六进制值与语义解释。对中山市香山杯2021这类题它能在3秒内暴露三个关键篡改点伪加密位、central directory offset错位、file name encoding异常。5.1 安装与基础用法对比正常zip与题目zip的输出差异# Ubuntu安装 sudo apt install libarchive-zip-perl # 或直接下载源码https://github.com/noloader/zipdetails # 分析题目zip zipdetails challenge.zip challenge_details.txt # 对比正常zip如用zip -r normal.zip test.txt生成 zipdetails normal.zip normal_details.txt # 差异聚焦点 diff challenge_details.txt normal_details.txt | grep -E (Flag|Offset|Name)输出中重点关注Flag行正常zip显示0000题目zip显示0001伪加密Offset of start of central directory行题目zip该值明显偏离文件末尾如文件长0x2000该值却为0x1000File name行题目zip中Name字段显示binary或invalid UTF-8而正常zip为可读字符串5.2 解析central directory record中的隐藏字段zipdetails默认不显示central directory record的全部46字节需加-v参数zipdetails -v challenge.zip | grep -A 20 Central directory输出中每条record包含Offset of local headerbytes 28–31若该值指向PK\x05\x06end of central directory而非PK\x03\x04即为错位File name lengthbytes 26–27若为0但Extra field lengthbytes 28–29非0说明文件名被移至extra fieldExtra field内容用xxd单独提取该区域搜索0x55 0x54UT timestamp extension或0x75 0x6eUNIX extension常藏有base64编码的hint5.3 快速定位被篡改的CRC32字段并验证数据完整性zipdetails在Local file header部分明确列出CRC-32值并标注Calculated CRC-32基于当前data block计算。若二者不一致即为CRC篡改Local file header: ... CRC-32: 12345678 Calculated CRC-32: 87654321 -- 不一致此时无需手动计算直接执行# 提取该文件data block从zipdetails输出中读取offset dd ifchallenge.zip ofdata.bin bs1 skip0x1234 count0x567 # 用zlib验证 python3 -c import zlib; print(hex(zlib.crc32(open(data.bin,rb).read()) 0xFFFFFFFF))输出0x87654321即确认篡改且data.bin即为原始篡改数据可直接编辑。注意zipdetails的Calculated CRC-32基于当前文件偏移处的raw bytes计算不受伪加密位影响因此是判断数据是否被篡改的最可靠依据。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价