1 汽车硬件安全模块

汽车可以看成一个大的IOT设备,所以汽车安全也可以借鉴IOT安全,汽车硬件安全模块构成如下:

1.1 平台引导完整性和信任链

1.1.1 硬件安全启动技术

通过数字签名检测汽车的启动加载程序和关键操作系统文件是否被篡改,以阻止恶意文件或者不受信任的系统运行,从而保障硬件可以安全启动。

1.1.2 可信执行技术

例如可信处理器模块,是指使用加密技术,为每个受信任的组件创建唯一标识符,以将启动环境的元素与已知产品进行准确比较,并阻止不匹配的组件的启动。

1.2 篡改检测和防止旁道攻击

对于密钥加密、算法模型、账号凭证以及其他有价值信息的编译和解密只在安全环境中进行,以保护信息免受逆向工程或者中间人监控。

1.3 安全存储

1.3.1 加密加速

这是最早的硬件安全形式之一,与其说是硬件防御,不如说是一种外设。加速加密是在硬件中而不是在软件中执行加密的硬件,这样不仅可以加速应用程序,还可以为硬件提供在软件中无法入侵的系统。

例如,软件版本的AES可能会被注入代码,从而使加密记过容易被攻击者撤销,但硬件版本的AES是不可改变的,不容易受到攻击。

1.3.2 主动内存保护

通过将指针检查功能嵌入硬件以防止缓冲区溢出漏洞。

1.4 安全通信

一般采取加密技术、认证技术、防窃听技术、防篡改技术、防重放技术等,在通信过程中使用硬件措施来保护数据的安全性。

1.5 安全调试与芯片丝印

通常可以通过芯片丝印查找到芯片型号;在芯片开发过程中,通过使用JTAG、SWD调试接口来调试程序,所以擦除丝印和关闭调试接口可以防止大部分黑客攻击。

2 参考链接

IoT Hardware Security Importance & Devices | Arrow.com // 了解硬件安全在物联网技术中日益增加的重要性

HSM简介

HSM是一个专用的硬件安全处理器,它以物理方式封装了安全功能,通常具有自己的处理器核心、各种内存(RAM、ROM、闪存等)和硬件密码加速器。用于提供加密和解密等安全功能,可以用于存储密钥和证书,并确保他们不会被恶意程序或攻击者访问。

HSM通常由硬件和软件两部分组成:

  • 硬件部分:负责安全处理和密钥存储

  • 软件部分:提供HSM的接口和安全服务

HSM在车联网中的应用

在车联网中,HSM模块用作专用加密设备,用于保护敏感信息、促进安全通信并确保联网的车辆内关键操作的完整性,例如保护车辆间通信、保护固件更新以及确保可信软件执行。

为了满足车辆应用的特定标准,HSM提供与ECU应用程序之间的接口以及用于调试的接口。

目前已经有几家大型芯片制造商提供了具有车载规格架构的安全硬件模块,包括Infineon、ST Microelectronics、Renesas和NXP。从根本上说,HSM通过其自己的处理器核心来执行汽车应用场景所需的所有IT安全功能。

1. 车辆安全通信

HSM支持安全通信协议,比如TLS(传输层安全协议),用于加密车辆与其他设备之间的通信,以防窃听和数据篡改,可实现车辆内电子控制单元(ECU)之间的安全通信通道;提供数字证书和密钥保护,确保车辆通信的安全性和可靠性。

2. 车辆远程控制

HSM确保只有经过身份验证的用户才能访问远程启动、关闭车门、车窗等远程控制功能,以防车辆被未经授权的用户控制;HSM还可以提供安全的OTA(空中升级)机制,用于升级车辆系统的软件和固件,在固件更新时,HSM对固件进行身份验证,验证其完整性。

OTA:是一种通过无线通信技术实现远程更新设备固件或软件的方法

3. 车辆数据安全

车辆系统产生大量数据:车辆位置、驾驶行为等,HSM可以用于加密和保护车辆数据,确保数据的机密性和完整性。

4. 车辆防盗保护

HSM提供密钥管理功能:HSM提供数字签名和加密技术,用于保护车辆系统的代码和数据,防止恶意攻击和软件篡改;HSM还提供防盗保护功能,如车辆启动时,需要输入密码或者指纹识别。

HSM在车辆中的物理位置

为了更深刻的理解HSM是一个硬件模块这个概念,我查找了一下HSM在车辆中常见位置:

