RFID安全:一次M1卡(洗澡卡、开水卡)破解历程

  • A+
所属分类:硬件安全
免责声明:本站提供安全工具、程序(方法)可能带有攻击性,仅供安全研究与教学之用,风险自负!

写在前面:

2014年的12月,由于某次巧合,逛到了Freebuf上关于RFID的文章,然后自己整个人简直要疯了,各种谷歌有关文章……嘿嘿,然后反复反复看(因为我是小白),整理了下大概有以下几处文章比较集中:

1.Freebuf上RFID相关文章

2.Bobylive博客上RFID相关文章

3.Flylai博客上RFID相关文章

又经过了一个寒假的纠结,终于决定入手了ACR122U,只是到手后机器看上去确实感觉比¥180要廉价,看图就明白了:

不过这个机器的价钱对初级的RFID研究算是合适的。

好吧,跑题了……

0×01密钥的获取&可行性分析

‍楼上几位大牛的M1卡的密钥破解过程非常详细,我写不出那么细致的文字,就在此略过吧。

在这次实验中:我手头有两张M1卡,洗澡卡(xzk)和开水卡(ksk),在对卡片进行破解的前后应该注意的是卡片的数据是离线的,即机器是没有联网的。

这是洗澡卡的读卡器的电源:

只有12V2A的两根电源线的输出,可以放心了。

开水卡的机器让我有些纠结,两台机器后只有一根很粗的漆包线(不敢扯出来看,左手边一个摄像头),不确定里面是否包含数据通信,纠结了几天后想到了如下的办法测试:

0×02开水卡数据的分析

这里先分析开水卡因为校验的算法相对洗澡卡的实在太简单了,囧

分析:

 40.00元对应十六进制0FA0校验位EC,0FxorA0xorEC=43

 34.48元对应十六进制0D78校验位36,0Dxor78xor36=43

结论:

 校验位:余额转化成十六进制后异或,再与0×43异或。

0×02洗澡卡数据的分析

首先对几组数据进行分析

经过简单对比可以得到如下结论

但是到这里我几乎要放弃了,因为根本找不出得到首位与末尾字节的异或算法,之后的三天每天就拿点时间出来比较计算,对比数据每次的变化规律,于是发现了如下规律:

可以发现方框里每次变化量的和为0,接下来用A0、A1、A3……来表示每一字节的数据

经过推算,可以发现A1+A9+A15=E4

为了判断这是否是一个固定值,就拿同学甲的数据进行对比

可以发现A1+A9+A15=114

‍再拿同学乙的数据对比

可以发现 A1+A9+A15=1E4

这里发现了点端倪:

‍1.三组结论的末尾都是4;

‍2.同学甲与同学乙的结果区别在于114与1E4,而两张卡的UID首字节是ED与1D;

‍3.如果这个结果与UID首字节相加呢,以上的三组数据结果 A1+A6+A9+A15分别为 ‍ 

                101  ←智商有限,只能先下假设与 A11=04 有关
        201  ←A11=02
        201  ←A11=02 到这里可以下一个定论了,当A11是02时,可以由一下公式得到数据的末位

 A15=0201-A1-A6-A9

接下来就是判断首位A0的计算方法了,这个数据找不出与计算末尾一样的变化规律,那么就进行各种异或运算吧:

从发现的第一个规律可以看出前后的计算校验的方法有些类似,那么就以中间的1D展开

这是甲乙两人都是6.61元时的数据情况,对A0和A6进行异或可以发现都是DF

接着进行无数次的尝试终于发现了上图中方框的各个字节进行异或运算的结果都是0

那么推出首位A0的计算公式为

 A0=A2xorA3xorA6xorA10xorA11

(简直要哭瞎啊,这是哪位程序猿写的啊)

0×03洗澡卡数据的伪造 

知道了算法下面就是验证的时刻啦,先来100的数据

8437102700C81D0000AEAC02005100FF  可行

8537102700C81D0000AFAD02005000FE  可行

2837102700C81D0000020002005000AB  不可行

为何不行呢

由于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  (^表示异或运算)

数据的分析破解工作就到此结束了,真心麻烦啊!

0×04交给电脑完成计算

这么坑爹的计算方法要是拿计算器按,再一个个填入MCT,浪费时间不说还容易算错。

‍于是打算交给电脑,自己只会vf(这个貌似帮不到忙),c语言(进行十六进制计算不方便)

‍然后百度了下最近眼熟的python,居然还有hex()函数,哈哈,现学现用啦。

第一次写python,for的用法还不熟,不会直接输出十六进制字符串,大牛们表喷,嘿嘿:

# coding: utf-8
A4 = 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此时验证是否大于0xFF
  a10 = 0xfe;
  a15 = 0x2ff - a1 - a6 - a10;        #A15校验位
else:                                 #A1此时验证是否小于0xFF
  a10 = 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("输入回车键退出"); 输入01600,得到数据

复制,写入卡片,去试验啦

0×05后记

银他妈第一次写文章,望各位捧个场呀^_^

  • 我的微信
  • 这是我的微信扫一扫
  • weinxin
  • 我的微信公众号
  • 我的微信公众号扫一扫
  • weinxin

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: