转载:安全客

酝酿了“三秒钟“,准备理清逻辑写写我学习的心得,自认为和Siemens S7协议有过一段时间浅浅的“交流”,所以这过程中涉及到了自己整理的自认为有用的东西,涉及工具、脚本这般,发出来让大家都能看到,逻辑也许简单,但努力写的尽量不那么的潦草。

0x01 环境介绍


Kali 2.0、Python2.7、Pycharm

0x02 初次尝试


都说scapy是很强势的第三方库,很多人用它实现端口扫描,那么我通过学习它并且尝试实现针对Siemens S7协议的Fuzz脚本。

首先需要明白几个特别重要的点,在下面一一总结。首当其中当然是做个最简单的三次握手,TCP没有三次握手又怎么能行呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/usr/bin python
# -*- encoding: utf-8 -*-
from scapy.all import *
src = sys.argv[1]
dst = sys.argv[2]
dport = int(sys.argv[3])
def tcpConnect():
    SYN = TCP(sport=sport, dport=dport, flags='S', seq=0)
    try:
        SYNACK = sr1(ip / SYN, timeout=1)
        print SYNACK[1][0]
    except:
        print "TCP Connect Error."
    else:
        ACK = TCP(sport=sport, dport=dport, flags='A', seq=SYNACK[1][0].ack, ack=SYNACK[1][0].seq + 1)
        send(ip / ACK)
        return SYNACK
if __name__ == __main__:
    sport = random.randint(1024, 65535)
    ip = IP(src=src, dst=dst)
    tcpConnect()

代码很简单的四行,实现的原理就是指定“源IP”、“目的IP”、“目的端口”完成三次握手的过程,我们可以通过运行这个Python脚本结合Wireshark抓包来分析具体的过程:

在外部主机通过TCP/UDP调试工具模拟开启服务端,在虚拟机运行脚本。

我们注意到,通过Wireshark抓包应该你会看到三次握手并没有像预想的那样建立,是被本机Reset掉了,是什么原因呢?

Iptables收到了返回的ACK数据包,而它检测到系统本身没有发送过任何的SYN握手包,所以重置这个握手连接(举个例子:你在一家饭店坐着,一句话没说服务员就端上一盘龙虾说“这是您点的龙虾”,其实是某位顾客给你叫的,你的本能可能也会是拒绝。)

怎样来避免出现这样的情况,可以添加iptables规则来解决,比如下面这条直接丢弃掉所有的RST包(当然最好自己根据实际的情况去添加规则,举例的这个规则有点儿极端)。

1
iptables -A OUTPUT -p tcp --tcp-flags RST RST -j DROP

添加规则之后,再次执行脚本,我们看到通过三次握手,建立连接。

0x03 Scapy几个函数


三次握手简单的实现了,但是我们从这个简单的代码中需要知道Scapy的几个函数:

Send(): 这个函数只会将数据包发送出去,也就是只发不收。

Sr1(): 这个函数会在发送数据包之后,接收返回的第一个数据包(如,你发送了一个数据包,对方先返回一个ACK数据包,之后返回了带有数据的数据包,那么这个函数会接收到第一个返回的ACK数据包)

Sr(): 这个函数会发送并接收数据包,区别于上面的Sr1(),这个函数会接收返回的所有数据包。

那么我们自然也可以明白在三次握手的代码中,我们首先用到Sr1()函数发送SYN数据包之后接收返回的ACK数据包,然后再收到ACK后Send()给对方一个ACK数据包。

0x04 Ack和Seq


每次数据的交互,从一次完整的三次握手开始,Ack和Seq的值是跟随着每一步在变化,在建立三次连接之后的数据交互过程中Ack和Seq的变化关系到通过Scapy伪造的数据包能不能正常被接收以及被回复。

这是之前做的一个很简陋的过程的图片,我们从这个过程中需要通过这样的变化规律来不断的改变Ack和Seq的值,以此来发送正确的数据包达到与目标设备正常交互的过程。

通过Wireshark抓包我们看到的效果是最直观的看到交互过程中Seq和Ack值的变化,最终在代码中如何实现,需要利用Scapy接收到数据包的格式来确定下一个数据包的Ack和Seq。需要发送的伪造的数据包的Seq值为接收到的数据包的Ack值,伪造的数据包的Ack值可以将接收到的数据包的Seq值加数据部分data的长度确定。

在上图中Wireshark数据包中解析已经显示了下一个Seq值,但实际上这一点并没有在数据包中提现,所以只是Wireshark自己计算并显示了这个值,可能用于方便抓包分析的人识别数据包的对应关系?不得而知……

对于如何通过Scapy来实现对这些参数的伪造呢?

