1355 字
7 分钟
2026 御网杯 线上 像素中的秘密 image_05.zip Writeup
像素中的秘密 image_05.png — 详细 Writeup
题目信息
| 项目 | 内容 |
|---|---|
| 附件 | image_05_2.zip → 解压得到 image_05.png |
| 文件大小 | 245 字节 (0xF5) |
| 题目类型 | Misc — PNG 文件尾部隐写 + LCG 流密码 + Base62 编码 |
| Flag | flag{file_carving_skill} |
1. PNG 文件结构分析
1.1 完整 Hex Dump
$ xxd image_05.png00000000: 8950 4e47 0d0a 1a0a 0000 000d 4948 4452 .PNG........IHDR00000010: 0000 0040 0000 0040 0802 0000 0025 0be6 ...@...@.....%..00000020: 8900 0000 7c49 4441 5478 9cd5 ce41 1100 ....|IDATx...A..00000030: 2000 c3b0 52ff 9e87 081e 5ca3 2067 1b65 ...R.....\. g.e00000040: 1227 7112 2771 1227 7112 2771 1227 7112 .'q.'q.'q.'q.'q.00000050: 2771 1227 7112 2771 1227 7112 2771 1227 'q.'q.'q.'q.'q.'00000060: 7112 2771 1227 7112 2771 1227 7112 2771 q.'q.'q.'q.'q.'q00000070: 1227 7112 2771 1227 7112 2771 1227 7112 .'q.'q.'q.'q.'q.00000080: 2771 1227 7112 2771 1227 7112 2771 1227 'q.'q.'q.'q.'q.'00000090: 7112 2771 1227 7112 2771 1227 71fe 0ebc q.'q.'q.'q.'q...000000a0: ba72 aa03 7d65 2883 7300 0000 0049 454e .r..}e(.s....IEN000000b0: 44ae 4260 8200 0000 0069 cb34 419d 2dc8 D.B`.....i.4A.-.000000c0: 55e9 4ba2 788d 485e 3c7b 34fc a298 62fa U.K.x.H^<{4...b.000000d0: e7b7 b6d2 d511 59b7 beab 50c6 0a75 3b5e ......Y...P..u;^000000e0: 2540 9f72 2974 43c6 6de8 275a f19c 4b2e %@.r)tC.m.'Z..K.000000f0: b590 af42 b9 ...B.1.2 PNG 块 (Chunk) 逐块解析
PNG 文件由 文件签名 (8字节) + 若干数据块 组成,每个块结构为:
┌──────────┬──────────┬──────────────┬──────────┐│ 长度 (4B) │ 类型 (4B) │ 数据 (N字节) │ CRC32(4B) │└──────────┴──────────┴──────────────┴──────────┘逐块遍历:
| 块序号 | 类型 | 偏移 | 数据长度 | CRC32 | 说明 |
|---|---|---|---|---|---|
| — | 签名 | 0x0000 | 8 | — | 89 50 4E 47 0D 0A 1A 0A PNG魔数 |
| 1 | IHDR | 0x0008 | 13 | 0x250BE689 | 图像头:64×64像素,8位色深 |
| 2 | IDAT | 0x0021 | 124 | 0x65288373 | 压缩图像数据 |
| 3 | IEND | 0x00A9 | 0 | 0xAE426082 | PNG结束标志块 |
| ⚠ | 隐藏 | 0x00B5 | 64 | — | ❗ IEND后不应有数据 |
关键发现:PNG 规范要求 IEND 是文件的最后一个块,但此文件 IEND 块结束于
0xB4,其后仍有 64 字节 额外数据,说明存在隐写。
2. 拆分隐藏数据 (File Carving)
IEND 块后 64 字节完整 hex:
0x00B5: 00 00 00 00 69 CB 34 41 9D 2D C8 55 E9 4B A2 78 ....i.4A.-.U.K.x0x00C5: 8D 48 5E 3C 7B 34 FC A2 98 62 FA E7 B7 B6 D2 D5 .H^<{4...b......0x00D5: 11 59 B7 BE AB 50 C6 0A 75 3B 5E 25 40 9F 72 29 .Y...P..u;^%@.r)0x00E5: 74 43 C6 6D E8 27 5A F1 9C 4B 2E B5 90 AF 42 B9 tC.m.'Z..K....B.数据结构:
┌─────────────────────┬──────────────────────┬────────────────────────────────┐│ 填充 (4字节) │ 种子 Seed (4字节) │ 密文 Ciphertext (56字节) ││ 0x00 0x00 0x00 0x00 │ 0x69 0xCB 0x34 0x41 │ 0x9D 0x2D 0xC8 0x55 ... 0xB9 ││ 无意义 │ 大端序 = 0x69CB3441 │ LCG-XOR 加密后的 Base62 文本 │└─────────────────────┴──────────────────────┴────────────────────────────────┘| 字段 | 字节范围 | 长度 | 值 | 含义 |
|---|---|---|---|---|
| 填充 | [0:4] | 4 | 00 00 00 00 | 无意义填充 |
| 种子 | [4:8] | 4 | 69 CB 34 41 | LCG 初始种子 |
| 密文 | [8:64] | 56 | 9D 2D C8 55 ... 42 B9 | XOR 加密数据 |
种子按大端序 (Big-Endian) 解析:
0x69CB3441 = 6×16⁷ + 9×16⁶ + C×16⁵ + B×16⁴ + 3×16³ + 4×16² + 4×16¹ + 1×16⁰ = 17749248653. LCG 流密码解密
3.1 LCG 参数
使用 Numerical Recipes 标准线性同余生成器参数:
| 参数 | 符号 | 值 | 说明 |
|---|---|---|---|
| 乘数 (multiplier) | a | 1664525 | — |
| 增量 (increment) | c | 1013904223 | — |
| 模数 (modulus) | m | 2³² (0xFFFFFFFF) | 32位无符号整数截断 |
3.2 递推公式
state₀ = seed = 0x69CB3441
stateₙ₊₁ = (a × stateₙ + c) mod 2³² = (1664525 × stateₙ + 1013904223) & 0xFFFFFFFF
keyₙ = stateₙ₊₁ & 0xFF ← 取低8位作为密钥字节
plainₙ = cipherₙ ⊕ keyₙ ← XOR解密3.3 密钥流计算过程(前8步 + 最后4步)
| 步骤 | LCG State | key | ct | pt | 明文字符 |
|---|---|---|---|---|---|
| 1 | 0xACEB80AC | 0xAC | 0x9D | 0x31 | '1' |
| 2 | 0x6A75041B | 0x1B | 0x2D | 0x36 | '6' |
| 3 | 0xAAA5EABE | 0xBE | 0xC8 | 0x76 | 'v' |
| 4 | 0xEEF19305 | 0x05 | 0x55 | 0x50 | 'P' |
| 5 | 0xFAC468A0 | 0xA0 | 0xE9 | 0x49 | 'I' |
| 6 | 0x71B8037F | 0x7F | 0x4B | 0x34 | '4' |
| 7 | 0xAB92BAD2 | 0xD2 | 0xA2 | 0x70 | 'p' |
| 8 | 0xA7D41C09 | 0x09 | 0x78 | 0x71 | 'q' |
| … | … | … | … | … | … |
| 53 | 0xBB2C7990 | 0x90 | 0x90 | 0x00 | '\x00' |
| 54 | 0x55307FAF | 0xAF | 0xAF | 0x00 | '\x00' |
| 55 | 0x5ADC2942 | 0x42 | 0x42 | 0x00 | '\x00' |
| 56 | 0x997F57B9 | 0xB9 | 0xB9 | 0x00 | '\x00' |
有趣的现象:最后4步的密钥字节恰好等于密文字节,XOR 结果为零字节(
\x00),作为填充使用。实际有效 Base62 字符串为前 52 字节对应的 52 个字符(去除尾部\x00后为 33 个有效字符)。
3.4 解密代码
A = 1664525C = 1013904223MASK = 0xFFFFFFFF
seed = int.from_bytes(raw_data[4:8], 'big') # seed = 0x69CB3441cur_seed = seeddecrypted = bytearray()
for b in raw_data[8:]: # 遍历56字节密文 cur_seed = (A * cur_seed + C) & MASK # LCG迭代 decrypted.append(b ^ (cur_seed & 0xFF)) # 取低8位 XOR 解密
# 去除尾部空字节base62_str = decrypted.rstrip(b'\x00').decode('ascii')# base62_str = "16vPI4pqYkxq33FsdItrG9pL5jAc3GLk9"3.5 解密结果
16vPI4pqYkxq33FsdItrG9pL5jAc3GLk9全部由 0-9 a-z A-Z 组成 → Base62 编码特征。
4. Base62 解码
4.1 字符集(⚠ 本题特殊顺序)
0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ└─0-9─┘└───────── a-z ──────────┘└───────── A-Z ──────────┘注意:本题字符集顺序为 数字 → 小写字母 → 大写字母,而非常见的「数字→大写→小写」。这是本题的关键坑点,使用标准 Base62 解码工具会得到错误结果。
4.2 解码原理
Base62 本质是 62 进制数 → 大整数 → 字节序列:
"16vPI4pqYkxq33FsdItrG9pL5jAc3GLk9" │ (62进制→整数) ▼2511413510841791937195854758407182524397597805993880480893 │ (转大端序字节) ▼666c61677b66696c655f63617276696e675f736b696c6c7d │ (UTF-8解码) ▼flag{file_carving_skill}4.3 解码细节
输入字符串 (33字符): "16vPI4pqYkxq33FsdItrG9pL5jAc3GLk9"
逐字符累加计算大整数: '1' → num = 0*62 + 1 = 1 '6' → num = 1*62 + 6 = 68 'v' → num = 68*62 + 57 = 4273 'P' → num = 4273*62 + 51 = 264977 ... '9' → num = ... = 2511413510841791937195854758407182524397597805993880480893
大整数: 2511413510841791937195854758407182524397597805993880480893
转大端序字节 (24 bytes): 0x66 0x6C 0x61 0x67 0x7B 0x66 0x69 0x6C 0x65 0x5F 0x63 0x61 0x72 0x76 0x69 0x6E 0x67 0x5F 0x73 0x6B 0x69 0x6C 0x6C 0x7D
UTF-8 解码: f l a g { f i l e _ c a r v i n g _ s k i l l }5. 完整解题流程
image_05_2.zip │ ▼ 解压image_05.png (245 bytes) │ ▼ xxd 查看 / PNG块遍历IEND 块 (0xA9-0xB4) 后有 64 字节隐藏数据 │ ▼ 提取: data[0xB5:]┌────────────────────────────────────┐│ 填充(4B) │ Seed(4B) │ 密文(56B) ││ 00000000 │ 69CB3441 │ 9D2DC855... │└────────────────────────────────────┘ │ ▼ LCG 解密 (a=1664525, c=1013904223, m=2³²)Base62 字符串: "16vPI4pqYkxq33FsdItrG9pL5jAc3GLk9" │ ▼ Base62 解码 (0-9a-zA-Z)flag{file_carving_skill}6. 涉及知识点
| 知识点 | 说明 |
|---|---|
| PNG 文件格式 | 文件签名、IHDR/IDAT/IEND 块结构、CRC32 校验 |
| File Carving | 从正常文件数据之后提取隐藏的额外数据 |
| 线性同余生成器 (LCG) | Numerical Recipes 标准参数 (a=1664525, c=1013904223) |
| XOR 流密码 | 伪随机密钥流与密文逐字节 XOR |
| Base62 编码 | 62 进制编码,字符集顺序为 0-9a-zA-Z(小写在大写前) |
7. Flag
flag{file_carving_skill}谢谢除草鸡的阅读!
2026 御网杯 线上 像素中的秘密 image_05.zip Writeup
https://nan.sajunan.cn/posts/像素中的除草鸡/分享文章
生成精美分享图或复制链接,与更多人分享本文。
继续阅读
换条路线
从其他文章中稳定抽取
最后更新于 ,距今已过 76 天
部分内容可能已过时