Fuzz简介 Fuzz是一种软件测试技术,其核心思想是将自动或者半自动生成的随机数据,输入到一个程序中,并监视程序异常,如崩溃、断言失败等,以发现程序漏洞。
根据测试数据生成的方式,可以将fuzz分为两种:
基于生成的fuzz需要了解程序的构成知识,比如要对协议fuzz的话,需要了解协议规范,字段含义等,来构建一个协议模型,使用模型来生成测试用例。基于生成的fuzz方法优点是构建的测试用例易于通过程序验证,能测试到更深此次的代码;缺点是在没有配置文件等先验知识的情况下,难以分析测试用例的格式。
基于变异的fuzz是根据已知的数据样本,通过对某个字段变异,来生成新的测试用例。比如可以打乱整个数据包、把数据包的某个部分替换掉。基于变异的fuzz关键思路是在数据包中放入大量随机数据。基于变异的模糊测试不需要对协议规约有很深的理解,其效率主要取决于测试样本的丰富程度以及所选用的变异算法,如果变异策略过于简单,会导致大部分测试数据被系统的浅层,逻辑所丢弃,达不到深入测试的目的。
一个基于变异的网络协议的Fuzz过程如下:
获得目标协议的正常数据包
用变异数据替换该数据包中的某些部分
用发包器向目标应用发包
观察目标应用的反应
在工控系统中,fuzz主要用来对工控设备使用的网络通信协议进行测试。工控网络通信协议可以分为两类:
对于基础通信协议和通用协议,可以用传统的fuzz工具,如Peach、Sulley进行测试,但由于工控协议大多私有,不同厂商使用自己的专有协议,导致传统的fuzz工具难以直接适用于工控系统,针对工控系统协议的fuzz可分为以下两种情况:
(1)标准公开的工控协议
一些已经公开标准的协议比如S7comm,可以采用基于生成发fuzz方法。可以根据协议规范,生成模型,通过对协议字段进行错误注入、对报文结构进行变异,对报文序列(标识上下文状态)进行变换来检测设备在处理异常时可能存在的漏洞。
(2)私有协议
对于未公开标准的私有协议,可以采用基于变异的fuzz方法。首先捕获私有协议正常的交互数据作为样本,在其基础上进行变异。
peach peach支持基于生成和基于变异的fuzz方法,其特点是可扩展性,这运行它支持多种格式、网络协议、应用协议等,使其适用于Android设备、装置驱动程序以及嵌入式硬件的安全测试。
peach使用流程为:
创建数据、状态模型
选择/配置Publisher
配置代理、监视器
配置日志
优点:
支持多种协议和格式
高度可定制化
支持分布式测试,可以使用多台机器同时进行模糊测试,从而提高测试效率
支持状态跟踪,peach可以跟踪目标系统的状态变化,确保测试能覆盖到更多执行路径和状态
跨平台支持,peach支持Windows、Linux和macOS
缺点:
peach更适合协议和格式的测试,不太适合GUI、游戏等测试
分布式测试对硬件资源要求较高
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结构为:
数据 数据域不确定,由具体的功能决定
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" /> <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" > <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博客