我们通过Scapy的sniff模块来嗅探并过滤几个数据包来举例查看数据的格式,我们可以看到Scapy模块接收到的数据以元组的方式存储,那么Sr()、Sr1()都是以元组的方式呈现接收到的数据包。我们通过元组的访问方式取得数据包中每层对应的参数。可以具体一步步调试确定准确的位置。

这样的话我们可以通过sniff模块中的各部分的具体参数来获取接收到数据的长度,获取上一个数据包中的Ack和Seq值,和自己准备的数据长度结合即可确定下一个数据包中Ack和Seq的准确值,同时还可以通过判断flags这个参数获取数据包的类型: S/SA/PA。

这样看来,我们基本已经完成了准备工作:

三次握手、Ack和Seq的变化,我们需要的是准备自己的Fuzz数据就可以实现一个简单的Fuzz脚本,基于Scapy实现的Fuzz脚本。

0x05 脚本实现流程


这一部分就先来确定自己实现一个简单脚本的思路流程,通过自己制作的一个糙的流程图来看:

TCP的三次握手

S7协议的建连

Fuzz数据的交互

日志收集

0x06 S7 建连过程


S7协议和TCP的感觉有点儿类似,需要一个建立连接的过程,在三次握手之后,需要发送S7协议自己的建立连接的数据,之后才能与设备建立连接进行数据的传输。

Wireshark中内置了S7协议的解析模块,不是对每个模块的功能都有完全的解释,但是在对协议理解的上手过程中会起到很重要的作用,可以帮助我这样的新手一定程度上很好的理解。

我们可以看到Wireshark在很大的程度上已经对协议数据中每个部分的内容进行了解释,同时我们可以在实现的时候通过整个数据进行重放来实现建立连接的过程。

1
2
3
4
5
6
7
8
9
10
11
12
def hello_plc(self):
    hello_data = str2byte(hello)
    hello_packet = TCP(sport=sport, dport=dport, flags='PA', seq=self.ack, ack=self.seq + 1)
    COTPACK = sr(ip / hello_packet / hello_data, multi=True, timeout=5)
    comm_data = str2byte(set_comm)
    comm_pkt = TCP(sport=sport, dport=dport, flags='PA',
                   seq=COTPACK[0][1][1].ack, ack=COTPACK[0][1][1].seq + len(COTPACK[0][1][1].load))
    COMMACK = sr(ip / comm_pkt / comm_data, multi=True, timeout=5)
    comm_ack = TCP(sport=sport, dport=dport, flags='A',
                   seq=COMMACK[0][2][1].ack, ack=COMMACK[0][2][1].seq + len(COMMACK[0][2][1].load))
    send(ip/comm_ack)
    return COMMACK

这个函数里面可能有几个参数需要简单说一下,因为它们的作用保证了这个Fuzz脚本可以正确的接收到返回的带有数据的数据包。

Sr()函数的“multi”和“timeout”,设置发出数据包后等待时间和超时时间,因为在实际的环境运行的时候,如果使用Sr1(),容易出现发送数据后设备先返回一个ACK数据包(不包含任何数据),使用Sr()会在接收异常的时候一直等待或一直接收,不能准确的定位到我们需要的数据部分,所以添加这两个参数有足够的时间等待接收到返回的带有数据的数据包,同时也避免了一直接收其他无关的异常数据。

0x07 暂告一段


到此为止,我们已经从TCP的三次握手,到通过与设备的Siemens S7协议进行交互建立连接,以及在过程中如何确保数据包中个参数的变化情况,保证伪造的数据包有效。剩下的部分就是如何针对自己的环境去实现一个简单的Fuzz脚本对协议进行Fuzz测试。我仍然在不断整理不断总结。

Scapy Fuzz实现——S7协议从建连到“正常交流“(一)的更多相关文章

  1. 基于S7协议实现与西门子PLC通信

    西门子PLC是目前工控行业市场占有额比较大的一款PLC,而且随着上位机的越来越普及, 有很多人开始考虑自己开发上位机实现与西门子PLC的通信,遇到的第一个问题就是数据通信. 其实西门子PLC提供的接口 ...

  2. [zencart教程]zencart外贸建站仿站交流俱乐部

    [zencart教程]zencart外贸建站仿站交流俱乐部 1.你想自主一天仿做一个精美的zencart 外贸网站; 2.你想自已自主定制精美的psd 图 zencart模板,并把它变成自定义精美 z ...

  3. ipad协议7.0,与大佬们分享几套新老版本的协议源码及算法,交流心得。

  4. C# 读写西门子PLC数据,包含S7协议和Fetch/Write协议,s7支持200smart,300PLC,1200PLC,1500PLC

    本文将使用一个gitHub开源的组件技术来读写西门子plc数据,使用的是基于以太网的TCP/IP实现,不需要额外的组件,读取操作只要放到后台线程就不会卡死线程,本组件支持超级方便的高性能读写操作 官方 ...

  5. python 读写西门子PLC 包含S7协议和Fetch/Write协议,s7支持200smart,300PLC,1200PLC,1500PLC

    本文将使用一个gitHub开源的组件技术来读写西门子plc数据,使用的是基于以太网的TCP/IP实现,不需要额外的组件,读取操作只要放到后台线程就不会卡死线程,本组件支持超级方便的高性能读写操作 nu ...

  6. java android 读写西门子PLC数据,包含S7协议和Fetch/Write协议,s7支持200smart,300PLC,1200PLC,1500PLC

    本文将使用一个gitHub开源的组件技术来读写西门子plc数据,使用的是基于以太网的TCP/IP实现,不需要额外的组件,读取操作只要放到后台线程就不会卡死线程,本组件支持超级方便的高性能读写操作 gi ...

  7. EPF:一种基于进化、协议感知和覆盖率引导的网络协议模糊测试框架

    本文系原创,转载请说明出处:from 信安科研人 目录 实验 工具的安装 1.安装AFL++ 2.安装epf 对IEC104协议库进行fuzz 实验准备 使用AFL++中的编译器插桩 开始fuzz 原 ...

  8. Thrift的TCompactProtocol紧凑型二进制协议分析

    Thrift的紧凑型传输协议分析: 用一张图说明一下Thrift的TCompactProtocol中各个数据类型是怎么表示的. 报文格式编码: bool类型: 一个字节. 如果bool型的字段是结构体 ...

  9. python自动化运维三:数据报表定制以及scapy模块介绍

    p { margin-bottom: 0.25cm; line-height: 120% } a:link { } Excel也是报表的一个重要的工具.这里首先接受下excel的操作.先来看一个简单的 ...

随机推荐

  1. Python 2和Python 3的编码问题

    在Python2中,字符串无法完全地支持国际字符集和Unicode编码.为了解决这种限制,Python2对Unicode数据使用了单独的字符串类型.要输入Unicode字符串字面量,要在第一个引号前加 ...

  2. Linux文件权限属性后面有个点

    坑啊,新上的机器,监控怎么都不好使,各种报错说:没有权限 什么情况? 仔细查看,发现文件权限属性后面怎么多了个点,类似如下: 这是什么? 原来: 开启了SELinux功能的Linux系统就会有这个点. ...

  3. BZOJ3322[Scoi2013]摩托车交易——最大生成树+贪心+倍增

    题目描述 mzry1992 在打完吊针出院之后,买了辆新摩托车,开始了在周边城市的黄金运送生意.在mzry1992 生活的地方,城市之间是用双向高速公路连接的.另外,每条高速公路有一个载重上限,即在不 ...

  4. Studio启动的时候报错 Could not install Gradle distribution from

    安装了studio以后,直接点击[Start]报如下错,绝对不是网络的问题. Could not install Gradle distribution from 'https://services. ...

  5. MT【35】用复数得到的两组恒等式

    特别的,当$r\rightarrow1^{-}$时有以下两个恒等式: 第二个恒等式有关的自主招生试题参考博文MT[31]傅里叶级数为背景的三角求和 评:利用两种展开形式得到一些恒等式是复数里经常出现的 ...

  6. POJ1088(记忆搜索加dp)

    滑雪 Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 106415   Accepted: 40499 Description ...

  7. Codeforces 382 D Permutations

    题目大意: 给出一张二分图,这张二分图完美匹配的个数是奇数,求删掉第$i(1<=i<=m)$条边后完美匹配个数的奇偶性. 设这张图的邻接矩阵为$A$,那么完美匹配的个数为$A$的积和式,即 ...

  8. [luoguU42591][小T的绝对值]

    luoguU42592 20分思路 对给出的序列求出前缀和,然后\(n^2\)暴力枚举即可拿到第一档分 40分思路 对于数列中的数都相同的情况.只需要特判即可.只要特别注意全都是0的情况即可. 100 ...

  9. bin内置函数

    光棍们对1总是那么敏感,因此每年的11.11被戏称为光棍节.小Py光棍几十载,光棍自有光棍的快乐.让我们勇敢地面对光棍的身份吧,现在就证明自己:给你一个整数a,数出a在二进制表示下1的个数,并输出. ...

  10. C#面向对象设计的七大原则

    本文我们要谈的七大原则,即:单一职责,里氏替换,迪米特法则,依赖倒转,接口隔离,合成/聚合原则,开放-封闭 . 1.   开闭原则(Open-Closed Principle, OCP) 定义:软件实 ...