当前位置:   article > 正文

零成本入门车联网安全研究(二)_车联网安全入门

车联网安全入门

本文是《零成本入门车联网安全研究》系列第二篇,第一篇简单介绍了下车内网络的架构,让大家对车内ECU组网的方式有了最基本的了解。本文则在车内网络的基础上,部署了真实的网络业务——基于以太网的车辆诊断服务,该服务基于doip(Diagnose On IP)协议栈实现通用诊断协议UDS。本文相比于第一篇文章更具可操作性与可玩性,可操作性的点在于大家根据文章介绍的步骤,可以搭建好自己的实验环境;可玩的点在于,本实验会在开源项目的基础上,加入可实际利用的协议漏洞,通过漏洞利用能够模拟远程控制车辆。此外,本文在描述实验步骤的同时,还会穿插介绍一些相关基础,包括:

  • CAN网络基础
  • UDS协议基础
  • DoIP协议基础
  • 远程诊断的实现原理

等等。为了帮助大家更好地开始,有必要先介绍下实验环境。本次实验的系统使用ubuntu20.04模拟车辆边缘节点,节点上运行DoIPServer,win10模拟DoIP诊断仪,诊断仪包含DoIPClient,其中win10与ubuntu组成可相互通信的局域网,即DoIP诊断仪可以通过以太网连接DoIPServer。车内CAN网络通过linux vcan实现,边缘节点、ICSim及车内UDS节点均连接到CAN网络,车内UDS节点上运行UDSServer,该Server能实现基于CAN网络的UDS诊断。整体网络架构如下图所示:

 

基于如上部署,DoIP诊断仪能够通过以太网连接边缘节点,通过发送诊断协议包的方式,直接对边缘节点执行远程诊断。另外,因为车内UDS节点也实现了UDS协议,因此DoIP诊断仪可以发送诊断协议包至边缘节点,由边缘节点执行DoIP转DoCAN,将基于DoIP的诊断协议包格式转换为基于CAN的诊断包格式,发送至车内UDS节点。

另外,由于ICSim未实现UDS协议,因此DoIP诊断仪的数据包理论上是不会被转发至ICSim,但我们在DoIPServer中插入了一个漏洞,将不合法的DoIP数据包转发至CAN网络,这样通过构造,便可以使用DoIP诊断仪远程发送控制报文至ICSim,实现远程车控。

关于实验环境就介绍这么多,接下来上手配置。首先在ubuntu上安装虚拟CAN网络的工具:

  1. # 安装python can
  2. pip3 install python-can
  3. # 按照can-utils
  4. sudo apt-get install can-utils
  5. # 安装can驱动,设置can网络
  6. sudo modprobe can
  7. sudo modprobe vcan
  8. sudo ip link add dev vcan0 type vcan
  9. sudo ip link set up vcan0

设置完CAN网络后,通过ifconfig查看状态:

配置ubuntu与windows10的通信环境,在同一个局域网可以相互ping通即可,ip地址不必完全按照本文配置。

其中ubuntu的网络配置如下:

windows10的网络配置如下:

安装ICSim依赖工具:

sudo apt-get install libsdl2-dev libsdl2-image-dev can-utils

下载ICSim源代码,make编译ICSim,运行ICSim:

  1. git clone https://github.com/zombieCraig/ICSim.git
  2. cd ICSim
  3. make
  4. # 运行ICSim,绑定vcan0
  5. ./icsim vcan0

下载DoIPServer与DoIPClient源码:

git clone https://gitlab.com/rohfle/doip-simulator.git

下载uds-server并编译:

https://github.com/zombieCraig/uds-server.git

启动uds-server并绑定到vcan0,uds-server用于模拟车内uds节点:

./uds-server vcan0

接下来对doipserver做一些修改,用来转发UDS报文给uds节点,以及插入漏洞代码:

修改一:

  1. ~/study/vehicle/doip-simulator$ git diff lib/server.py
  2. diff --git a/lib/server.py b/lib/server.py
  3. index 16f0248..6315479 100644
  4. --- a/lib/server.py
  5. +++ b/lib/server.py
  6. @@ -20,6 +20,7 @@ import time
  7.  from . import uds
  8.  from . import doip
  9. +from . import utils
  10.  from . import simulator as sim
  11. @@ -90,6 +91,22 @@ class DOIPServer(object):
  12.                          if not self.simulator.has_target_address(target_address):
  13.                             logger.error('Error: target_address 0x{:02x} is unknown'.format(target_address))
  14. +
  15. +                            # send fake message to vcan0
  16. +                            # print(utils.bytes_to_hex(userdata))
  17. +                            data_len = len(userdata) + 1
  18. +                            can_data = bytearray(data_len)
  19. +
  20. +
  21. +                            laddr = target_address
  22. +                           if target_address != 0x188 and userdata[0] == 0x22:
  23. +                                can_data[0] = 0x02
  24. +                                can_data[1:] = userdata
  25. +                           else :
  26. +                                can_data[:] = userdata[1:]
  27. +                            utils.send2vcan0(bytes(can_data), target_address)
  28. +                            time.sleep(1)
  29. +
  30.                             response = doip.DiagnosticMessageNegativeAck(source_address, target_address,

修改二:

  1. ~/study/vehicle/doip-simulator$ git diff lib/utils.py
  2. diff --git a/lib/utils.py b/lib/utils.py
  3. index 427de2c..802e58f 100644
  4. --- a/lib/utils.py
  5. +++ b/lib/utils.py
  6. @@ -15,6 +15,15 @@
  7.  """
  8.  import inspect
  9. +import can
  10. +
  11. +
  12. +def send2vcan0(can_data, laddr):
  13. +    bus = can.Bus(channel='vcan0', interface='socketcan')
  14. +    msg = can.Message(arbitration_id=laddr, data=can_data, is_extended_id=False)
  15. +    bus.send(msg)
  16. +
  17. +
  18.  def get_subclasses(mod, cls):

在doipclient的源码中,加入canid为0x188及0x710的报文配置,分别针对ICSim和UDS节点:

  1. config = {
  2.    'datamap': {
  3.        # target_address (hex) : {
  4.        #   identifier (hex) : tuple(label (str), key (str), parser (func))
  5.         # }
  6.        0x188: { # control ICSim
  7.            0x0100: ('Fake Msg', 'fake', parse_fake_msg),
  8.            0x0200: ('Fake Msg', 'fake', parse_fake_msg),
  9.        },
  10.        0x3300: {
  11.            0x3200: ('Dummy Accelerator', 'accelerator', parse_accelerator),
  12.            0x3230: ('Dummy Brake', 'brake', parse_brake_pressure),
  13.        },
  14.        0x3301: {
  15.            0x3250: ('Dummy Steering', 'steering', parse_steering_angle),
  16.        },
  17.        0x710: { # send to uds-server
  18.            0xF187: ('Fake Msg', 'fake', parse_fake_msg),
  19.        }
  20.    }
  21. }

修改完成之后,分别在ubuntu和windows10上将doipserver、doipclient运行起来:

  1. # on ubuntu
  2. python3 doipserver.py
  3. # on windows10
  4. python3 doipclient.py

此时,所有组件都开始工作。doipserver运行起来后会监听13400端口,等待doipclient连接。同时doipserver会周期性地发送广播帧向外报活,广播帧的内容主要包含车辆VIN码及边缘节点的逻辑地址,如下图所示:

广播节点逻辑地址的原因和UDS协议中的寻址方式有关系,UDS协议规定了两种寻址方式:功能寻址与物理寻址。功能寻址可以简单地理解为广播的形式,例如诊断仪发送一个广播帧询问有哪些节点存活着,它不针对指定的ECU;而物理寻址则是针对指定的ECU,因此每个ECU都会对应确定的逻辑地址,当诊断仪想要和指定的ECU进行通信时,就会采用物理寻址的方式,指定ECU的逻辑地址发起连接请求。

简单了解了UDS的寻址方式之后,我们就能明白Doipserver广播帧中携带逻辑地址的意义。

doipclient起来后首先接收广播帧,即协议中描述为“车辆发现”的动作,通过接收doipserver的广播帧,doipclient获得了server端的逻辑地址及车辆VIN码信息,接着连接13400端口,并发起激活路由的请求(Routing activation request)。UDS协议中,在执行针对某个ECU的诊断之前,首先要激活路由。接着发送具体的诊断报文“ReadDataByIdentifier”,“ReadDataByIdentifier”属于UDS的标准服务之一,诊断仪通过指定需要读取数据的Identifier,读取目标ECU中的对应数据:

通过调整doipclient的log级别,我们可以在终端输出doipclient接收到的数据,这些数据由边缘节点生成,包括accelerator、brake和steering的实时数据:

到目前为止,我们看到了doipclient连接doipserver的过程,并简单分析了doipclient与doipserver之间进行UDS诊断通信的过程。该过程仅包含了以太网的通信,接下来我们看看诊断报文转发到CAN网络的过程,首先上一张效果图: 

上面的gif效果显示,ICSim周期性地接收到了左转向和右转向信号,说明doipclient的报文被成功转发到了vcan0,即我们成功地通过远程诊断仪实现了对车辆功能的控制。通过candump验证vcan0接收到的消息:

vcan0上接收到的消息包括ICSim左转向、ICSim右转向、VCDS gateway request及VCDS response。candump的结果显示了can消息中包含的canid,消息id(方括号中的内容),以及can报文的data部分。canid 0x188即ICSim的逻辑地址,数据01表示开启左转向灯,数据02表示开启右转向灯。VCDS的request和response包含两个不同的逻辑地址0x710、0x77A,因为当ECU节点作为发送方和接收方时,分别对应一个逻辑地址。uds-server接收到的请求数据如下:

通过调整doipserver的log级别,我们可以看到doipserver收发请求的完整过程,如下图所示:

实验至此就结束了,过程中涉及到的相关知识点均轻笔带过,本文仅作为大家学习的一个引子,提供一种可实验、可操作的入门方式,感兴趣的朋友可以继续全面深入地学习相关的知识。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/88816
推荐阅读
相关标签
  

闽ICP备14008679号