1. 主控制单元(ECU)

HSM常安装在车辆的中央控制系统或者动力总控制单元内部,这些主控制单元用于处理车辆的关键安全和通信任务。

2. 车载通信网关模块

当HSM被集成在车载通信网关模块中时,HSM负责管理里各个ECU之间的数据通信和安全保护,并在此提供安全加密、身份验证和数据保护。

3. 信息娱乐系统

当HSM被集成在信息娱乐系统中时,用于保护车辆的通信和娱乐数据安全,防止黑客攻击或数据泄露。

4. 电池管理系统(BMS)

HSM模块在此确保电池的安全监控和数据的加密传输。

参考链接

汽车电子领域的保卫者——HSM浅述_搜狐汽车_搜狐网汽车电子领域的保卫者——HSM浅述_搜狐汽车_搜狐网

https://www.freebuf.com/articles/web/363743.html

https://mp.weixin.qq.com/s/DulhqA1o0nnkYTQFjasWjg

https://blog.csdn.net/dianqicyuyan/article/details/138132331https://blog.csdn.net/dianqicyuyan/article/details/138132331

https://www.eet-china.com/mp/a213412.html //HSM攻击实例

https://www.i-newcar.com/index.php?m=home&c=View&a=index&aid=2010 //HSM、HSE、SHE区别

Fuzz简介

Fuzz是一种软件测试技术,其核心思想是将自动或者半自动生成的随机数据,输入到一个程序中,并监视程序异常,如崩溃、断言失败等,以发现程序漏洞。

根据测试数据生成的方式,可以将fuzz分为两种:

  • 基于生成的fuzz

  • 基于变异的fuzz

基于生成的fuzz需要了解程序的构成知识,比如要对协议fuzz的话,需要了解协议规范,字段含义等,来构建一个协议模型,使用模型来生成测试用例。基于生成的fuzz方法优点是构建的测试用例易于通过程序验证,能测试到更深此次的代码;缺点是在没有配置文件等先验知识的情况下,难以分析测试用例的格式。

基于变异的fuzz是根据已知的数据样本,通过对某个字段变异,来生成新的测试用例。比如可以打乱整个数据包、把数据包的某个部分替换掉。基于变异的fuzz关键思路是在数据包中放入大量随机数据。基于变异的模糊测试不需要对协议规约有很深的理解,其效率主要取决于测试样本的丰富程度以及所选用的变异算法,如果变异策略过于简单,会导致大部分测试数据被系统的浅层,逻辑所丢弃,达不到深入测试的目的。

一个基于变异的网络协议的Fuzz过程如下:

  1. 获得目标协议的正常数据包
  2. 用变异数据替换该数据包中的某些部分
  3. 用发包器向目标应用发包
  4. 观察目标应用的反应

在工控系统中,fuzz主要用来对工控设备使用的网络通信协议进行测试。工控网络通信协议可以分为两类:

  • 基础通信协议:ARP、IP、ICMP、TCP、UDP

  • 通用服务协议:HTTP、FTP、SNMP

对于基础通信协议和通用协议,可以用传统的fuzz工具,如Peach、Sulley进行测试,但由于工控协议大多私有,不同厂商使用自己的专有协议,导致传统的fuzz工具难以直接适用于工控系统,针对工控系统协议的fuzz可分为以下两种情况:

(1)标准公开的工控协议

一些已经公开标准的协议比如S7comm,可以采用基于生成发fuzz方法。可以根据协议规范,生成模型,通过对协议字段进行错误注入、对报文结构进行变异,对报文序列(标识上下文状态)进行变换来检测设备在处理异常时可能存在的漏洞。

(2)私有协议

对于未公开标准的私有协议,可以采用基于变异的fuzz方法。首先捕获私有协议正常的交互数据作为样本,在其基础上进行变异。

peach

peach支持基于生成和基于变异的fuzz方法,其特点是可扩展性,这运行它支持多种格式、网络协议、应用协议等,使其适用于Android设备、装置驱动程序以及嵌入式硬件的安全测试。

peach使用流程为:

  1. 创建数据、状态模型
  2. 选择/配置Publisher
  3. 配置代理、监视器
  4. 配置日志

优点:

  1. 支持多种协议和格式

  2. 高度可定制化

  3. 支持分布式测试,可以使用多台机器同时进行模糊测试,从而提高测试效率

  4. 支持状态跟踪,peach可以跟踪目标系统的状态变化,确保测试能覆盖到更多执行路径和状态

  5. 跨平台支持,peach支持Windows、Linux和macOS

