编写简单的hql命令_原创 | 工业网络通讯数据分析之Wireshark插件编写

绿盟科技 工业物联网安全实验室 陈杰 

前言

在分析工控设备流量时,通过Wireshark内置的协议解码插件可以解析一些开放协议的数据格式,但是很多厂家考虑到安全性和产品独特性并不会公开私有的报文格式。这就需要通过逆向工程或者查阅相关文档来了解通讯协议的数据格式,从而编写Wireshark协议解码插件来解析未知的工业网络通讯数据报文格式。

协议分析

本文中,我们以一个国产某工控设备的上位机流量作为例子,如下:

7a75f74dc240f94e51a88e80928c1522.png

使用Wireshark抓取到的流量如下,可以看到该数据报文是基于TCP协议的,下位机的端口为500。

7672b824e879947d86f97db107d106b2.png

由于上位机是C#写的,可以用dnSpy快速定位到其协议解析的逻辑代码,通过静态分析和动态调试的手段来分析出上位机和下位设备之间通信的报文格式。

e1e06a28516144344a9307f82f8de739.png

该报文简单格式如下表格,这里只分析到报文格式的头部,不过对于工业网络通讯数据分析来说,识别出该报文对应的业务操作已经足够了。

字段

字节数

说明

ID

4

包序号

length

2

数据包长度

station

1

站号

cmd

1

命令

address

1

地址

subcmd

1

子命令

operate

1

操作号

subaddress

2

子地址

datalen

1

读/写数据的长度

Data (可选)

Datalen (可变)

读/写数据

编写插件 Lua脚本

目前对于Wireshark来说,C/C++语言和Lua脚本是编写插件的主流语言,对于C/C++语言这类语言来说,不可否认它具有非常高的性能,但是其编译配置较为麻烦,每次修改都要重新编译,而Lua脚本虽然解析效率没前者那么高,但是它的语法和修改都非常简单,可以提高了开发效率。所以,这里选择了Lua作为编写插件的语言。

959a7e957fbcdc1712f660babe55f294.png

Wireshark软件是否支持Lua插件脚本的检查方法:启动Wireshark,依次点击”帮助”,”关于 Wireshark“菜单,在打开的对话框中的”Wireshark”标签页上观察版本信息,如果如下图一样显示With Lua,说明此版本支持Lua插件。

6041bde8360b373ad3310749b1fb30aa.png

编写插件

1. 开始编写Lua插件,首先简单定义协议名称和协议说明。

6ff3e1453559efaa80688670db17e8cd.png

2. 根据不同的报文字段类型添加每个字段的名称。

76eab1ec6c05b94fc42965a76fe93d29.png

在这里,可以将不同的命令解释显示出来,从而增加可读性,如下:

dc39e3892d684cbaab79b4fc901a2d80.png

3. 构建一个解析器函数,根据每个字段的偏移和大小,对每个字段进行显示。

561e4bb90c97ebebe346c7a1080c0ea9.png

4. 最后将编写好的解析器添加到TCP 500端口上。

ac566ed3c019bb09d5583202ee58704d.png

5. 最后的插件代码如下:

--Etrol plugin local subcmd_desc={    [1]="SYSCOM",    [2]="SCANCOM",    [3]="EVENCOM",    [4]="PIDCOM",    [5]="PIDPARA",    [6]="SYSMSG",    [7]="HARTCOM",    [8]="SYSRESET",    [17]="DNP3DBCOM",    [18]="DNP3CHN0COM",    [19]="ZIGBEECOM",    [20]="DNP3OTHER",}local operate_desc={    [0]="CLRMOD",    [1]="READCOM",    [2]="WRITECOM",    [4]="WRITEFLASH",}local cmd_desc={    [137]="read/write",    [144]="PROG_update",}Echo_protocol=Proto("Echo_500","Echo_500 protocol")pktid = ProtoField.uint32("Echo_500.ID", "ID", base.DEC)pktlen = ProtoField.uint32("Echo_500.length", "length", base.DEC)station=ProtoField.uint32("Echo_500.station", "station", base.DEC)cmd = ProtoField.uint32("Echo_500.cmd", "cmd", base.DEC,cmd_desc)address = ProtoField.uint32("Echo_500.address", "address", base.DEC)subcmd = ProtoField.uint32("Echo_500.subcmd", "subcmd", base.DEC,subcmd_desc)operate = ProtoField.uint32("Echo_500.operate", "operate", base.DEC,operate_desc)subaddress = ProtoField.uint32("Echo_500.subaddress", "subaddress", base.DEC)datalen = ProtoField.uint32("Echo_500.datalen", "datalen", base.DEC)data = ProtoField.bytes("Echo_500.Data", "Data")hex=function(num) return string.format("%#x",num) endEcho_protocol.fields={pktid,pktlen,station,cmd,address,subcmd,operate,subaddress,datalen,data}function Echo_protocol.dissector(buffer,pinfo,tree)    local length=buffer:len()    if length<14 then return end    pinfo.cols.protocol=Echo_protocol.name    local subtree=tree:add(Echo_protocol,buffer(),"Echo Protocol Data")    subtree:add(pktid,buffer(0,4))    subtree:add(pktlen,buffer(4,2))    subtree:add(station,buffer(6,1))    subtree:add(cmd,buffer(7,1))    subtree:add(address,buffer(8,1))    subtree:add(subcmd,buffer(9,1))    sub_cmd=buffer(9,1):uint()    subtree:add(operate,buffer(10,1))    Operate=buffer(10,1):uint()    subtree:add(subaddress,buffer(11,2))    subtree:add(datalen,buffer(13,1))    if length>14 then        local databuf=buffer(14,length-14)        local data_subtree=subtree:add(data,databuf)    endendlocal tcp_port=DissectorTable.get("tcp.port")tcp_port:add(500, Echo_protocol)
运行插件

为了Wireshark加载编写好的插件,需要打开Wireshark主目录下的init.lua文件,确保disable_lua的值为false,即开启了lua。同时将编写好的插件保存为echo_500.lua放到Wireshark主目录,在init.lua文件最后一行添加dofile(DATA_DIR.."echo_500.lua"),通过这样的方式加载自定义的插件。

d071b07b589c6874e2e561c266785336.png

重启Wireshark,重新抓取数据包,可以看到协议已经解析成功。这里识别出来这是一个SYSMSG命令,用于读取设备状态。

1d7f1013a7fd123d2d07ed4b1f51ccfb.png

之后每次修改脚本后,可以通过快捷键“Ctrl+Shift+L”重新加载脚本,不需要每次重启Wireshark软件。

1f5fea9a5777e0ff3bcbd7a05c11a4ed.png 总结

本文简单介绍了Wireshark插件的编写方法,通过编写插件来解析第三方的私有协议,帮助我们更好理解工控上位机和下位机的交互。当然,有些工控流量可能比本文的例子相对复杂一些,可能包含加密和签名等字段,这就需要更长的逆向分析时间,只要把协议数据的报文格式了解清楚了,那么编写插件也是水到渠成的事情。

转载请注明来自:工业互联网安全应急响应中心(微信号ICSCERT)

a8a95651bf928560587332eb7825ea93.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值