在这篇文章中,我描述了为什么廉价的磁条阅读器不能读取所有的磁条,只能读取信用卡和借记卡。这并不能帮助了解酒店钥匙卡上的数据,而这正是我真正想要知道的。我没有特意地去购买更好的阅读器,而是选择了打开廉价的磁条阅读器,略作探索,找到了一种从酒店钥匙卡读取原始数据的方法。这些数据意味着什么,仍然是个谜,因此在某个时候我可能会发布文章的第二部分。
关于我的磁条阅读器
我在2017年以11.85英镑购买了以下阅读器:
来自eBay的廉价阅读器
它通过USB连接,被检测为键盘。如果你通过阅读器刷信用卡/借记卡,那么文本编辑器就会像得到输入指令一样显示来自磁条的相应数据。如果你当时没有打开文本编辑器,你将看不到磁条上的任何信息。
它在Windows和Linux下都能正常工作,但仅适用于信用卡/借记卡。当我刷酒店钥匙卡时,我什么数据都没有得到。
为什么不换一个阅读器?
我本可以采取一些不同的(毫无疑问更好的)方法来实现这个项目,找一个更好的磁条阅读器就是其中一种选择。通过谷歌搜索来更好地了解酒店磁条无疑是最有成效的方法,但可能会降低一些我们解决问题的能力。当被卡住时,我总是可以通过谷歌搜索来解决。
我投资了一台MSR605X读写器。我之前没有使用过它,但它能够做原始读取。我可能会在以后的文章中对它进行介绍。
为廉价的阅读器做好计划
我认为廉价的阅读器中的磁读头几乎肯定能够从酒店钥匙卡或任何其他带有磁条的卡中读取数据。但实际上,它们只能读取支付卡数据。如果我可以在阅读器内的正确位置探测电子信号,我应该能够看到磁条上的1和0代码信息。
阅读器内的磁读头
我只有一个模糊的计划,当然不会是阻力最小的道路,但最终会有成效……
探索模拟信号
我有两种工具可以使用(这是一个基于家庭的项目,而不是基于办公室的项目):
l 廉价的手持式示波器(Sainsmart DS202)
l Saleae Logic逻辑分析仪
我很快意识到,可以把探头连接到读头上,上面有7个连接点。
读头背面的连接点
如果将读头直接连接到我的示波器上,我就可以在刷卡时看到模拟信号。最终,我希望用这个信号做一些事情来获取我想要的数据。
将读头直接连接到示波器上
我尝试将这7个探测点以不同的组合连接到我的示波器,但根本没有发现任何信号。也许是信号太弱了,或者(回想起来)我做的探测工作还不到位。
至此,我只能在去谷歌搜索更多关于芯片的信息了。它有一个2倍运算放大器和一个1倍模拟比较器:
l 2xLM2902DG(运算放大器)
l 1xLM2901DG(模拟比较器)
2倍运算放大器
模拟比较器(左),STM32微控制器(右)
这些芯片负责放大来自读头的信号。因此,如果连接到每个输出,我可能会看到一个信号,我可以用它来确定磁条上的数据。为此,我通过使用数据表来识别每个芯片的输出引脚。
2倍运算放大器的输出峰值为0.5-0.6v,使用我的示波器可以轻松查看,但我无法将其提供给我的逻辑分析仪。我需要大约3v的峰值。信号看起来也很没有规律,不是我希望的方波。
模拟比较器的输出正是我所追求的。一个不错的3或4v的峰值方波,仅在我刷卡时出现。这时,比较器有4个输出,其中一个从未发出信号,对于可以读取3轨磁条的读头来说,这似乎是合理的。是时候将它提供给逻辑分析仪,并开始计算由0或1构成的信号的内容了……
计算信号的内容
到目前为止,进展非常快。这正在形成一个有趣的项目。
这是Saleae Logic软件中比较器的输出:
通过逻辑分析仪查看比较器输出
请注意,我们只看到1个方波,而不是3个。这是因为这个特定的钥匙卡在3个轨道中的只有1个有数据。
所以,我们只有一个信号要分析,但我们还没有计算出信号的内容。
1992年的Phrack37给了我们帮助:
关于1和0如何在磁条上编码的ASCII解释
本质上0和1在编码时都是相同的长度。只是1改变了状态,而0没有改变状态。注意,0可以是高的或低的。
我没有仅通过观察来解码1和0,而是编写了一个Python脚本,它解析了逻辑分析仪中导出的数据并转储了1和0。以下是导出为CSV时“Logic”(Saleae软件)使用的格式:
从Saleae的Logic软件导出CSV格式
由于数据的波特率不是常量,因此编写Python代码很难。它取决于钥匙卡划过读头的速度。在编写代码时,我因为一些错误而走了弯路,但最终找到了一个有效的解决方案。
这是一个散点图,所显示的方波脉冲的持续时间并没有预期的两个值。相反,可以看到各种范围的值。它仍然可以从1(短脉冲,蓝色/紫色点)到0(长脉冲,绿点),见下图(上)。每个连续脉冲与最后一个脉冲的比率是从1到o的,见下图:
图表显示脉冲持续时间(delta)需要多少值,而不是预期的两个值
字节/字符
正如在phrack论文中提到的,信用卡使用2个轨道,其中一个字符由5位(4位+ 1个奇偶校验)组成,另一个字符由7位(6位+ 1个奇偶校验)组成。
我花了很多时间来编写信用卡解码器。部分原因是因为我需要确定我正确读取了1和o,另一部分原因是因为我认为我需要代码来查看酒店钥匙卡中是否使用了相同的字符类型。
对此进行编码的挑战之一是需要知道数据的开始位置和前导码何时结束。似乎“Sentinel ”命令可用于标记数据的开始/结束。这些是特殊字符(位模式),读者可以在条带的开头和结尾查找…然后它才会有意义。这就是阅读器只能用于信用卡的原因:固件正在寻找信用卡使用的标记。它无法解码酒店钥匙卡,因为数据的开始或结束位置并不明显或数据没有构成一个什么进程。此外,可能缺乏有效的纵向冗余校验(LRC)。
识别酒店钥匙卡磁条上的字符
我在酒店钥匙卡的磁条上运行了信用卡代码,看看是否有所有5位或所有7位的奇数奇偶校验。不幸的是,没有。这可能是廉价的磁条阅读器失败的另一个原因。
然后我对1和0进行了一些频率分析。由于很多5位和7位的值都有自己的特点,我在信用卡磁条上看到了它们各自对应的内容。7位磁条上有20个空格。因此,使用频率分析,我应该能够猜测到正在使用7位字符。
通过将一些酒店钥匙卡数据分成8位模式,我们注意到1和0的相同字符串发生的次数比预期的要多得多。所以我的猜测是,酒店钥匙卡使用了8位字符。
下面是我的Python脚本的一些输出样本:
l 原始位
l 字符串(带十六进制转储),如果使用5位、6位、7位或8位字符,则是正确的。虽然“正确性”取决于奇偶校验、位顺序以及位值映射到的字符集。这里有很多错误和改进的空间
l 检查字符内的奇数/偶数奇偶校验
l 寻找常见字符的频率分析,用于改变字符长度
[+] Parsing file export .csv
[-] Flips in channel 0: 3
[-] Flips in channel 1: 1652
[-] Flips in channel 2: 3
[+] Analysing swipes [-] Channel 0:
[-] Channel 1:
[-] Swipe 0: 693 bits
[-] Swipe 1: 701 bits
[-] Channel 2:
[+] Creating Plots [-] creating plots with dimensions (1637, 1637), (1637, 1637)
[-] saving plot to file : export .csv-plot-channel-1.png
----------------------- CHANNEL 1 SWIPE 0 ----------------------- [+] Length (bits) = 266 (%5 = 1, %6 = 2, %7 = 0, % 8= 2) [+] Data: 10100110001001100010011000100110001001100010011000100110001001100010011000100110001001100101011011100110101001001101100110100110001001100111110110111100111101100010000000100110011001101100001010010101001001001110110100000111001101011101100001100101101000101010011001 [+] Strings: [-] 5 bit: 5398621<4398621<43:>62<3539<;><=409<615549=1>6>36=1:6
[-] length: 53
[-] hex:
35 33 39 38 36 32 31 3c 34 33 39 38 36 32 31 3c 5398621<4398621<
34 33 3a 3e 36 32 3c 33 35 33 39 3c 3b 3e 3c 3d 43:>62<3539<;><=
34 30 39 3c 36 31 35 35 34 39 3d 31 3e 36 3e 33 409<615549=1>6>3
36 3d 31 3a 36 6=1:6
[-] 6 bit: E(1C&,9RD(1CFM92;+1S;G;"D,-**DMPLW8M4, [-] length: 38
[-] hex:
45 28 31 43 26 2c 39 52 44 28 31 43 46 4d 39 32 E(1C&,9RD(1CFM92
3b 2b 31 53 3b 47 3b 22 44 2c 2d 2a 2a 44 4d 50 ;+1S;G;"D,-**DMP
4c 57 38 4d 34 2c LW8M4,
[-] 7 bit: %.. #...2$..#&-.....3.'..$....$-0,7.-.
[-] length: 37
[-] hex:
25 08 11 23 06 0c 19 32 24 08 11 23 26 2d 19 12 %.. #...2$..#&-..
1b 0b 11 33 1b 27 1b 02 24 0c 0d 0a 0a 24 2d 30 ...3.'..$....$-0
2c 37 18 2d 14 ,7.-.
[-] 8 bit: .&&&&&&&&&&V....&}.. &f..$..5.e..@ [-] length: 34
[-] hex:
a6 26 26 26 26 26 26 26 26 26 26 56 e6 a4 d9 a6 .&&&&&&&&&&V....
26 7d bc f6 20 26 66 c2 95 24 ed 07 35 d8 65 a2 &}.. &f..$..5.e.
a6 40 .@
[+] Parity for 5 bit chars: odd: False, even: False)
[+] Parity for 6 bit chars: odd: False, even: False)
[+] Parity for 7 bit chars: odd: False, even: False)
[+] Parity for 8 bit chars: odd: False, even: False)
[+] Frequency analysis for potential char lengths:
[-] 5 bits:
10011: 5
11000: 4
01100: 4
00110: 4
00100: 4
[-] 6 bits:
100110: 5
100010: 5
011000: 5
011001: 4
001001: 4
[-] 7 bits:
1000100: 3
0010011: 3
1101100: 2
1100010: 2
1011010: 2
[-] 8 bits:
00100110: 12 < common 8-bit patter implies 8-bit chars?
10100110: 3
...snip... |
上面的数据来自于实际的酒店钥匙卡(尽管酒店后来改用了RFID锁)。
我还开始研究XORing、旋转字符(rot13格式)、位序和偏移的整个位流(以防止我在把字符组合放到错误的位置)。不过,到目前为止这些都还没有成功。
这就是我所得到的。如果我能解码钥匙上的任何数据,我一定会再次发布。我希望能看到我的房间号和结账日期。但同样,一个不以明文形式出现的加密字符串也不会让我惊讶——这是我在某些卡片上所看到过的。
结论
以廉价和耗时的方式来做事也可以很有趣——这也是练习编写代码、了解matplotlib以及逻辑分析仪的好机会。
进一步阅读/观看
如果你想了解更多有关磁条的信息(在它们变得完全过时之前),请查看:
Samy Kamkar的magspoof工具(视频链接)–如果你需要你的计算机通过磁头来传输恶意数据,可能会很有用。
DEF CON 24-Weston Hecker –黑掉酒店钥匙和销售点系统
我很受这些项目的启发。
审核人:yiwang 编辑:边边