CTF:Modbus协议报文_恶意节点查找及错误报文分析

一. 问题描述

所提供的压缩包是某工控业务网络中的实际捕获的通信数据包。请你发现并找出其中所有的Modbus/TCP包。仅仅针对Modbus数据包分析如下几点:

  1. 发现Modbus通信的Master节点地址与相对应的slave节点地址。有几组master-slave? 请绘制业务包中的Modbus基本通信拓扑结构。
  2. 请解析Modbus报文。以几组典型的Modbus通信为例,解析Modbus访问-应答机制的通信。
  3. 请绘制此业务Modbus中的通信数据的时间序列图。要求覆盖数据包中出现的所有的master与slave及其节点.

二. 分析过程

  1. 发现Modbus通信的Master节点地址与相对应的slave节点地址。有几组master-slave? 请绘制业务包中的Modbus基本通信拓扑结构。

1.使用wireshark打开.pcap文件, 设置过滤器规则为modbus,然后右上角文件->导出为csv文件,便于我们读取与分析.

2.编写python程序解析csv文件,详情见AnalysisCSV.py

主要思想为: 若为query请求则判为master节点,若为Response包则判为slave节点,并加入已有master节点所管理的slave节点列表中.运行结果为:

 

假设所有数据包无误, 故有四组master-slave,其拓扑结构为:

注:考虑到192.168.1.13地址应归属于Slave, (根据ip分配顺序的推断)但是其却发送query报文,故疑似该节点受到攻击, 此报文为攻击报文,请求是写多个线圈值.

故正确的拓扑结构应为:

3. 请绘制此业务Modbus中的通信数据的时间序列图。要求覆盖数据包中出现的所有的master与slave及其节点.

1.使用wireshark将数据包 导出为json格式, (导出方式见第一问).此问使用json格式进行分析.具体详见modbus.json

2.编写分析代码AnalysisJson.py

大致思想为:逐项读取json文件,如果发现是slave节点,则将这个包所携带的寄存器值信息压入所对应的Master类中的reg列表中.

最后绘制图表.(运行后,鼠标放在点上面,右上角就会出现time和value值).输入为寄存器值和时间(此处的时间格式是16:49:55-569031000,调试代码可以发现. 点数太多,所以绘制的图表横坐标都粘连在了一起, 因为点太多,散点图还是无法确切判断寄存器数值变化情况,如果要详细查看,源代码中注释的部分(64~67行)可以打印出寄存器值和时间的列表值.)

Slave:192.168.1.10 (太多了,点右边小箭头可以收起来)

Register0:

Register16:

Register14:

Register16:

 Slave:192.168.1.12:

Register0:

Register10:

Register12:

Register16:

 三. 程序源码

1. AnalysisCSV.py

import csv


class Master:
    def __init__(self, s):
        self.src = s
        self.slave = []

    def pushslave(self, s):
        self.slave.append(s)


def main():
    filename = "./modbus.csv"
    master = []
    srclist = []
    with open(filename) as f:
        render = csv.reader(f)
        header_row = next(render)
        print(header_row)
        for row in render:
            src = row[2]
            dst = row[3]
            info = row[6]

            if info.find("Query:") != -1:
                if src not in srclist:
                    srclist.append(src)
                    m = Master(src)
                    master.append(m)

            if info.find("Response") != -1:
                for i in master:
                    if dst == i.src:
                        if src not in i.slave:
                            i.pushslave(src)
            # ii += 1
            # if (ii == 10000):
            #     break
    print("\n\n\n------------------搜索结束,打印出所有的master与对应的slave信息:-----------------------")
    for mst in master:
        print("master:")
        print(mst.src)
        print("slave:")
        for slv in mst.slave:
            print(slv)
        print("----------------------------")


if __name__ == '__main__':
    main()

2. AnalysisJson.py

import json
import jsonpath
import matplotlib.pyplot as plt


class Slave:
    def __init__(self, src):
        self.src = src
        self.reg = [[], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], []]

        self.time = [[], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], []]


def draw(h, ll):
    plt.figure(figsize=(16, 8))
    plt.xlabel("Time :Oct 15, 2019  from 16:46:10-000000000 to 16:49:55-569031000")
    plt.ylabel("The value of register")
    plt.title("the slave.ip.src is in console, the register number also is in console")
    plt.scatter(h, ll)
    plt.show()


def main():
    jsondata = json.load(open('modbus.json', encoding='utf-8'))
    slavecheck = ['192-168-1-10', '192-168-1-11', '192-168-1-12']
    srclist = []
    slavelist = []

    # print(jsondata)
    for pack in jsondata:
        src = jsonpath.jsonpath(pack, '$._source.layers.ip.ip-src')
        src = src[0]
        if src in slavecheck:
            if src not in srclist:
                srclist.append(src)
                slave = Slave(src)
                slavelist.append(slave)

            for sl in slavelist:
                if sl.src == src:
                    newtime = pack["_source"]["layers"]["frame"]["frame-time"]
                    newtime = newtime[13:30]
                    # time = jsonpath.jsonpath(pack, '@._source.layers.frame.frame-time')
                    modbus = pack['_source']['layers']['modbus']
                    for modbusitem in modbus:
                        if 'Register' in modbusitem:
                            regnumber = int(modbusitem[9:11])
                            regvalue = int(modbusitem[21:])
                            sl.reg[regnumber].append(regvalue)
                            sl.time[regnumber].append(newtime)

    print("\n\n-------------------------------search result------------------------------------------------")
    # print(slavelist)

    for slaveitem in slavelist:
        print("slave src:(The dots are replaced by horizontal bars)")
        print(slaveitem.src)
        i = 0
        for regi in slaveitem.reg:
            if len(regi) > 0:
                print("the register number:" + str(i))
                draw(slaveitem.time[i], slaveitem.reg[i])
                # print("the register value list:")
                # print(slaveitem.reg[i])
                # print("the time list:")
                # print(slaveitem.time[i])
            i += 1
        print("--------------one slave has been drawed--------------")


if __name__ == '__main__':
    main()

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值