1. 项目概述:为什么我们要深挖一张“过时”的卡片?
如果你接触过门禁卡、公交卡或者一些早期的电子钱包,那么你大概率已经和Mifare Classic卡片打过交道了。这张诞生于上世纪90年代的卡片,凭借其低廉的成本和在当时看来足够快的交易速度,迅速占领了全球非接触式智能卡市场。然而,它核心的Crypto1加密算法,却成为了信息安全史上一个经典的“反面教材”。今天,我们不是要简单地复现一个攻击,而是要像外科手术一样,完整地解剖其从认证到通信加密的整个流程。理解这个流程,不仅是为了“破解”,更是为了深刻理解对称流加密在资源受限的嵌入式环境中是如何实现的,以及一个微小的设计缺陷如何导致整个安全体系的崩塌。这对于从事物联网安全、嵌入式开发甚至只是对底层安全机制好奇的开发者来说,都是一次绝佳的学习机会。我们将绕过纯理论,直接进入实战视角,用你能看懂的语言和逻辑,把每一步都掰开揉碎。
2. 核心思路拆解:逆向工程Crypto1的“心脏”
要解析Crypto1,不能把它当成一个黑盒。我们的思路是沿着卡片与读卡器交互的真实数据流,一步步向前推进,最终触及算法核心。
2.1 从交互协议到加密边界
Mifare Classic遵循ISO/IEC 14443 Type A标准进行无线通信。在未加密状态下,读卡器和卡片通过明文进行“对话”。加密的触发点,始于一个特定的命令:认证(Authentication)。读卡器会选择一个扇区,并向卡片发起认证请求。此时,卡片和读卡器各自掌握着一个该扇区的密钥(分为A密钥和B密钥)。认证过程的核心目的,就是让双方在不泄露密钥的前提下,向对方证明“我知道密钥”。一旦认证成功,后续的所有通信数据(包括读、写、增值、减值等命令及其响应)都将被一个动态生成的密钥流(Keystream)进行异或加密。
所以,整个流程可以清晰地划分为两个阶段:
- 认证阶段:一个三次握手过程,基于共享密钥和随机数挑战,完成双向验证。
- 加密通信阶段:利用认证过程中产生的内部状态,生成伪随机的密钥流比特,对传输的每一个比特进行流加密。
攻击者的经典思路(如“幽灵”攻击和嵌套认证攻击)正是利用了认证阶段随机数生成器的缺陷,以及密钥流生成算法的线性特性,通过监听一次或多次认证过程,来逆向推导出密钥或直接预测后续密钥流。
2.2 工具选型:为什么是Proxmark3?
工欲善其事,必先利其器。在Mifare Classic的研究中,Proxmark3几乎是无可替代的“瑞士军刀”。它不仅仅是一个高频(13.56MHz)读卡器,更是一个全功能的射频嗅探、模拟和攻击平台。
- 硬件优势:其开源的硬件设计允许我们直接捕获射频模拟信号,并解码出原始的曼彻斯特编码或米勒编码数据,这对于分析底层通信时序、捕捉认证过程中的完整数据帧至关重要。很多软件读卡器无法捕获到认证失败或异常的交互,而Proxmark3可以。
- 软件生态:其强大的客户端
pm3内置了丰富的Mifare Classic相关指令,例如hf mf autopwn可以自动尝试多种攻击方式获取密钥,hf mf nested用于执行嵌套认证攻击,hf mf sim可以模拟卡片行为。更重要的是,我们可以直接查看和操作其固件中实现的Crypto1算法相关函数,进行单步调试和状态注入。 - 不可替代性:虽然也有像ChamelaonMini、Flipper Zero这样的便携设备,但在功能的深度、灵活性和社区支持上,Proxmark3依然是进行原理性研究和深度攻击验证的首选。
注意:使用Proxmark3进行安全研究必须在你自己拥有完全所有权的卡片或法律明确授权的测试环境中进行。对他人所属的卡片或系统进行未授权测试是违法行为。
3. 实战解析第一阶段:认证流程深度剖析
现在,让我们进入实战环节。假设我们手头有一张Mifare Classic 1K卡片和一个Proxmark3。我们首先来捕获并理解一次完整的认证过程。
3.1 捕获一次明文认证会话
在Proxmark3客户端,我们首先将设备置于嗅探模式,监听13.56MHz频段的通信。
# 启动Proxmark3客户端 pm3 # 进入高频嗅探模式 hf 14a sniff然后,我们用一个普通的读卡器(或者Proxmark3的另一模式)去读取卡片的某个扇区。Proxmark3会捕获到所有交互数据。一次成功的认证交互数据流通常如下所示(数据为示例,已简化):
- 读卡器 -> 卡片:
60 04// 认证请求命令60,扇区号04(对应第4扇区,块地址计算方式为 扇区号*4) - 卡片 -> 读卡器:
bb 63 dd 52 49 a1// 卡片返回一个4字节的随机数NT(例如bb 63 dd 52) 和其2字节的CRC-A校验值49 a1。 - 读卡器 -> 卡片:
bb 63 dd 52 49 a1 88 69 b3 70// 读卡器发送:NT+NR(读卡器生成的4字节随机数,例如88 69 b3 70) +{NT}^+{NR}^。这里的{NT}^和{NR}^是NT和NR经过某种变换(后文详述)后的结果。 - 卡片 -> 读卡器:
NR^// 卡片返回读卡器随机数NR的变换值{NR}^。
如果第4步验证通过,认证成功。这里最关键的,就是第3步中读卡器发送的{NT}^和{NR}^,以及第4步卡片返回的{NR}^。它们就是“证明我知道密钥”的凭据。
3.2 解密认证令牌:{NT}^ 与 {NR}^ 的生成
{NT}^和{NR}^并不是对NT和NR的直接加密,而是Crypto1流密码算法在特定初始状态下产生的前32位密钥流,与NT和NR进行异或(XOR)的结果。
具体过程如下:
- 初始化密码机:读卡器(或卡片)使用共享密钥
Key和认证开始时收到的随机数NT(对于读卡器是卡片发的,对于卡片是自己生成的),作为输入,初始化Crypto1算法的48位移位寄存器(LFSR)。这个初始化过程是确定性的,相同的Key和NT必然产生相同的初始状态。 - 生成密钥流:密码机初始化后,开始运行。它会连续产生密钥流比特。丢弃前若干比特(为了混淆)后,连续取出32个比特(4字节),这32个比特就构成了一个密钥流片段
KS1。 - 生成令牌:将
KS1与要发送的随机数(对于读卡器,是NT和NR;对于卡片,是NR)进行按位异或,得到的就是{NT}^和{NR}^。- 读卡器计算:
{NT}^ = NT XOR KS1,{NR}^ = NR XOR KS2(这里KS2是继KS1之后产生的下一个32位密钥流)。 - 卡片验证:卡片用同样的
Key和NT初始化自己的密码机,生成KS1,用它去异或收到的{NT}^,应该能得到自己发出的NT,从而验证读卡器知道密钥。然后卡片再生成KS2,用它异或收到的{NR}^得到NR,接着用NR初始化(实际上是参与下一步计算)并生成KS3,计算{NR}^ = NR XOR KS3发回给读卡器。
- 读卡器计算:
- 验证:读卡器收到
{NR}^后,用自己计算出的KS3与之异或,如果得到自己发出的NR,则认证卡片成功。
这个过程实现了双向认证,且密钥Key从未在信道中传输。然而,致命弱点在于随机数NT和NR的生成质量。早期Mifare Classic卡片的伪随机数生成器(PRNG)是线性的且状态可预测,攻击者通过监听一次认证,就能获得NT,{NT}^,NR,{NR}^四个值。由于{X}^ = X XOR Keystream,那么Keystream = X XOR {X}^。攻击者可以直接计算出KS1和KS2(来自读卡器)以及KS3(来自卡片响应)的部分密钥流!
实操心得:在嗅探时,务必确保捕获到完整的四次数据交换。有时因为信号干扰,数据包可能不完整。Proxmark3的
hf 14a list命令可以查看缓存的完整数据帧,比实时嗅探更稳定。对于关键测试,建议多次捕获以确保数据一致性。
4. 实战解析第二阶段:Crypto1算法与密钥流生成
拿到了几段密钥流片段,我们如何攻击呢?这就需要深入Crypto1算法的内部。
4.1 Crypto1算法结构:一个脆弱的LFSR
Crypto1是一个基于48位线性反馈移位寄存器(LFSR)的流密码。它的核心是一个48位的寄存器,每次时钟脉冲,寄存器向右移动一位,新的最高位由某些特定抽头位(Tap)经过一个非线性滤波函数f计算后填充。
- LFSR初始化:密钥
Key(48位)和随机数NT(32位)通过一个特定的混合算法(并非简单拼接)加载到LFSR中,形成初始状态。这是整个算法安全的基础,但混合过程也存在弱点。 - 非线性滤波函数
f:为了增加复杂性,算法从LFSR中选取20个位,通过一个带有非线性的函数f计算出一个比特。这个比特再与下一个LFSR反馈位进行异或,产生最终的密钥流比特。f函数的设计是保密的,但已被逆向工程破解。 - 密钥流生成:每产生一个密钥流比特,LFSR就移位一次。产生的密钥流比特与明文比特异或得到密文,与密文比特异或得到明文。
算法的安全性严重依赖于LFSR的初始状态(即密钥)的保密性。一旦初始状态被破解,整个密钥流序列就可以被完全预测。
4.2 从密钥流片段到密钥恢复:已知明文攻击
我们之前通过一次认证监听,获得了至少96位的密钥流(KS132位 +KS232位 +KS332位)。由于Crypto1算法是线性的(尽管有非线性滤波函数,但其与LFSR状态的关系已被充分研究),这些已知的密钥流比特构成了对48位LFSR初始状态(即密钥)的方程组。
攻击的核心工具是相关性攻击或快速相关攻击的变种。由于滤波函数f的输入(20个LFSR位)和输出(1个密钥流比特)之间存在统计相关性,攻击者可以建立大量的线性近似方程。已知的密钥流比特越多,这些方程就越能精确地限定LFSR的初始状态。
实际操作中,我们不需要自己实现这些复杂的数学攻击。Proxmark3的hf mf nested命令自动化了这个过程:
- 它首先利用一个已知密钥的扇区(例如扇区0通常使用默认密钥
FFFFFFFFFFFF)发起认证。 - 在认证过程中,它会尝试对目标扇区(未知密钥)发起“嵌套”认证。因为第一次认证已经建立加密通信,所以嵌套认证的命令也是加密的。
- 攻击工具会利用已知密钥产生的密钥流,以及嗅探到的嵌套认证过程中的密文,通过求解方程组来恢复目标扇区的密钥。这个过程通常只需要几秒钟到几分钟。
# 假设我们已经知道扇区0的密钥是默认密钥 hf mf nested 0 A FFFFFFFFFFFF d # 尝试用已知密钥A去嵌套探测所有扇区的密钥注意事项:嵌套攻击成功的前提是至少有一个扇区的密钥已知。这就是为什么Mifare Classic系统如果所有扇区都使用独立强密钥,攻击难度会大大增加。但现实中,很多系统为了管理方便,多个扇区甚至所有扇区都使用相同或默认密钥,这为攻击打开了大门。
4.3 密钥流生成与通信加密模拟
在成功恢复某个扇区的密钥后,我们不仅可以解密该扇区的数据,还可以完全模拟卡片或读卡器的加密通信。
例如,我们可以用Proxmark3模拟一张卡片,并使用恢复的密钥来响应读卡器的认证请求:
# 将Proxmark3模拟成一张Mifare Classic卡片,并加载指定扇区的密钥 hf mf sim u *1k # 模拟1K卡片,UID为* hf mf eset 04 A A0A1A2A3A4A5 # 在模拟卡中设置第4扇区A密钥为A0A1A2A3A4A5当外部读卡器尝试认证第4扇区时,Proxmark3会使用我们设定的密钥A0A1A2A3A4A5和它自己生成的NT(或可指定的NT)来计算正确的{NT}^和{NR}^,完成认证流程。此后,所有通信都将使用正确的密钥流进行加解密,我们可以借此深入研究加密后的数据交换格式,或者测试读卡器的行为。
5. 常见问题与排查技巧实录
在实际操作中,你会遇到各种各样的问题。下面是我踩过的一些坑和解决方案。
5.1 问题:Proxmark3嗅探不到数据或数据混乱
- 可能原因1:天线问题或距离不当。Proxmark3的天线需要调谐,且卡片与天线距离应在1-3厘米内。距离太远信号弱,太近会导致过载失真。
- 排查:运行
hw tune查看天线调谐情况。确保天线线圈完好,没有断裂。尝试调整卡片与天线的相对位置和角度。
- 排查:运行
- 可能原因2:读卡器信号干扰。有些读卡器发射功率大或协议有微小差异,可能导致Proxmark3无法正确解码。
- 排查:尝试使用Proxmark3自己作为读卡器(
hf mf rdbl等命令)与卡片通信,看是否能成功。这可以排除外部读卡器兼容性问题。
- 排查:尝试使用Proxmark3自己作为读卡器(
- 可能原因3:标签类型不匹配。Mifare Classic有1K和4K变种,且ISO14443 Type A底层细节(比特率、帧格式)可能有差异。
- 排查:先用
hf 14a reader或hf search命令识别卡片类型。在嗅探时明确指定标准:hf 14a sniff -c或-r尝试不同的编码模式。
- 排查:先用
5.2 问题:嵌套攻击(nested)长时间无法成功
- 可能原因1:已知密钥错误或对应扇区不可用。嵌套攻击需要一个有效的已知密钥作为起点。如果提供的已知密钥错误,或者该扇区被设置为永不接受认证(例如,某扇区的访问位被配置为拒绝任何认证尝试),攻击无法开始。
- 排查:使用
hf mf chk命令验证你提供的已知密钥是否真的能通过认证。使用hf mf fchk进行快速密钥扫描确认。检查目标扇区的访问条件(Access Bits),确认其是否允许认证。
- 排查:使用
- 可能原因2:捕获的认证数据不足或有误。嵌套攻击需要利用一次成功的认证过程数据。如果嗅探到的数据包不完整、时序错误或包含了校验错误,攻击会失败。
- 排查:重新进行嗅探,确保在已知密钥扇区认证时,捕获到了清晰完整的
NT,{NT}^,NR,{NR}^四组数据。可以使用hf 14a list仔细检查捕获到的数据帧。
- 排查:重新进行嗅探,确保在已知密钥扇区认证时,捕获到了清晰完整的
- 可能原因3:目标密钥不是标准密钥或算法有变种。极少数情况下,某些定制系统可能使用了非标准的密钥派生方法或修改了算法(尽管Crypto1硬件是固定的)。
- 排查:这比较棘手。可以尝试使用
hf mf hardnested命令,它是一种计算量更大但更鲁棒的攻击方式,对某些特殊情况的容忍度更高。或者,如果可能,尝试获取系统的其他信息。
- 排查:这比较棘手。可以尝试使用
5.3 问题:模拟卡片(sim)时,外部读卡器不响应或认证失败
- 可能原因1:UID不匹配。许多读卡器会检查卡片的UID(唯一标识符),如果模拟的UID不在其允许列表内,会直接拒绝。
- 排查:尝试模拟一个原卡的UID(如果你知道的话)。或者,对于只读UID的测试,可以尝试使用一个常见的UID,如
0x08010203。使用hf 14a sim u <UID>进行模拟。
- 排查:尝试模拟一个原卡的UID(如果你知道的话)。或者,对于只读UID的测试,可以尝试使用一个常见的UID,如
- 可能原因2:时序问题。Proxmark3的模拟模式在响应时间上可能与真卡有细微差异,某些挑剔的读卡器可能会因此超时。
- 排查:这通常是固件或硬件限制。确保你使用的是最新版本的Proxmark3固件和客户端软件。尝试将Proxmark3和读卡器放得非常近,减少信号延迟。
- 可能原因3:协议细节差异。除了ISO14443-3,读卡器可能实现了某些厂商特定的指令或流程。
- 排查:使用嗅探模式捕获真卡与读卡器的完整交互流程,然后与Proxmark3模拟时产生的交互进行对比,查看在哪一步出现了分歧。可能需要编写自定义的Lua脚本来精确模拟特定流程。
5.4 高级技巧:利用“侦听-重放”进行无密钥操作
在某些特定场景下,甚至不需要恢复密钥。如果系统没有使用随机数或随机数质量极差(例如,每次认证NT都相同),你可以直接侦听一次成功的加密通信数据包(例如“扣款10元”指令),然后将其原封不动地重放(Replay)。由于密钥流相同,系统会再次执行相同操作。这就是重放攻击。
- 操作:使用Proxmark3的
hf 14a snoop捕获完整交互,保存为文件。然后使用hf 14a play将捕获到的信号原样发射出去。 - 防护:防御重放攻击的唯一有效方法是在交易中使用不可重复的随机数(Nonce)或递增序列号,确保每次通信数据都不同。这也是现代安全协议的标准做法。
通过对Mifare Classic Crypto1从认证到密钥流生成的完整拆解,我们看到的不仅是一个算法的失败,更是一系列安全设计原则的违背:脆弱的伪随机数生成器、保密性通过隐匿(算法最初保密)、以及线性反馈移位寄存器在面临已知明文攻击时的固有脆弱性。今天,Mifare Classic早已不再被视为安全设备,但它的故事和其背后清晰可辨的技术脉络,为我们理解现代加密技术(如AES)、认证协议(如相互认证、随机数挑战)以及安全单元(SE)的设计提供了极其宝贵的反面教材。在物联网设备泛滥的今天,资源受限环境下的安全设计挑战依然存在,避免重蹈Mifare Classic的覆辙,是每一位嵌入式开发者和安全研究员应有的警觉。