【文末赠书】工控安全之Modbus协议实现和安全性分析(上)

  • A+
所属分类:逆向工程

概述

Modbus 最初是由 Modicon 于 1979 年发布的用于 PLC 设备之间的通讯协议,后被 Schneider Electric 收购并与 2004 年将 Modbus 交于 Modbus Organization 管理和维护,Modbus 在工业界很受欢迎,因为它不仅公开而且免税,如今 Modbus 已经成为行业的标准通信协议,是连接工业电子设备的常用手段。
Modbus 是一个应用层协议,位于 OSI 模型的第七层。它为建立在不同总线或网络类型的设备之间提供一种基于 Client/Server 的通讯方式( 也称为 Master/Slave )。

【文末赠书】工控安全之Modbus协议实现和安全性分析(上)

通过 Modbus 我们可以在各种类型的设备之间通讯,包括 PLC、HMI、Control Panel、Motion Control、I/O Device 等等。

协议版本

由于历史原因和技术的发展,Modbus 现存有的协议版本有非常多种,这些实现使得 Modbus 既能支持串口通信也能在以太网的基础上通信,以下作简单介绍,后面会详细介绍几种常见的实现。
  • Modbus RTU : 基于串口通信,通信数据以二进制形式传递,CRC 校验保证可靠性。

  • Modbus ASCII : 基于串口通信,通信数据以 ASCII 字符传递,LRC 校验保证可靠性。

  • Modbus TCP/IP :  基于 TCP/IP 通信,一般在端口 502 通信,依赖于 TCP/IP 的校验保证可靠性。

  • Modbus over TCP/IP 或 Modbus over TCP 或 Modbus RTU/IP : 与 Modbus TCP 不同之处在于校验和被包含在有效载荷里。

  • Modbus RTU over TCP/IP 或 Modbus ASCII over TCP/IP : 这是串口 Modbus 协议借助 Modbus TCP 传输的情况,此时 CRC 或 LRC 校验字段仍然存在。

  • Modbus over UDP : 基于 UDP 通信,可以降低 TCP 所需要的开销。

  • Modbus Plus : 这是 Schneider Electric 的专利产品,支持各主设备之间的 P2P 通信。

  • Pemex Modbus : 这是一个标准 Modbus 的扩展,是专为 Pemex 石油天然气公司设计的,并未广泛应用。

  • Enron Modbus : 这是一个标准 Modbus 的扩展,是 Enron 公司开发用于支持 32 bit 整数和浮点变量的。


通讯机制

Modbus 是一种单主多从的通信协议,在一条总线上只能有一个主设备,可以有多个从设备 ( Modbus 在数据链路上的设备寻址被限制在 254 个,在 TCP 的实现中无此限制 ),主设备向从设备发送指令并等待从设备的响应,从设备只能被动响应,不会主动发送数据,从设备之间不能相互通信。一般 HMI ( Human Machine Interface ) 或者 SCADA ( Supervisory Control and Data Acquisition )  系统作为主设备,而传感器、PLC ( Programmable Logic Controller )、PAC ( Programmable automation controller ) 作为从设备。

【文末赠书】工控安全之Modbus协议实现和安全性分析(上)

Modbus RTU、Modbus ASCII、Modbus Plus ,都是基于 RS-232/485 总线通信介质实现串口传输,只有主设备发送指令时,从设备才能作响应,而在 Modbus TCP 的实现中,在总线上的每一个设备都可以作为主设备发起指令,只不过通常情况下在 Modbus TCP 的方案下我们只选择一个设备作为主设备。
在 Modbus 的实现中,每一个从设备都有一个唯一的地址,从设备地址范围 1 ~ 247 ,248 ~ 255 地址保留,地址 0 为广播地址,主设备不占用地址。
主设备有两种方式向从设备发送指令,一种是单播模式,仅寻址单个设备发送请求。另一种是广播模式,请求指令必须是 Modbus 标准功能中的写指令,在单播模式中线路上所有的设备都会收到命令,但只有指定的设备会执行并回应指令,在广播模式中所有收到指令的设备都会运行,不过不用回应指令。
我们来简单看下,Client 和 Server 之间的事务处理细节。

【文末赠书】工控安全之Modbus协议实现和安全性分析(上)

对于一个没有发生异常的请求,Client 端发送 Function Code 和 Data Request 给 Server,Server 执行相应的操作之后响应的数据中包含的 Function Code 与 Client 发送的一致,并包含需要返回的 Data Response。

【文末赠书】工控安全之Modbus协议实现和安全性分析(上)

如果 Client 发送的请求有问题,Server 无法识别或者执行过程中发生了错误,Server 会返回一个 Exception Function Code,这个值等于将 Client 发送的 Function Code 的最高位置为 1 ,也可以理解成 Exception Function Code = Function Code + 0x80 ,除了这个 Exception Function Code 之外,返回的数据中还包含一个 Exception Code 用于确定异常的类型和产生原因。
从这里可以看出,Modbus 考虑了异常处理机制,避免出现 Client 端永久等待无响应的情况出现。


数据模型

在 Modbus 中,为数据定义了模型,如下表所示。

【文末赠书】工控安全之Modbus协议实现和安全性分析(上)

在这里只给出了 Modbus 标准定义的数据模型,实际上对于很多比较先进的系统来说,仅仅支持这四种数据模型是不够的,还会有很多额外的数据模型,包括但不限于 Bit Access、Data Endianness、Strings 等等,这里因为篇幅的原因就不赘述了。
在表中我们可以清晰的看到,Discrete Input 和 Coils 只支持以 bit 的方式进行访问,而 Input Registers 和 Holding Registers 只支持以 word 的方式进行访问,Discretes Input 和 Input Registers 只支持以只读的方式进行访问,而 Coils 和 Holding Registers 既可以读也可以写。
每一种数据类型,Modbus 协议都支持 65536 个数据项,对不同的数据类型读写时,可能会根据数据类型的大小去跨越多个连续的数据项。
这里的数据模型只是一种抽象,在实际使用的时候,它们需要被映射到真实的物理存储区。在给定的系统中,不同的数据模型之间可以分别占据独立的分开的内存地址,但同时它们也可以互相重叠。举个简单的例子,Coil 1 所在的内存位置可能与 Holding Register 1 所存储数据的第 1 位在同一个位置。这些内存地址的映射全由设备定义,设备依照自己的标准去解析。
我这里简单介绍一下 Modbus 文档中提到的两种管理映射的方式,实际生产环境中定义是自由的,完全由设备自己决定。

【文末赠书】工控安全之Modbus协议实现和安全性分析(上)

在这个方案中,设备有 4 个独立的内存块,每一种数据模型都映射到各自的内存块中,它们之间互不重叠。

【文末赠书】工控安全之Modbus协议实现和安全性分析(上)

在这个方案中,设备只有 1 个内存块,各个数据模型占据的空间之间是存在重叠的。

寻址模式

Modbus 中定义了 PDU 的寻址规则,在 PDU 中每一种数据的地址编号为 0 到 65535,也就是说在数据模型中的每一种数据最多允许有 65536 个元素,数据元素的编号为 1 ~ 65536。在 Wikipedia 上针对这两个概念的叫法会有所不同,分别是实体地址 ( Entity address ) 和 实体编号 ( Entity numbers )。
需要说明的是,65536 只是协议允许的最大元素范围,但并不要求全部实现。设备可以根据自己的情况做调整,甚至不要求实现模型中的全部四种数据。
在实际的应用场景中,特定的设备供应商会将 Modbus 的数据模型与自己的设备应用程序的模型做一个预映射。

【文末赠书】工控安全之Modbus协议实现和安全性分析(上)


例如,在上图中,编号为 Coils 5 的元素地址为 Coils 4。
在实际的应用中,为了更直观的区分编号范围,我们可能还会引入一些前缀。

【文末赠书】工控安全之Modbus协议实现和安全性分析(上)

对于 Coils 来说,元素编号范围可以是 000001~065536,同样的,对于 Discretes Input ,编号范围可以是 100001~165536,对于 Input Registers 来说,编号范围可以是 300001~365536,对于 Holding Registers 来说,编号范围可以是 400001~465536。
PLC 厂商如果用不到那么大的存储区,也可以自定义采用更小的编号范围,比如 10000 以内。
通过这种前缀的方式,我们就可以单从编号就判断出区块的类型( 前提是设备真的是这么实现的 ),并且计算出元素地址。
举个简单的例子,例如编号为 40001 的 holding registers ,它的地址实际上是 0x0,编号为 40100 的 holding registers 它的地址实际上是 0x63 (99) 。

数据编码

在 Modbus 定义中,所有的地址,数据项都采用大端序来排列,这意味着在传送多字节数据的时候,高位数据会被优先传输。例如我们要传输 0x12345678,其中 0x12 为最高位字节,0x78 为最低位字节,按照定义会被优先传送 0x12 接着是 0x34 以此类推。

