CTF新手实战:从损坏的PNG图片中提取Flag的完整指南
当你第一次参加CTF比赛,面对一张"损坏"的PNG图片时,是否感到无从下手?本文将带你深入理解PNG文件结构,通过十六进制编辑器和Python脚本,一步步修复被篡改的图片参数,最终提取隐藏的Flag。我们将以最常见的"修改图片宽高"题型为例,提供可复用的解题框架。
1. 理解PNG文件基础结构
PNG文件由多个数据块(chunk)组成,每个块包含特定信息。对于CTF隐写题,我们需要重点关注三个核心部分:
- 文件头签名:固定8字节
89 50 4E 47 0D 0A 1A 0A,标识这是一个PNG文件 - 关键数据块:
- IHDR块:包含宽高、颜色类型等关键参数
- IDAT块:存储实际图像数据
- IEND块:文件结束标记
- CRC校验:每个数据块末尾的4字节校验码
使用010 Editor打开PNG文件时,你会看到类似这样的结构:
code复制00000000: 89 50 4E 47 0D 0A 1A 0A 00 00 00 0D 49 48 44 52
00000010: 00 00 03 13 00 00 01 F4 08 02 00 00 00 DA 5A 4A 50
其中:
00 00 03 13表示宽度(787像素)00 00 01 F4表示高度(500像素)DA 5A 4A 50是CRC校验值
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 识别被篡改的图片参数
当遇到显示不全或看似损坏的PNG图片时,按以下步骤排查:
- 检查文件头签名:确认前8字节是否正确
- 分析IHDR块:
- 定位IHDR标识(49 48 44 52)
- 检查宽高值是否合理(常见篡改点)
- 验证CRC校验:
- 计算当前IHDR块的CRC值
- 与文件中的CRC值对比
使用Python快速验证CRC:
python复制import binascii
import struct
def check_crc(png_path):
with open(png_path, 'rb') as f:
data = f.read()
ihdr_start = 12 # IHDR块起始位置
ihdr_data = data[ihdr_start:ihdr_start+17] # 获取IHDR块数据
crc32 = binascii.crc32(ihdr_data) & 0xffffffff
stored_crc = struct.unpack('>I', data[ihdr_start+17:ihdr_start+21])[0]
return crc32 == stored_crc
如果返回False,说明IHDR块可能被修改过。
3. 修复被篡改的图片宽高
当发现宽高值被修改时,我们需要通过CRC碰撞找出原始值。以下是完整操作流程:
3.1 手动修复方法
- 用010 Editor打开图片
- 定位到IHDR块的宽高字段(通常位于0x10-0x17偏移处)
- 尝试修改宽高值:
- 逐步增加高度值(常见Flag藏在底部)
- 保持宽度不变,仅调整高度
- 保存后查看图片是否正常显示
注意:直接修改可能导致CRC校验失败,部分查看器会拒绝显示
3.2 自动化CRC碰撞脚本
当手动调整无效时,使用Python脚本暴力破解正确的宽高值:
python复制import binascii
import struct
def find_original_
