Uconnect系统

优质
小牛编辑
135浏览
2023-12-01

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 的软件开发工具来开发和调试这些系统。