跳至正文
首页 » 博客 » 星舆实验室之 ‘CAN’ you hack it ?

星舆实验室之 ‘CAN’ you hack it ?

朱海生 星舆车联网安全实验室

0x00 前言

大家好, 我是星舆车联网实验室的 Krypt0n,星舆取 “星辰大海, 舆载万物”之意,实验室是专注于车联网技术研究、漏洞挖掘和工具研发的安全团队。团队成员在漏洞挖掘,硬件逆向与AI大数据方面有着丰富经验,连续在GeekPwn等破解赛事中斩获奖项,并获众厂商致谢。团队研究成果多次发表于DEFCON等国内外顶级安全会议。

0x01 背景

当前,汽车领域正在向着智能化,网联化,电动化,共享化的四化方向发展,给出行驾驶体验带来方便的同时,也带来了很多的新的安全风险,暴露的攻击面也越来越多,而作为汽车电子系统通信链路上最重要的也是应用最多的总线 CAN ,针对 CAN 的逆向和攻击利用也越来越多,本文从 CAN 协议基础讲起,逐步让大家了解 CAN 协议的基础知识,后续文章在从 CAN 仿真,逆向,和真车实战攻防的角度对 CAN 进行深入的研究研讨。

0x02 Classic CAN 总线及协议介绍

历史

1983年,Robert Bosch GmbH 开发了CAN总线技术,并于 1986 年在SAE 汽车工程学会大会上将其作为全新串行总线系统发布,目前CAN总线在汽车的动力系统、底盘系统和舒适系统等 ECU 网络中发挥着重要作用,同时CAN总线具有数据传输可靠的特点,可以满足应用领域的实时要求;自从引入CAN总线之后,汽车中的复杂线束得到了大大的简化,有效的降低了车内线束布线重量和空间。

Classic CAN OSI-1/2层数据帧格式

CAN 总线是一种反逻辑电平,物理上的高电平对应逻辑上的 ‘0’,即显性电平,帧格式有数据帧、遥控帧、错误帧、过载帧、帧间隔5 种,只有数据帧和遥控帧有标准格式和扩展格式之分,并且只有数据帧和遥控帧有 SOF 和 EOF 段。

标准数据帧构成:帧起始[1 bit]、仲裁段[11+1 bit]、控制段[2+4 bit]、数据段[0-64 bit]、CRC段[15+1 bit]、ACK段[1+1 bit]、帧结束[7 bi],共7段;

  • 仲裁段[11+1]:11位的ID比特位,指示报文内容和优先级,1位RTR位,显性表示数据帧,隐性表示遥控帧
  • 控制段[2+4]:IDE[标识符扩展位],显性电平表示该帧是标准数据帧,IDE后1位保留,默认显性电平,然后是4位的数据长度码 DLC
  • CRC段[15+1]:15位 CRC 序列[CRC15 多项式算法]加上1位隐性的CRC界定符组成
  • ACK段[1+1]:1位应答段,显性电平表示有应答,1位ACK占位符
  • 结束段[7]:7位隐性电平
  • 在两个帧之间至少需要3个隐性电平[ 即帧间隔 ],若没有节点发送帧,则总线一直保持隐性电平的空闲状态

总结:标准帧格式中,SOF 位显性电平,数据帧的 RTR[远程发送请求] 位显性电平,控制帧的保留位 IDE/R0 显性电平,CRC 界定符位隐性电平,ACK 槽比特位显性电平表示接收,隐性电平表示发送,ACK 界定符是隐性电平,EOF 是7位隐性电平。

总线访问及优先级

总线节点在发送数据时,同时也会监听总线,CAN 总线仲裁字段连续出现显性电平最多的单元获得总线控制权;从软件角度看 ID 值越小,优先级越高,因为是反逻辑电平,逻辑 0 表示显性电平即物理高电平;总线仲裁失败的节点会继续监听总线,当总线再次处于空闲状态时,会第一时间继续发送仲裁帧。

1.节点发送显性电平[逻辑0],监测到总线此时处于显性电平[逻辑0],此时该节点继续发送,继续进行仲裁

2.节点发送显性电平[逻辑0],监测到总线此时处于隐性电平[逻辑1],此时发生总线错误

3.节点发送隐性电平[逻辑1],监测到总线此时处于显性电平[逻辑0],此时竞争失败,此节点转为接收方

4.节点发送隐性电平[逻辑1],监测到总线此时处于隐性电平[逻辑1],此时该节点继续发送,继续进行仲裁

数据帧和数据帧之间的优先级判定:根据 ID 值的大小进行仲裁判定;

数据帧和遥控帧之间的优先级判定:具有相同 ID 的数据帧和遥控帧,仲裁最后一位 RTR 为显性位的数据帧具有优先级;

