关于Modbus协议攻防与检测
2024-3-29 16:13:12 Author: www.freebuf.com(查看原文) 阅读量:5 收藏

0x00 简述

Modbus协议是一种用于工业控制系统中设备间通信的通用协议,它广泛应用于自动化领域。然而,正如许多其他通信协议一样,Modbus也存在安全漏洞,这使得它容易受到恶意攻击。当前有很多Scada软件都通过modbus协议来对PLC进行控制与管理。

Modbus协议由于没有认证的环节,再加上现在很少有将modbus进行加密通信的,所以modbus在内网里面基本上都是透明的,只要控制内网的某个控制器,就可以进行重放modbus协议攻击。目前都是modbus协议攻击都是以破坏的目的为主。根据modbus协议攻击的方法,大致分为以下3种:

  • 中间人攻击:黑客可以截取Modbus通信流量,并修改数据或注入虚假命令,从而干扰设备的正常运行。

  • 拒绝服务攻击(DoS):通过发送大量无效请求或者使设备超载,攻击者可以使Modbus从站无法正常工作,导致服务停止。

  • 协议重放:攻击者可以利用Modbus协议的漏洞,向设备发送恶意指令,例如修改参数、篡改数据或者执行不当操作。还可能通过读请求获取泄露敏感信息,例如设备配置、生产数据等,为攻击者提供可利用的情报。

其中中间人攻击、协议重放的原理大致相同,都是通过修改modbus的功能函数与寄存器的值来达到读写数据,拒绝服务攻击则是大量发送正常或是异常modbus请求,让modbus从机瘫痪。

0x01 Modbus协议解析

Modbus主从机通讯分为串口通讯(RTU和ASCII)与TCP通讯,目前Modbus攻击通常都是以TCP为主,所以这里只分析tcp协议。Modbus协议解析相关的内容各大社区都可以获取得到,这里不做详细说明,只说明几个站在攻击角度比较关键的点。

首先是modbus协议的交互方式

Modbus协议发送slave的时候,如果slave解析为合法协议,就给与一个相应的回复,如果不合法,那么就不会响应

然后是协议结构

  • 00 00 事务标识符
  • 00 00 协议标识符
  • 00 06 长度标识符
  • 站号(1个byte)
  • 功能码(1个byte)
  • 首个寄存器地址 (2个byte)
  • 读取寄存器的个数 (2个byte)

协议样例:

00 00 00 00 06 01 05 00 1a ff 00(无校验位)

其中比较重要的位置就是在于站号、功能码、寄存器地址、寄存器值这四个位置。

1) 站号

站号是slave(Modbus从站)的编号,通常可以利用爆破来获取编号,如果站号不对,slave通常不会有响应。

2) 功能码

功能码对应的能力如下表

功能码

描述

PLC地址

寄存器地址

位/字操作

操作数量

01H

读线圈寄存器

00001-09999

0000H-FFFFH

位操作

单个或多个

02H

读离散输入寄存器

10001-19999

0000H-FFFFH

位操作

单个或多个

03H

读保持寄存器

40001-49999

0000H-FFFFH

字操作

单个或多个

04H

读输入寄存器

30001-39999

0000H-FFFFH

字操作

单个或多个

05H

写单个线圈寄存器

00001-09999

0000H-FFFFH

位操作

单个

06H

写单个保持寄存器

40001-49999

0000H-FFFFH

字操作

单个

0FH

写多个线圈寄存器

00001-09999

0000H-FFFFH

位操作

多个

10H

写多个保持寄存器

40001-49999

0000H-FFFFH

字操作

多个

3) 寄存器地址

寄存器地址通俗一点的理解就是PLC的功能块,简单是说就是标识,例如搅拌机、电源开关之类的,指定寄存器地址的值可以对这个功能块进行操作。

4) 寄存器值

值就是功能块的状态,例如电源开就是:00 00,电源关就是:FF 00。

0x02Modbus协议攻击

本次攻击测试采用Matesploit与Modbus模拟器ModbusPal来进行,Matesploit在2012年就集成modbus相关攻击脚本。

用的比较多的就是auxiliary/scanner/scada/modbus_findunitid(站ID爆破)和auxiliary/scanner/scada/modbusclient(modbus功能操作)模块。

打开ModbusPal来模拟一个slave,添加一个coil(线圈)

模拟modbus slave之后,就可以开始攻击了,首先可以先爆破UNITID(站ID)

Msf这个脚本是单线程,爆破起来很慢,也可以写一个python进行多线程爆破

可以看到UNITID是233的时候有返回值。确定UNID为233。

再使用auxiliary/scanner/scada/modbusclient模块对modbus进行攻击,这里以修改Coil(线圈)的值为攻击点。

首先设置攻击点

Set action WRITE_COIL为修改单个Coil的值,带S代表修改多个Coil。设置如下图

其中DATA_ADDRESS为Coil起始地址,DATA_COIL为地址偏移量,DATA为值(0或1)

修改前

修改后

一般PLC的指令是以写线圈的请求下发的,Modbus协议重放攻击篡改PLC基本都是以篡改Coil为主。

0x03Modbus攻击检测

传统的IDS对工控攻击协议的解析能力不是特别强,例如snort,虽然支持对modbus的协议进行解析,但是使用的是预处理机制的,在原理上还是还是使用的特征匹配,虽然能够进行威胁识别,但是灵活度不高,不止snort,其他传统的特征匹配型的IDS均存在这个问题,所以建议使用zeek来进行工控类别的威胁检测。

Zeek(以前称为Bro)是一种开源的网络安全监控系统和网络流量分析框架。它最初是由加州大学伯克利分校开发的,旨在帮助网络管理员和安全专家实时监控和分析网络流量,以发现安全威胁、异常行为和网络性能问题。Zeek采用了一种基于网络流量分析的更为灵活的方法。它对网络流量进行深度分析,提取并聚合各种元数据,然后将这些元数据与用户定义的策略进行匹配,以检测潜在的威胁或异常活动。并且zeek的规则编写更加灵活,支持更多的插件。

工控安全漏洞库CISA为zeek量身打造了一个关于modbus的协议解析套件。项目地址:https://github.com/cisagov/icsnpp-modbus/

可以根据项目地址进行安装组件

可以利用这款套件对modbus攻击做检测,这里以暴力破解UNITID为例,DDOS攻击同样可以使用这种方法进行检测。

暴力破解以DOS类攻击都有相同的特点,就是发送大量的TCP包,但是传统的特征匹配型的IDS没有检测单位时间内包数量的功能,如果需要检测,只能编写插件,zeek自带了一个SumStats插件,可以统计数量(虽然很多人吐槽SumStats不好用,但是有总比没有好)

利用wireshark抓一下破解UNITID的包,输入"modbus"过滤一下modbus协议内容

发现这些包统一的func都是4,即读输入寄存器操作,且UNITID在进行遍历,访问都没有回包,是一个很明显的扫描操作。

我们可以参考icsnpp-modbus中的zeek规则文件提取出解析modbus的协议结构体加以利用。

这个record定义了modbus数据包的各个字典,由于是读输入寄存器操作,可以直接使用zeek自带的event:modbus_read_input_registers_request,相关的功能和定义可以参考zeek帮助

要识别扫描操作需要统计包中的所有读输入寄存器操作,使用event:modbus_read_input_registers_request进行来过滤包,并加入SumStats模块进行请求数量统计,参考icsnpp-modbus的event,我们可以编写如下功能

这个地方的if判断可以不用,因为这个event已经对流量进行过滤了。

然后使用SumStats::observe进行统计。SumStats需要两个比较关键的参数,一个是单位时间,一个是阈值,含义就是设置的单位时间内如果请求数量如果超过阈值,那么就判定为扫描攻击。我这里设置的是10秒发送5个包以上即判断为扫描攻击。

由于调用的SumStats插件代码过滤复杂,其中的细节不做赘述,有兴趣的同学可以参考detect-bruteforcing.zeek来进行编辑。

规则测试结果:

我将告警存放到了notice.log文件

总的来说,zeek检测modbus协议的方案已经比较成熟,可以很好的检测到modbus的威胁。


文章来源: https://www.freebuf.com/articles/ics-articles/396458.html
如有侵权请联系:admin#unsafe.sh