ACM CCS 2026 The Hague, Netherlands · Nov 15–19, 2026

“We just went with
what seemed the
best supported”

Lessons on Cryptographic Practices in Securing Microcontrollers from Embedded CTFs

从嵌入式 CTF 看:在单片机上用密码学,开发者到底怎么选、怎么用

Zheyuan Ma1 · Xi Tan2 · Gaoxiang Liu1 · Alex Eastman1 · Md Armanuzzaman3 · Ziming Zhao4
1CactiLab, University at Buffalo 2SUNRISE Lab, University of Colorado Colorado Springs 3T3SLab, University of Texas at El Paso 4CactiLab, Northeastern University
组会论文分享汇报人:曾杨2026.10.14
MCU · Cortex-M4
背景 / 01 · Microcontroller

MCU:一颗芯片里的“小电脑”

专门负责控制某一个设备

车钥匙2023 eCTF
胰岛素泵2024 eCTF
智能门锁日常
传感器日常

每个设备里,都有一颗 MCU 在当“大脑”

MCU 芯片内部 CPU执行指令80–100 MHz Flash存程序和常量256–512 KB SRAM运行时的草稿纸32–128 KB 外设和外界通信UART · I²C · GPIO
你的笔记本eCTF 的 MCU
主频3–5 GHz80–100 MHz≈ 1/40
内存16 GB32–128 KB≈ 1/130,000
系统Windows / Linux裸机,无操作系统
加密库默认你有的,MCU 上往往没有
堆内存malloc 文件系统存密钥文件 可靠随机源/dev/random 内存隔离MMU · 安全区
一整片 = 笔记本的 16 GB 内存,切成 131,072 格MCU 的全部 SRAM(128 KB)= 其中一格
eCTF 用板 · 2023:TI TM4C123GXL(Cortex-M4F 80 MHz,256 KB Flash,32 KB SRAM,2 KB EEPROM)· 2024:MAX78000FTHR(Cortex-M4 100 MHz,512 KB Flash,128 KB SRAM,无 EEPROM)
背景 / 02 · MITRE eCTF

eCTF:先造一个安全系统,再去攻破别人的

01
设计实现按功能 + 安全需求
写出整套固件
02
交接主办方验证功能
往固件里埋入 flag
03
攻击互相攻击
从别队固件里夺 flag
2023汽车遥控钥匙
车Car 钥匙Fob UART
解锁认证防重放配对 PIN 保密功能授权
2024胰岛素泵
I²C AP主控 CP1血糖监测 CP2胰岛素注射
双向安全启动本地秘密保护总线消息认证部件替换
年度赛事、持续数月;每队都要先“防”后“攻”。主题与需求见论文补充材料 §B.1
背景 / 03 · Threat Model

攻击者:源码、实物、总线、时间,全都有

源码仅删去密钥与 flag
板子在手可拆、可刷、可克隆
总线全可见UART / I²C 随便接
时间充足慢慢测、慢慢试
= 白盒攻击者
AP主控 MCU CP1血糖监测 CP2胰岛素注射 if (sig_ok) ✗ 01 A7 3F … 录制 → 重放 KEY2B 7E… RNG ↓ 偏置 1 2 3 4 5
1
侧信道测功耗、电磁、时间,反推密钥
2
故障注入电压 / 时钟毛刺,跳过签名检查
3
总线窃听I²C 明文可录、可重放
4
密钥存储没有 MMU,一个内存漏洞就能读出密钥
5
熵退化控制温度 / 电压,让随机数变慢、有偏
洞察 / Insight

不问“算法能不能再快一点”,而问“人到底怎么选”

多数研究

让算法更快、更小、更省电

AES-128
Ascon
ChaCha20
BLAKE2s
…

示意:算法性能基准,越短越好

这篇论文

资源有限、条件不确定时,
普通开发者怎么选、怎么接、怎么测?

AES?ChaCha20?Ascon? wolfSSL?tiny-AES? ECB?CBC?GCM? 迭代次数调多大? 要开哪些编译开关? 怎么证明它是对的?
Q1做了什么怎样设计和使用密码机制?
Q2为什么这么选什么在影响选型、适配与集成?
Q3卡在哪里实现、测试、维护时遇到什么挑战?
方法 / Mixed Methods

两路证据:看代码 + 听人说

47
份固件进入攻击阶段、通过功能测试
2023 · 20 队2024 · 27 队
代码级分析
  1. 识别用到的原语与库
  2. 编译 + 调试,确认运行时真的被调用
  3. 3 人独立审查,讨论消歧
Q1做了什么
22
场访谈本科 / 硕士 / 博士参赛者
15 人中等以上密码学经验 · 14 人有嵌入式经验
主题分析
半结构化 · Zoom · 平均 25 min · 3 人独立编码、每周讨论
109codes→32子主题→6主题
Q2 · Q3为什么 · 卡在哪
三角互证
§4 实现实践§5 参与者洞察§6 实践挑战
代码里看到“用了 ECB” → 访谈里问出“为什么用 ECB”
IRB 豁免 · MITRE 书面授权;作者自己队伍的作品只计入统计、不作为案例
发现 / Findings

一句话:能跑、好接,压过了更强的安全

和通用软件一样
①
速度、好集成 > 更强的安全保证§4 · §5.1
②
文档不清,比资源受限更挡路§6.3
嵌入式特有
③
侧信道防护很受重视,静态数据却没人管§5.2 · §5.3
④
平台各异,可移植的实现很难做§6.2
⑤
调试与验证手段匮乏§6.4
论文描述访谈人数的用词
a fewsomeabout halfmostalmost all
0%25%45%55%75%100%
① 实现实践 / §4 · Figure 1

用了什么:成熟原语 + 默认配置

2023 · 20 队
2024 · 27 队
AES 最常用8/20 · 12/27
SHA-256 是哈希主力8/20 · 11/27
风险用法不少用 AES 的 20 队里,11 队用 ECB
2024 年还有 3 队用 MD5
默认库效应2024 年 17/27 队直接用默认库 wolfSSL
口令哈希极少只有 3 队,且为塞进 MCU 调低了参数
① AES-ECB / §4 · §5.2.4

AES 很安全,ECB 用法却会“漏图”

11/20
使用 AES 的队伍里,选了 ECB 模式
PIN=12348f3a…c2
PIN=12348f3a…c2

ECB:相同明文块 → 相同密文块

“I didn't know that the ECB algorithm has this inherent vulnerability.”

— P16
有人把 AES 输出称作“哈希”只关心密钥长度,不知道有模式
明文 (可以直接画)
AES-128
ECB 模式
CBC 模式(随机 IV)

每个小方块 = 一个 16 字节分组,颜色由该分组的密文决定 · 真实 AES-128 实时加密

例外:P11 知道 ECB 不安全,但只加密单个 16 字节分组,并在协议层加了 nonce 与临时密钥 · 建议 3:库应默认禁用 ECB,或给出明确警告
① 参与者洞察 / §5.1
“We just went with what seemed
the best supported.”— P3,谈签名算法的选择
速度第一多数参与者把速度放在首位

非对称太慢 → 改用只需哈希的 SCRAM 双向认证 P3

好接入库里有没有现成的

“Did wolfcrypt have it? Because we already have wolfcrypt.” P2

大家都在用名气 = 可靠

“We just went with a package that other people do.” P2

课程 · 网上 · 导师经验来源很“随机”

上网搜“最难算的哈希”→ 选了 bcrypt P8

被放在后面的:理论最优新颖设计秘密的安全存储(时间紧时)
③ 侧信道 / §2.2 · §5.2.1

侧信道:不破解算法,偷看它怎么算

明文 MCUAES 计算中 密文 执行时间 功耗变化 电磁辐射 缓存行为 其他物理信号
for (i = 0; i < 6; i++) if (in[i] != pin[i]) return FAIL; // 一错就返回
2023 赛题明确要求:PIN 必须常数时间比较
0123456789
响应时间
已尝试0次 · 暴力枚举最多 1,000,000 次
参赛者怎么防: 带掩码的 Ascon C 实现 P1 P18 选“无已知时序攻击”的 SHA3 P5 放弃 AES-GCM P4 每次通信换密钥 P5 建议 1:库要写清有无侧信道防护、何时有效
③ 静态数据 / §5.2.3

前门装了三道锁,钥匙挂在门口

前门:侧信道
  • 掩码实现
  • 常数时间
  • 每次换密钥
攻击成本
示波器 + 上千条轨迹 + 专业知识
// secrets.h —— 编译后直接进 Flash #define PAIRING_PIN "530921" static const uint8_t AES_KEY[16] = { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c };
防护:
attacker@lab: 读取 Flash
攻击成本
一个内存读漏洞 / 调试口
≈ 一半2023 年的队伍把秘密写进 C 头文件
(板上明明有专用 EEPROM)

“We did zero trust on the protocol… but we thought it would be fine just to have it in the header.”

— P2,自评 “in between lazy and overconfident”
2024 赛题要求 PIN / 令牌 / 证明数据在 Flash 与 RAM 中都必须保密 · 建议 2:开发者默认 Flash 会被读走;厂商应提供 EEPROM 等安全存储
③ 多年参赛者 / §5.3 · Observation 3

经验让通信越来越安全,却没让存储变安全

20232024为什么换
对称加密AES-GCMChaCha20-Poly1305缓冲区放不下、3 秒时限;流密码免填充(I²C 包 ≤ 255 B)P2 P7
签名 / 密钥交换secp256r1Ed25519 / X25519验签更快 P7
口令哈希Ascon-Hashbcrypt“太快了,容易暴力破解” P4
密码库wolfSSL(黑盒)wolfcrypt 原语 / 自写握手内存太大、看不见内部 P2 P7
侧信道Rust 版 Ascon带掩码的 C 版 AsconC 版经过侧信道测试 P1
秘密存储明文头文件明文头文件“No hash, pure in header.” P2 P7
挑战 / §6.1 资源有限

口令哈希:越慢越安全,可 MCU 等不起

为什么不直接用 SHA-256 存口令?哈希越快,暴力破解越方便。

防暴力破解希望 RAM ↑ 计算 ↑
MCU 正常运行希望 RAM ↓ 计算 ↓
成本参数—
攻击者 · 拿到哈希后用 GPU 离线枚举
—
试遍所有 8 位字母数字口令
1 秒1 天1 年1 万年
MCU · Cortex-M4 @100 MHz
验证一次—
占用 RAM—
——
P4:2023 用 Ascon-Hash,“太快” → 2024 换 bcrypt P4:Argon2 推荐参数“达不到时限” 用了口令哈希的队伍:为塞进 MCU 调低了迭代 / 内存参数 其他招:超频 P3 P9 · 循环展开 P9 · 放弃完整 TLS P2 P7
数字为量级估算:攻击者 = 单张高端 GPU;口令空间 62⁸ ≈ 2.2×10¹⁴;MCU 耗时按 Cortex-M4 @100 MHz 粗估;Argon2 取 t=3;RFC 9106 的低内存推荐也要 64 MiB
②④ 适配与文档 / §6.2 · §6.3

真正挡路的,是“接不进去”

把 wolfSSL 移植到 MAX78000 · 第 0 次编译
$ 点“编译”开始…
user_settings.h— 几十个开关,哪个才对?
查文档
编译出错后,这里会出现“文档说法”
P16“It was so sparse… it looked random to me.” → 最后去 Reddit 提问
P20“Dragging the entire thing just works, so we kind of stuck with that.”
P3硬件 AES 加速器:头文件套头文件,“13 or 14 different linkages… a nightmare”
P13没有 FPU,浮点被软件模拟,“super, super slow”
对比:P4 2024 年用 Rust 官方 crypto 实现,“most of the algorithms worked without issue” · 建议 4–6:别硬上完整 TLS;库要模块化、可裁剪,写清依赖与 MCU 编译开关 · 编译过程为示意
⑤ 测试与调试 / §6.4

“能跑”就算测过了?

串口 UART · 115200
≈ 一半
参与者只靠 print 调试

“When it printed the encrypted stuff, we assumed that was validly encrypted.”

— P6
P16 的真实漏洞:两个大 nonce 拼接后做 HMAC
buf
nonce₁
nonce₂
溢出 —— 因为 “there were a lack of testing in our work”
测试手段:越往上,越少人做
硬件在环真板子自动化,“super painful” P13
自动化测试JSON 描述场景 + UART 比对 P19
交叉比对 · 自己攻自己同算法换 PC 库对比;伪造消息试探 P9
离板测试先在 PC 上跑通,再移植 P5 P7
print 调试“arbitrary print, like the main way I debug” P11
建议 7:研究者做 MCU 友好的自动化测试框架(单测 / 模糊测试 / 一致性检查,支持 UART) · 建议 8:先离板验证再上板自检;厂商改善调试支持
⑤ 随机数 / §2.1 · §2.2 · §6.4

随机数:看起来随机 ≠ 真的猜不到

熵= 有多“猜不到”。像化学里的“熵”——混乱度越高,越难预测
128 bit 真熵2¹²⁸ ≈ 3.4×10³⁸ 种;每秒猜 10¹² 次,平均也要 5.4×10¹⁸ 年
抖动 jitter没有真随机硬件时,用振荡器时钟边沿极微小的时间波动当噪声源
① 振荡器边沿抖动(放大显示)
② 原始比特采样得到的噪声
③ 最终输出哈希 / DRBG 之后
每比特熵
1.00
128 位密钥的有效熵128 bit
每秒猜 10¹² 次,平均破解5.4×10¹⁸ 年
攻击者:降温 / 调电压0%
健康测试失败:熵不足,拒绝生成密钥
输出“看起来随机”,肉眼和 print 都看不出熵塌了 访谈:随机性验证反复被提及——从“相信厂商”,到大规模统计测试 TRNG,再到直接去问厂商
建议 / Recommendations

8 条建议,分给 4 类人

库维护者4
R1写清有无侧信道防护、在什么条件下有效
R3默认禁用 ECB 等不安全模式,或明确警告
R5模块化、可裁剪;在主流 MCU 工具链上验证
R6文档写清依赖、MCU 编译开关、哪些组件适合嵌入式
开发者3
R2默认 Flash 里的数据会被读走
R4别硬上完整 TLS,用轻量库或基础原语
R8先离板验证算法,再上板做自动化自检
设备厂商2
R2提供 EEPROM 等存放秘密的替代存储
R8改善 UART 日志、半主机等调试支持
研究者1
R7MCU 友好的自动化测试框架:单测、模糊测试、一致性检查;支持无界面运行与 UART
库维护者拿到一半的建议——问题主要出在工具与文档这一侧,而不只是开发者不够小心
总结 / Takeaways

我学到的 3 件事

1安全瓶颈常在“人 + 工具链”,不在算法选型看支持度;真正挡路的是文档与适配
2攻击者永远走最便宜的路侧信道防得再好,明文密钥一读就破——防护要按攻击成本排序
3能跑 ≠ 安全缺少能自动验证安全属性的工具:ECB、熵塌、溢出,print 都看不出
本文核心思路(可复用的研究方法)
真实又可控的场景竞赛 = 自然实验室+ 代码证据做了什么+ 访谈证据为什么 · 卡在哪→ 三角互证按角色给建议
局限
全是学生,未必代表工业界 访谈 22 人,未声称达到饱和 自述与回忆偏差(事隔 1–2 年) 只分析到原语层面,可能漏掉深度改动
启发 / Research Ideas

值得继续研究的两个方向

方向一把论文的发现,变成可自动检查的安全属性
FirmwareAgentProtocol
自动分析安全属性
发现反例counterexample
告诉开发者哪行违反了哪条策略
secrets.h:3密钥以明文存于 Flash违反:静态秘密必须加密或哈希
pin.c:31逐位比较、提前返回违反:PIN 须常数时间比较
crypto.c:88AES 使用 ECB 模式违反:禁止确定性分组模式
hmac.c:42nonce₁‖nonce₂ 超出缓冲区违反:拼接长度必须校验
方向二数学上安全,还要真实系统里安全
数学上安全吗?真实系统里还安全吗?
AES 可证明安全+ECB 模式泄露图案
bcrypt / Argon2 设计安全+参数被调低
零信任协议+密钥明文躺在 Flash
128 位密钥+熵源被降温压到十几 bit
谢谢 · 欢迎讨论

“We just went with what seemed the best supported.”

学生竞赛的结论,能推广到工业界吗?
如果你来维护一个 MCU 密码库,第一件事改什么?
“安全属性检查”能不能像单元测试一样进 CI?
doi.org/10.1145/3830454.3832681 · 补充材料:github.com/CactiLab/eCTF-Crypto-Material
01 / 21

总览 · 点击跳转(O / Esc 关闭)

快捷键

→空格PgDn下一步 / 下一页
←PgUp上一步
O总览(点击跳转)
F全屏
T深色 / 浅色主题
P打开演讲者窗口(讲稿 + 计时)
N讲稿浮层(排练用)
R重置当前页演示
B黑屏