-
-
[原创]第九题「丑寅同墟·星海抉择」解析
-
发表于: 6天前 146
-
本文只使用官方附件中的相对文件名,不涉及本机绝对路径、用户名或其他环境信息。
附件给出一个字符级「语言模型」ICTFForCausalLM 及其权重。
配套文件:
config.json:
参数量极小:16 → 21 → 64,总共一千多个参数。真正的前向在 model_def.py 里只有几行:
三个反常点:
分词器字符集:
共 62 个字符,id 为 0..61。输入不足 16 时用 pad_token_id = 0 右填充——而 id 0 恰好是字符 '0'。因此「短字符串」和「后面带 0 的 16 字符」在数值上无法区分。后文求解时按满 16 维整数向量处理即可。
inference.py 取 argmax,打印对应字符。本题要的是让 argmax 落到 id 62。
用 safetensors(或不装任何深度学习库,按文件头解析)读出四个张量:
记输入 (x \in {0,\dots,61}^{16}),前向为:
lm_head 一眼露馅:
普通字符和 <fail> 的 logit 不随输入变化:恒为 -10000 和 0.4。唯一会动的是第 62 行:
<success> 要胜过 <fail>,必须:
h[j] ≥ 0。h[1]…h[20] 前面挂着 -1e10:任何一个约束单元哪怕只激活一个很小的正数,logit[62] 都会掉到 -1e10 量级,不可能超过 0.4。
因此成功条件拆成两条:
条件 A(可行性) —— 第 1 到第 20 个隐藏单元必须被 ReLU 压成 0:
条件 B(阈值) —— 第 0 个单元必须够大。此时 h[0] = W_d[0] · x + b_d[0](该值本身为正),代入:
W_d[0] 与 (x) 都是整数,点积必为整数,故:
整道题变成:在 (x_i \in {0,\dots,61}) 上解 20 条线性不等式,并让一条整数线性函数达到 64573。
dense.weight 全部是整数。第 0 行数量级是几千(目标函数),其余 20 行落在 (\pm 100)(约束)。dense.bias[1:] 也全部是整数。
这是典型的出题构造:
因此可以先把条件 A 当成等式 来解:
A 是 (20 \times 16)、秩 16 的超定系统。最小二乘残差约为 (0)(数值上 (10^{-12}) 量级),说明方程组相容,存在唯一实数解。把解四舍五入:
全部落在 0..61。按字符集映射:
得到候选口令:
代回检查:
余量只有 0.1。这不是训练出来的边界,是手工把 dense.bias[0] = 311558.71875 和 lm_head.bias[62] = -376131.21875 配出来的。
条件 A 写的是 ≤ 0 而不是 = 0,所以只凭等式求解,逻辑上还不能说「多面体里没有别的整点」。需要把条件 B 一起加上。
在整数格 (x_i \in {0,\dots,61}) 上,对
做约束求解(任意整数线性求解器即可,例如 Z3)。搜索结果表明:满足两条条件的整点只有上面这一组。
直观原因:
改一个字符的对照:
dense.weight 第 0 行与 bias:
约束行 (j=1..20)(整数):
在 (x^\star) 上,上表每一行的点积都等于 (-b_d[j])。
只需 numpy。safetensors 文件是「8 字节头长度 + JSON + 裸 float32」,也可以只用标准库解析。
运行后打印:
在附件目录下(已按题目依赖安装 torch / transformers):
提示 Enter your prompt: 时输入 f1ag2026c7fa1666,应输出:
等价的纯 numpy 前向(用于核对,不改官方脚本):
本题不是语言模型,而是一台硬编码的整数约束检查器:
| 项目 | 内容 |
|---|---|
| 比赛 | 看雪·2026 KCTF |
| 题目 | 第九题:丑寅同墟·星海抉择 |
| 题面模型名 | ICTFForCausalLM |
| 类型 | Reverse / 模型权重逆向 |
| 目标 | 找出使模型输出 <success> 的 16 字符输入,即 flag |
| Flag | f1ag2026c7fa1666 |
| 文件 | 作用 |
|---|---|
题目要求.txt |
题面说明 |
model_def.py |
分词器与模型定义 |
inference.py |
加载权重并交互推理 |
ictf_model/config.json |
超参数 |
ictf_model/model.safetensors |
权重 |
| 张量 | 形状 | 含义 |
|---|---|---|
dense.weight |
(21, 16) |
第一层权重 (W_d) |
dense.bias |
(21,) |
第一层偏置 (b_d) |
lm_head.weight |
(64, 21) |
输出层权重 (W_l) |
lm_head.bias |
(64,) |
输出层偏置 (b_l) |
| 输出 id | 权重(21 维) | bias | 含义 |
|---|---|---|---|
| 0 – 61 | 全 0 | -10000 |
普通字符 |
| 62 | [1, -1e10, -1e10, …, -1e10] |
-376131.21875 |
<success> |
| 63 | 全 0 | 0.4 |
<fail> |
| 量 | 数值 |
|---|---|
| 20 条约束 (A x + b) | 精确为 0 |
| (W_d[0] \cdot x) | 64573(刚好达到下界) |
| (h[0]) | 376131.71875 |
logit[62] |
0.5 |
logit[63] |
0.4 |
| argmax | 62 <success> |
| 输入 | 输出 | 原因 |
|---|---|---|
f1ag2026c7fa1666 |
<success> |
约束全 0,logit[62]=0.5 |
f1ag2026c7fa1665 |
<fail> |
多个约束单元被激活,-1e10 打穿 |
f1ag2026c7fa1667 |
<fail> |
约束被激活,且 (h[0]) 也掉到门槛下 |
hello(右填成 hello00000000000) |
<fail> |
多条约束被激活 |
{
"architectures": ["ICTFForCausalLM"],
"hidden_size": 21,
"max_position_embeddings": 16,
"model_type": "ictf_causal_lm",
"vocab_size": 64
}
冰与火的战歌:Windows内核攻防实战高级班!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。