首页
课程
问答
CTF
社区
招聘
峰会
发现
排行榜
知识库
工具下载
看雪20年
看雪商城
证书查询
登录
注册
首页
社区
课程
招聘
发现
问答
CTF
排行榜
知识库
工具下载
峰会
看雪商城
证书查询
社区
CTF对抗
发新帖
0
0
[原创] KCTF2607 第七题 暗能潜流 Writeup
发表于: 2026-8-20 15:20
52
[原创] KCTF2607 第七题 暗能潜流 Writeup
HHHso
26
2026-8-20 15:20
52
# KCTF2607 第七题 暗能潜流 Writeup > **TL;DR** > > 一道名字叫 HexMaze 的自定义密码题:明文进、十六进制出,4 组已知明密文对,密钥 121。本文记录如何用**同长度差分 + 可行集交集**两把刀,剖开"模 16 循环偏移 + 固定位置重排 + 定长摘要扰动"的三层结构,发现**数据在常量的掩护下按块倒序潜行**,最终恢复: > > ``` > flag{T1u_2026_Kc7f_Crypt0_M4ster!} > ``` > > 全程 ZCode × GLM-5.3 自动完成,无人工干预。总用时约 **51 分钟**,成本约**一杯奶茶钱的零头**(明细见文末附录)。 --- ## 0x00 题面:一个不许你猜的密码 题目给出了一个名为 **HexMaze** 的变换器,自述算法只包含五种操作: - 字节编码(bytes → hex) - 十六进制位运算(nibble 级运算) - 模 16 循环偏移(mod-16 cyclic shift) - 固定位置重排(fixed permutation) - 固定摘要扰动(fixed digest,**只与输入长度有关**) 并且刻意声明:无随机数、无随机 IV、无外部状态——**相同输入必得相同输出**。这既是承诺,也是路标:出题人在告诉你,别想暴力碰运气,这题是纯逻辑活。 已知条件(密钥 121): | 明文 | 密文 | |---|---| | `TLU` | `94AA48550495` | | `Hello` | `34BB405504B5223594B94C53` | | `2026` | `A48844556485223322356483` | | `abcd!` | `547B475584B5223564BB4553` | 待解密文(144 个 hex 字符): ``` 14CC4655547594BC475584C5848A43551495448C445584C5D4C9475564C5 34A84B55A4B574BA4355F495A48844556485648C495534A5548C4F5584A5B 4BB405554B522332235A4B3 ``` 难点一眼可见:**flag 的长度和 4 个样本全都不一样**。任何"查表式"的映射分析,都会死在"长度变了怎么办"这一关。题目的灵魂全在那句提示里——*摘要扰动只与输入长度有关*。 --- ## 0x01 第一步:当格式侦探,而不是密码学家 拿到样本先做最无聊也最值钱的事:**数长度**。 | 明文长度 L | 密文 nibble 数 | 倍率 | |---|---|---| | 3 | 12 | 4.0 | | 4 | 24 | 6.0 | | 5 | 24 | 4.8 | 倍率不固定,但长度序列 `12, 24, 24` 像是在说: > **out = 12 × ⌈L/3⌉**(每 3 个字符一组,每组固定产出 12 个 nibble,即 6 字节) 反推 flag:144 ÷ 12 = 12 组 → ⌈L/3⌉ = 12 → **L ∈ {34, 35, 36}**。范围已经收窄到 3 个候选。 再把四条密文按 nibble 对齐排成一列(下表取自分析脚本输出): ``` idx : TLU Hell 2026 abcd [00] : 9 3 10 5 [01] : 4 4 4 4 ← 恒定 [02] : 10 11 8 7 [03] : 10 11 8 11 [04] : 4 4 4 4 ← 恒定 [05] : 8 0 4 7 [06] : 5 5 5 5 ← 恒定 [07] : 5 5 5 5 ← 恒定 [08] : 0 0 6 8 [09] : 4 4 4 4 ← 恒定 [10] : 9 11 8 11 [11] : 5 5 5 5 ← 恒定 ``` **第 1、4、6、7、9、11 号 nibble,在四条明文完全不同的密文里纹丝不动**。字节视角下更醒目:每组第 3 字节永远是 `0x55`。 这不是巧合,这就是题目自述的"固定摘要扰动"——常量水位线。而水位线之上流动的,才是真正的数据。题目叫"暗能潜流",常量是明面,数据在暗处流——后文会看到这个"流"字有多贴切。 --- ## 0x02 第二步:同长度差分——给密码做个"减法 CT" 4 个样本里只有 `Hello` 和 `abcd!` 同为 5 字符。**同长度意味着摘要项完全相同,做差即可消去**——这是差分分析的经典切入点。 对两条密文做 **nibble 级 mod-16 减法**,再与明文 nibble 差分对照: ``` 密文差分(非零位) 明文 nibble 差分对照 out[00] = E ←────────── (H−a).hi = E out[02] = 4 ←────────── (o−!).hi = 4 ★跨组! out[05] = 9 ←────────── (l−c).lo = 9 out[08] = 8 ←────────── (l−d).lo = 8 out[16] = 3 ←────────── (e−b).lo = 3 out[19] = E ←────────── (o−!).lo = E out[21] = 7 ←────────── (H−a).lo = 7 其余位 = 0 ``` 每一个非零差分,都能在明文差分里找到**唯一**(或近乎唯一)的对应。这给出两个重磅结论: **结论一:变换是 nibble 加法性的。** `out[i] = in[σ(i)] + T(i) (mod 16)`。(顺带证伪了 XOR 假设——XOR 差分会在 `0x12`、`0x09` 这类位置留下无法解释的残渣,而减法差分全部严丝合缝。) **结论二:`out[02]` 的差分对应第 4 个字符,而它位于第 1 组。** 位置重排是**全局的、跨组的**——按组独立解码的死路就此堵死,同时也预告了"潜流"的存在。 --- ## 0x03 迷宫的第一次误导:一张"无规律"的 K 表 接下来的惯性思路是:固定 `σ` 不变,跨长度求每个槽位的偏移 `K(i, L)`,然后拟合 `L` 的函数。于是得到这样一张表(`σ(0)=in0` 假设下): | 槽位 | L=3 | L=4 | L=5 | |---|---|---|---| | rel0 | 4 | 7 | F | | rel3 | 5 | 5 | 5 | | rel5 | ? | 2 | 4 | | rel8 | ? | 0 | 4 | `rel0` 的 `4, 7, F` 既非线性也非线性之外的任何讨好公式;`rel3` 却又恒为 5。**同一张表一半在变一半不变**——这是典型的"模型错了"信号,而不是"数据错了"。 复盘这一步:差分 `E` 在 `in0` 与 `in9` 之间存在二义性,而我当时锚定了前者。**罪魁不是偏移 K 在随长度变,而是映射 σ 本身在随长度变。** 死磕 K 的公式,等于在错误的坐标系里找物理定律。 --- ## 0x04 突破口:反过来,让证据自己说话 方法论掉个头:**不再假设 σ,转而假设槽位偏移 T 跨长度恒定**,对每个数据槽位求"四样本可行 T 集合的交集"。 以 rel0 为例,逐样本列出 `T = out − in` 的所有可能值再取交集: ``` TLU (out=9): T ∈ {4, 5, D} 2026 (out=A): T ∈ {7, 8, A, 4} Hello (out=3): T ∈ {F, B, D, E, 7, 4} abcd! (out=5): T ∈ {5, A, 3, 2, 1, 4} ───────────────────────────────────── 交集 T(0) = 4 (唯一!) ``` 六个数据槽位逐一做同样操作,结果干净得不像话: ``` 槽位: rel0 rel2 rel3 rel5 rel8 rel10 T 值: 4 5 5 4 4 5 ``` 进一步看这些 T 对应的明文来源——`+4` 全部落在字符的**低** nibble,`+5` 全部落在**高** nibble。所谓"模 16 循环偏移",落到实处就是一条字节级规则: > **每个字节 b → ((b>>4)+5, (b&15)+4) (mod 16),即整体 +0x54 的高低位错位版。** T 固定后,σ 的真容浮出水面。逐样本反解每个槽位取的是哪个输入 nibble,全部对齐到**距输入末尾的距离**: | 槽位 | 取的是 | |---|---| | rel0 | 倒数第 1 个 nibble | | rel2 | 倒数第 2 个 | | rel8 | 倒数第 3 个 | | rel10 | 倒数第 4 个 | | rel5 | 倒数第 5 个 | | rel3 | 倒数第 6 个 | **迷宫是倒着走的。** 输出最左边的组,编码的是明文最右边的 3 个字符;输出最右边的"残缺组",装的才是明文开头。四条样本逐一回代验证,`TLU`→`94AA48550495`、`2026`、`Hello`、`abcd!` 全部命中——这就是"暗能潜流"的题眼:数据逆着读序在常量河床下潜行。 --- ## 0x05 全貌:完整算法规格 汇总成一张正式的版图。明文从**尾部**向前按 3 字符切块,块 `[a, b, c]`(a 为时序最早字符)编码为 6 字节: ``` nibble: [c.lo+4, 4, c.hi+5, a.hi+5, 4, a.lo+4, 5, 5, b.lo+4, 4, b.hi+5, 5 ] 字节: B0 B1 B2 B3 B4 B5 B3 ≡ 0x55(常量水印) ``` - **满块**:常量槽 `{1,4,6,7,9,11} = {4,4,5,5,4,5}`,数据槽 `{0,2,3,5,8,10}`; - **部分块(明文开头剩余 1~2 字符)**——这就是"摘要只与长度有关"的真身,长度决定残缺块的形状: - 2 字符块 `[a,b]`:`[2,2,3,5, b.lo+4, 4, b.hi+5, a.hi+5, 4, a.lo+4, 5, 3]` - 1 字符块 `[a]`:`[2,2,3,3,2,2,3,5, a.lo+4, 4, a.hi+5, 3]` - **拼接**:输出组按块的**逆序**连接(最左组 = 最后 3 字符,最右组 = 开头残块)。 对照样本一眼验证:`Hello` 末组 `2235…` 与 `abcd!` 末组 `2235…` 同为 2 字符残块、前缀相同;`2026` 末组 `2233…` 是 1 字符残块的另一套常量。而 flag 的末组 `22332235A4B3` 与 `2026` 的残块模式逐位同型——**flag 的 L ≡ 1 (mod 3),L = 34**,三选一落定。 还有一个漂亮的旁证:flag 第 8 组 `A48844556485` 与 `2026` 的首组**完全相同**——因为它编码的正是同一个块 `('0','2','6')`,而满块布局与总长度无关。flag 里嵌着年份 `2026`。 ## 0x06 解码:顺着河道把水抽干 解码即逆操作。12 个组依次还原: | 输出组(hex) | 还原出的 3 字符(按明文序) | |---|---| | `14CC46555475` | `r ! }` | | `94BC475584C5` | `s t e` | | `848A43551495` | `_ M 4` | | `448C445584C5` | `p t 0` | | `D4C9475564C5` | `C r y` | | `34A84B55A4B5` | `7 f _` | | `74BA4355F495` | `_ K c` | | `A48844556485` | `0 2 6` | | `648C495534A5` | `u _ 2` | | `548C4F5584A5` | `{ T 1` | | `B4BB405554B5` | `l a g` | | `22332235A4B3` | `f`(残块) | 按"残块在前、其余逆序拼接"组装: ``` f + lag + {T1 + u_2 + 026 + _Kc + 7f_ + Cry + pt0 + _M4 + ste + r!} = flag{T1u_2026_Kc7f_Crypt0_M4ster!} ``` **一个小插曲**:分析中途一度解出 `Kc7a`、`T1u_` 之外的乱码段——排查发现是手工转抄 144 位 hex 时抄错了一位,导致某组常量槽出现异常值。改用**程序化直接从题目文件提取**密文后,所有组常量恢复整齐,解码归位。教训值一行加粗:**永远让机器读原始文件,不要让人眼当 USB 线。** 最终验证(必须做满两道): 1. **正向复现**:用还原的算法重新加密 4 组样本明文,与题目密文**逐位一致**; 2. **往返闭合**:将解出的 flag 重新加密,与题目 144 位密文**逐位一致**。 由于每个数据 nibble 槽位都被 +4/+5 偏移一一占据、常量槽不携载信息,该密码对固定长度是单射——**往返闭合即证明解唯一**,不存在第二解。 --- ## 0x07 复盘:这道题教会我们什么 1. **同长度差分是自定义对称结构的 CT 扫描**。只要拿到两条同长度样本,摘要项自动消去,加法性立刻现形。 2. **证伪比拟合更快**。`4, 7, F` 这种"无规律"K 表不是让你继续猜公式,是模型在报警。改一个假设(σ 变而 T 定),废表瞬间变成常数。 3. **可行集交集 > 单点硬猜**。让每个样本各自陈述"T 可能是什么",再取交集——证据会自己收敛到唯一解,这比任何灵感都可靠。 4. **验证要闭环**。正向复现 4 样本 + 往返重加密 flag,双保险后才敢落笔 flag。 5. 題面的每一句自述都是线索:*"摘要只与长度有关"*直接指向"残块形状由 L mod 3 决定"。出题人的免责声明,常常就是解题人的藏宝图。 --- ## 附录:ZCode × GLM-5.3 用时与成本 | 指标 | 数值 | 口径说明 | |---|---|---| | 总用时 | **≈ 51 分钟**(14:18 → 15:09) | 取自文件系统时间戳:题目落盘 14:18,首个分析脚本 14:41(此前约 23 分钟为纯推理推演、零代码),模型定稿并解出 flag 15:09 | | 人工干预 | **0 次** | 全程单条自然语言指令启动,无中途纠偏 | | 工具调用 | ≈ 13 次 | 文件读取 / Bash(py) / 脚本编写与迭代 | | 产出代码 | 2 个分析脚本,约 190 行 | `analyze.py`(结构探测)+ `analyze2.py`(完整编解码 + 双重验证) | | Token 消耗(估) | 累计输入 ≈ 30–40 万(含每轮上下文重读),输出 ≈ 3 万(含长思维链) | 按 14 轮对话、上下文逐步增长估算,非精确计量 | | 成本(估) | 按量计费约 **¥1–2**;包月 Coding Plan 内边际成本趋近于 **0** | 依所用套餐单价代入上表 token 数即可复算;单价以官方价目为准 | > 一句话总结这次人机协作:**51 分钟、两块钱以内、零人工干预,换来一道纯逻辑密码题的完整解剖和唯一解。** 对出题人而言,这也标定了"自造对称变换"在 2026 年的真实防御强度——没有随机性,就没有秘密。 *—— Writeup by ZCode (GLM-5.3),2026-08-20*
传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!!
上传的附件:
analyze.py
(1.68kb,2次下载)
analyze2.py
(4.42kb,2次下载)
收藏
・
0
点赞
・
0
打赏
分享
分享到微信
分享到QQ
分享到微博
赞赏记录
参与人
雪币
留言
时间
查看更多
赞赏
×
1 雪花
5 雪花
10 雪花
20 雪花
50 雪花
80 雪花
100 雪花
150 雪花
200 雪花
支付方式:
微信支付
赞赏留言:
快捷留言
感谢分享~
精品文章~
原创内容~
精彩转帖~
助人为乐~
感谢分享~
最新回复
(
1
)
mb_tlkgtbuf
雪 币:
0
能力值:
( LV1,RANK:0 )
在线值:
发帖
3
回帖
3
粉丝
0
关注
私信
mb_tlkgtbuf
2
楼
zcode这么强吗
2026-8-21 14:26
0
游客
登录
|
注册
方可回帖
回帖
表情
雪币赚取及消费
高级回复
返回
HHHso
26
75
发帖
84
回帖
2198
RANK
关注
私信
他的文章
[原创] KCTF260A 第十题 曦光初现 Writeup
3860
[原创] KCTF2609 第九题 同墟·星海抉择 Writeup
31
[原创] KCTF2607 第七题 暗能潜流 Writeup
52
[原创] KCTF2605 第五题 忆海倒带 Writeup
102
[原创] KCTF2602 第二题 绿光幽语 Writeup
250
关于我们
联系我们
企业服务
看雪公众号
专注于PC、移动、智能设备安全研究及逆向工程的开发者社区
谁下载
×
huangyalei
pzhxbz
谁下载
×
huangyalei
pzhxbz
看原图
赞赏
×
雪币:
+
留言:
快捷留言
为你点赞!
返回
顶部