缺点:

  1. peach更适合协议和格式的测试,不太适合GUI、游戏等测试

  2. 分布式测试对硬件资源要求较高

Modbus简介

Modbus是一个通用的总线通信协议,属于应用层协议。它不依赖于硬件总线,协议标准公开并支持多种电气接口,所以广泛应用于工业控制系统中。

Modbus是一主多从的通信协议,在Modbus通信中,只有一个主设备可以发送请求,其他从设备接收主设备的数据并响应,从设备可以是任何外围设备,比如I/O传感器、阀门、网络驱动器等。也就是说Modbus不能同步通信,总线上每次只有一个数据进行传输,即主设备发送,从设备应答;如果主设备不发送请求,总线上就没有数据传输。

Modbus通讯物理接口可以选用串口(RS232、RS485、RS422等),也可以选择以太网接口,对应的通信方式也有三种:

  • Modbus-TCP/IP

  • Modbus-RTU/Modbus-ASCII

  • Modbus-PLUS

Modbus存储区

Modbus协议规定了4个存储区,分别是0,1,2,3,可以通过读写寄存器访问。其中1、4区是可读可写的,1、3区是只读的。

  • 0区:输出线圈,可读可写的布尔变量,PLC地址范围为00001-09999,协议地址范围是0000H-FFFFH

  • 1区:输入线圈,只读布尔变量,PLC地址范围为10001-19999,协议地址范围是0000H-FFFFH

  • 3区:输入寄存器,只读寄存器,PLC地址范围为30001-39999,协议地址范围是0000H-FFFFH

  • 4区:保持寄存器,可读可写寄存器,PLC地址范围为40001-49999,协议地址范围是0000H-FFFFH

这里要着重注意一下PLC地址与协议地址的区别

PLC地址与协议地址

PLC地址是指存放于控制器中的地址,地址的第一位表示寄存器类型(1区、2区、3区、4区),协议地址是指通信时使用的寄存器地址,地址范围都是0000H-FFFFH,这里要主要的是,PLC地址0x00001对应的协议地址是0x0000,PLC地址0x10001对应的协议地址也是0x0000,3、4区也一样,不用担心在使用modbus读写寄存器时出错,因为访问不同寄存器的功能码不同,比如访问PLC地址0x00001使用的功能码是01,默认访问1区寄存器,所以就不存在寻址冲突啦。

Modbus TCP/IP 报文格式

Modbus TCP/IP报文格式如下图所示:

MBAP报头

  • 事务元标识符:2个字节,Modbus请求/响应事务处理的识别码

  • 协议识别符:2个字节,0000表示Modbus协议

  • 长度:2个字节

  • 单元标识符:1个字节,串行链路或其他总线上连接的远程从站的识别码

功能码

Modbus常用功能码如下,当主设备发起一个功能码为01的请求时,此时PDU结构为:

  • MBAP报头

  • 功能码:0x01(1个字节)

  • 起始地址:可选范围为0x0000~0xFFFF(2个字节)

  • 线圈数量:可选范围为1~2000(2个字节)

数据

数据域不确定,由具体的功能决定

Fuzz过程

搭建环境

使用MODSIM模拟modbus协议:

使用modbus数据采集工具modscan监测数据:

协议分析

由于Modbus主要用于读写寄存器,所以这里使用modscan修改某个寄存器的值,并使用wireshark抓包:

写寄存器的数据包如下,Modbus/TCP的报文为:9d 00 00 00 00 06 01 06 00 01 00 06,其中06是功能码,写寄存器,00 01是地址,00 06是写入目标寄存器的值,本次测试计划对写入寄存器的值进行变异。

pit文件编写

在安装好peach之后,将安装包中的模板文件复制一份,更名为modbus.xml,根据分析好的报文来修改模板文件。

DataModel

1
2
3
4
5
6
7
8
9
10
<DataModel name="send_data">
<Block name="mod_write_reg">
<Number name="01" size="16" value="9d 00" valueType="hex" signed="false" multable="false"/> <!--标识符-->
<Number name="02" size="16" value="00 00" valueType="hex" signed="false" multable="false"/> <!--标识符-->
<Number name="03" size="16" value="00 06" valueType="hex" signed="false" multable="false"/> <!--长度-->
<Number name="04" size="16" value="01 06" valueType="hex" signed="false" multable="false"/> <!--标识符和功能码(06)-->
<Number name="05" size="16" value="00 01" valueType="hex" signed="false" multable="false"/> <!--地址-->
<Number name="06" size="16" value="00 06" valueType="hex" signed="false" /> <!--数据-->
</Block>
</DataModel>

