作者/坂田银时,属FreeBuf原创奖励计划文章,未经许可禁止转载
免责声明:本站提供安全工具、程序(方法)可能带有攻击性,仅供安全研究与教学之用,风险自负!
‍‍
写在前面:‍‍
2014年的12月,由于某次巧合,逛到了Freebuf上关于RFID的文章,然后自己整个人简直要疯了,各种谷歌有关文章……嘿嘿,然后反复反复看(因为我是小白),整理了下大概有以下几处文章比较集中:
1.Freebuf上RFID相关文章
2.Bobylive博客上RFID相关文章
3.Flylai博客上RFID相关文章
又经过了一个寒假的纠结,终于决定入手了ACR122U,只是到手后机器看上去确实感觉比¥180要廉价,看图就明白了:
<img src="http://image.3001.net/images/20150315/14263984344305.png!small" title="122u.png" data_ue_src="http://image.3001.net/images/20150315/14263984344305.png!small" width="690" height="548" border="0" hspace="0" vspace="0" style="width: 690px; height: 548px;"/></p>
不过这个机器的价钱对初级的RFID研究算是合适的。
好吧,跑题了……
0×01密钥的获取&可行性分析
‍‍楼上几位大牛的M1卡的密钥破解过程非常详细,我写不出那么细致的文字,就在此略过吧。‍‍
在这次实验中:我手头有两张M1卡,洗澡卡(xzk)和开水卡(ksk),在对卡片进行破解的前后应该注意的是卡片的数据是离线的,即机器是没有联网的。
这是洗澡卡的读卡器的电源:
<img src="http://image.3001.net/images/20150315/1426400312458.png!small" title="xzkdc.png" data_ue_src="http://image.3001.net/images/20150315/1426400312458.png!small" width="418" height="542" border="0" hspace="0" vspace="0" style="width: 418px; height: 542px;"/></p>
只有12V2A的两根电源线的输出,可以放心了。
开水卡的机器让我有些纠结,两台机器后只有一根很粗的漆包线(不敢扯出来看,左手边一个摄像头),不确定里面是否包含数据通信,纠结了几天后想到了如下的办法测试:
<img src="http://image.3001.net/images/20150315/14264017707911.png!small" title="kskfx.png" data_ue_src="http://image.3001.net/images/20150315/14264017707911.png!small" width="690" height="455" border="0" hspace="0" vspace="0" style="width: 690px; height: 455px;"/></p>
0×02开水卡数据的分析
这里先分析开水卡因为校验的算法相对洗澡卡的实在太简单了,囧
<img src="http://image.3001.net/images/20150315/14264021175642.png!small" title="Screenshot_2015-03-15-14-11-09~01.png" data_ue_src="http://image.3001.net/images/20150315/14264021175642.png!small" width="690" height="770" border="0" hspace="0" vspace="0" style="width: 690px; height: 770px;"/></p>
分析:
40.00元对应十六进制 0FA0 校验位EC,0F xor A0 xor EC = 43
34.48元对应十六进制 0D78 校验位36,0D xor 78 xor 36 = 43
结论:
校验位:余额转化成十六进制后异或,再与0×43异或。
0×02 洗澡卡数据的分析
首先对几组数据进行分析
<img src="http://image.3001.net/images/20150315/14264031902879.png!small" title="xzkbj.png" data_ue_src="http://image.3001.net/images/20150315/14264031902879.png!small" width="690" height="190" border="0" hspace="0" vspace="0" style="width: 690px; height: 190px;"/></p>
经过简单对比可以得到如下结论
<img src="http://image.3001.net/images/20150315/14264040848750.png!small" title="xzkjl1.png" data_ue_src="http://image.3001.net/images/20150315/14264040848750.png!small" width="690" height="278" border="0" hspace="0" vspace="0" style="width: 690px; height: 278px;"/></p>
但是到这里我几乎要放弃了,因为根本找不出得到首位与末尾字节的异或算法,之后的三天每天就拿点时间出来比较计算,对比数据每次的变化规律,于是发现了如下规律:
<img src="http://image.3001.net/images/20150315/14264048828549.png!small" title="xzkjl2.png" data_ue_src="http://image.3001.net/images/20150315/14264048828549.png!small" width="690" height="264" border="0" hspace="0" vspace="0" style="width: 690px; height: 264px;"/></p>
可以发现方框里每次变化量的和为0,接下来用A0、A1、A3……来表示每一字节的数据
<img src="http://image.3001.net/images/20150315/14264052399514.png!small" title="QQ拼音截图未命名.png" data_ue_src="http://image.3001.net/images/20150315/14264052399514.png!small" width="690" height="57" border="0" hspace="0" vspace="0" style="width: 690px; height: 57px;"/></p>
经过推算,可以发现 A1+A9+A15=E4
为了判断这是否是一个固定值,就拿同学甲的数据进行对比
<img src="http://image.3001.net/images/20150315/14264066029082.png!small" title="xzkjl3.png" data_ue_src="http://image.3001.net/images/20150315/14264066029082.png!small" width="690" height="152" border="0" hspace="0" vspace="0" style="width: 690px; height: 152px;"/></p>
可以发现 A1+A9+A15=114
‍‍再拿同学乙的数据对比‍‍
<img src="http://image.3001.net/images/20150315/14264068537056.png!small" title="xzkjl4.png" data_ue_src="http://image.3001.net/images/20150315/14264068537056.png!small" width="690" height="152" border="0" hspace="0" vspace="0" style="width: 690px; height: 152px;"/></span></p>
可以发现 A1+A9+A15=1E4
‍‍这里发现了点端倪:‍‍
‍‍1.三组结论的末尾都是4;‍‍
‍‍2.同学甲与同学乙的结果区别在于 114与1E4,而两张卡的UID首字节是 ED与1D;‍‍
‍‍3.如果这个结果与UID首字节相加呢,以上的三组数据结果 A1+A6+A9+A15分别为 ‍‍
- 101 ←智商有限,只能先下假设与 A11=04 有关201 ←A11=02201 ←A11=02
复制代码到这里可以下一个定论了,当A11是02时,可以由一下公式得到数据的末位
A15= 0201-A1-A6-A9
接下来就是判断首位A0的计算方法了,这个数据找不出与计算末尾一样的变化规律,那么就进行各种异或运算吧:
从发现的第一个规律可以看出前后的计算校验的方法有些类似,那么就以中间的1D展开
<img src="http://image.3001.net/images/20150315/14264089586307.png!small" title="xzkjl5.png" data_ue_src="http://image.3001.net/images/20150315/14264089586307.png!small" width="690" height="132" border="0" hspace="0" vspace="0" style="width: 690px; height: 132px;"/></p>
这是甲乙两人都是6.61元时的数据情况,对A0和A6进行异或可以发现都是DF
接着进行无数次的尝试终于发现了上图中方框的各个字节进行异或运算的结果都是0
那么推出首位A0的计算公式为
A0= A2 xor A3 xor A6 xor A10 xor A11
(简直要哭瞎啊,这是哪位程序猿写的啊)
0×03 洗澡卡数据的伪造
知道了算法下面就是验证的时刻啦,先来100的数据
8437102700C81D0000AEAC02005100FF 可行
8537102700C81D0000AFAD02005000FE 可行
2837102700C81D0000020002005000AB 不可行
为何不行呢
<img src="http://image.3001.net/images/20150315/1426409843519.png!small" title="xzkjl6.png" data_ue_src="http://image.3001.net/images/20150315/1426409843519.png!small" width="372" height="116" border="0" hspace="0" vspace="0" style="width: 372px; height: 116px;"/></p>
由于A10太小,造成造成A1+19+A15=101,而不是201
那么就让A9=FF吧
D537102700C81D0000FFFD02000000AE 可行
接下来又发现问题了,如果余额转换成十六进制后,
A2与A3的和即A1大于FF呢,那不造成了要向A0进位?
A10与A11的和即A9大于FF呢,那不造成了要向A8进位?
‍‍结果A1+A6+A9+A15=301,这么纠结…………‍‍
为了避免A11的影响,把公式里的A9换成A10吧,对应的公式为
当A2+A3大于1FF时,A15= 2FF-A1-A6-A10
当A2+A3小于1FF时,A15= 1FF-A1-A6-A10
A0 = A2 ^ A3 ^ A6 ^ A10 ^ A11 (^表示异或运算)
数据的分析破解工作就到此结束了,真心麻烦啊!
这么坑爹的计算方法要是拿计算器按,再一个个填入MCT,浪费时间不说还容易算错。‍‍
‍‍于是打算交给电脑,自己只会vf(这个貌似帮不到忙),c语言(进行十六进制计算不方便)‍‍
‍‍然后百度了下最近眼熟的python,居然还有hex()函数,哈哈,现学现用啦。‍‍
‍‍第一次写python,for的用法还不熟,不会直接输出十六进制字符串,大牛们表喷,嘿嘿:‍‍- # coding: utf-8A4 = A7 = A8 = A12 = A14 = "00"; A11 = "02";a11 = 0x02;a6 = 0x4b; IDnM = raw_input("请输入学号与金额(例如:01 200):");ID = IDnM [0:2]; Money = IDnM [3:]+"00"; #字符 Decmoney = int(Money,10); #十进制 Hexmoney = hex(Decmoney); a2 = int(Hexmoney[4:6],16); #十六进制a3 = int(Hexmoney[2:4],16); #十六进制a1 = a2 + a3;a5 = a1 ^ 0xff; if a1 > 0xff: #A1此时验证是否大于0xFFa10 = 0xfe;a15 = 0x2ff - a1 - a6 - a10; #A15校验位 else: #A1此时验证是否小于0xFFa10 = 0xec;a15 = 0x1ff - a1 - a6 - a10; #A15校验位a0 = a2 ^ a3 ^ a6 ^ a10 ^ a11; #A0校验位a9 = a10 + a11; a13 = a9 ^ 0xff; print ID, "号当前金额为",IDnM [3:],"元"; print "10扇区对应数据为:";A0 = hex(a0)[len(hex(a0))-2:];A1 = hex(a1)[len(hex(a1))-2:];A2 = hex(a2)[len(hex(a2))-2:];A3 = hex(a3)[len(hex(a3))-2:];A5 = hex(a5)[len(hex(a5))-2:];A6 = hex(a6)[len(hex(a6))-2:];A9 = hex(a9)[len(hex(a9))-2:];A10 = hex(a10)[len(hex(a10))-2:];A11 = "02";A13 = hex(a13)[len(hex(a13))-2:];A15 = hex(a15)[len(hex(a15))-2:];data = A0+A1+A2+A3+A4+A5+A6+A7+A8+A9+A10+A11+A12+A13+A14+A15;data=data.replace("x","0").upper(); print data;f = open("card.txt","w"); #将数据写入同目录下的data.txt print >>f,data;f.close();raw_input("输入回车键退出");
复制代码输入01 600,得到数据
<img src="http://image.3001.net/images/20150315/14264117357016.png!small" title="QQ拼音截图未命名.png" data_ue_src="http://image.3001.net/images/20150315/14264117357016.png!small" width="324" height="139" border="0" hspace="0" vspace="0" style="width: 324px; height: 139px;"/></p>
复制,写入卡片,去试验啦
<img src="
ID
!small" title="52E968198B042F0323A7AA6534F349C0.jpg" data_ue_src="!small" width="690" height="388" border="0" hspace="0" vspace="0" style="width: 690px; height: 388px;"/></p>
0×05 后记
银他妈第一次写文章,望各位捧个场呀^_^
|