CAN总线逆向

一、前言

​ 某日在浏览车联网安全文章时无意间发现了一些师傅通过在Linux系统中搭建汽车模拟器来实现CAN总线的逆向和重放攻击,搭建过程简单并且非常适合拿来进行CAN总线逆向入门,对于我这个车联网安全的新人来说简直再合适不过了,遂通过这篇文章记录一下自己学习CAN总线逆向的一些心得体会。

二、前置知识

​ CAN总线在1991年被大规模应用于汽车中,从那以后CAN总线就成为了汽车的标配。
​ CAN帧运行在两条线路上,分别是CAN-H和CAN-L。当总线遇到干扰时会同时发生在CAN-H和CAN-L上,因此采用差分数据传输的方式可以有效的避免汽车内的干扰影响数据传输的问题。
​ CAN信息帧总共有四种类型,分别是:

数据帧(Data Frame)
远程帧(Remote Frame)
错误帧(Error Frame)
重载帧(Overload Frame)

​ 而这四种类型的数据帧同时可以使用两种消息格式来发送,分别是标准帧格式和扩展帧格式。

​ 图片来源:智能汽车安全攻防大揭秘

​ 如上图所示,我们可以看到在标准帧格式中存在许多的元素,我们主要介绍一下标准帧中的几个主要元素。

仲裁ID(Arbitration ID):在CAN中是通过广播消息来发送给所有接入CAN的结点,而仲裁ID则是用来决定信息的优先级,数值越小的仲裁ID有着越高的优先级。
标识符扩展(IDE):在标准数据帧格式中此位一直为0,而使用扩展帧格式时此位置1。
数据长度码(DLC):表示数据的字节数。
数据(Data):其中包含着我们要传输的数据,标准帧格式一次只能发送最多8字节,若不满8字节则会填充0。

​ 从上面对于CAN的前置知识中我们不难发现一些问题,比如说CAN中通过广播的方式传输数据并且没有对发送数据的来源进行严格的检测,这就造成了黑客可以在CAN中发送一些恶意伪造的流量,并造成严重的后果。

三、环境搭建

​ 前面我们对CAN有了初步的了解,接下来就该上手来操作一下了。我这边使用的是Ubuntu 20.04的环境,主要用到了以下工具:

ICSim(Instrument Cluster Simulator)
Can-utils

ICSim安装

​ GITHUB下载地址:https://github.com/linux-can/can-utils

​ 安装前需要几个依赖库,输入如下命令

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

​ 然后将下载下来的项目解压,进入解压后的文件夹内,执行下面的命令启动vcan0接口,并看到如下界面,我们的模拟汽车和仪表盘就在这里面。

amall@amall-virtual:~/tools/ICSim-master$ ./setup_vcan.sh
amall@amall-virtual:~/tools/ICSim-master$ ./icsim vcan0

​ 启动另一个终端,输入指令打开控制器。

amall@amall-virtual:~/tools/ICSim-master$ ./controls vcan0

​ 控制器界面可以键入的命令如下所示:

上下键(PgUp、PgDn):控制车速仪表盘
左右键(Left、Right):控制左右车灯
键盘右边的Shift键 + X键、Y键、A键、B键:打开车门
键盘左边的Shift键 + X键、Y键、A键、B键:关闭车门
右Shift键 + 左Shift键:关闭所有车门
左Shift键 + 右Shift键:开启所有车门

需要注意的是我们要控制虚拟汽车时,需要选中控制器界面再键入命令,否则无法令我们的虚拟汽车执行对应操作。

Can-utils

​ GITHUB地址:https://github.com/linux-can/can-utils
​ 两种方式安装,一种是直接apt-get安装;如果第一种不行则可以在github中下载项目并通过make安装

sudo apt-get install can-utils

​ 安装好以后我们来介绍一下常用的几个工具:

candump:显示CAN流量数据,显示的数据格式为 [接口] + [仲裁ID] + [数据长度] + [数据]。我们也可以使用-l参数将显示的CAN流量保存到log文件中用于分析,默认生成log文件格式为candump + 日期。
canplayer:可以将我们使用candump保存的can流量进行重放。
cansend:当我们确定或需要测试某条can流量的功能时,可以通过cansend来发送can数据。
cansniffer:与candump类似,会将发生变化的字节进行高亮处理。

四、CAN逆向与重放

​ 在实际环境中,不同的制造商和车型都有自己唯一的CAN数据格式,所以通过对于CAN流量的逆向来确定某个特定信号的功能是车联网安全研究员必须要具备的能力。在现实环境中会有许许多多嘈杂的数据,这主要是由于汽车本身会有很多的设备按照指定的时间间隔来发送数据,这对于我们逆向CAN流量带来了麻烦,所以通过一些技巧来确定汽车的某一个功能对应的信号可以大大提高我们的逆向效率。

1、观察法

​ 我们可以使用cansniffer的变化数据高亮功能来锁定一些因为我们开关车门或车灯使得相同仲裁ID的数据发生变化的信号,同时可以配合着cansniffer中的仲裁ID筛选功能只查看某一个ID的数据信息。这种方法最直观暴力,需要有好的眼力劲。

2、二分法

​ 相信二分法大家都不陌生,顾名思义就是通过每次折半的方式来确定我们想要搜索的信息,接下来我将会给大家演示一下如何通过二分法来确定开启车门的流量,首先我们先执行如下操作:

  1. 输入candump -l vcan0 命令记录can流量数据
  2. 使用控制器打开虚拟汽车的任意一个车门(我这边打开的是俯视图中左下方的车门)
  3. 使用控制器关闭刚才打开的车门
  4. 按下Ctrl + C 键关闭candump,查看流量信息
amall@amall-virtual:~/tools/ICSim-master/data_log$ wc -l candump-2022-06-05_103036.log 
29814 candump-2022-06-05_103036.log

​ 可以看到我这边总共记录了29814行的数据,要是一条条来分析可是太要命了,使用split来将这个文件对半分,会生成cp1aa与cp1ab两份文件。

amall@amall-virtual:~/tools/ICSim-master/data_log$ mv candump-2022-06-05_103036.log ./source
amall@amall-virtual:~/tools/ICSim-master/data_log$ split -l 15000 source cp1

​ 然后使用canplayer重放刚才分割的其中一个文件,如果重放完成后我们的虚拟汽车执行了开启车门的操作,那么就说明开启车门的数据流量就在当前这个文件里面。

amall@amall-virtual:~/tools/ICSim-master/data_log$ canplayer -I cp1aa

​ 可以看到成功执行了开启车门的命令,重复刚才的操作不断的进行二分法可以逐渐缩小确定流量的范围,当执行到12次左右的时候基本就可以确定开门流量了,如下图所示:

​ 使用cansend来发送can数据,幸运的是第一条就是我们的开门can数据,确定了ID为19B。

amall@amall-virtual:~/tools/ICSim-master/data_log$ cansend vcan0 19B#00000B000000

2、脚本统计

​ 二分法虽然可以帮助我们提高一定的效率,但是纯人工操作的办法还是有些费力气。既然can流量已经被记录在log文件中了,我们为何不写一个python脚本来帮助我们统计出不同的ID流量在log文件中出现的次数呢,我们改变一下刚才二分法的操作,让python来减轻我们的任务量。

  1. 输入candump -l vcan0 命令记录can流量数据
  2. 使用控制器连续键入打开虚拟汽车的任意一个车门命令6次(我这边打开的是俯视图中左下方的车门)
  3. 使用控制器关闭刚才打开的车门
  4. 按下Ctrl + C 键关闭candump,查看流量信息
  5. 通过Python脚本分析log文件,查看出现次数为六次的ID有哪些,并查看其对应的流量数据
  6. 使用cansend重放单条can流量,观察虚拟汽车变化
amall@amall-virtual:~/tools/ICSim-master/data_log$ python3 1.py candump-2022-06-05_110828.log

​ 可以看到我们在二分法中确定的19B为开车流量的ID,通过这种方式能大大提升我们逆向CAN流量的效率。

python脚本

import sys

result_id = []
result_data = []		

for line in open(sys.argv[1], "r"):
	result_id.append(line.split(' ')[2].split('#')[0])
	result_data.append(line.split(' ')[2])

for i in list(set(result_id)):
	print("{}: {}".format(i, result_id.count(i)))

while True:
	inp = input("please input id: ")
	try:
		for i in range(len(result_data)):
			if (result_data[i].split("#")[0].find(inp) != -1):
				print(result_data[i])
	except:
		continue

五、总结

​ 从搭建一个自己的虚拟汽车,到使用can-utils工具包来完成对CAN流量的逆向与重放,深深体会到了汽车黑客的那份酷炫感。也是在实习之前体验了一次车联网安全的魅力。关于车联网安全所涉及到的知识还有很多,无线电安全、蓝牙安全许多许多,新的领域新的挑战,希望自己能在未来将更多掌握的知识写在文章里分享给大家,让更多的人了解到车联网安全的魅力和重要性。

posted @ 2022-06-06 18:26  Amalll  阅读(1603)  评论(0编辑  收藏  举报