StateModel

StateModel定义了如何给目标发送和接收数据。

1
2
3
4
5
6
7
<StateModel name="TheState" initialState="Initial">
<State name="Initial">
<Action type="output">
<DataModel ref="send_data"/>
</Action>
</State>
</StateModel>

Agent

由于我使用的是modbus模拟器,所以在测试过程中无法实时监测设备状态,所以监视器选择Socket,对被测设备进行主动监听。

Socket是更精确级别的监听,可以查看端口是否存在,但Socket会使Fuzz测试速度变慢。

1
2
3
4
5
6
<Agent name="TheAgent">
<Monitor name="Socket">
<Param name="Host" value="172.29.152.130" />
<Param name="Port" value="502" />
</Monitor>
</Agent>

Test

Test用于配置一个指定的fuzzing测试,配置内容包括一个Publisher和其他选项组合成一个stateModel。

1
2
3
4
5
6
7
8
9
10
11
<Test name="Default">
<Agent ref="TheAgent"/>
<StateModel ref="TheState"/>
<Logger class="File">
<Param name="Path" value="logs"/>
</Logger>
<Publisher class="tcp.Tcp"> <!--指定通信方式为tcp-->
<Param name="Host" value="="172.29.152.1"/>
<Param name="Port" value="502"/>
</Publisher>
</Test>

Publisher

Publisher是Peach发送和接收数据的IO接口。

测试过程

运行peach.exe,fuzz正常运行:

关闭MODSIM之后,查看peach日志,可以看到peach检测出一个异常:

总结

这次主要是学习peach的用法,对modbus写寄存器功能的数据部分进行变异,看别人说如果只是发送合法的功能码,对数据部分进行编译会导致fuzz的时间非常长,所以要通过逆向固件先找到模糊测试点,再精确地进行fuzz,这块知识点要mark一下,后续继续学习。

参考链接

https://blog.csdn.net/as480133937/article/details/123197782[详解Modbus通信协议---清晰易懂-CSDN博客](https://blog.csdn.net/as480133937/article/details/123197782)

7.Peach 监听模块【工业控制系列】 - 奋斗的安卓勇士Blog

工控网络协议模糊测试:用peach对modbus协议进行模糊测试 - FreeBuf网络安全行业门户

工控安全研究:基于Peach的Modbus协议模糊测试 - 安全内参 | 决策者的网络安全知识库

工具:Peach_peach工具-CSDN博客

背景

在学习二进制时,GDB是必不可少的工具。我经常使用GDB来动态调试一个ELF文件,但是却不能准确、完整地说出GDB调试的原理,所以在这里总结一下。
GDB能attach 到一个正在运行的进程中,以实时获取进程中的内存数据、增加断点、查看当前运行状态下函数变量值、修改寄存器的值。其基本的调试功能是通过系统调用ptrace实现的。GDB有本地调试和远程调试两种模式:

  • 本地调试:GDB与目标程序在同一台电脑中

  • 远程调试:GDB与目标程序不在同一台电脑,此时需要GdbServer,GdbServer与目标程序在同一个设备中,GDB可以通过串口或者RSP协议(GDB Remote Serial Protocol协议)通信

    gdb工作流程

    直接调试目标程序

    当在终端输入命令gdb ./test时,此时gdb启动并从头开始调试test,gdb工作流程如下:

  1. 操作系统启动gdb进程,gdb进程fork出一个子进程

  2. 子进程调用系统函数ptrace(PTRACE_TRACEME , …)

  3. 子进程调用execve加载,执行目标程序test
    示例如下:
    首先使用gdb ./pwn,建立追踪关系,接着使用pstree -p | grep 'pwn',可以看到pwn程序的父进程为gdb。
    gdb_pwn.jpg

    使用attach调试已运行程序

    当在终端输入命令gdb attach -p $pid时,gdb调试一个已经在运行中的程序,此时gdb的工作流程为:

  4. gdb成为test进程的父进程

  5. test进程进入TASK_TRACED,表示当前进程正在被追踪,此时test进程会停下来,等待gdb的命令,在TASK_TRACED状态下的进程只接受ptace指定的PTRACE_DETACH和PTRACE_CONT请求,从而唤醒进程执行操作

  6. 发送给test进程的信号会被转发给父进程,除了SIGKILL

  7. 父进程收到信号后对子进程进行修改,实现对子进程的调试

示例如下:

  • 首先运行目标程序:./pwn
  • 接着使用ps -a查看pwn的进程号,如下图所示,为6161
  • 使用gdb调试已经运行的pwn程序gdb attach -p 6161,(此时可能有报错ptrace: Operation not permitted,使用root即可解决)
  • 查看pwn对应的父进程ps -ef | grep 6161,可以看到gdb为pwn进程的父进程

pwn_pid.jpg
attach_pid.jpg
pid.jpg

ptrace

ptrace是Linux内核提供的一个用于进程追踪的系统调用函数,其接口声明如下,通过ptrace,gdb可以读写目标进程test的指令空间、数据空间、堆栈和寄存器的值,并且gdb进程接管了test进程所有信号,操作系统发送给目标进程的信号都会被gdb截获。

1
2
3
#include <sys/ptrace.h>
long ptrace(enum __ptrace_request request, pid_t pid,
void *addr, void *data);

ptrace的参数非常重要,这里参考大佬博客

request PTRACE_TRACEME、PTRACE_ATTACH PTRACE_TRACEME表示被追踪进程调用,让父进程来追踪自己。通常是gdb调试新进程时使用。
PTRACE_ATTACH父进程attach到正在运行的子进程上,这种追踪方式会检查权限,普通用户无法追踪root用户下的进程
PTRACE_PEEKTEXT、PTRACE_PEEKDATAPTRACE_PEEKUSERPTRACE_GETREGS 表示读取子进程内存,寄存器等内容
PTRACE_POKETEXT,PTRACE_POKEDATA,PTRACE_POKEUSR 表示修改子进程的内存,寄存器的内容
PTRACE_CONTPTRACE_SYSCALL, PTRACE_SINGLESTEP PTRACE_CONT表示重新启动被追踪进程
PTRACE_SYSCALL每次进入或者退出系统调用时都会触发一次SIGTRAP(Trace/breakpoint trap),strace的追踪系统调用就是通过该配置进行追踪的,进入时获取参数,退出时获取系统调用返回值
PTRACE_SINGLESTEP 每执行完一次指令之后会触发一次sigtrap,支持获取当前进程的内存/寄存器状态。gdb的next指令通过该选项实现
PTRACE_DETACH, PTRACE_KILL 解除父子进程之间的追踪关系
如果父进程在在子进程前结束,则会自动解除追踪关系。
pid
表示要跟踪的进程pid
addr
表示要跟踪的进程pid
data 根据前面设置的requet选项而变化,比如要开始追踪时则设置request= PTRACE_CONT,同时将data设置为对应signal数字(SIGTRAP – 5)。

GDB实现原理

GDB断点实现

当使用gdb为程序设置断点时,gdb实现如下:

  1. gdb将断点处指令修改为INT 3,同时保存断点信息以及修改前的指令

  2. 当子进程(test)执行到断点时,出发INT 3终端,产生SIGTRAP信号

  3. ptrace将子进程的SIGTRAP信号发送给父进程(gdb),父进程与保存的断点信息对比,通过确认INT 3指令的未知,来确认当前信号是否因为断点产生

  4. 若是,将断点处的INT 3指令替换为原指令,将PC指针回退一步,等待用户输入命令,否则继续执行代码

    GDB单步调试实现

    当使用gdb单步调试一个程序时,gdb实现如下

  5. gdb与test建立追踪关系,此时ptrace系统调用的参数为PTRACE_ATTACH

  6. 获取test进程的EIP和ESP的值,其中EIP存放CPU将要执行的下一条指令,ESP中存放当前栈帧的地址

  7. 通过ptrace的PTRACE_SINGLESTEP参数不断将EIP和ESP向下移动,每执行一条指令,寄存器指针移动一次,直到指针达到栈尾,结束调试

参考链接

https://www.cnblogs.com/sewain/articles/14131927.html //原来gdb的底层调试原理这么简单

https://blog.csdn.net/mrhesongze/article/details/81980397 //GDB调试二进制和符号表symbol分开的程序
https://blog.csdn.net/Z_Stand/article/details/108395906 //一文带你看透GDB实现原理
https://blog.csdn.net/wohu1104/article/details/124934068 //gdb三种调试方式

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment