初探M1 card

0x01背景知识


Mifare Classic 提供 1 Kb - 4Kb 的容量,现在国内采用的多数是 Mifare Classic 1k(S50)[后面简称 M1 卡]。

M1 卡有从 0 到 15 共 16 个扇区,每个扇区配备了从 0 到 3 共 4 个段,每个段可以保存 16 字节的内容,为什么这里要强调从 0 开始呢?这跟 C 语言里面数组下标默认从 0 开始是差不多的,好计算地址偏移,我们不必太过在意,只是要记住是从 0 开始,写入数据的时候不要写错地方就可以了。每个扇区的第 4 个段(也就是 3 段)是用来保存 KeyA,KeyB 和控制位的,因为 M1 卡允许每个扇区有一对独立的密码保护,这样能够更加灵活的控制数据的操作,控制位就是这个扇区各种详细权限计算出来的结果。

M1介绍pdf

0x02数据分析


M1 card

通过对比(上为3元,下为13元)
2C 01为余额,14 05为余额.
3元
2C 01 D3 FE 75 8A
44 1 211 254 117 138 转10进制

13元
14 05 EB FA 2D D2
20 5 235 250 45 210
2C 01倒序后转十进制为0300
14 05同上
2C与D3转十进制相加=255,01与FE转加=255
13元同上
75 8A转后加255

0x03IC卡密码破解的几种方法:


0x03.1 使用默认的密码攻击


很多应用IC卡都没有更改默认密码,所以导致可以直接使用默认密码来尝试接入IC卡,常见的默认密码有: ffffffffffff
000000000000
a0a1a2a3a4a5
b0b1b2b3b4b5
aabbccddeeff
4d3a99c351dd
1a982c7e459a
d3f7d3f7d3f7
714c5c886e97
587ee5f9350f
a0478cc39091
533cb6c723f6
8fd0a4f256e9
FFzzzzzzzzzz
A0zzzzzzzzzz

0x03.2 nested authentication 攻击(大家常说的验证漏洞攻击)


每个扇区都有独立的密码,一些情况下,比如某饭卡,扇区3中存储着钱等数据,扇区3的更改了默认密码,扇区5中也存储着一些数据,扇区5也更改了密码,其他扇区没有更改默认密码。我们要操作扇区3跟5,不知道密码怎么办?使用nested authentication 攻击,这种攻击方式是在已知了16个扇区中任意一个扇区的密码之后,采用的攻击方式,可以获得其他扇区的密码。我们前面都提到了,16个扇区的密码都是独立的,那么怎么能通过某个扇区的密码获得其他扇区的密码呢?如果可以,那说明扇区就不是独立的呀,有人会说,由于M1卡的加密算法被破解了,我只能说那是还没有理解,具体算法不讲,只说明一下,算法只是使得猜解密码的时间变短,使得猜解密码成为可能。

这是什么样的原理呢?首先先了解,这是一个对等加密算法,也就是读卡器跟tag中都保存着同样的密码,也都是用同样的算法加密,然后看rfid的验证过程:开始交互的时候,tag就已经把uid给reader说了,主要牵扯到防冲撞机制,之后才开始验证。 第一次验证时,读卡器首先验证0扇区的密码,tag给读卡器发送一个随机数nt(明文),然后读卡器通过跟密码相关的加密算法加密nt,同时自己产生一个随机数nr,(密文)发送给tag,tag用自己的密码解密之后,如果解密出来的nt就是自己之前发送的nt,则认为正确,然后通过自己的密码相关的算法加密读卡器的随机数nr(密文)发送给读卡器,读卡器解密之后,如果跟自己之前发送的随机数nr相同,则认为验证通过,之后所有的数据都通过此算法加密传输。

首先记住这里面只有第一次的nt是明文,之后都是密文,而且nt是tag发送的,也就是验证过程中,tag是主动先发随机数的。我们破解的时候,读卡器中肯定没有密码(如果有就不用破解了),那么tag发送一个nt给读卡器之后,读卡器用错误的密码加密之后发送给tag,tag肯定解密错误,然后验证中断,这个过程中,我们只看到tag发送的明文随机数,tag根本没有把自己保存的密码相关的信息发送出来,那怎么破解呢?

