技术探讨“北京地铁收费系统算法漏洞”


bjykt


 

前几天网上广泛流传一个帖子:

网友“eycp”在乌云网上发布《北京地铁收费系统基础安全算法漏洞》一帖,称北京地铁收费系统基础安全算法存在漏洞,属于设计缺陷、逻辑错误。


 

按照该网友的说法,该漏洞

  1. 违反国家标准《CJ/T-166》,使用私自开发的签名算法,
  2. 由于未经测试便投入工程应用,
  3. 现发现强度不够,可以被完全破解”。
  4. 根据网友发布在网上的视频显示,在北京地铁站内,试验者曾购买了一张面值2元的单程地铁票,并利用NFC手机中app应用对单程地铁票进行修改余额操作,修改后的卡片拿到查询机上可以成功显示修改后新余额。

本人对上述描述持一定的怀疑态度!

这里从纯技术上来对这个事情可能性进行一个探讨,并不是说此事一定不可能成立,所以以下文章也许某些地方并不准确。

ul

北京地铁单程票是一个Ultralight卡,这种卡片共512位(64字节)的EEPROM,被划分成16页,每页4字节。如下图所示:

大小(位) 说明
1 96 UID区
2 32 一次可编程(OTP)区
3 384 用户读写区
总共:512 位(64字节)

其中,OTP被用于存储卡的序列号,该号码是在卡制造时写进去的,此后无法更新。用户读写区分为静态数据区和动态数据区两部分。整个用户读写区没有任何安全保护,可以被任意读写。

所以UL卡的安全性是由整个系统保证的。

具体流程是:

  1. 卡片在售卡机上出售时会根据用户选择的乘车时间、入出站点计算出金额(目前是固定2元),将此信息写入静态数据区和动态数据区,
  2. 为了确保数据为合法授权写入,系统端对应两个数据区分别有2个密钥:静态区密钥A和动态区密钥B,数据会先被写入静态区,
  3. 同时系统用静态数据和密钥A进行DES运算,生成静态区MAC;
  4. 接下来数据再写入动态区,系统用静态区MAC、动态区数据CRC32校验结果、UID、动态区密钥B等计算生成动态区MAC。
  5. 刷卡时闸机会用DES及相同的密钥进行数据验证,如果MAC相同则交易可以继续完成。

本文开头中的报道提到在破解中使用私有开发的签名算法,这里的描述很含混,从整个的安全机制来分析,私有开发算法应该指的是CRC32。

CRC32是什么呢?

CRC32是在数据传输过程中进行数据校验的一种散列函数。代码处理其实只需要几行,所以问题是:

  1. 再自行开发一个私有CRC32的意义何在?此处存有很大疑问!
  2. 同时这个私有CRC32是否经过实际检验也未可知,地铁公司是否确实这么做也有很大的疑问!
  3. 因为开发私有CRC32的代价肯定大于使用公开标准的公式,从成本上来说完全没有这个必要。
  4. 而且从地铁单程票的技术文档看也确实使用的标准CRC32,而不是私有定义的

那另一方面,如果使用的是标准的CRC32,原则上来说因为CRC32只有4字节,所以确实是存在一定的碰撞概率

这个问题其实有点和生日悖论类似,给定一个区间,至少需要选择多少个数,使得至少其中两个数相同的概率超过50%。如果两组不同的数据生成了相同的CRC32,那么MAC也会相同,而闸机只根据验证MAC的对错授权交易,他并不能判断数据是被授权改写还是被人非法篡改的。但即便是存在着一定的碰撞概率,理论上也不会有很大问题,因为闸机除了校验MAC外,还会进行很多数据的判断,比如时间、站点等,一旦某个数据错误,交易也会无法完成。

所以为了可以有效的篡改数据要必须满足两个条件,

  • 一是能有效的修改相应的数据字段(就目前来说,比如将过期的单程票改为有效),
  • 同时必须修改其他某些不影响交易的非关键数据位来使得CRC32保持不变,从而使MAC可以被闸机校验通过。

而这种方法不能确保修改到无用数据后可以保证CRC32值维持不变。另外,根据目前网上已有的代码进行分析并亲自尝试,通常保持CRC32校验值不变的方法是根据目的值和原始值逆向计算出需要在原值后面多填充的几字节数据,而这样做就违背了地铁单程票规范中按固定数据格式计算CRC32的要求。

综合以上分析,本人认为“北京地铁收费系统的算法漏洞”一文所介绍的内容中对CRC32算法的缺陷攻击的思路虽然基本是可行的,但结合北京地铁的实际情况能真正完成实际充值消费应该难度很大,当然如果有更多的信息或线索也许有助于我们能进一步分析和判断从而得出最终结论。

 

Leave a comment

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>