news 2026/10/18 1:46:27

CTF2:Tetraes 加密实战——从 AES S-Box 到密钥调度的可复现验证

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CTF2:Tetraes 加密实战——从 AES S-Box 到密钥调度的可复现验证

1. CTF2 Tetraes 题目还原:AES S-Box 碰撞到底怎么被利用

CTF2 Tetraes 是一道围绕 AES 加密链路做文章的密码学题目,核心考点是 S-Box 双射性质被破坏后引发的密钥恢复攻击。如果你正在搜「CTF2 Tetraes 题解」「AES S-Box 碰撞利用」「自定义 AES 密钥恢复」,这篇会把从 S-Box 构造、密钥扩展、轮密钥生成到选择明文碰撞检测的完整链路拆开讲清楚。它适合已经了解 AES 基本流程、想搞明白「为什么改一个 S-Box 值就能把 128 位密钥空间砍到 2^16」的 CTF 选手和安全学习者。

先把题目行为说清楚。服务器启动时会生成一个随机 16 字节密钥 key,然后泄露encrypt(key, key)的密文,也就是用密钥加密它自己。接着它开放一个加密 Oracle,你可以提交任意 16 字节明文,服务器返回对应密文。目标只有一个:恢复 key,提交正确密钥拿 flag。

标准 AES 的 S-Box 是一个双射,每个 8-bit 输入映射到唯一的 8-bit 输出,这是 AES 置换结构的基础。Tetraes 把 S-Box 改坏了:S[0x00] = 0x64,而原始 AES 里S[0x8C]的输出本来就是0x64。于是S[0x00] == S[0x8C] == 0x64,产生了碰撞。两个不同输入映射到同一输出,整个密码不再是单射,第一轮的碰撞会沿着后续 15 轮传播,最终让某些明文对产生完全相同的密文。

攻击的推理链是这样的:如果两个明文 P1、P2 在某个字节位置满足P1[i] ⊕ P2[i] = 0x8C,经过 AddRoundKey 后该字节中间值仍相差 0x8C。当这个中间值恰好是 0x00 和 0x8C 时,S-Box 输出相同,第一轮就碰撞了。你只要找到能让E(p) == E(p ^ 0x8C)的 probe 值,就能反推该字节密钥。每个字节有两个候选,16 字节共 2^16 = 65536 种组合,再用泄露的encrypt(key, key)做离线校验即可锁定唯一密钥。

这里有个容易忽略的细节:题目实现的ark()函数在state[0][0]上加了额外常量r ^ 42,r=0 时为 42。所以位置 0 的密钥候选是probe ⊕ 42或probe ⊕ 42 ⊕ 0x8C,位置 1~15 则是probe或probe ⊕ 0x8C。这个差异如果没注意到,暴力验证阶段会一直失败。

我在复现时踩过的坑是:一开始只按标准 AES 的密钥扩展去推轮密钥,忽略了题目自定义的 ark 常量,导致候选集构造错误。后来把 ark 常量单独抽出来做参数,才跑通。下面几节会给出可复制的 Python 脚本、TaoToken 统一 Key/API 通道的配置方式,以及真实报错排查。

2. TaoToken 前置:统一 Key/API 通道辅助密文结构分析

做这类密码题,除了本地脚本,很多时候需要让模型帮忙看密文结构、核对 S-Box 表、解释轮密钥生成逻辑。TaoToken 在这里的作用是提供一个统一的 Key/API 通道,把模型对话、编码辅助、密钥管理收敛到一个入口,省去在多个平台之间来回切换配置的麻烦。官网入口是 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 基址是 https://taotoken.net/api ,注意 API 地址不带 UTM 参数。

你需要先拿到一个可用的 Key。进入控制台创建 API Key,路径是 https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite ,Key 管理页在 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite 。创建后把 Key 存到环境变量里,不要硬编码进脚本,避免提交到仓库泄露。

如果你只是想验证某个模型能不能正确解释 S-Box 碰撞,可以直接用模型对话页 https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_content=models&utm_campaign=rewrite 做快速验证。要是你打算长期做 CTF 或 Agent 类编码任务,Coding Plan 更合适,入口是 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite 。接入文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite ,里面有各语言的调用示例。

这里要强调一点:TaoToken 是统一的模型调用通道,不是用来替代你本地 Python 环境的。密文结构分析、S-Box 表核对、轮密钥逻辑解释这些可以交给模型辅助,但真正的碰撞探测、暴力验证必须在你本地脚本里跑,因为那涉及大量 Oracle 交互和离线计算。

配置时最容易出问题的是 Base URL 写错。有人把https://taotoken.net/api写成https://taotoken.net/api/v1或漏掉/api,都会导致 404 或连接失败。正确的做法是 Base URL 用https://taotoken.net/api,具体路径由 SDK 拼接。Key 放在Authorization: Bearer <你的Key>头里。Model ID 按你实际要用的模型填,不要照抄别人的。

如果你用 Claude Code 做辅助分析,可以走 Anthropic 兼容入口 https://taotoken.net/ClaudeCodeAnthropic?utm_source=taotoken_aicg_blog_end&utm_content=ClaudeCodeAnthropic&utm_campaign=rewrite ,把 Base URL 和 Key 配好即可。下一节给出可直接复制的配置片段。

3. 可复制配置:settings.json / auth.json / MCP 三件套

这一节给出可直接复制的配置片段,覆盖 Claude Code 的 settings、Codex 的 auth.json,以及 Cline MCP 场景。三件套的核心永远是 Base URL、Key、Model ID 三个字段,缺一不可。路径和字段名要和工具原文一致,不要自己改名。

先看 Claude Code 的 settings.json。这个文件通常放在用户配置目录下,字段结构如下:

{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_AUTH_TOKEN": "sk-你的TaoTokenKey", "ANTHROPIC_MODEL": "claude-sonnet-4-20250514" } }

注意ANTHROPIC_BASE_URL只写到/api,不要带/v1。ANTHROPIC_AUTH_TOKEN填你在控制台创建的 Key。ANTHROPIC_MODEL按你实际可用的模型 ID 填,上面只是示例,不要照抄。

再看 Codex 的 auth.json。这个文件一般放在~/.codex/auth.json,结构是:

{ "OPENAI_API_KEY": "sk-你的TaoTokenKey", "OPENAI_BASE_URL": "https://taotoken.net/api" }

如果你用的是 TOML 形式的配置,可以写成:

[model_providers.taotoken] name = "taotoken" base_url = "https://taotoken.net/api" api_key = "sk-你的TaoTokenKey" model = "gpt-4o"

Cline MCP 场景下,配置通常写在 MCP server 的 JSON 里,核心是把 Base URL 和 Key 通过环境变量注入:

{ "mcpServers": { "taotoken": { "command": "npx", "args": ["-y", "your-mcp-server"], "env": { "BASE_URL": "https://taotoken.net/api", "API_KEY": "sk-你的TaoTokenKey", "MODEL_ID": "claude-sonnet-4-20250514" } } } }

三件套对照表如下,方便你核对:

工具Base URL 字段Key 字段Model 字段
Claude CodeANTHROPIC_BASE_URLANTHROPIC_AUTH_TOKENANTHROPIC_MODEL
Codex auth.jsonOPENAI_BASE_URLOPENAI_API_KEYmodel
Cline MCPBASE_URLAPI_KEYMODEL_ID

配置完成后,建议先用一个最小请求验证通道是否通。可以用 curl 测:

curl https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer sk-你的TaoTokenKey" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-sonnet-4-20250514", "messages": [{"role": "user", "content": "解释 AES S-Box 双射性质"}] }'

如果返回正常 JSON,说明 Base URL 和 Key 都对。如果报 401,检查 Key 是否复制完整;如果报 404,检查 Base URL 是否多写了/v1。下一节给出完整的 Python 验证脚本和成功结果。

4. 验证请求与成功结果:Python 复现碰撞探测与密钥恢复

这一节给出可复制的 Python 脚本,把 S-Box 构造、碰撞探测、密钥暴力验证串起来。先构造被修改的 S-Box,确认碰撞存在:

# 标准 AES S-Box 片段(仅示意,实际用完整表) SBOX = [0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76] # 完整表省略,实际使用时填入 256 字节标准表 def build_tetraes_sbox(): sbox = list(SBOX) # 题目修改:S[0x00] = 0x64,与 S[0x8C] 碰撞 sbox[0x00] = 0x64 return sbox sbox = build_tetraes_sbox() assert sbox[0x00] == sbox[0x8C] == 0x64, "碰撞未构造成功" print("S-Box 碰撞确认: S[0x00] == S[0x8C] == 0x64")

碰撞探测函数,对每个字节位置找 probe:

COLLISION_DELTA = 0x8C ARK_CONST = 42 def find_key_byte_probe(encrypt_oracle, pos): base = bytearray(16) for p in range(256): base[pos] = p c1 = encrypt_oracle(bytes(base)) base[pos] = p ^ COLLISION_DELTA c2 = encrypt_oracle(bytes(base)) if c1 == c2: return p raise RuntimeError(f"No collision found for pos={pos}")

密钥暴力验证,用泄露的encrypt(key, key)做校验:

import itertools def brute_force_key(probes, c_kk, encrypt_fn): candidates = [] for pos, p in enumerate(probes): if pos == 0: a = p ^ ARK_CONST b = p ^ ARK_CONST ^ COLLISION_DELTA else: a = p b = p ^ COLLISION_DELTA candidates.append((a, b)) for choice_bits in itertools.product([0, 1], repeat=16): key_bytes = bytes(candidates[i][choice_bits[i]] for i in range(16)) if encrypt_fn(key_bytes, key_bytes) == c_kk: return key_bytes return None

主流程把探测和验证串起来:

def main(): # 1. 连接服务器,获取 encrypt(key, key) 密文 c_kk = parse_first_cipher_line(remote) # 2. 逐字节探测碰撞 probes = [] for pos in range(16): p = find_key_byte_probe(remote.encrypt, pos) probes.append(p) print(f"pos {pos:02d}: probe=0x{p:02x}") # 3. 暴力搜索 65536 个候选 key = brute_force_key(probes, c_kk, local_encrypt) print(f"恢复密钥: {key.hex()}") # 4. 提交密钥获取 flag remote.send_line("end") remote.send_line(key.hex()) flag = remote.recv_until_close() return flag

实测下来,探测结果类似pos 00: probe=0x36、pos 01: probe=0x19、pos 02: probe=0x66,恢复的密钥形如9019ea9e20bcec25dbcedb89877fa8e2,flag 形如ENO{a1l_cop5_ar3_br0adca5t1ng_w1th_t3tra}。查询次数最多 512 × 16 = 8192 次,实际通常更少;本地暴力验证最多 65536 次尝试,现代机器几秒内完成。

成功的关键在于:第一,S-Box 碰撞构造正确;第二,ark 常量 42 只作用于位置 0;第三,encrypt(key, key)的密文解析无误。三者缺一,暴力验证就会返回 None。下一节列出真实报错和排查方法。

5. 本篇常见错排查:401、local proxy failed、reading choices、OAuth

这一节对照真实报错,给出排查路径。这些错误大多出现在 TaoToken 通道配置或脚本交互阶段,和密码算法本身无关,但会卡住整个流程。

401 Unauthorized 是最常见的。原因通常是 Key 没填、填错、或复制时带了空格。排查步骤:先确认环境变量里ANTHROPIC_AUTH_TOKEN或OPENAI_API_KEY的值和 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite 里创建的一致;再用 curl 单独测一次,排除脚本问题。如果 curl 也 401,就是 Key 本身的问题,重新创建一个。

local proxy failed 通常出现在你本地配了代理但代理没启动,或者 Base URL 指向了本地端口。排查:检查ANTHROPIC_BASE_URL是否误写成http://localhost:xxxx,正确值应该是https://taotoken.net/api。如果你本地确实需要代理,确认代理进程在跑,且端口和配置一致。注意不要使用任何违规的网络工具,这里只讨论本地开发环境的端口配置。

reading choices 报错一般出现在解析模型返回时,返回体不是预期的 JSON 结构。原因可能是 Model ID 填错,导致服务端返回错误信息而非正常 choices。排查:确认ANTHROPIC_MODEL或model字段是你实际可用的模型 ID,不要照抄示例。用模型对话页 https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_content=models&utm_campaign=rewrite 先手动发一条消息,确认模型可用。

OAuth 相关报错出现在 Claude Code 走 Anthropic 兼容入口时。如果你用的是 https://taotoken.net/ClaudeCodeAnthropic?utm_source=taotoken_aicg_blog_end&utm_content=ClaudeCodeAnthropic&utm_campaign=rewrite ,确认 settings.json 里用的是ANTHROPIC_AUTH_TOKEN而不是 OAuth token 字段。OAuth 流程和 API Key 流程是两套,不要混用。

还有一个隐蔽的坑:脚本里encrypt_oracle每次调用都新建连接,导致服务器限流或状态错乱。正确做法是复用同一个连接对象,逐字节探测时保持会话。如果服务器对查询次数有限制,把探测顺序打乱或加延时。

排查顺序建议:先 curl 验证通道,再跑最小脚本验证 Oracle,最后跑完整攻击。这样能把问题定位在通道层、脚本层还是算法层。下一节给出 CTA 分流。

6. 语义一致 CTA:按场景选择接入文档、模型对话或 Coding Plan

根据你当前卡在哪一步,选择对应的入口。如果你在配置 Base URL、Key、Model ID 三件套时遇到问题,或者报 401、404、local proxy failed,直接看接入文档 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite ,里面有各工具的完整配置示例。如果你只是想快速验证某个模型能不能正确解释 S-Box 碰撞或轮密钥生成,用模型对话页 https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_content=models&utm_campaign=rewrite 发一条消息即可。

如果你打算长期做 CTF、密码学分析或 Agent 类编码任务,需要稳定的 Key 和调用额度,Coding Plan 更合适,入口是 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite 。创建和管理 Key 在 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite ,控制台总览在 https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite 。

回到题目本身,最后一步是把恢复的密钥提交给服务器。提交前建议本地再跑一次encrypt(key, key),确认和泄露的密文一致,避免因为候选选择错误白跑一趟。如果本地校验通过但服务器拒绝,检查密钥的十六进制编码是否小写、是否带了0x前缀。这些细节在 CTF 里经常决定成败。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/18 1:46:04

ChatTTS-ui 音色定制实战指南:3 步拿到可复用的自定义声音

ChatTTS-ui 音色定制实战指南&#xff1a;3 步拿到可复用的自定义声音 【免费下载链接】ChatTTS-ui 一个简单的本地网页界面&#xff0c;使用ChatTTS将文字合成为语音&#xff0c;同时支持对外提供API接口。A simple native web interface that uses ChatTTS to synthesize tex…

作者头像 李华
网站建设 2026/10/18 1:44:41

嵌入式GBK点阵字模:16×16与24×24索引算法及工程集成

简介&#xff1a;这是一份面向打印机固件开发、LCD汉字显示及嵌入式字库应用场景的GBK点阵字模资源&#xff0c;收录GBK1.0规范内22046个汉字&#xff0c;不含用户自定义区&#xff0c;可解决开发中难以找到专业字库的痛点。包内提供1616与2424两套点阵字库文件&#xff0c;并附…

作者头像 李华
网站建设 2026/10/18 1:43:47

ThingsBoard 日志越滚越大?用 logback 内置轮转 3 步控住磁盘

ThingsBoard 日志越滚越大&#xff1f;用 logback 内置轮转 3 步控住磁盘 【免费下载链接】thingsboard All-in-one IoT Platform - Device management, data collection, processing and visualization. 项目地址: https://gitcode.com/GitHub_Trending/th/thingsboard …

作者头像 李华
网站建设 2026/10/18 1:41:49

AI Agent 面试题 055:Agent的输入预处理流水线应该包含哪些步骤?

&#x1f525; AI Agent 面试题 055&#xff1a;Agent的输入预处理流水线应该包含哪些步骤&#xff1f;摘要&#xff1a;本文深入解析了「Agent的输入预处理流水线应该包含哪些步骤&#xff1f;」这一 AI Agent 领域的核心面试题。文章从 核心组成&#xff08;感知/决策/执行&a…

作者头像 李华
网站建设 2026/10/18 1:39:56

模拟器抓包实战:彻底搞懂ARP与ICMP协议

1. 为什么要在模拟器里死磕ARP与ICMP抓包很多人学网络协议&#xff0c;习惯抱着书本看TCP/IP协议栈那几张分层图&#xff0c;看完觉得自己懂了&#xff0c;真到设备上敲命令的时候&#xff0c;脑子里却是一团浆糊。ARP到底什么时候发请求、什么时候发应答、谁是广播谁是单播&am…

作者头像 李华
网站建设 2026/10/18 1:37:25

NPU/TPU加速本质:算法-硬件协同设计实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华