标准格式和扩展格式的优先级判定:标准格式ID和具有相同ID的遥控帧或者具有扩展格式的数据帧在总线上竞争时,标准格式的 RTR 位为显性电平的具有优先权,可继续发送;

错误分类及协议处理机制

错误的种类:位错误、格式错误、填充错误、CRC 错误、ACK 错误;

填充位:为防止突发错误而设定的功能,由于 CAN 使用 NRZ 编码,为了确保所有总线节点都能够重新同步,使用填充的方法,在协议解析的时候,收发器物理上在接收端会去掉填充的比特位,如果示波器在物理层测量 CAN 协议数据时,若示波器本身没有 CAN 功能的话,需要人工手动的去掉填充位信息;

发送单元的填充机制:在发送数据帧和遥控帧时,SOF~CRC 段间的数据,相同电平如果持续 5 位,在下一个位(第六位)要插入 1 位与前 5 位相反的电平;

接收单元的填充机制:在接收数据帧和遥控帧时,SOF~CRC 段间的数据,相同电平如果持续 5 位,需要删除下一个位(第六位)在接收,如果这个第 6 位的电平与前 5 位相同,将视为错误并发送错误帧;

位时序及时序同步

基本概念

位速率:发送单元在非同步情况下发送的每秒钟的位数称为位速率,即波特率;

位时间:指一个(二进制逻辑)位在物理总线传输所需要的时间,位时间是位速率的倒数,即 Tbit;

位时序:每一帧数据(即一个完整的数据帧)有很多位 [Tbit] 组成,每位 [Tbit] 一般分为四段,同步段[SS]、传播时间段[PTS]、相位缓冲段1[PBS1]、相位缓冲段2[PBS2],每个段又由若干个 Tq 构成,这称为位时序;还有一个再同步补偿宽度段[SJW];

1 位 [Tbit] 分为四个段,每个段又由多个 Tq 构成,Tq [ Time Quantum ] 时间量子叫做最小时间单位;

通过位时序设定,可设置 1 位 [Tbit]  由多 Tq 构成,每个段又由多个 Tq 构成;可做到让多个单元同时采样,也可任意设置采样点;

以下是 1位[Tbit]的图示

CAN 控制器为了适应各种波特率,对四个段的时间长度,不是使用纳秒(ns)或微秒(us)来度量,而是使用节拍来度量,这个节拍称为时间量子 Tq [ Time Quantum ]。例如 500k 的波特率[位速率],每个 Tbit 位时间是 2000ns,如果分为 10[NBT] 个节拍,则每个 Tq 为 200ns;

一个位[Tbit]时间由波特率的倒数即位速率决定,Tbit = 1 / BaudRate;

Tq 由 位时间除以名义位时间 NBR [Nominal Bit Time] 计算,即 NBR * Tq = Tbit;

CAN节点 MCU 的时钟频率 F,则MCU的最快工作时间 T = 1 / F,分频计算方式 Tq = (BRP + 1)/ F 或 Tq = 8 *(BRP + 1)/ F ,BRP[Baud Rate Prescaler]是位速率分频值;根据此公式可对CAN控制器的BRP寄存器进行设置;

采样点位于 PBS1 末和 PBS2 头 的位置;

时序同步意义

CAN协议的通信方法为NRZ[Non-Return to Zero]方式,各个位的开头或者结尾都没有附加同步信号;发送单元以位时序同步的方式开始发送数据。另外,接收单元根据总线上电平的变化进行同步并进行接收工作。但是,发送单元和接收单元存在的时钟频率误差及传输路径上的(电缆/驱动器等)相位延迟会引起同步偏差,因此接收单元会通过硬件同步或者再同步的方法调整时序进行接收;

硬同步是指在总线空闲状态,接收节点检测出帧起始位(SOF)时,会调整当前位的同步段(SS)与发送节点的帧起始位SS段一样,每帧只可能出现一次硬同步;

再同步是指接收节点检测出除SOF位以外的其他位时进行的同步调整。再同步会通过加长PBS1段,或缩短PBS2段来调整同步,以保证采样点的准确;这里加长或缩短(即跳转)操作涉及到一个概念—同步跳转宽度 [SJW],SJW必须小于PBS1和PBS2的最小值,SJW最大值不能超过4;

Classic CAN 的物理电路设计

0x03 与CAN有关的协议

ISO 11898-1

ISO 11898-1 定义了控制器[数据链路层和 PLS子层]的规范;

ISO 11898-2

ISO 11898-2 定义了物理层高速CAN 的收发器的规范

ISO 11898-3

ISO 11898-3 定义了物理层低速CAN 的收发器的规范,注意此协议下的显性和隐形电平物理值与 ISO 11519-2 不同

ISO 11898 和 ISO 11519-2

0x04 UDSonCAN

车载诊断协议定义了诊断请求/响应的报文格式,ECU 如何处理请求的行为,请求和响应的消息内容等。

