Uconnect系统
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系统的引导程序。虽然很有意思,但是我们并没有深入地检查这个引导程序。因为我们的目标是物理控制目标车辆,所以头单元中的其他部分更具相关性。
IFS:IFS中包含了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上并没有多少有趣的数据,所以我们就不深入了。
Example: /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,并且如上所述,用于跨进程通讯。进程之间的交互如下:
图-http://dbus.freedesktop.org/doc/diagram.png
综述
这里只有两个总线值得一提:系统总线,守护进程和系统服务主要都注册到这个总线;会话总线,为用户应用保留的一个总线。
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 的软件开发工具来开发和调试这些系统。