首页
课程
问答
CTF
社区
招聘
峰会
发现
排行榜
知识库
工具下载
看雪20年
看雪商城
证书查询
登录
注册
首页
社区
课程
招聘
发现
问答
CTF
排行榜
知识库
工具下载
峰会
看雪商城
证书查询
社区
CTF对抗
发新帖
0
0
[原创]第九题:丑寅同墟·星海抉择 (解题思路)
发表于: 2026-8-22 12:13
12
[原创]第九题:丑寅同墟·星海抉择 (解题思路)
秋白
2026-8-22 12:13
12
# ICTFForCausalLM Writeup ## 题目信息 附件给出一个字符级「因果语言模型」`ICTFForCausalLM`、权重 `ictf_model/`,以及加载脚本 `inference.py`。 题面要求:分析模型代码与权重,找出藏在模型里的秘密,恢复正确 flag。 输入:长度 ≤ 16 的字符串(字符集为 `[0-9a-zA-Z]`) 输出:模型预测的下一个 token --- ## 一、模型结构 `model_def.py` 里的网络非常「不像」真 LM: ```text input_ids ∈ R^{16} # token id 直接当浮点特征,不是 embedding ↓ Linear(16 → 21) + bias ↓ ReLU ↓ Linear(21 → 64) + bias # lm_head ↓ logits ∈ R^{64} ``` Tokenizer 要点: | id | 含义 | |----|------| | 0–61 | `0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ` | | 62 | `<success>` | | 63 | `<fail>` | 不足 16 字符会用 `pad_token_id = 0`(字符 `'0'`)右侧填充。 `inference.py` 对最后一维做 `argmax`,打印对应字符。真正的成功汇点是预测出 **`<success>` (id=62)**。 --- ## 二、从权重读出判定逻辑 加载 `model.safetensors` 后看 `lm_head`: - token `0..61`:权重全 0,bias ≈ `-10000` → 永远选不中 - token `63` (`<fail>`):权重全 0,bias ≈ `0.4` → 默认失败基线 - token `62` (`<success>`): ```text w_success ≈ [1, -1e10, -1e10, ..., -1e10] # 长度 21 b_success ≈ -376131.22 ``` 因此: ```text logit_62 = h[0] + (-1e10)·h[1] + … + (-1e10)·h[20] + b_success logit_63 = 0.4 ``` 只要 `h[1]…h[20]` 里有任意一个 **ReLU 后为正**,`logit_62` 会被打到 −∞,必然失败。 要成功,必须同时满足: 1. **校验神经元全灭**:`h[i] = 0`(即 ReLU 前 `pre[i] ≤ 0`),`i = 1..20` 2. **主通道够大**:`h[0] + b_success > 0.4`,即 `h[0] ≳ 376131.6` 这不是训练出来的语言模型,而是把 **口令校验硬编码进 MLP** 的壳。 --- ## 三、dense 层在干什么 记输入向量为 `x ∈ {0,…,61}^{16}`(各位置 token id),则 ```text pre = W·x + b # W ∈ R^{21×16}, b ∈ R^{21} h = ReLU(pre) ``` 观察权重: - `W` 的元素都是精确整数(浮点误差为 0) - `b[1:]` 近似整数;`b[0]` 带一点小数,配合 `lm_head` bias 做阈值比较 前 16 个「校验」神经元(`i = 1..16`)构成线性方程组: ```text W[i] · x + b[i] = 0, i = 1..16 ``` 16 个未知数、16 个方程,且系数矩阵满秩 → **唯一解**。 用最小二乘或 Z3 整数求解均可,得到: ```text x = [15, 1, 10, 16, 2, 0, 2, 6, 12, 7, 15, 10, 1, 6, 6, 6] ``` 映射回字符集: ```text f1ag2026c7fa1666 ``` 代入后: ```text pre[0] ≈ 376131.72 > 阈值 pre[1..20] = 0 → h = [376131.72, 0, 0, …, 0] → logit_62 ≈ 0.5 > logit_63 ≈ 0.4 → argmax = 62 (<success>) ``` `i = 17..20` 的额外行在该解上同样为 0,属于冗余/加固约束,不改变唯一性。 --- ## 四、求解流程(可复现) 1. **Inventory** 读 `model_def.py` / `config.json`:无 embedding、无 attention,本质是 16→21→64 的两层感知机。 2. **钉汇点** 成功 = `argmax(logits) == 62`,不是去「生成一段自然语言」。 3. **切片 `lm_head`** 从 success 行的 `-1e10` 惩罚读出:校验维必须被 ReLU 清零。 4. **反推 `dense`** 对 `W[1:17]·x + b[1:17] = 0` 求解(Z3 / `numpy.linalg.solve` / lstsq)。 5. **Prove** 把候选喂回 `ICTFForCausalLM.from_pretrained("./ictf_model")`,确认输出 `<success>`。 最小验证脚本: ```python import torch from model_def import ICTFForCausalLM, ICTFTokenizer text = "f1ag2026c7fa1666" tok = ICTFTokenizer() model = ICTFForCausalLM.from_pretrained("./ictf_model").eval() ids = tok(text, return_tensors="pt")["input_ids"] with torch.no_grad(): logits = model(ids)["logits"] nid = int(torch.argmax(logits[:, -1, :], dim=-1)) print(nid, tok.id2char[nid]) # 62 <success> ``` --- ## 五、原理小结 | 表象 | 实质 | |------|------| | Causal LM + safetensors | 口令比较器换皮 | | hidden_size = 21 | 1 个成功通道 + 20 个校验通道 | | ReLU | 把「等式成立」变成「激活为 0」 | | `lm_head` 的 ±1e10 | 硬门控:任一校验维泄漏 → 强制 fail | | 字符 id 当特征 | 线性约束直接作用在 id 空间,便于精确构造 | 出题手法:选定口令 → 构造若干线性式在口令处取 0、别处为正 → 再配一条使口令处 `h[0]` 刚好压过 fail bias 的主通道。求解方只要 **别被「语言模型」叙事带走**,从成功 logit 后向切片即可。 --- ## 六、Flag ```text f1ag2026c7fa1666 ``` (若平台要求包裹格式,按比赛统一前缀提交,例如 `ICTF{f1ag2026c7fa1666}`;本题模型侧验证的秘密即为上述 16 字符口令。)
冰与火的战歌:Windows内核攻防实战高级班!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。
收藏
・
0
点赞
・
0
打赏
分享
分享到微信
分享到QQ
分享到微博
赞赏记录
参与人
雪币
留言
时间
查看更多
赞赏
×
1 雪花
5 雪花
10 雪花
20 雪花
50 雪花
80 雪花
100 雪花
150 雪花
200 雪花
支付方式:
微信支付
赞赏留言:
快捷留言
感谢分享~
精品文章~
原创内容~
精彩转帖~
助人为乐~
感谢分享~
最新回复
(
0
)
游客
登录
|
注册
方可回帖
回帖
表情
雪币赚取及消费
高级回复
返回
秋白
6
发帖
12
回帖
10
RANK
关注
私信
他的文章
[原创]第九题:丑寅同墟·星海抉择 (解题思路)
12
[原创]第七题:戌时·暗能潜流(AI解析)
13
[原创][原创]KCTF2026第四题:未时·车流困城(AI总结)
860
[建议]气死我了 KCTF解开了为什么服务器暴了??
91
关于我们
联系我们
企业服务
看雪公众号
专注于PC、移动、智能设备安全研究及逆向工程的开发者社区
看原图
赞赏
×
雪币:
+
留言:
快捷留言
为你点赞!
返回
顶部