数据帧格式

协议数据单元(Protocol Data Unit)

PDU 简单来说就是 Modbus 定义的一个与任何基础通信层无关的简单协议数据单元,换句话说,不考虑任何实际的协议传输要求,只关注 Modbus 协议本身需要实现的东西,我们只需要 PDU。
PDU 的结构很简单就是我们前面提到过的,功能码 ( Function Code ) + 数据 ( Data )。
Function Code 的长度为 1 个字节,其中 0 为无效的功能码,128 ~ 255 为保留的或者用于异常响应的 ( Exception Function Code ),在 1 ~ 127 的范围中,分别有 Public Function Code 和 User Defined Function Code ,Public Function Code 主要是 Modbus 标准中定义的大家通用的功能码,User Defined Function Code 则是留给用户自行定义的,具体的分布如下图。

【文末赠书】工控安全之Modbus协议实现和安全性分析(上)

在某些 Function Code 下,是可以省略 Data 的,Data 一般包含一些请求的额外信息,包括但不限于 discrete 和 register 地址、要处理的数据项数量、实际的数据字节数等。
PDU 的最大字节数受限于 Modbus 最初实现的针对串口通信的版本。当时用于 RS-485 总线通信介质进行串口传输,所以对于整个 ADU 只允许传输 256 字节。
因此 PDU 在串口通信中的最大字节数为 256 - Server address ( 1 byte ) - CRC ( 2bytes ) = 253 bytes。

协议数据单元(Application Data Unit)

为了在特定的总线或者网络上能够传输 PDU ,Modbus 定义了几组 ADU 引入了一些附加域以实现完整而准确的数据传输。
大体上我们可以把 ADU 简单理解为 ADU = Address + PDU + Error check。

Address 为地址域,主要用来区分各个从设备,之前已经讲过从设备的地址范围 0 ~ 247 ,当从设备响应主设备时,也会将自己的地址放入回应的地址域中方便主设备知道是哪个从设备作出的响应。

实际上在不同的应用场景和协议版本中 ADU 的实现各有不同,但是在大体上,它们都具备一些通用特征,即包含了目标设备地址和数据的校验,后面我们会详细分析几种不同协议版本的 ADU 的实现。
最后再来简单了解下 ADU 的大小限制。
在 RS-232 / RS-485 上通信的 ADU 的最大字节数为 253 bytes + Server address (1 byte) + CRC (2 bytes) = 256 bytes。
在 TCP/IP 上通信的 ADU 的最大字节数为 253 bytes + MBAP (7 bytes) = 260 bytes 。

ASCII ADU

当设备在 Modbus 网络上以 ASCII 模式通信时,ADU 的格式如上表所示。消息以字符 ":" (0x3A) 开始,以回车换行符 ( CR/LF ) 结束 ( 0x0D,0x0A )。

【文末赠书】工控安全之Modbus协议实现和安全性分析(上)

处于网络上的设备通过不断检测 ":" 字符的方式来接收数据,当检测到 ":" 字符时每个设备就会进入解码状态,并解码下一个字段 Address 来判断是否是发给自己的。消息帧中的字符间的发送时间间隔最长不能超过 1 秒,否则接收的时候会判定为传输错误。
在这种传输方式中,所有的数据包括 ":"、Address、Function Code、data、LRC、CR/LF 都是以十六进制可读字符对来表示一个 8-bit 值的。

比如,":"(0x3A),实际传输的是 0x33 ( "3" ),0x41 ( "A" )。

在 ASCII 的传输方式中可以解决 RTU 的很多问题,并且以 CR/LF 结尾的特性可以方便现在的很多程序去处理数据流。但是这也意味着需要传输原始数据两倍多的数据,而且发送和接收端都必须能够解析 ASCII。
Modbus ASCII 传输方式使用 LRC 校验来保证数据传输不出现差错,后面会统一介绍校验的实现细节。

RTU ( Remote Terminal Unit ) ADU

【文末赠书】工控安全之Modbus协议实现和安全性分析(上)

当设备在 Modbus 网络上以 RTU 模式通信时,ADU 的格式如上表所示。在 RTU 模式中,消息的发送和接收以至少 3.5 个字符时间间隔来标识。
也就是说在 RTU 模式中,3.5 字符时间间隔是区分前后两帧数据的分隔符,类似 ASCII 模式中的 ":" 和 CR/LF。
在实际的实现中,网络设备不断检测总线信号,计算字符的停顿时间,如果两个字符之间的空闲间隔大于 1.5 个字符时间间隔,那么认为报文是不完整的,会丢弃报文。较高的波特率会加重 CPU 的负担,因此协议规定波特率大于 19200 bps 的情况下使用固定值。通常建议 1.5 个字符时间间隔为 750 μs,帧间时间间隔为 1750 μs。
在 RTU 模式中所有的传输都以二进制比特位的形式传输,使用 CRC 来校验。

Modbus TCP/IP ADU

前面已经有提到过,在 Modbus TCP/IP 的实现中,不再有主/从设备的概念,而是可以理解为客户端/服务器。其实是在说原本的一主多从变成了多客户端/多服务端的架构。
Modbus TCP/IP 的 ADU 可以直观表示成下表。

【文末赠书】工控安全之Modbus协议实现和安全性分析(上)

由于 TCP/IP 链路层已确保传输数据的准确性,所以 Modbus TCP/IP 协议中已不再需要校验。
上表中 MBAP( Modbus Application Header ) 可表示为下表。

【文末赠书】工控安全之Modbus协议实现和安全性分析(上)

Transaction identifier 该值是一个标识,主要用来同步客户端和服务端的通信,在同一时刻该值需要是唯一的,我们可以简单理解成 TCP 发送数据包的顺序号(但这只是一种情况,实际上该值的发送由客户端的实现决定,满足唯一即可),该值由客户端生成,服务端在应答时复制该值应答。
这对于同时处理多个请求的网络是很有帮助的,例如主机可以发送三个请求,标识分别是 1,2,3,然后在某个时刻,服务器端响应了三个请求,标识分别是 3,1,2 尽管他们没有按照请求的顺序响应,但是我们仍然可以通过标识区分出哪些响应是对应哪些请求的。
Protocol identifier 是协议标识,默认情况下设置为 0x00 表示 Modbus 协议,也是由客户端生成,应答时复制该值。这里值得注意的是,我们可以通过定义其他的协议标识值来扩展我们自己想要实现的功能。
Length 字段用来描述当前数据包其余部分的长度,该字段有两个字节分别是 High 和 Low ,高位默认被置为 0x00,低位记录后续字节的个数,该字段应答时需要根据应答数据包情况重新生成。
Unit identifier 该字段针对单纯的 Modbus TCP/IP 设备来说,利用 IP 地址即可实现寻址,此时该字段是无用的,必须使用值 0xFF 填充。在 Modbus 服务器设备处于一个串行链路子网通过一个网关配置这个服务器 IP 地址时,TCP 连接中的 IP 识别了网关本身,而网关则通过 Unit identifier 将请求转交给正确的服务器设备。同样的该字段遵循 Modbus 从设备地址的定义,范围为 1~247,地址 0 作为广播地址。应答时复制该值。

Modbus RTU Over TCP/IP、Modbus ASCII Over TCP/IP

简单介绍一下这两种协议,这两种协议主要应用在一种很特殊的情况。即我们需要将串行的 Modbus 协议数据通过 Modbus TCP 传输的情况,此时整个串行的数据都作为 Modbus TCP 的数据部分传输。


参考资料

  1. https://modbus.org/docs/Modbus_Application_Protocol_V1_1b.pdf

  2. https://www.ni.com/en-us/innovations/white-papers/14/the-modbus-protocol-in-depth.html#section--1331881982

  3. https://en.wikipedia.org/wiki/Modbus

  4. https://www.anquanke.com/post/id/185513#h3-5

  5. https://www.prosoft-technology.com/kb/assets/intro_modbustcp.pdf

  6. https://zhuanlan.zhihu.com/p/164885080

  7. http://www.fivevisual.com/uploads/20181121/5062b42fdc36a46c2cbef19b11c9912c.pdf



我是文末福利

《从0到1:CTFer成长之路》签名书赠送:

整整5本!

值此国庆中秋双节

赠送 ICS漏洞监控邮件提醒 *5


Exphub - ICS安全情报平台

http://www.exphub.org/

【文末赠书】工控安全之Modbus协议实现和安全性分析(上)


1.关注ChaMd5安全团队公众号

2.于2020.10.3(周六)中午12点之前

转发本条推文至朋友圈

(凭转发截图兑奖,开奖前删除无效)

3.点击抽奖小程序进行抽奖

【文末赠书】工控安全之Modbus协议实现和安全性分析(上)


end


ChaMd5 ctf组 长期招新

尤其是crypto+reverse+pwn+合约的大佬

欢迎联系[email protected]



【文末赠书】工控安全之Modbus协议实现和安全性分析(上)

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: