如何用 Proxmark3 与 Flipper 实测验证 MIFARE Ultralight AES(MF0AES20)卡片功能
【免费下载链接】unleashed-firmwareFlipper Zero Unleashed Firmware项目地址: https://gitcode.com/GitHub_Trending/un/unleashed-firmware
Flipper Zero Unleashed Firmware 为 NFC 新增了 MIFARE Ultralight AES(MF0AES20)协议支持,覆盖身份读取、原创签名(originality signature)、AES 三轮认证与受保护读取、字典攻击、密钥管理、写回、模拟、单向计数器、配置解码和 Secure Messaging(CMAC)。仓库中的 MifareUltralightAES_QA.md 和 MifareUltralightAES_SecureMessaging_QA.md 给出了用真卡 + Proxmark3 + 一台 Flipper 做端到端硬件验证的完整方案。本文按这两份文档把验证路径整理成可执行的操作序列:用 PM3 建立真值基线并个性化卡片配置,用 Flipper 读取/解锁/模拟/写入,再用 PM3 复核结果。
准备条件
- 一张真MF0AES20 卡(文档称 "OG card")。出厂默认状态为:DataProtKey 与 UIDRetrKey 全零、
SEC_MSG关、RID关、AUTH0不保护任何页、AUTH_LIM无限、配置未锁定(CFGLCK= 0)、密钥页未锁定。 - 一台 Proxmark3(Iceman),承担三个角色:抓取真值 dump、把卡片个性化成各测试配置、作为模拟测试的外部读卡器。它不会说 Secure Messaging,只能检测
SEC_MSG_ACT位。 - 一台运行本固件的 Flipper,作为被测设备。
- 在 Flipper 上开启 Debug 日志:Settings → System → Log Level → Debug,这样各功能的日志标记才能看到。
PM3 的 MF0AES20 命令语法较新且与构建相关,开始写作前先确认语法:hf mfu --help/hf mfu wrbl -h。在开放(factory)卡上,hf mfu rdbl -b <blk>/hf mfu wrbl -b <blk> -d <8 hex>不需要密钥。
写配置页前必须记住的安全规则
以下位写错可能永久锁死或弄坏卡片,整个方案全程不要写:
AUTH_LIM(页0x2A字节 2–3)CFGLCK(页0x2Abit6,永久配置锁)LOCK_KEYS(页0x2D)及静态锁字节
其余规则:
- 方案里的每次个性化都可逆,前提是卡片保持开放(
AUTH0关闭、允许明文写)。一旦设置了AUTH0/PROT,改配置本身需要先认证——恢复时永远先把AUTH0/PROT恢复为开放,再改其他项。 - 只做 read-modify-write:写某页前读出当前 4 字节,只改目标位,保留其他 3 字节。页
0x29字节 3 是AUTH0,绝不能被覆盖。 - 保留 Phase 0 的原始 dump,作为之后每个阶段 diff 的真值。
配置位位置以固件自带解码器 + 数据手册为准(PM3 的hf mfu info对 MF0AES20 用旧 Ultralight 模板解码,会把页0x34–0x37——实际是 UIDRetrKey——标成cfg0/cfg1/PWD/PACK,请以这张表为准):
| 项目 | 位置 |
|---|---|
| DataProtKey | 页0x30–0x33 |
| UIDRetrKey | 页0x34–0x37 |
| CFG 页 | 0x29:字节 0 bit0 =RID_ACT,bit1 =SEC_MSG_ACT;字节 3 =AUTH0 |
| ACCESS 页 | 0x2A:字节 0 bit2 =CNT_RD_EN,bit3 =CNT_INC_EN,bit6 =CFGLCK,bit7 =PROT;字节 2–3 =AUTH_LIM |
| LOCK_KEYS 页 | 0x2D:字节 0 = 每密钥锁位 |
第一步:基线抓取(PM3,不改卡)
hf mfu info→ 记录 UID、版本、三个计数器、配置,以及Known UL-AES keys(出厂卡应显示 Data 与 UID 密钥全零、( ok ))。- 用全零密钥 dump 原始内存并保存——这是后面每个阶段对比的真值。
- 记下页
0x29、0x2A、0x2D的原始字节,后面要 read-modify-write 它们。
第二步:身份与读取验证(开放卡,不改卡)
Flipper 操作路径:NFC → Read。
预期结果:类型为Mifare Ultralight AES,ATQA0044,SAK00,60/60页全部读出,计数器0/0/0;完整信息页的配置解码与 PM3 一致(Auth off、unlimited、user cfg open、RIDoff、SEC_MSGoff、key lock N)。文档实测卡片的 UID 为04 7B A2 C2 45 13 90(文档示例值,你的卡会不同)。
这一步同时验证了配置解码器对开放卡的正确性,且不需要任何写操作。
第三步:原创签名(读取 + PM3 验证模拟)
签名(signature)是 UL-AES 区别于普通 Ultralight 的关键防伪特征:
- Flipper:Read →Save→ 打开保存的
.nfc文件,应有一行AES signature:,即 48 字节的签名(PM3 也能显示同一块数据)。 - Flipper:Emulate 这份 dump。
- PM3:对模拟出的卡执行
hf mfu info。
预期:.nfc携带 48 字节签名;PM3 打印Tag Signature块,并输出Signature verification: successful(而不是旧版的 READ-SIGNATURE 超时)。
第四步:AES 认证 + 受保护读取(PM3 建保护区)
用 PM3 把卡片设置成"部分区域需认证",再验证 Flipper 的解锁路径。
PM3 侧(先记录当前0x29/0x2A):
- 把
AUTH0(0x29字节 3)设为第一个想保护的数据页(文档示例用0x10),并置PROT(0x2A字节 0 bit7,即 OR0x80),使受保护区域的读需要认证。AUTH_LIM/CFGLCK保持不动。 - 配置解码交叉验证阶段(P9)给出的现成写法示例:
hf mfu wrbl -b 41 -d 0000002A,Flipper 完整信息页应显示Auth from: page 0x2A (r+w),恢复用hf mfu wrbl -b 41 -d 0000003C。 - 写之前把目标页当前 4 字节粘给文档工具链,可算出精确的
-d值,确保不碰AUTH0。
Flipper 侧:
Read → 开放页能读、受保护页需认证 →Unlock → Run Dictionary Attack(应找到全零密钥)或Enter Key Manually输入00…00→ 受保护页可读。
预期:全部 60 页与 Phase 0 真值一致;恢复出的密钥被显示并随 dump 一起保存。
恢复:PROT= 0,AUTH0恢复为开放值(0000003C)。
补充两个实测中确认过的行为边界:
- UL-AES 没有一次性"输密码"框。手动录入密钥 = 把它加入User dictionary(Extra Actions →MIFARE Ultralight AES Keys → Add)。读取不完整时 AES 字典攻击会自动启动,先试User词典再试System词典;User 词典里只有错误密钥时,会干净地落到 System 词典(不挂死、不无限重选),
AUTH_LIM无限所以不会锁卡。 - DataProtKey 字节序:原始
wrbl按 tag 内存序写字节,而 AES 引擎(Flipper 手动录入与 PM3hf mfu aesauth --key都是)使用逆序。页0x30–0x33为A0A1A2A3 A4A5A6A7 A8A9AAAB ACADAEAF的卡,认证密钥是AFAEADACABAAA9A8A7A6A5A4A3A2A1A0。手动录入恢复出的密钥时用AES 序(相对原始wrbl显示值逆序)。
第五步:写回与模拟(PM3 复核)
写回只在完整读出的 UL-AES dump 上提供两个入口:Write (Keep Key)和Write (Copy Key)。写入会先用词典里的密钥对目标卡做认证(目标卡当前密钥必须能在词典里找到,出厂即全零),然后写入;数据页0x04–0x27总会写,配置/锁页0x28–0x2F从不写;Keep Key 写到密钥前停下,Copy Key 额外写 DataProtKey0x30–0x33(UIDRetrKey0x34–0x37永不写)。
- Keep Key 验证:PM3 先在数据页打标记
hf mfu wrbl -b 10 -d DEADBEEF(卡片开放状态);Flipper 加载出厂 dump →Write (Keep Key);PM3 重新 dump:页 10 变回00000000(数据页确实被写),页 48–51 仍全零,0x29/0x2A/0x2D不变,hf mfu info→ 全零 Data 密钥仍( ok )。 - Copy Key 验证:
.nfc是纯文本,DataProtKey 存在于Page 48–51的页行里(屏幕上显示的DataProtKey:只是渲染、不是存储字段)。把这几行按 tag 内存序编辑成非零密钥(文档示例00 11 22 33 / 44 55 66 77 / 88 99 AA BB / CC DD EE FF),load →Write (Copy Key)。PM3 验证:dump 显示 48–51 页即为该值;全零 Data 密钥不再( ok );hf mfu aesauth --key FFEEDDCCBBAA99887766554433221100→( ok )——逆序密钥能认证,端到端证明了写回路径的字节序。恢复:卡片保持开放,PM3 明文把 48–51 页写回00000000即可。
模拟(PM3 充当外部读卡器):
- Emulate 出厂 dump → PM3
hf mfu info:身份/版本/计数器/配置与真卡一致且签名验证通过;hf mfu aesauth --key 000…0→( ok ),证明 listener 以卡身份完成了三轮 AES 质询-应答。 - 用 Copy Key 后带非零密钥的 dump 再 emulate →
hf mfu aesauth --key FFEEDDCCBBAA99887766554433221100(逆序密钥)→( ok );--key 000…0(错误密钥)→ 失败。这同时确认 listener 按reverse(pages 0x30–0x33)提取密钥且拒绝错误密钥。
第六步:Secure Messaging(CMAC)验证——关键门槛
这是整套功能中没有参考实现对账的部分:PM3 只检测SEC_MSG_ACT位,不能充当 CMAC 读卡器,所以必须靠文档 MifareUltralightAES_SecureMessaging_QA.md 的 R/W 组行项在真卡上验证。
关键可恢复性规则:SEC_MSG_ACT一旦打开,受保护区域的任何配置写入都需要 CMAC 认证写——PM3 做不到,而 Flipper 的写会跳过配置页。所以SEC_MSG_ACT开启期间绝不设AUTH0 ≤ 0x29,否则可能无法再清除该位。用AUTH0 = 0x2A:它让0x29保持在 AUTH0 之下(PM3 可明文恢复),同时迫使 Flipper 走认证——这正是触发 CMAC 会话的条件。
Setup(PM3):
hf mfu wrbl -b 41 -d 0200002A hf mfu rdbl -b 41读回应为02 00 00 2A。保持 Debug 日志开启。
验证行项:
- R1 全量 CMAC 读:Flipper Read → 读不完整 →Unlock with Dictionary→ 日志出现
UL-AES: plain read failed post-auth, switching to secure messaging→ 全部 60 页经 CMAC 读出(约 15 次READ交互,顺带验证了+2 计数器步进与 MAC 字节序),无MAC mismatch;数据与 PM3 真值一致。 - R2 计数器:R1 之后看完整信息页,三个计数器
0/0/0(与 PM3 一致)。 - W1 CMAC 写回:Write (Keep Key) 一份保存的 dump → 写操作先认证 → 日志显示第一页写入时切到 CMAC → 数据页以 MAC 包裹写入、无
MAC mismatch;用 PM3 重读复核(数据页在 AUTH0 之下,PM3 可明文读)。 - R4 密钥页不泄露:保存的 dump 中页
0x30–0x37读回为零(被掩码),绝不含真实密钥字节。
干净跑一遍时,日志里不应出现UL-AES response MAC mismatch (ctr N)、UL-AES command MAC mismatch, dropping session、UL-AES secure-messaging write: re-auth failed, page N locked等告警。
恢复:
hf mfu wrbl -b 41 -d 0000003C hf mfu info确认Secure msgoff、AUTH0 开放、全零 Data 密钥( ok )。
文档记录了该步骤的真实硬件发现:真卡对认证后的第一条明文命令是**静默(frame-wait Timeout)**而非 4-bitProtocolNAK,导致 CMAC 检测门槛不触发、读写停在 0/60(commitce541e129修复,读/写门槛同时接受Timeout)。这也是该步骤必须"跨过第一帧"看多帧交互的原因。
可选项:Random ID 与配置位解码
- Random ID(P8):PM3 置位
hf mfu wrbl -b 41 -d 0100003C(RID_ACT,保留 AUTH0),卡片改呈 4 字节随机反碰撞 UID(ISO14443-3 单尺寸,首字节0x08),真实 7 字节 UID 在认证读取前被隐藏。Flipper Read 应显示随机 UID 且完整信息页解码出Random ID: on。注意 Flipper 显示的 4 字节与 PM3 显示的 7 字节(尾部补00 00 00)是同一个随机值,都不是真实 UID。恢复:hf mfu wrbl -b 41 -d 0000003C。 - 配置位逐位解码(P9):在开放卡上对每个位单独做 PM3 写 → Flipper Read + 完整信息 → 确认对应解码行 → 恢复。文档给出的示例位包括
SEC_MSG_ACT(wrbl -b 41 -d 0200003C→Secure msg: on)、CNT_RD_EN/CNT_INC_EN各组合(wrbl -b 42 -d ...)与AUTH0。基线参考值为0x29 = 00 00 00 3C、0x2A = 8C 05 00 00。再次强调:不要测CFGLCK(永久)和AUTH_LIM(触发锁卡)。
结果判定与覆盖边界
- 回归项:普通开放 UL-AES 卡应干净读出 60/60 且不触发 CMAC;受保护但非 SEC_MSG 的卡(
AUTH0=0x10、SEC_MSG off)应通过字典攻击读出 60/60 且无误触发 CMAC 切换;Ultralight-C、NTAG、普通 Ultralight 的读取/模拟行为不受影响。 - 签核:P1–P11 加上 Secure Messaging 读卡侧行项(R1/R2/W1/R4)通过,即可认为该功能在本套装允许的范围内完成真硅验证;签名表中记录固件构建(
git describe)、OG 卡 UID、PM3 构建、结果与已知缺口。 - 本套装覆盖不到的路径(签核时如实标注):克隆到空白卡(W2)需要第二张空白 UL-AES 卡;Flipper↔Flipper 交叉验证(X 组)需要第二台 Flipper;模拟侧 Secure Messaging(CMAC 读卡器读模拟卡)需要支持 CMAC 的读卡器或第二台 Flipper——PM3 无法胜任。Random ID 背后真实 UID 的自动获取(P12)在文档中列为计划中的独立能力,不属于本次验证范围。
相关实现可对照阅读:CMAC 加密在 mf_ultralight_aes_crypto.c(mf_ultralight_aes_cmac8_ctr),读侧自适应切换在 mf_ultralight_poller.c 与 mf_ultralight_poller_i.c(mf_ultralight_poller_txrx_aes_cmac),模拟侧在 mf_ultralight_listener.c。
【免费下载链接】unleashed-firmwareFlipper Zero Unleashed Firmware项目地址: https://gitcode.com/GitHub_Trending/un/unleashed-firmware
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考