Mifare1卡,又称M1卡或者S50卡。虽然安全漏洞已经被爆出好几年了,但还是非常广泛地作为电子钱包应用于各种消费系统中。一个最典型的例子就是各个单位和高校的水卡、饭卡等。之前有很多前辈讲了如何利用漏洞读出并修改卡中的数据,我在这里就不再赘述了(其实是我懒→_→)。在此我利用现有的审计软件和读卡器,针对用作电子钱包的M1卡的内部数据格式进行分析。
所用工具如下:
1.读卡器ARC122U 2.mfocGUI(win平台,我找了一个汉化版的) - 用来读卡 3.RFID RadioEye(win平台,by Lenny) - 用来写卡 4.用来读写二进制.dump文件的文本编辑器
我的手中有三种M1卡,分别是开水卡、饮水机卡和太阳能水卡,而且也刚刚好是三种不同的数据格式。我将按照分析数据由易到难的顺序来给大家介绍。 如果你不喜欢看过程,请直接看粗体黑字。
0×02 开水卡数据分析
首先,用mfocGUI读出卡中的数据,得到的dump文件存储余额数据的sector如下(假设它们分别叫block0~block3):
0488 8888 0000 0000 0000 0000 0000 4f2e 5d0d 0000 a2f2 ffff 5d0d 0000 11ee 11ee 5d0d 0000 a2f2 ffff 5d0d 0000 12ed 12ed 7072 8e8e 8c8c ff07 8069 7072 8e8e 8c8c
block0是根据卡的uid通过某种算法生成的卡号(这是我根据读的多张卡猜的,并没有验证过);block3是Sector Trailer,控制整个sector的读取权限;block1、block2存储了卡的余额,这是我们要关注的两个block。为了防止在读写数据时发生未知的错误,它们的余额数据完全相同。
我的这一张开水卡,使用了 M1卡标准电子钱包应用的数据格式 ,如下图(截自M1卡datasheet):
0~3字节和8~9字节是余额,4~7字节是余额的取反,后面的12~15字节我不太懂,只知道读卡过程中这4Byte的数据不变化。
要注意的是,余额数据在其中是“倒序”存储的。所以上图中的开水卡中的余额是这样读的——0x00000d5d,转换成十进制为3421,即卡中余额为34.21元。
假如我们要修改卡的余额变成45元,对应的十进制为4500。转换为十六进制数为0×00001194,则0~3字节的数据是94110000。其他字节按此数据修改即可。
按照此种数据格式,卡中能存储的最大余额为0xffffffff,大概是4200多万元吧。是不是在想改了之后大概可以用一辈子了o(∩_∩)o ?too naive!我这里的卡充值时的金额为50元,只要你把卡里面的余额改成大于50,读卡机就不!识!别!
饮水机卡中的数据比较特别,没有采用标准的电子钱包数据格式而且加了校验位。
下面是存储余额的sector的数据:
00ca 0901 0000 0000 0000 0000 0140 2338 cf01 0000 0000 1311 0600 0000 0200 5a56 cf01 0000 0000 1311 0600 0000 0200 5a56 3847 fd12 bd08 7f07 88da 32c0 fe32 b864
block1和block2的数据完全相同。 我们假设block1(也是block2)中的16个字节分别为B0~B15。经过几次刷卡之后发现,只有B0、B1、B15的数据会发生变化(对饮水机卡的研究已经过去很久了,数据都不在了,而我也懒得再出门去刷卡,请大家见谅哈)。经过多次对比卡机上显示的余额,初步确定B0、B1是余额数据(后来觉得B2B3应该也是余额数据的一部分)。然后猜测B14、B15是校验位,当然这是错的→_→。我的Sublime 3自动将2个字节放在一起显示,就像上面给的数据一样。
受此影响,我想当然的认为校验的时候是2个字节一组,于是发现校验位的值始终在0x5a00~0x5aff变化,而余额是一直减少的,试了相加、异或甚至MD5,都百思不得其解┬_┬。于是到这里就算中断了,过一段时间后再看了看数据,发现0x5a是01011010,突然就想试试按字节校验(我也不知道为什么会这么想),结果还真是这样⊙0⊙。正确的数据结构是这样的:
B0~B3是余额,B14固定为0x5a,B15为B0~B14求和后舍去进位的值,猜测B6开始的131106应该是卡首次投入使用的时间 (饮水机卡是循环使用的)。以上面的数据为例,余额是4.63元。对B0~B14求和是0×156,因此B15是0×56。
这种加了校验的数据相对来说还是比较难分析的,但也并不安全。
0×04 太阳能水卡数据分析
太阳能卡是在有余额和校验位的基础上又增加了其他数据。下面是存储余额数据的block连续3次刷卡的记录:
020d 0000 2c06 5c09 1500 2c06 4900 5a90 f60c 0000 2f06 5d09 1500 2f06 4a00 5a8b ea0c 0000 3206 5e09 1500 3206 4b00 5a87
从以上刷卡数据中,结合饮水机卡中的分析,经过计算可以确定:
2、B13B12和B7B6的数据每次刷卡会加一,所以我们猜测其中一个数据可能是刷卡次数,取第一行刷卡的数据,0x095c(B7B6)是十进制2396,不可能是这么多,所以 B13B12是刷卡次数 ,而 B7B6的初始值为 0x095c-0×0049=0×0913 ;
3、 B8B9的值固定不变为0×1500 ,试试看 B6B7的初始值和B8组合的结果——是130915 , 觉得熟悉吗?是的,是日期(好机智的设计有木有!)。
4、B4B5和B10B11的值是相同的,而它们也在增加。你发现了吗?它们每次增加3,也就是刷卡次数的3倍。据此我们能够计算出B5B4的初始值=0x062c-3*0×0049=0×0551。
现在,所有的数据都搞清楚了,我们要改写它的数据,让它的余额变成100元,也就是刚刚买到时候的余额。可以构造出这个block的数据为:
1027 0000 5105 1309 1500 5105 0000 5a6e
我们把它写入到卡中。刷刷看:
Bingo!
以上,我介绍了三种用作电子钱包的卡的数据结构。只要能够读出M1卡的数据,被攻击利用是很简单的。以我拙见,针对用作电子钱包的M1卡的攻击有三个层次:
1、重放。把卡中数据读出来,用完了再将保存下来的数据写进去,可以重复利用被攻击的卡; 2、修改。如本文中所述,分析卡的数据结构,达到随心所遇修改卡中余额的目的; 3、创造。破解根据卡的uid生成block0、密钥A和密钥B的算法,从而能够使任意白卡变成可被系统识别的卡片,这个难度较大,但是一旦成功危害极大,将会可以任意出售自己伪造的卡,且不能通过购卡记录追踪到自己(因为自己制作的卡根本不是官方发行的)。
那么是不是就完全没有办法了呢?如果M1卡的所有sector都使用了非默认的AB密钥,mfocGUI好像就无能为力了(这是在网上看到的,手边没有这样的卡,没有证实),但不排除有其他工具可以搞定全加密卡的可能。最好的方法当然是不要再用M1卡了。
第一次投稿,如果有不对的地方,还请大家指正。