1. 题目背景与初步分析
这是一道来自某国家级CTF比赛的杂项题目,主要考察隐写术(Steganography)相关技能。题目给出一个看似普通的文件,但其中隐藏了多层加密和隐写信息。作为参赛选手,我们需要通过一系列技术手段逐步揭开这些隐藏信息,最终获取flag。
提示:在CTF比赛中,杂项题目往往需要综合运用文件分析、编码解码、隐写术等多种技能,这道题目就是典型的例子。
1.1 初始文件检查
首先我们拿到的是一个无扩展名的文件。经验丰富的CTF选手会立即想到几种可能性:
- 文件可能被故意删除了扩展名
- 可能是某种特殊格式的文件
- 可能包含多个文件的组合(如文件拼接)
使用file命令检查文件类型:
bash复制file mystery_file
但输出结果可能并不明确,这时我们需要更深入的分析。
2. 二进制分析与文件修复
2.1 十六进制查看
使用十六进制编辑器(如xxd或010 Editor)查看文件内容:
bash复制xxd mystery_file | less
在文件头部和尾部分别发现了7z压缩包的标志性特征:
- 文件头应有:
37 7A BC AF 27 1C(7z魔数) - 文件尾应有特定的结束标记
但当前文件这些部分可能有损坏或被修改过。
2.2 文件修复技巧
通过对比正常7z文件的头部和尾部结构,我们可以手动修复:
- 确认原始文件的偏移量
- 使用
dd命令提取有效部分:
bash复制dd if=mystery_file of=fixed.7z bs=1 skip=[起始偏移] count=[有效长度]
或者直接在十六进制编辑器中删除无关数据,保留完整的7z文件结构。
注意:实际操作中可能需要多次尝试,因为文件损坏程度可能不同。建议保留原始文件的多个备份版本。
3. 第一层解压与图片分析
3.1 解压修复后的文件
使用7z工具解压修复后的文件:
bash复制7z x fixed.7z
得到一个图片文件(假设为hidden.png)。
3.2 LSB隐写分析
LSB(Least Significant Bit)隐写是一种常见的图片隐写技术,它将信息隐藏在图片像素的最低有效位中,对人眼几乎不可见。
使用工具检查LSB隐写:
bash复制steghide extract -sf hidden.png
或者使用Python的PIL库进行手动提取:
python复制from PIL import Image
img = Image.open('hidden.png')
pixels = img.load()
binary_data = []
for y in range(img.height):
for x in range(img.width):
r, g, b = pixels[x, y]
binary_data.append(str(r & 1))
binary_data.append(str(g & 1))
binary_data.append(str(b & 1))
# 将二进制数据转换为字节
binary_str = ''.join(binary_data)
hidden_data = bytes([int(binary_str[i:i+8], 2) for i in range(0, len(binary_str), 8)])
with open('hidden.zip', 'wb') as f:
f.write(hidden_data)
这将提取出一个ZIP压缩包,进入下一层挑战。
4. 多重压缩包破解
4.1 压缩包结构分析
解压得到的ZIP文件包含7个子压缩包:
- 6个
passX.zip(X为1-6) - 1个
flag.zip
尝试解压flag.zip发现需要密码,而6个passX.zip也都需要密码。
4.2 密码破解策略
传统思路是尝试爆破密码,但观察到:
- 每个
passX.zip内仅包含一个4字节的文本文件 - 压缩包使用真加密(AES等强加密)
- 文件体积非常小(约100字节左右)
这种情况下,爆破密码不现实(需要极长时间),应该转换思路。
4.3 CRC32碰撞攻击
ZIP格式存储了每个文件的CRC32校验值(32位循环冗余校验)。对于小文件(特别是4字节),我们可以通过CRC32值反推出原始文件内容。
原理:
- 4字节文件有2^32种可能
- 计算每种可能的CRC32,与目标值比对
- 匹配即找到原始文件
实现代码(Python):
python复制import zlib
import itertools
import string
def crack_crc32(target_crc, length=4):
# 转换为整数格式(处理十六进制字符串)
if isinstance(target_crc, str):
target_crc = int(target_crc, 16)
# 定义搜索字符集:通常4字节数据多为可见字符
chars = string.printable.encode()
# 如果爆破失败,请使用下方全字节范围(速度较慢):
# chars = bytes(range(256))
print(f"正在爆破CRC: {hex(target_crc)} ...")
# 迭代所有可能的组合
for guess in itertools.product(chars, repeat=length):
guess_bytes = bytes(guess)
if zlib.crc32(guess_bytes) & 0xFFFFFFFF == target_crc:
return guess_bytes
return None
# 已知的CRC32值
tasks = {
"data1.txt": "CE70D424",
"data2.txt": "F90C8A70",
"data3.txt": "FF3FE4BB",
"data4.txt": "242A5387",
"data5.txt": "9A27098E",
"data6.txt": "D3F6DF9F"
}
results = {}
for name, crc in tasks.items():
found = crack_crc32(crc)
if found:
print(f"成功! {name}内容为: {found.decode(errors='ignore')} (Hex: {found.hex()})")
results[name] = found
else:
print(f"未找到{name}的匹配项。")
print("\n最终结果汇总:", "".join([r.decode() for r in results.values() if r]))
运行后得到拼接密码:c1!xxtLf%fXYPkaA
5. 最终flag获取
5.1 解压flag.zip
使用获得的密码解压最终压缩包:
bash复制unzip -P 'c1!xxtLf%fXYPkaA' flag.zip
得到一个flag.txt文件,但打开后看似空白或只有少量字符。
5.2 零宽字符隐写分析
零宽字符是不可见的Unicode字符,常用于隐写。常见的有:
- U+200B(零宽空格)
- U+200C(零宽非连接符)
- U+200D(零宽连字符)
- U+FEFF(零宽无间断空格)
使用Python解析:
python复制with open('flag.txt', 'r', encoding='utf-8') as f:
content = f.read()
binary_str = []
for char in content:
if char == '\u200b': # 零宽空格
binary_str.append('0')
elif char == '\u200c': # 零宽非连接符
binary_str.append('1')
# 将二进制转换为ASCII
flag = ''.join([chr(int(''.join(binary_str[i:i+8]), 2))
for i in range(0, len(binary_str), 8)])
print("Flag:", flag)
最终得到flag:dart{bf4100d9-cc8d-48f6-a095-54cbfad189e1}
6. 经验总结与技巧
6.1 文件分析技巧
-
遇到无扩展名文件时:
- 使用
file命令初步判断 - 用十六进制查看器检查文件头
- 尝试常见文件格式的魔数
- 使用
-
文件修复要点:
- 始终保留原始文件备份
- 修改前记录所有操作步骤
- 使用
dd等工具精确提取数据
6.2 隐写术技巧
-
LSB隐写检测:
- 使用
stegsolve工具可视化不同位平面 - 检查颜色通道异常
- 注意PNG文件的IDAT块异常
- 使用
-
零宽字符处理:
- 使用支持显示Unicode控制字符的编辑器
- Python的
repr()函数可以帮助显示 - 注意不同零宽字符的编码差异
6.3 压缩包处理技巧
-
CRC32碰撞适用场景:
- 文件非常小(通常<8字节)
- 知道或能猜测文件内容类型(如纯文本)
- 加密强度高,无法爆破
-
提高碰撞效率:
- 限制字符集(如可打印ASCII)
- 使用多进程/多线程加速
- 预先计算常见值的CRC32
7. 扩展思考
这道题目展示了CTF比赛中典型的"洋葱式"挑战设计 - 层层包裹,每层需要不同的技术解开。在实际比赛中,还可能遇到以下变种:
-
文件拼接的更多形式:
- 多个文件简单拼接
- 交错拼接(如按字节交替)
- 加密后拼接
-
更复杂的隐写技术:
- DCT系数的JPEG隐写
- 音频文件的频谱隐写
- 视频文件的帧间隐写
-
密码破解的进阶技巧:
- 已知部分明文攻击
- 字典攻击与规则变形
- 侧信道攻击
对于想深入学习CTF杂项技能的选手,建议:
- 熟悉常见文件格式规范
- 掌握至少一种编程语言(Python首选)
- 积累各种隐写工具的用法
- 参与实战练习(如CTFtime上的比赛)
这道题目虽然已经解决,但其中涉及的技术点值得反复练习。我在实际比赛中就曾因为忽略了CRC32碰撞的可能性而浪费了大量时间在无谓的密码爆破上。后来养成了对小文件先检查CRC32的习惯,效率提升明显。