车载诊断协议的应用有很多,今天主要介绍UDS;UDS 可基于 CAN、LIN、车载以太网、蓝牙、WI-FI 等底层协议,UDS 本质上是一系列服务的集合,UDS的服务包含6大类,共26种;每种服务都有自己独立的ID,即服务标识符SID。

又由于CAN总线目前在车载总线中应用很广泛,所以下面我们主要介绍在OSI 7层协议中涉及 UDSonCAN 的相关层协议,如下图所示的红色标注部分

ISO 11891-1/2 已经在上一节中做了简单介绍,下面着重介绍其余层的协议

应用层 ISO 14229-1

UDS由 ISO-14229 系列标准定义,适用于汽车诊断服务,ISO 14229-1 定义了应用层服务诊断服务,不涉及网络及实现,不基于任何底层标准,它是诊断服务的规范化标准,如读取故障码应该向 ECU 发的指令,读数据流发的指令等;而ISO 14229-3则定义了UDS在CAN总线上的实现。UDS 14229-1 规定了6类,26种应用层服务。

  1. 诊断和通信管理功能单元
  2. 数据传输功能单元
  3. 存储数据传输功能单元
  4. 输入输出控制功能单元
  5. 例行程序功能单元
  6. 上传下载功能单元

SID 定义

SID 即服务标识符,是一个字节无符号整数,取值范围是 [0x00~0xFF],符合ISO 14229-1 规范的ID取值范围如下图所示,其中0x10-0x3E代表请求服务表示符,0x50-0x7E代表肯定响应标识符, 0x7F 代表所有的否定响应标识符,可以看出相应的肯定响应SID 等于请求服务标识符加上0x40;

下图展示了其它范围的SID和所定义的协议之间的关系,限于篇幅原因,这里不做铺开解读,读者可根据定义文档自己检索学习了解

[不同SID及其带有子服务SF的具体含义读者可参考 UDS 14229-1 协议]

UDS 的三种会话模式

  • 默认诊断会话
  • 编程会话
  • 扩展诊断会话

TP层 ISO 15765-2

UDS网络层,又称为 TP 层[Transport Protocol Layer],其存在的目的是为了解决ISO 11898 协议中定义的经典CAN数据链路层与ISO 14229协议中定义的应用层,彼此之间数据长度不统一的问题。经典CAN数据链路层最大能够支持8个字节,但ISO 14229并不仅仅是为了CAN总线设计的,最大容量达到4095个字节。比如VIN码是17个字节,CAN总线必然需要传递3帧才能传完VIN码,如何将多个字节通过经典CAN来进行传输,就成了一个需要解决的问题;ISO 15765-2 协议由此诞生;ISO15765-2 可以但不限于与 ISO 14229-1 和 ISO 15031-5 一起使用,它与车载网络的大多数其他通信需求相兼容;ISO 15765-2 协议将CAN的8字节数据域腾出一到两个字节的做法,来体现网络层的控制信息[N_PCI];

几个概念

  • A_PDU:应用层协议数据单元
  • A_SDU:应用层服务数据单元
  • N_PDU:网络层协议数据单元
  • PCI:层协议控制信息
  • DID:数据标识符
  • A_PDU = A_PCI[SID or NR_SID,SID] + A_SDU
  • A_PDU = A_AI + A_data
  • A_AI = Mtype,SA,TA,TA,TA_Type,[RA,],[Length]
  • A_Data = A_PCI + [parameter1,…]
  • [N_PDU = N_PCI + N_SDU]
  • SA 源地址,DA 目标地址,TA_Type:描述是物理寻址还是功能寻址
  • 应用层协议数据单元中的 A_PCI 指的是服务标识符 SID,注意区分与 ISO 15765-2 的 N_PDU 中的 N_PCI 字段

下图简单展示了各层协议间的封装关系

N_PCI 帧信息

网络层PDU的PCI格式如下表所示

帧类型bit7-4bit3-0byte2byte3
单帧PCItype=0SF_DLN/AN/A
多帧首帧PCItype=1FF_DLFF_DLN/A
连续帧PCItype=2SNN/AN/A
流控帧PCItype=3FSBSST_min
  • 0:单帧[SF],表示该帧包含整个载荷[payload],后 4 个 bit [SF_DL]表示数据段包含数据字节数
  • 1:首帧[FF],表示多数据帧的第一帧,后面的 12 bit [FF_DL]表示载荷的数据大小
  • 2:连续帧[CF],即多数据帧剩余部分,后 4 bit [SN]作为接收到数据包的排序索引[从1开始计数],如果传输内容的长度超过 112 字节,该索引可以作为包裹
  • 3:流控制帧[FC],作为首帧数据帧的回馈信息,即诸如分发速率这样额外传输数据包的特定参数;FS 有三种状态:继续发送0、保持等待1、数据溢出2BS 规定发送端允许持续传输连续帧数目的最大值[0~255]STmin 限定连续帧相互之间所允许的最小时间间隔

会话举例

以 SID=2E的写数据服务为例;

请求服务帧:2E + DID + Data

响应服务帧:6E + DID

方向DLCDATA
Tx810 14 2E F1 90 01 02 03
Rx830 00 0A AA AA AA AA
Tx821 04 05 06 07 08 09 0A
Tx822 0B 0C 0D 0E 0F 10 11
Rx803 6E F1 90 AA AA AA AA

第一行 10 表示请求帧的首帧, 0 14 表示一共20个字节需要发送,F190表示子服务号,此处表示车架号VIN,01 02 03 表示具体写入数据[VIN一共17个字节];

第二行 30 表示响应的流控帧,0 00 0A 中的第一个0表示允许继续发送,0A表示连续帧最短的间隔时间是 10ms;

第三行表示连续帧,21 中的1表示连续帧的序号,后面是数据;

第四行表示连续帧,22 中的2表示连续帧的序号,后面是数据;

第五行表示ECU的响应,03 表示单帧,含有3个字节的数据,6E 是 对应着请求的 2E 的 SID,F190 是子服务号,代表着车架号VIN码;

0x05 仿真环境搭建

使用icsim 和 uds-server 及 can-utlis工具进行测试(默认ID为0x710)

环境 kali 5.6.0-kali1-amd64

ICSim 安装及使用

ICSim是一个ECU的模拟工具

# GITHUB 源地址
git clone https://github.com/zombieCraig/ICSim.git 

# 依赖组件的安装
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install libsdl2-dev libsdl2-image-dev can-utils

# 编译,生成icsim和controls两个可执行文件
cd ICSim
make 

# 编译,生成icsim和controls两个可执行文件
cd ICSim
make 

# 建立一个虚拟 CAN 接口,vcan0 是可变参数,可以是 vcan1 等其它名字;
sudo modprobe can
# 加载虚拟vcan模块
sudo modprobe vcan
# 添加vcan0网卡
sudo ip link add dev vcan0 type vcan bitrate 500000
sudo ip link set up vcan0

# 其它相关命令
sudo ip link add 
sudo ip link show
sudo ip link delete

# 关闭 vcan0 线路
sudo ip link set down vcan0

# 此时通过 ifconfig 可以看见 vcan0 接口
./setup_vcan.sh

# 打开仪表盘
./icsim vcan0

# 打开车联模拟控制器,使用手柄控制更方便
./controls vcan0

uds-server 安装及使用

统一诊断服务服务器,提供 UDS 支持的 ECU 模拟器,程序最初是为了与 [ICSim] 一起训练而编写的;目前也可作为安全研究测试的工具;

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

# 启动
./uds-server 

caringcaribou安装及使用

git clone https://github.com/CaringCaribou/caringcaribou
sudo apt-get install python3-pip -y

# 我的python 环境是 Python 3.8.6

# 安装 python can 包
pip3 install python-can

# 切换到 tools 目录 
cd tool/libs
 
# 修改相关参数,否则会启动失败
sudo vim can_actions.py
self.bus = can.Bus(bustype='socketcan',channel=DEFAULT_INTERFACE)

sudo vim io15765_.py
self.bus = can.Bus(bustype='socketcan',channel=DEFAULT_INTERFACE)

# 启动 
python3 cc.py -i vcan0 uds discovery
# 进入 tool 目录
# 列出帮助信息及所有可获取使用的模块
python3 cc.py -h

# 查找某一模块的帮助信息及使用举例,如 send
python3 cc.py send -h

# 若某一模块还有子功能,也可以进一步列出子功能的帮助信息及使用距离
python3 cc.py send message -h
python3 cc.py send file -h

软件的组合使用

# 在 ICSim 目录下,启动 ICSim
sudo modprobe can
sudo modprobe vcan
sudo ip link add dev vcan0 type vcan bitrate 500000
sudo ip link set up vcan0

# 切换 uds-server 目录,启动 uds-server,为模拟车辆搭建 uds 服务
./uds-server vcan0

# 切换 caringcaribou 目录,开启 uds 服务扫描
python3 cc.py -i vcan0 uds discovery

0x06 参考

  1. https://www.bilibili.com/video/BV1aP4y1p7Vo?spm_id_from=333.999.0.0
  2. https://zhuanlan.zhihu.com/p/37310388
  3. https://zhuanlan.zhihu.com/p/44857562
  4. ISO 14229-1/2/3
  5. https://github.com/zombieCraig/ICSim
  6. https://github.com/CaringCaribou/caringcaribou

未完待续,想看 Tesla Model 3 的 CAN 逆向么?后续文章即将揭晓

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注