-
-
[原创]第七题:戌时·暗能潜流(AI解析)
-
发表于: 2026-8-20 14:41 9
-
[KCTF] HexMaze 题解:密钥织墙、长度摘要与两层重排
题型:Crypto / Misc 边界题
密钥:121
Flag:flag{T1u_2026_Kc7f_Crypt0_M4ster!}
0. 题面在说什么
题目给出 4 组明文–密文样例和一个 FLAG 密文,算法声明大致是:
- 只用字节编码、十六进制位运算、模 16 循环偏移、固定位置重排、固定摘要扰动
- 无随机数 / IV / 外部状态
- 摘要扰动过程只与输入长度有关
- 需要在 WP 里说明密钥
121每一位的作用
输出是 0-9A-F,看起来像「把数据塞进十六进制迷宫里」。这题的味道很 Misc:骨架靠观察,核心靠猜对几个小构造,而不是硬刚 AES/RSA。
样例:
| 明文 | 密文 |
|---|---|
TLU |
94AA48550495 |
Hello |
34BB405504B5223594B94C53 |
2026 |
A48844556485223322356483 |
abcd! |
547B475584B5223564BB4553 |
FLAG 密文长度 144 hex = 12 段 × 12。
1. 第一步:长度律与分块
观察密文长度:
TLU(3 字节)→ 12 hexHello/abcd!(5 字节)→ 24 hex2026(4 字节)→ 24 hex
规律很明确:按 3 字节一组切块,每块膨胀成 12 个 hex 字符;余 1 / 余 2 字节走另一套「尾块」模板。
于是:
- 完整 3 字节主块:墙位固定
- 余 2(如
Hello的lo):另一种骨架 - 余 1(如
2026的6):再一种骨架
FLAG 144 hex → 11 个主块 + 1 个 1 字节尾块 → 明文长度 34。
2. 第二步:看见「墙」——密钥 121 的第一层作用
把主块 12 个半字节对齐看(以 TLU 为例):
位置: 0 1 2 3 4 5 6 7 8 9 10 11
TLU : 9 4 A A 4 8 5 5 0 4 9 5
所有主块在位置 1,4,6,7,9,11 上永远是:
4 4 5 5 4 5
也就是骨架:
? 4 ? ? 4 ? 5 5 ? 4 ? 5
这和密钥 121 对得太齐了:
- 数字
d→ 墙半字节d + 31 → 4,2 → 5
- 按密钥展开成主块墙序列
445545
所以密钥的数值决定墙的颜色(4/5),排列决定墙插在哪(迷宫骨架)。
数据只占自由位:0,2,3,5,8,10 —— 正好 6 个半字节 = 3 字节,和明文半字节数一致。
尾块同理,只是墙型不同:
| 余数 | 骨架(示意) | 自由位 |
|---|---|---|
| 2 | 2235?4??4?53 |
4 个半字节 |
| 1 | 22332235X4Y3 |
2 个半字节 |
抽出自由位后,密文就退化成与明文等长的半字节流,后面的变换都作用在这条流上。
3. 第三步:长度摘要 —— 题面最大的提示
提示:摘要扰动只与长度有关。
同长度样例 Hello 与 abcd! 可做差分:摘要项相消,用来钉重排;不同长度样例用来钉摘要本身。
最终摘要是一条只依赖长度的半字节串:把周期
4 5 5 4 4 5
重复展开到 n = 2 × len(明文),再与数据流做 mod 16 加法。
对照:
| 长度 L | 摘要(前 2L 个半字节) |
|---|---|
| 3 | 455445 |
| 4 | 45544545 |
| 5 | 4554454554 |
455445 与主块墙 445545 同源,都来自密钥 121 的 4/5 墙色,只是排法不同。
这正是「固定摘要 + 只跟长度有关」:内容不进摘要,长度只决定展开多长。
4. 第四步:模长循环偏移 + 块内重排
去掉摘要之后,半字节流与明文半字节之间还差两步。
4.1 循环偏移
对长度为 n 的半字节数组做循环移位:
rol(stream, 6 % n)
n=6(3 字节)→6%6=0,不转n=8,10,...→ 转 6 格(等价于字节层面转 3 字节)
这对应题面里的「模 16 / 循环偏移」在变长数组上的落地:偏移常量 6,再对当前长度取模。
4.2 固定位置重排(半字节块)
按「每 3 明文字节 → 6 半字节」切段,段内置换:
| 段长 | 置换 | 字节语义 |
|---|---|---|
| 6 | P6 = (5,4,0,1,3,2) |
(A,B,C) → (swap(C), A, swap(B)) |
| 4(余 2) | P4 = (3,2,0,1) |
(A,B) → (swap(B), A) |
| 2(余 1) | P2 = (1,0) |
A → swap(A) |
swap = 字节高低半字节对调。
主块三字节的几何图像很「迷宫」:最后一个字节翻过来放到最前,中间字节原样,中间那个字节再翻过来垫后——像在格子里换位。
5. 第五步:外层重排(样例上看不见的坑)
按上面管道解密 FLAG,会得到一串可读乱码:
ste_M4pt0Cry7f__Kc026u_2{T1lagfr!}
它能完美回编成 FLAG 密文,但不是 flag{...}。
原因是:还有一层固定位置重排,在 3/4/5 字节样例上恰好是恒等,只有更长明文才暴露。
定义(L = len):
rem = pt[: L%3],其余按 3 字节分块后整块逆序,再把rem接到末尾 →rb2(pt)- 再整体 左旋 3 字节 → 得到进入「半字节管道」的中间串
解密时做逆变换。对 FLAG:
中间串 --F--> flag{T1u_2026_Kc7f_Crypt0_M4ster!}
这层解释了题面强调的「固定位置重排」为何在短样例上几乎无感:余数结构让 F 在样例长度上退化成恒等,属于典型 Misc 假进度陷阱。
6. 完整加密流程(汇总)
对明文 pt:
1. mid = Finv(pt) # rb2 后左旋 3 字节(样例上常为恒等)
2. x = 半字节展开(mid)
3. x = rol(x, 6 % len(x))
4. x = 分块重排(x) # P6 / P4 / P2
5. x[i] = (x[i] + Dig[i]) mod 16
Dig = (455445) 重复到 len(x)
6. CT = 按密钥墙型织入 x 的自由位
解密逆序即可。FLAG 长度 34,解得:
flag{T1u_2026_Kc7f_Crypt0_M4ster!}
回编与题目 FLAG 密文一致。
7. 密钥 121 各数字作用(WP 必写)
| 要素 | 作用 |
|---|---|
数字 值 1 / 2 |
墙半字节 = 值 +3 → 4 / 5 |
数字 顺序 1,2,1 |
展开主块墙序列 445545,决定骨架 ?4??4?55?4?5 |
| 由墙色派生 | 长度摘要周期 455445(与墙同色不同排) |
| 与「3」相关的节奏 | 明文按 3 字节分块织墙;半字节偏移常量 6(=2×3);外层也按 3 字节块重排 |
一句话:121 不是加密密钥流,而是迷宫图纸——决定墙刷什么色、插在哪,并派生出只跟长度走的摘要条纹。
8. 解题路径回顾(踩坑与转折)
- 先看骨架再谈密码:主块墙恒为
445545,立刻绑定121。 - 自由位长度 = 明文半字节数:排除「每位密钥扩成不等长编码」等过度假设。
- 同长度差分钉住「摘要与内容无关」;跨长度钉住
455445周期。 - 短样例过拟合:只有核心管道时 FLAG 回编成功但不是
flag{...}——说明还有样例上恒等的外层重排。 - 验证标准:样例加解密 + FLAG 回编 +
flag{...}形态,三线同时满足才收工。
这题像 Misc 的原因也在这里:真正难点不是大数分解,而是分清「墙 / 数据 / 长度摘要 / 两层重排」各自的自由度,并用样例长度故意藏起其中一层。
9. 小结
HexMaze = 密钥织墙的十六进制迷宫 + 长度唯一确定的条纹摘要 + 半字节循环偏移与块内换位 + 对短串隐形的外层块重排。
Flag:
flag{T1u_2026_Kc7f_Crypt0_M4ster!}
附:完整可运行求解脚本见同目录 hexmaze_solver.py。
冰与火的战歌:Windows内核攻防实战高级班!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。