工控防火墙作为在国家重要基础设施(如大铁、电力、核电厂等)环境中使用的网络安全设备,对其工作的正确性和可靠性都有着极高的要求,特别是对现场协议报文的解析与处理尤为关键。站在客户的角度思考,接入客户生产环境的网络设备只有经过充分测试能够做到以下两点,才可以被放心使用:
两点:
◇ 对现场协议报文可以正确解析
◇ 设备可以稳定工作以上两点与工控防火墙在现场环境中工作的节点位置有关,工控防火墙连接着不同安全级别的网络,如果不能正确解析现场的协议报文就有可能导致“该放过的动作没有放过”和“该拦截的动作没有被拦截”,这将是严重性的,甚至灾难性的。而稳定性对工控行业客户的影响也是不言而喻,如果设备发生崩溃或者程序异常退出导致客户现场通信中断,则会产生严重的影响,甚至可能影响生产!如何在交付客户使用前对产品的核心功能-工控报文解析进行充分测试,是质量保证人员需要认真思考的问题!下面将以在工控领域被广泛使用的Modbus协议(Modbus TCP)为例,来说明如何对工控防火墙的核心功能“报文解析及处理”进行深入、全面的测试和验证!本篇文章的呈现思路是找到一种思想(战略),去深入验证工控防火墙业务报文处理的正确性、持续性、容错性及设备(系统级)的可靠性,然后把战略分解成对应的战术支撑(即本文要介绍的“场景构造及Fuzzing”),最后找到一种高效、可行的方法实现战术的落地。
从报文的格式中可以看出Modbus TCP是以太格式封装,上层Modbus ADU由三部分构成:Modbus应用协议头+功能码+数据,数据部分的内容和长度要根据具体的事务来定。
事务处理标识符:用于区分事务对,可以理解为报文的序列号,每次通信之后就要加1以区别不同的通信数据报文。
从列表中可以看出,功能码涉及到两大类,数据访问和诊断。在Modbus TCP中使用到的数据访问包含了线圈、离散量、输入寄存器、保持寄存器。其中线圈和离散量的访问方式为按位访问,寄存器相关的为16位访问。数据部分可以先来看下面的Modbus TCP的事务通信模型,可以看到数据分为两种:客 户端的请求数据和服务端的响应数据。
知道了C/S的通信方式,再结合功能码表中的不同类型事务,下面就以功能码16(0x10)为例来说明“写多个寄存器”的客户端请求数据报文和服务器端的响应数据报文。
上面是“写多个寄存器”请求报文和响应报文的组成、字节数及数值范围,到此我们终于可以知道一种具体的Modbus TCP报文(请求/响应)长什么样了,而且还能给每个字段定义具体的数值。更具体一点,现在我们可以给出“写10个寄存器”的客户端请求报文的Modbus ADU和服务器响应报文的Modbus ADU。1)“写10个寄存器”客户端请求报文的Modbus ADU36 33 00 00 00 1B 04 10 00 64 00 0A 14 00 0A 01 02 06 10 07 08 09 10 06 10 06 10 06 10 06 10 06 10MBAP Header: 36 33 00 00 00 1B 04PDU: 10 00 64 00 0A 14 00 0A 01 02 06 10 07 08 09 10 06 10 06 10 06 10 06 10 06 102)“写10个寄存器”服务器响应报文的Modbus ADU36 33 00 00 00 06 04 10 00 64 00 0AMBAP Header: 36 33 00 00 00 06 04
在详细了解了具体Modbus TCP协议后,我们现在已经可以确定某一种功能码的Modbus TCP报文格式及取值范围了,也就可以通过某种具体的方法去构建特定功能码的ModbusTCP报文和构建特定场景下的业务逻辑去验证防火墙的功能和行为了。 具体方法为借助python语言实现,按照TCP/IP协议分层模型去快速构建对应的Modbus TCP协议报文。形如Ether()/IP()/TCP()/Raw()modbus_request=Ether()/IP(src="100.100.100.100",dst="200.200.200.200")/TCP(dport=502)/Raw(load='\x36\x33\x00\x00\x00\x1B\x04\x10\x00\x64\x00\x0A\x14\x00\x0A\x01\x02\x06\x10\x07\x08\x09\x10\x06\x10\x06\x10\x06\x10\x06\x10\x06\x10')modbus_response=Ether()/IP(dst="100.100.100.100",src="200.200.200.200")/TCP(dport=502,flags=16)/Raw(load='\x36\x33\x00\x00\x00\x06\x04\x10\x00\x64\x00\x0A')注:需要自己解决网络的连通性及保证ARP报文解析的可达性.以该功能码为基础进行场景构建,以下列出了大致涉及到的需要覆盖的场景:1)MBAP Header中事务处理标识符,包括范围内和超出范围的2)MBAP Header中长度值,包括范围内和超出范围的。3)MBAP Header中单元标识符,包括范围内和超出范围的。III)寄存器数量:功能码16(0x10)"写多个寄存器".1-123个 2.响应报文:
1)MBAP Header中事务处理标识符,包括范围内和超出范围的;
2)MBAP Header中事务处理标识符,响应事务标识符与请求事务标识符不匹配;
3)MBAP Header中长度值,包括范围内和超出范围的。
4)MBAP Header中单元标识符,包括范围内和超出范围的。
5)MBAP Header中单元标识符,与请求端不一致。
6)功能码及数据
I)功能码:可识别的,不可识别的
II)起始地址:范围内的,超出范围的
III)寄存器数量:功能码16(0x10)"写多个寄存器".1-123个
针对某种场景,会有对单个字段值进行不同取值覆盖的需求,此时引入fuzzing测试的思想最为高效,即对python脚本进行修改,有针对性地控制报文长度及报文不同协议层中需要变换覆盖的字段值。 比如对协议报文的功能码字段,以及起始地址等去快速进行变换以验证防火墙的解析能力。下面举例实现三个场景构造,其它场景就不详细列举了:功能码16(0x10) “写多个寄存器”的客户端请求报文分片36 33 00 00 00 1B 04 10 00 64 00 0A 14 00 0A 01 02 06 10 07 08 09 10 06 10 06 10 06 10 06 10 06 10
构造报文完成后发出,使用wireshark抓包,此时发现重组后的报文chksum值报错,可以调整报文,手工修改成正确的chksum值再次发送即可。
例如双层Modbus封装(其余场景还有很多,不一一列举)
以上就是在实际工作中总结的场景构造和Fuzzing测试方法,希望能给大家一些启发和帮助!附:Modbus客户端活动图、Modbus服务端处理逻辑
1. Modbus_Application_Protocol_V1_1b3.pdf
2. Modbus_Messaging_Implementation_Guide_V1_0b.pdf
版权说明:本篇文章为个人参考以上两个Modbus标准协议文档及总结个人在实际工作中的积累而成,如需引用该文章内容时注明出处。
威努特简介北京威努特技术有限公司(以下简称“威努特”), 是国内工控网络安全领军企业、全球六家荣获国际自动化协会安全合规学会ISASecure CRT Tool认证企业之一和亚太地区唯一国际自动化学会(ISA)全球网络安全联盟(GCA)创始成员。
威努特作为国家高新技术企业,以创新的“白环境”整体解决方案为核心,自主研发了全系列工控网络安全专用产品,拥有52项发明专利、50项软件著作权、52项原创漏洞证明等核心知识产权。积极牵头和参与工控网络安全领域国家、行业标准制定,受邀出色完成新中国70周年庆典、中共十九大、全国两会等重大活动的网络安保任务,被授予“国家重大活动网络安保技术支持单位”,得到了中央网信办、公安部、工信部等国家政府部门的高度认可。迄今已成功为电力、轨道交通、石油石化、军工、烟草、市政、智能制造、冶金等国家重要行业1000多家工业企业提供了全面有效的安全保障。
威努特始终以“专注工控,捍卫安全”为使命,致力于为我国关键信息基础设施网络空间安全保驾护航!
渠道合作咨询 张先生 18201311186
稿件合作 微信:shushu12121