所以,要已知一个扇区的密码,第一次验证的时候,使用这个扇区验证成功之后,后面所有的数据交互都是密文,读其他扇区数据的时候,也需要验证,也是tag首先发送随机数nt,这个nt是个加密的数据,我们前面也说过每个扇区的密码是独立的,那么加密实际上就是通过tag这个扇区的密码相关的算法加密的nt,这个数据中就包含了这个扇区的密码信息,所以我们才能够通过算法漏洞继续分析出扇区的密码是什么。

这也是为什么nested authentication攻击必须要知道某一个扇区的密码,然后才能破解其他扇区的密码。

0x03.3 darkside攻击


假设某个IC卡的所有扇区都不存在默认密码怎么办?暴力破解根本不可能,那这时候就是算法的问题导致的darkside攻击,我们照样不说具体算法什么漏洞之类,同样,我们考虑首先要把tag中的key相关的数据骗出来,也就是让tag发送出来一段加密的数据,我们通过这段加密的数据才能把key破解出来,如果tag不发送加密的数据给我们,那没法破解了。

前面我们也说了,第一次验证的时候tag会发送明文的随机数给读卡器,然后验证读卡器发送加密数据给tag,tag验证失败就停止,不会发送任何数据了,这样看,根本就没有办法破解密码。

实际上经过研究人员大量的测试之后,发现算法还存在这样一个漏洞,当读卡器发送的加密数据中的某8bit全部正确的时候tag会给读卡器发送一个加密的4bit的数据回复NACK,其他任何情况下tag都会直接停止交互。

那么这个4bit的加密的NACK就相当于把tag中的key带出来了,然后再结合算法的漏洞破解出key,如果一个扇区的key破解出来,就可以再使用nested authentication 攻击破解其他扇区密码。

0x03.4 正常验证过程获得key


1-3都是通过一般的读卡器,把tag中的密码破解出来,破解的原理中,不管密码破解算法的漏洞,实际上都是要让tag中发送出来一段密文。

那如果读卡器本身就保存有密码,卡也是授权的卡,也就是说卡和读卡器都是正确授权的,那么他们之间的加密数据交换就可以直接使用PM3等监控下来,然后通过“XOR效验与算Key”程序算出密码来。

这种情况下一般都是内部人员做案,或者把读卡器中的SAM偷出来,SAM实际上就是保存读卡器中密码的一个模块,然后通过另外的读卡器插入SAM,用正常的授权的卡刷卡,然后监控交换数据,从而算出密码。

0x03.5 现场有卡嗅探


暂不解释

0x03.6 克隆卡片


这是一个很简单也很实用的方法,因为M1卡自带扇区可以保存数据,所以大部分的卡片会选择加密扇区后将数据保存在里面,所以我们完全可以克隆一张带有一样数据的克隆卡。这就会用到一种叫 UID 卡的特殊 M1 模拟卡,前面说到每张 M1 卡在 0 扇区第 1 段都会有一个全球唯一的 UID 编号,而且这个块在出厂之后是被厂商设定保护无法修改的,UID 卡就是没有设定 0 扇区保护的卡,所以你可以随意的修改你想要的 UID,这样我们就可以克隆出一张连 UID 都相同的卡片了。

0x04 数据分析


0x04.1比对法


比对法,就是将已知数据换算成十六进制,寻找卡片中能与之对应的数据,从而确定卡片中对应的存储位置所存储的数据的意义,或者将卡片中变化的字节转成十进制,判断是否存在相应的数据信息。 最常用的比对值当然是卡片余额,还有当前的消费金额,或者是累计的消费金额,这两个数据有出现在前文的引用文中。那么除了这些,还应该考虑哪些数据呢?这里我作一个简单的罗列:消费次数、日期、时间、读卡器编号、卡号(非UID)等 之所以认为上面的数据可以存储在卡片中,是因为两个字节(16bit),不考虑符号位,可以表示的最大数值是65535,一个字节(8bit)可以表示最大数值为255。一张卡按四年有效期来算的话,每天要刷44次才能再四年内超过这个数值;日期也可以用两个字节来表示,可以选择整体表示,譬如12月31日,记为1231,对应到16进制04CF,也可以一个字节表示月一个字节表示日,仍然是12月31日,可以记为0C1F(1F=31);时间(不考虑秒)的最大表示数字是23:59,也可以参考日期的表示方式,选择不同的方案;读卡器编号,一般情况下一个单位也不会同时具有65535台读卡设备;卡号,这里卡号一般可以用两个字节表示,如果单位人数较多(超过65535),也可以使用四个字节表示,卡号的意义可以标识一个人,也可以标识单位内的一个部门等。

0x04.2试错法


试错法就是针对一些不明意义的字节(可能是校验字节),通过修改已知意义的字节来确定其关联性,找出不明意义字节的计算方法。 数据比对法,有时并不能分析出所有数据块的数据,这时可以考虑试错法来确定隐晦数据和哪些字段有关联,譬如下面的案例: 卡片只有0号扇区有数据:

43 9A ** ** ** ** 04 00 46 BA 14 12 51 10 03 10 第0段 0C 0D 0C 11 00 00 4A 3D 00 2D 00 00 00 01 00 47 第1段 37 0B BC E4 01 C2 00 00 0E A6 02 7D 08 1D 05 60 第2段 11 01 ** ** ** ** FF 07 80 69 FF FF FF FF FF FF 第3段

第0段为厂商写死的UID,不可修改,经过多次信息收集发现第1段的数据是不变的,变化的只有第二段,经过比对法,发现第1段的4A 3D是卡号,第2段的01 C2是本次消费金额,0E A6是余额,027D是消费和充值次数,081D是日期,到此,第2段中还有前四个字节以及最后两个字节的意义不明。 下面通过试错来定义各个字节的意义 尝试直接修改K1余额,读卡会失败,于是认为刷卡消费过程存在验证,余额和消费金额并不能构成验证对,所以认为验证信息在意义不明的6个字节内。 只修改消费金额也会导致读卡失败。 尝试使用K2的值整体替换K1的第2段,结果读卡依然失败。 最后尝试使用K2的值,整体替换K1的第1和第2段,等价于复制卡片,终于读卡成功了。 通过以上几步,可以确定消费读卡器在进行扣钱之前,会先校验卡片的正确性,校验值和余额、消费金额以及第1段中的数据都有关联。为了进一步定位信息,做出如下试错计划:

1、修改卡号,确认卡片是否可正确识别; 2、逐个修改第2段中已知意义的字节,确认卡片是否可正确识别,排除与校验无关的字节 3、对第2段中不明意义的6个字节逐个修改,确认卡片是否可正确识别,排除非校验字节 4、对第1段中的3个不明意义的字节逐个修改,确认卡片是否可正确识别 本质是就是对所有数据字节进行试错,排除与校验无关的字节! 通过以上过程缩小与校验相关的字节,再结合比对法中找出的已知意义的字节,从而确定不明意义字节的意义和校验算法。 由于刷卡条件限制,以上案例尚未破解完成,试错法也有待该案例进一步验证。

0x05攻击方式


复制 改写

0x06卡片防护


破解和防护是一对冤家,既然M1卡这么容易被破解,那有没有合适的防护方法呢?上一小节中提到的校验案例就算是一个很小的防护手段,但是依然存在很大被破解的风险。 为了降低水卡和饭卡被破解的风险,同时又不增加替换M1卡的成本,可以完全加密数据字段,基于密钥和算法保密性,保证即使可以通过验证攻击获取到M1卡中的数据,黑客也无法快速判断各个数据字段的意义,从而无法完成余额修改! 如果所有数据再与一个2字节的密钥进行异或处理,这时就无法简单的通过比对法判断出哪些字节是余额、哪些是消费金额,进一步降低了破解风险。当然针对密钥可以设计一套动态密钥方案,效果类似支付宝令(需要考虑如何处理长期不使用的卡片),而加密算法可以选择更加复杂的对称加密算法,只要保证不会对消费刷卡机造成过大延迟即可。

小结


有些可能防护,可使用cuid fuid 卡

参考

	freebuf  
	wooyun  
	http://www.proxmark.org 
Written on November 11, 2016