2016年10月份美国半个国家互联网陷入瘫痪,黑客挟持成千上万物联网设备对美国DNS服务商Dyn发动了三波流量攻击,使得Dyn多个数据中心服务器受到影响,导致美国大部分网站都出线无法访问情况,包括:亚马逊、Etsy、GitHub、Shopify、Twitter 、Netflix、Airbnb等热门网站,此次的DDOS攻击让很多人觉得整个互联网都陷入了瘫痪。

DDOS网络攻击是互联网上最为常见的针对IDC基建攻击方式,借助多台计算机设备发送大量合理/伪造数据包成倍提高对目标的攻击能力,导致合法用户无法正常访问服务器资源,直接影响着网站的正常经营。

而iptables是Linux平台下的包过滤防火墙,与大多数的Linux软件一样,这个包过滤防火墙是免费的,它可以代替昂贵的商业防火墙解决方案,完成封包过滤、封包重定向和网络地址转换(NAT)等功能。上文所提到的ddos就可以通过简单的配置iptables来防止ddos攻击,就比如iptables -A INPUT -i eth0 -p tcp --syn -m connlimit --connlimit-above 15 -j DROP这么一句只要是一个ip超过15个连接就直接drop。由此我们可以看出iptables的使用是非常方便的,而我们的工业控制防火墙中,iptables起到了一个框架性的包过滤作用,在相应的进入点上实现防火墙功能,本人主要负责iptables这一块的实现,下面我们就针对iptables来进行深度的分析。

关键词:工业控制,协议,防火墙。

Depth analysis of Firewall Based on iptables

abstract

Gulong

School of computer science and technology, Shanghai University of Electric Power, Shanghai 20142181, China

In 2016 October the United States half a national Internet hackers paralyzed, holding hundreds of things networking equipment to the United States DNS service Dyn launched a three wave of attack traffic, Dyn makes multiple data center servers are affected, resulting in the United States most of the sites are unable to access the line, including: Etsy, GitHub, Amazon, Shopify, Twitter, Netflix, Airbnb and other popular sites, the DDOS attack makes a lot of people think the Internet has paralyzed.

DDOS network attacks on the Internet is the most common attacks on IDC infrastructure, with the help of computer equipment to send a large number of reasonable / bogus data doubled on the target attack, leading to the legitimate users can not access the server resources, directly affects the normal operation of the site.

Iptables is a packet filtering firewall under Linux platform, as with most of Linux software, the firewall is free, it can replace the expensive commercial firewall solution, complete packet filtering, packet redirection and network address translation (NAT) function. The above mentioned DDoS can prevent DDoS attacks through the simple configuration of iptables, such as iptables -A INPUT -i eth0 -p TCP --syn -m connlimit --connlimit-above 15 -j DROP such a sentence as long as a IP of more than 15 directly connected drop. It is very convenient to see the use of iptables and firewall in our industrial control, iptables played a role in the framework of packet filtering, firewall function in the corresponding entry point, I am mainly responsible for the implementation of iptables in this piece, we have the following in the iptables analysis of depth.

Keywords: industrial control, protocol, firewall.

1绪论

1.1 课题背景及意义

2010年6月,“震网”病毒首次被发现,它被称为有史以来最复杂的网络武器,因为它悄然袭击伊朗核设施的手法极其阴险。

2010年9月,瑞星公司监测到这个席卷全球工业界的病毒已经入侵中国。瑞星反病毒专家警告说,我国许多大型重要企业在安全制度上存在缺失,可能促进Stuxnet病毒在企业中的大规模传播。2010年12月15日,一位德国计算机高级顾问表示,“震网”计算机病毒令德黑兰的核计划拖后了两年。这个恶意软件2010年一再以伊朗核设施为目标,通过渗透进“视窗”(Windows)操作系统,并对其进行重新编程而造成破坏。2011年1月26日,俄罗斯常驻北约代表罗戈津表示,这种病毒可能给伊朗布什尔核电站造成严重影响,导致有毒的放射性物质泄漏,其危害将不亚于1986年发生的切尔诺贝利核电站事故。2012年6月1日的美国《纽约时报》报道,揭露“震网”病毒

震网传播起源于2006年前后由美国前总统小布什启动的“奥运会计划”。2008年,奥巴马上任后下令加速该计划。2013年3月,中国解放军报报道,美国曾利用“震网”蠕虫病毒攻击伊朗的铀浓缩设备,已经造成伊朗核电站推迟发电,目前国内已有近500万网民、及多个行业的领军企业遭此病毒攻击。 这种病毒可能是新时期电子战争中的一种武器。震网病毒,截止2011年,感染了全球超过45000个网络,60%的个人电脑感染了这种病毒。

可以说震网病毒带来的危害及其可怕的,而最关键的是,工业设备在内网环境中大多数没有防火墙一类的设备去阻止基于modbus等一系列工业控制协议的过滤规则。

而iptables正好是可以进行规则匹配来进行一系列保护措施的利器。将来智能工厂采用标准化的以太网络,实现实时监控、远程管理,对于生产、管理效率提升有莫大价值,不容任何恶意攻击破坏。历经2010年伊朗核电厂遭骇等重大事件,用户纷纷对工业设备安全有所警觉,捍卫设备生产力价值的过程中,最可望发挥关键助力的工业防火墙在未来将会有巨大的前景。

1.2 国内外研究现状

其实国内现在逐渐开始已经有一些成熟的工业专用的防火墙,例如GUARD,它利用了许多自主研发的技术例如:无IP隔离技术,分布式部署集中管理,二层协议防护,工业协议深度包检测,报警日志管理等。包括北京威努特公司的产品,我们可以看到它能够保护工业控制网与管理信息网之间的边界,支持对OPC等协议的深度解析,阻止来自管理信息网的安全威胁,保护数据采集系统安全。而加拿大多芬诺的产品内置50多种专有工业通信协议,与常规防火墙不同的是,Tofino防火墙是基于内置工业通讯协议的防护模式,由于工业通讯协议通常是基于常规TCP/IP在应用层的高级开发所以该防火墙不仅是在端口上的防护,更重要的是基于应用层上数据包深度检查,属于新一代工业通讯协议防火墙,为工业通讯提供独特的、工业级的专业隔离防护解决方案。

我国的工业不断发展,工控网络采用业者自行定义的通讯协议,网络环境封闭。然随着智能化生产意识抬头,加上以太网络普及、连网成本急遽下降,封闭式工控网络逐渐接轨开放式以太网络,但工控网络一旦开放,将可能让有心人士乘隙潜入,为避免生产线受到滋扰,工控网络必须增设工业防火墙

1.3 论文组织形式

本论文共分为四章。

第一章 绪论。

第二章 iptables防火墙简介和其使用,将会把与iptables相关的知识全都普及并作分析和实例解析

第三章 modbus等工业控制协议的数据传输模式和在本工业防火墙中的解析。

第四章 使用python-iptc实现对iptables框架的操作进而实现modbus/TCP协议的深度检测

第五章 总结与其他可扩展性

1.4 本章小结

本章主要为绪论部分,对课题的背景、研究意义和论文组织形式等进行阐述。详情可见各章节。

2 iptables简介

iptables是一个用户空间的应用程序,允许系统管理员配置表[ 2 ]利用Linux内核的防火墙设置(如不同的Netfilter模块实现)和链和规则存储。目前不同的内核模块和程序用于不同的协议;iptables适用于IPv4,IPv6 arptables ip6tables,ARP,和ebtables以太网帧。

iptables需要提升权限的操作,必须由root用户执行,否则没有作用。在大多数的Linux系统,安装iptables是/usr/sbin /在man iptables和记录,可以使用iptables安装时打开的人。它也可以在/ sbin/iptables发现,但由于iptables更像是而不是一个“基本的二进制”服务,首选的位置是/usr/sbin。

术语iptables也是常用“指的是内核级的组件。x_tables是内核模块进行代码共享部分由所有四个模块,也提供了API,用于扩展使用的名称;随后,Xtables或多或少是指整个防火墙(V4,V6,ARP,EB)架构。

xtables允许系统管理员定义包含了对数据包的处理规则链表。每个表都与一种不同的分组处理相关联。数据包通过顺序遍历链中的规则来处理。链中的规则可以导致跳转或跳转到另一个链,这可以重复到任何嵌套级别所需的。(跳转就像一个“调用”,即从一个跳起来的点被记住)每个到达或离开计算机的网络包遍历至少一个链。数据包在一个给定的框开始,并将沿着一定的路径,这取决于情况。数据包的起源决定它最初遍历哪个链。有五个预定义的链,虽然表面上没有所有链。预定义的链有一个策略,它应用到数据包,如果它到达链的末端。系统管理员可以创建尽可能多的其他链。这些链没有策略,如果数据包到达链的末端,则返回链,但是链可能是空的。

PREROUTING:包将在路由决定进入这个链。

输入:包将在本地交付。它与打开套接字的进程无关,本地传输由“本地传送”路由表控制:IP路由表。

转发:所有已被路由和不用于本地传送的数据包将遍历此链。

输出:从机器本身发送的数据包将访问此链。

POSTROUTING:路由已作出决定。数据包在将它们交给硬件之前输入这个链。

链中的每个规则都包含与其匹配的数据包的规范。它也可能包含一个目标(用于扩展)或判决(一个内置的决定)。当数据包遍历一个链时,每一条规则依次检查。如果规则与包不匹配,则将数据包传递给下一个规则。如果一个规则与数据包匹配,则该规则接受目标/判断所指示的操作,这可能会导致数据包继续沿着链或不可能继续。匹配制定规则集中的很大一部分,因为它们包含的条件包测试。这些可以在OSI模型的任何一层发生,当然,也有与协议无关的匹配。数据包将会继续遍历链,直到一个规则匹配数据包,并决定最终的数据包的命运,例如通过调用一个接受或下降,或模块返回这样一个最终的命运;或规则调用返回判决,在这种情况下处理返回到调用链;或链到达结束位置;遍历或继续在父链(如返回使用),或基本链策略,这是一个最终的结局,使用目标还返回一个判定,如接受(NAT模块)或下降(例如拒绝模块),但也可能意味着继续(例如日志模块)继续下一个规则,因为如果没有目标/裁决指定在所有。

iptables的继任者是nftables,这是融入在内核3.13版本Linux内核主线,这是在一月19日2014发布。

2.1 iptables历史和工作机制

iptables的前身叫ipfirewall (内核1.x时代),这是一个作者从freeBSD上移植过来的,能够工作在内核当中的,对数据包进行检测的一款简易访问控制工具。但是ipfirewall工作功能极其有限(它需要将所有的规则都放进内核当中,这样规则才能够运行起来,而放进内核,这个做法一般是极其困难的)。当内核发展到2.x系列的时候,软件更名为ipchains,它可以定义多条规则,将他们串起来,共同发挥作用,而现在,它叫做iptables,可以将规则组成一个列表,实现绝对详细的访问控制功能。

他们都是工作在用户空间中,定义规则的工具,本身并不算是防火墙。它们定义的规则,可以让在内核空间当中的netfilter来读取,并且实现让防火墙工作。而放入内核的地方必须要是特定的位置,必须是tcp/ip的协议栈经过的地方。而这个tcp/ip协议栈必须经过的地方,可以实现读取规则的地方就叫做 netfilter.(网络过滤器)

作者一共在内核空间中选择了5个位置,

    1.内核空间中:从一个网络接口进来,到另一个网络接口去的

    2.数据包从内核流入用户空间的

    3.数据包从用户空间流出的

    4.进入/离开本机的外网接口

    5.进入/离开本机的内网接口

        

2.iptables的工作机制

从上面的发展我们知道了作者选择了5个位置,来作为控制的地方,但是你有没有发现,其实前三个位置已经基本上能将路径彻底封锁了,但是为什么已经在进出的口设置了关卡之后还要在内部卡呢? 由于数据包尚未进行路由决策,还不知道数据要走向哪里,所以在进出口是没办法实现数据过滤的。所以要在内核空间里设置转发的关卡,进入用户空间的关卡,从用户空间出去的关卡。那么,既然他们没什么用,那我们为什么还要放置他们呢?因为我们在做NAT和DNAT的时候,目标地址转换必须在路由之前转换。所以我们必须在外网而后内网的接口处进行设置关卡。        

 这五个位置也被称为五个钩子函数(hook functions),也叫五个规则链。

1.PREROUTING (路由前)

2.INPUT (数据包流入口)

3.FORWARD (转发管卡)

4.OUTPUT(数据包出口)

5.POSTROUTING(路由后)

        这是NetFilter规定的五个规则链,任何一个数据包,只要经过本机,必将经过这五个链中的其中一个链。  

2.2 iptables传输数据包过程

上面说的可能还没有那么清楚,我们来看一下这个传输的3个过程:首先当一个数据包进入网卡时,它首先进入PREROUTING链,内核根据数据包目的IP判断是否需要转送出去。 其次如果数据包就是进入本机的,它就会沿着向下移动,到达INPUT链。数据包到了INPUT链后,任何进程都会收到它。本机上运行的程序可以发送数据包,这些数据包会经过OUTPUT链,然后到达POSTROUTING链输出。 最后如果数据包是要转发出去的,且内核允许转发,数据包就会如图所示向右移动,经过FORWARD链,然后到达POSTROUTING链输出。这样一个说短不短的过程其实就是一个完整的iptables传输数据包的过程了。

2.3 iptables之python利用的库iptc

关于iptables的类程序操作我们一般情况下可能会选择利用python去调用shell命令来实现对iptablse的操作,但是要我们来说,必须使用内核级的代码来操作才算是真正的内核型的程序,于是我们找到了由先人为我们写好的api接口,也就是我们说的iptc。接下来我会详细的讲述iptc的作用以及用法。

Python API在Python iptables中试图模仿iptables的逻辑。我们将会由表table.filter,table.nat,IPv4 table.mangle和table.raw;table6.filter,table6.security,IPv6 table6.mangle和table6.raw。它们可以用来过滤数据包,做网络地址转换或修改数据包多种方式来进行不同的操作。Chains inside tables我们叫做表内链。每个表有几个内置的链,但你也可以创建自己的链,并从其他链跳转到他们。当你创建你的链的时候,你还可以指定哪些表将被用于这个操作。链本身有着有规则,告诉你什么时候链结束。

每个链有零个或多个规则。一个规则指定什么样的数据包匹配(匹配,每个规则可以有零,一个或多个匹配)和如何处理它们(目标,每个规则有一个)。iptables实现了大量的匹配和目标扩展。IPv4,类的实施这就是规则,IPv6被称为第六。匹配:指定何时需要将规则应用于数据包。若要创建匹配对象,还必须指定其所属的规则。目标:指定当一个规则应用于一个数据包时该做什么。若要创建目标对象,还必须指定其所属的规则。所以说iptc相当高级,隐藏了用户的低级细节。只使用类表、链、规则匹配和目标几乎任何事情都可以实现,你可以从命令行工具去对它进行操作。

2.4iptables之iptc的安装

Iptc的安装很简单我们只需要去到python的官网支持,去下载python-iptables.tar就可以了。接着运行三行命令:

tar zxvf python-iptables-0.3.0.tar.gz

cd python-iptables

python setup.py install

这样就可以轻松安装完成了

2.5 iptables之iptc的配置和使用

iptc模块我觉得使用最多的是Table(iptable的表操作,需要实例化)、Chain(iptables的链操作,需要实例化)、Match(iptables的匹配包,需要实例化)、Target(iptables的目标动作,需要实例化)。另外还有policy等。

首先我们来看一下table,table在iptables中是一个最基本的模块,有四个固定的表他们是Table.FILTER, the filter table,Table.NAT, the NAT table,Table.MANGLE, the mangle table 和 Table.RAW, the raw table.这四个表被初始缓存在table中,所以如果你创建一个新的表,并且它已经被实例化之前,它将被重用。获得过滤表的访问权。由于表的权限非常低,而事实上它的库函数api的调用是一个接着一个的,并且采取低结构的参数,因此他们隐藏了用户的低级别细节。

ALL = ['filter', 'mangle', 'raw', 'nat']

这是所有的tables的常量。

接着我们来看一下chain,各种规则都包含链。iptables有内置链,用户也可以创建额外的链。规则对象可以指定跳转到另一个链并继续处理其规则,或返回到调用方链。表是这个链属于的表,名称是链的名称。如果表中已存在名称已返回的链。而匹配是可以与数据包的特殊头字段或其他属性相匹配的扩展。在iptables的目标和匹配的扩展参数。这些参数作为Python中的实例属性实现。但是,要使它们必须转换的参数名称是合法的属性名称。规则就是从名称中剪切引导的双破折号,并用下划线替换参数名称中的破折号,以便它们被Python接受为属性名称。一个参数的值是一个字符串,如果参数不带任何值在iptables的延伸,一个空字符串“”应使用。这个匹配属于这个规则中;它可以改变以后通过set_rule()。名字是iptables匹配扩展名(小写),比赛是比赛结构原缓冲如果调用它。必须提供名称或匹配。修订是应该使用的扩展版本的修订号;不同的修订在C中使用不同的结构,它们通常只适用于某些内核版本。Python iptables默认将使用最新版本可用。规则是链中的条目。每个规则有三个部分:带有协议族属性的条目,如源地址和目的地址、传输协议等。如果包与此处设置的属性不匹配,则继续处理下一条规则或在链的末端应用链式策略。任何数量的匹配。它们是可选的,并使其能够匹配进一步的包属性。一个目标。这就决定了如果数据包匹配的话会发生什么。入口是ipt_entry缓冲或无如果调用者没有它。链是这个规则属于的链对象。

2.6 iptables之简单手动和脚本配置防止普通的ddos

# 如果同时在80端口的连接数大于10,就Drop掉这个ip
netstat -an | grep :80 | awk -F: '{ print $8 }' | sort | uniq -c | awk -F\ '$1>10 && $2!="" { print $2 }' >> /etc/fw.list
less /etc/fw.list | sort | uniq -c | awk -F\ '$2!="" { print $2 }' > /etc/fw.list2
less /etc/fw.list2 > /etc/fw.list
while read line
do
t=`echo "$line"`
$IPTABLES -A INPUT -p tcp -s $t -j DROP
done < /etc/fw.list2
$IPTABLES -A INPUT -m state –state ESTABLISHED,RELATED -j ACCEPT
$IPTABLES -A INPUT -p tcp –dport 22 -j ACCEPT
$IPTABLES -A INPUT -p tcp –dport 443 –tcp-flags SYN,ACK,FIN,RST SYN -m limit –limit 30/m –limit-burst 2 -j ACCEPT
$IPTABLES -A INPUT -p tcp –dport 80 –tcp-flags SYN,ACK,FIN,RST SYN -m limit –limit 30/m –limit-burst 2 -j ACCEPT
#限制连往本机的web服务,单个IP的并发连接不超过10个,超过的被拒绝
$IPT -A INPUT -i $INTERNET -p tcp –dport 80 -m connlimit –connlimit-above 10 -j REJECT
$IPT -A INPUT -i $INTERNET -p tcp –dport 443 -m connlimit –connlimit-above 10 -j REJECT
#限制连往本机的web服务,单个IP在60秒内只允许最多新建15个连接,超过的被拒绝
$IPT -A INPUT -i $INTERNET -p tcp –dport 80 -m recent –name BAD_HTTP_ACCESS –update –seconds 60 –hitcount 15 -j REJECT
$IPT -A INPUT -i $INTERNET -p tcp –dport 80 -m recent –name BAD_HTTP_ACCESS –set -j ACCEPT
$IPT -A INPUT -i $INTERNET -p tcp –dport 443 -m recent –name BAD_HTTP_ACCESS –update –seconds 60 –hitcount 15 -j REJECT
$IPT -A INPUT -i $INTERNET -p tcp –dport 443 -m recent –name BAD_HTTP_ACCESS –set -j ACCEPT
#限制连往本机的web服务,1个C段的IP的并发连接不超过150个,超过的被拒绝
$IPT -A INPUT -i $INTERNET -p tcp –dport 80 -m iplimit –iplimit-above 150 –iplimit-mask 24 -j REJECT
$IPT -A INPUT -i $INTERNET -p tcp –dport 443 -m iplimit –iplimit-above 150 –iplimit-mask 24 -j REJECT

$IPTABLES -A OUTPUT -p tcp -s 127.0.0.1 -j ACCEPT
$IPTABLES -A OUTPUT -p udp -s 127.0.0.1 -j ACCEPT

$IPTABLES -A INPUT -p tcp –syn -j DROP
#防止被tracert
iptables -A INPUT -m ttl –ttl-eq 1 -j DROP
iptables -A INPUT -m ttl –ttl-lt 4 -j DROP
iptables -A FORWARD -m ttl –ttl-lt 6 -j DROP

以上是通过手动配置iptables的命令解析,以下是一个简单的py-iptc的脚本以tables为前提的操作:

通过节点位置的配置来操作tables在chain中加入规则使得过滤生效。

def insert(mac):

    istarget = 0

    try:

        existrule = 0

        table = iptc.Table(iptc.Table.FILTER)

        for chain in table.chains:

            if (chain.name.startswith('neutron-openvswi-s')):

                break

        for rule in chain.rules:

            for match in rule.matches:

                if (match.mac_source == mac.upper()):

                    istarget = 1

                    break

            if (rule.src.startswith('0.0.0.0/') and rule.dst.startswith('0.0.0.0/0') and rule.target.name == 'RETURN'):

                existrule = 1   

        if (istarget == 1 and existrule == 0):

            rule = iptc.Rule()

            rule.src = '0.0.0.0/0.0.0.0'

            rule.dst = '0.0.0.0/0.0.0.0'

            target = iptc.Target(rule, 'RETURN')

            rule.target = target

            chain.insert_rule(rule)

        if (istarget == 1 and existrule == 1):

            logger.debug(mac + ' rule already added')   

    except Exception, e:

        logger.error(e)

    return istarget

2.7 libiptables(在本工业防火墙中担当框架性的作用)解析

首先本程序用到了两个类,第一个是class ShowIptables,这个类被用来做检查tables和chains的异常错误,再者就是利用table=iptc.TABLES(TABLE_NAME)来加载系统命令,从而添加table而我们选择的节点是固定在forword上。接下来直接贴出函数:

def check_table(self, table_name):这个函数是用来检查tablename返回一个true or false否则将显示错误。

def check_chain(self, table_name, chain_name):这个函数是用来在表中查看chain是不是正确。不是将抛出异常。

def show_chians(self, table_name):

            table = iptc.Table(table_name)

            chains = []

            for chain in table.chains:

                chains.append(chain)

            return chains

这段是将上文所提到过的table以iptc的格式赋给用户态的table,然后将chain也就是规则一条一条返回到此表。

def get_rules(self, table_name, chain_name):这个函数是用来将chain真正的成为审核的规则来加载到table中。

def display(self, table_name, chain_name):这个函数主要是帮助用户很好的交互,它显示所有错误的语法错误的表名错误的chain名,并且有帮助来显示规则和动作还有一些协议类型源目ip等一系列有关的参数。

第一个类基本上差不多就是这样,然后介绍第二个类。第二个类是用来配置iptables的主要程序。主要是让用户通过我们定义的例如动作,方法等去实现对iptables的操作。

我们在这行代码中:

if check_string(table_name) and check_string(chain_name) and check_string(method)可以看到首先要满足三个同时都没有抛出异常才能最终将三个参数传入真正的table、chain和method中。然后这是调用的iptables本来的规则是写死的。我们还加入了可以让用户自己去定义规则的这个函数,def add_rule(self),这个函数用来真正实现用户的自定义功能,rule.target = rule.create_target(self.add_or_insert_rule_dict.get("action"))这句话就用来自己创建一条用户规则。用户可以定义如源ip目的ip入口点和出口点,包括协议类型,当然这里主要是modbus和tcp,关于modbus会在之后有详细的阐述。然后就是通常的抛出异常和错误。在这里还专门定义了一个函数来删除chain,也就是delete_rules(self)

这个函数用来删除自定义的规则。方便了用户的操作。在不用重启的情况下就可以简单的操作这个iptables的自定义chain。

Libiptables中定义了主函数,用来在命令提示符中给予用户一个完整的提示操作。

2.4 本章小结

本章主要介绍了iptables的基本情况,以及其在防火墙中的作用和简单配置,讲述了两个实例来防止ddos攻击,并将此次工业防火墙的核心框架iptc的操作代码进行了深度解析。Iptables主要的功能和我们使用python-iptables也就是iptc这个库基本的操作和内容都已经完整的在上文阐述。

3 modbus协议分析

3.1 modbus协议简介

Modbus 协议是应用于电子控制器上的一种通用语言。通过此协议,控制器相互之间、控制器经由网络(例如以太网)和其它设备之间可以通信。它已经成为一通用工业标准。有了它,不同厂商生产的控制设备可以连成工业网络,进行集中监控。此协议定义了一个控制器能认识使用的消息结构,而不管它们是经过何种网络进行通信的。它描述了一控制器请求访问其它设备的过程,如果回应来自其它设备的请求,以及怎样侦测错误并记录。它制定了消息域格局和内容的公共格式。当在一Modbus网络上通信时,此协议决定了每个控制器须要知道它们的设备地址,识别按地址发来的消息,决定要产生何种行动。如果需要回应,控制器将生成反馈信息并用Modbus协议发出。在其它网络上,包含了Modbus协议的消息转换为在此网络上使用的帧或包结构。这种转换也扩展了根据具体的网络解决节地址、路由路径及错误检测的方法。

3.2 modbus在Modbus网络上转输

标准的Modbus口是使用一RS-232C兼容串行接口,它定义了连接口的针脚、电缆、信号位、传输波特率、奇偶校验。控制器能直接或经由Modem组网。控制器通信使用主—从技术,即仅一设备(主设备)能初始化传输(查询)。其它设备(从设备)根据主设备查询提供的数据作出相应反应。典型的主设备:主机和可编程仪表。典型的从设备:可编程控制器。主设备可单独和从设备通信,也能以广播方式和所有从设备通信。如果单独通信,从设备返回一消息作为回应,如果是以广播方式查询的,则不作任何回应。Modbus协议建立了主设备查询的格式:设备(或广播)地址、功能代码、所有要发送的数据、一错误检测域。从设备回应消息也由Modbus协议构成,包括确认要行动的域、任何要返回的数据、和一错误检测域。如果在消息接收过程中发生一错误,或从设备不能执行其命令,从设备将建立一错误消息并把它作为回应发送出去。在其它网络上,控制器使用对等技术通信,故任何控制都能初始和其它控制器的通信。这样在单独的通信过程中,控制器既可作为主设备也可作为从设备。提供的多个内部通道可允许同时发生的传输进程。在消息位,Modbus协议仍提供了主—从原则,尽管网络通信方法是“对等”。如果一控制器发送一消息,它只是作为主设备,并期望从从设备得到回应。同样,当控制器接收到一消息,它将建立一从设备回应格式并返回给发送的控制器。

3.3 modbus查询回应周期

(1)查询

 查询消息中的功能代码告之被选中的从设备要执行何种功能。数据段包含了从设备要执行功能的任何附加信息。例如功能代码03是要求从设备读保持寄存器并返回它们的内容。数据段必须包含要告之从设备的信息:从何寄存器开始读及要读的寄存器数量。错误检测域为从设备提供了一种验证消息内容是否正确的方法。

(2)回应

 如果从设备产生一正常的回应,在回应消息中的功能代码是在查询消息中的功能代码的回应。数据段包括了从设备收集的数据:象寄存器值或状态。如果有错误发生,功能代码将被修改以用于指出回应消息是错误的,同时数据段包含了描述此错误信息的代码。错误检测域允许主设备确认消息内容是否可用。

3.3.1 两种传输方式

控制器能设置为两种传输模式(ASCII或RTU)中的任何一种在标准的Modbus网络通信。用户选择想要的模式,包括串口通信参数(波特率、校验方式等),在配置每个控制器的时候,在一个Modbus网络上的所有设备都必须选择相同的传输模式和串口参数。

ASCII模式

:

地址

功能代码

数据数量

数据1

...

数据n

LRC高字节

LRC低字节

回车

换行

RTU模式

地址

功能代码

数据数量

数据1

...

数据n

CRC低字节

CRC高字节

 所选的ASCII或RTU方式仅适用于标准的Modbus网络,它定义了在这些网络上连续传输的消息段的每一位,以及决定怎样将信息打包成消息域和如何解码。

 在其它网络上(象MAP和Modbus Plus)Modbus消息被转成与串行传输无关的帧。

1、ASCII模式

 当控制器设为在Modbus网络上以ASCII(美国标准信息交换代码)模式通信,在消息中的每个8Bit字节都作为两个ASCII字符发送。这种方式的主要优点是字符发送的时间间隔可达到1秒而不产生错误。

 代码系统

  • 十六进制,ASCII字符0...9,A...F
  • 消息中的每个ASCII字符都是一个十六进制字符组成

每个字节的位

  • 1个起始位
  • 7个数据位,最小的有效位先发送
  • 1个奇偶校验位,无校验则无
  • 1个停止位(有校验时),2个Bit(无校验时)

 错误检测域

  • LRC(纵向冗长检测)

2、RTU模式

 当控制器设为在Modbus网络上以RTU(远程终端单元)模式通信,在消息中的每个8Bit字节包含两个4Bit的十六进制字符。这种方式的主要优点是:在同样的波特率下,可比ASCII方式传送更多的数据。

代码系统

  • 8位二进制,十六进制数0...9,A...F
  • 消息中的每个8位域都是一个两个十六进制字符组成
  • 每个字节的位
  • 1个起始位
  • 8个数据位,最小的有效位先发送
  • 1个奇偶校验位,无校验则无
  • 1个停止位(有校验时),2个Bit(无校验时)

错误检测域

  • CRC(循环冗长检测)

3.4 modbus消息帧

两种传输模式中(ASCII或RTU),传输设备以将Modbus消息转为有起点和终点的帧,这就允许接收的设备在消息起始处开始工作,读地址分配信息,判断哪一个设备被选中(广播方式则传给所有设备),判知何时信息已完成。部分的消息也能侦测到并且错误能设置为返回结果。

1、ASCII帧

 使用ASCII模式,消息以冒号(:)字符(ASCII码 3AH)开始,以回车换行符结束(ASCII码 0DH,0AH)。其它域可以使用的传输字符是十六进制的0...9,A...F。网络上的设备不断侦测“:”字符,当有一个冒号接收到时,每个设备都解码下个域(地址域)来判断是否发给自己的。

2、RTU帧

 使用RTU模式,消息发送至少要以3.5个字符时间的停顿间隔开始。在网络波特率下多样的字符时间,这是最容易实现的(如下图的T1-T2-T3-T4所示)。传输的第一个域是设备地址。可以使用的传输字符是十六进制的0...9,A...F。网络设备不断侦测网络总线,包括停顿间隔时间内。当第一个域(地址域)接收到,每个设备都进行解码以判断是否发往自己的。在最后一个传输字符之后,一个至少3.5个字符时间的停顿标定了消息的结束。一个新的消息可在此停顿后开始。

3、地址域

 消息帧的地址域包含两个字符(ASCII)或8Bit(RTU)。可能的从设备地址是0...247 (十进制)。单个设备的地址范围是1...247。主设备通过将要联络的从设备的地址放入消息中的地址域来选通从设备。当从设备发送回应消息时,它把自己的地址放入回应的地址域中,以便主设备知道是哪一个设备作出回应。

 地址0是用作广播地址,以使所有的从设备都能认识。当Modbus协议用于更高水准的网络,广播可能不允许或以其它方式代替。

4、如何处理功能域

 消息帧中的功能代码域包含了两个字符(ASCII)或8Bits(RTU)。可能的代码范围是十进制的1...255。当然,有些代码是适用于所有控制器,有此是应用于某种控制器,还有些保留以备后用。

 当消息从主设备发往从设备时,功能代码域将告之从设备需要执行哪些行为。例如去读取输入的开关状态,读一组寄存器的数据内容,读从设备的诊断状态,允许调入、记录、校验在从设备中的程序等。

 当从设备回应时,它使用功能代码域来指示是正常回应(无误)还是有某种错误发生(称作异议回应)。对正常回应,从设备仅回应相应的功能代码。对异议回应,从设备返回一等同于正常代码的代码,但最重要的位置为逻辑1。

 例如:一从主设备发往从设备的消息要求读一组保持寄存器,将产生如下功能代码:

0 0 0 0 0 0 1 1 (十六进制03H)

 对正常回应,从设备仅回应同样的功能代码。对异议回应,它返回:

1 0 0 0 0 0 1 1 (十六进制83H)

 除功能代码因异议错误作了修改外,从设备将一独特的代码放到回应消息的数据域中,这能告诉主设备发生了什么错误。

 主设备应用程序得到异议的回应后,典型的处理过程是重发消息,或者诊断发给从设备的消息并报告给操作员。

5、数据域

 数据域是由两个十六进制数集合构成的,范围00...FF。根据网络传输模式,这可以是由一对ASCII字符组成或由一RTU字符组成。

 从主设备发给从设备消息的数据域包含附加的信息:从设备必须用于进行执行由功能代码所定义的所为。这包括了象不连续的寄存器地址,要处理项的数目,域中实际数据字节数。

 例如,如果主设备需要从设备读取一组保持寄存器(功能代码03),数据域指定了起始寄存器以及要读的寄存器数量。如果主设备写一组从设备的寄存器(功能代码10十六进制),数据域则指明了要写的起始寄存器以及要写的寄存器数量,数据域的数据字节数,要写入寄存器的数据。

 如果没有错误发生,从从设备返回的数据域包含请求的数据。如果有错误发生,此域包含一异议代码,主设备应用程序可以用来判断采取下一步行动。

 在某种消息中数据域可以是不存在的(0长度)。例如,主设备要求从设备回应通信事件记录(功能代码0B十六进制),从设备不需任何附加的信息。

6、错误检测域

 标准的Modbus网络有两种错误检测方法。错误检测域的内容视所选的检测方法而定。

ASCII

 当选用ASCII模式作字符帧,错误检测域包含两个ASCII字符。这是使用LRC(纵向冗长检测)方法对消息内容计算得出的,不包括开始的冒号符及回车换行符。LRC字符附加在回车换行符前面。

RTU

 当选用RTU模式作字符帧,错误检测域包含一16Bits值(用两个8位的字符来实现)。错误检测域的内容是通过对消息内容进行循环冗长检测方法得出的。CRC域附加在消息的最后,添加时先是低字节然后是高字节。故CRC的高位字节是发送消息的最后一个字节。

3.5 modbus在本防火墙中的实现

master = modbus_tcp.TcpMaster("192.168.2.20",502)首先是链接到远程的modbusserver,然后进行调用modbus_tk库的接口,向slave请求采集的数据,类tcpmaster有几个接口,即set_timeout,_send(modbus request),这就表明了我们需要自己封装modbus的协议头和请求命令。_recv返回modbus的协议数据,excute(slave,功能码,开始地址,quantity_of_x=0,output_value=0,data_format=’’’’,指定长度为-1)

举个例子就是:import modbus_tk.defines as de

master.execute(slave_id=1,de.READ_HOLDING_REGISTERS,100,3)

slave_id:1

这里面quantity是寄存器或者线圈的数量,output_value是一个可迭代的值

READ_COILS = 1 读线圈
READ_DISCRETE_INPUTS = 2 读离散输入
READ_HOLDING_REGISTERS = 3  【读乘法寄存器】
READ_INPUT_REGISTERS = 4  读输入寄存器
WRITE_SINGLE_COIL = 5  写单一线圈
WRITE_SINGLE_REGISTER = 6  写单一寄存器
WRITE_MULTIPLE_COILS = 15 写多个线圈 【强制多点线圈】
WRITE_MULTIPLE_REGISTERS = 16  写多寄存器 【写乘法寄存器】

接下来是对modbus的封装和数据解析。深度解析由同组成员完成。

3.6 本章小节

本章介绍了modbus协议,着重介绍了modbus的基础传输模式和消息帧的分类。最后还简述了modbus在本防火墙中的实现。

4 pyhon代码实现基于iptables的modbus协议深度分析

由4个函数构成的Judge_modbus类中分别用来完成函数和参数的初始化,完成拆包和解码之后完成对握手包的深度分析,和对tcp标志位的检测,记入mongodb。

4.1 运行环境

kali2.0

python 2.7

4.2 主要模块构成

Judge_modbus类:

(1)def __init__(self,debug=False)函数:完成参数初始化

(2)def start(self,package)函数:完成拆包和解码,包含def judge_tcp_attack(self)和def judge_modbus_attack(self)函数

(3)def judge_tcp_attack(self)函数,完成对握手包深度分析即TCP标志位攻击检测,并记录数据库

(4)def judge_modbus_attack(self)函数,和modbus/TCP攻击检测,并记录数据库

4.3 modbus协议深度分析之握手包深度分析

此部分代码对握手包进行了深度解析和判断(黑名单原则):

  1. 握手包中syn和fin标记位不能同时为1
  2. 握手包中标记位不能都为0
  3. 握手包中不存在fin标记位为1且ack标记位为0的情况

主要代码不再赘述,由同组成员已经描述。

4.4 modbus协议深度分析之mongodb数据库记录

   self.mongodb.log_collect()函数完成mongodb数据库记录,详情可见mongodb部分

4.5 本章小结

本章是由iptables这个框架之后进行深度包检测的一个功能扩展,实现了对modbus包的提取解码和分析,在一些标志位上做安全标识。这是我们将要不断扩展的一个功能,直至实现内核级代码,将给予用户极大的便利。

5 结论

5.1 主要的研究成果

这学期我们主要研究了从一个基础的linux下的防火墙模块到modbus协议的拆分,再到对modbus包的展示和对其标志位的分析,从而达到了基础的对工业级协议的分析,从iptables的四表五链,再到最后我们的深度报文解析,这学期可谓是收获满满。

但是说起代码我们还是要感谢python为我们提供的强大的第三方库,可以说是先人为我们铺好了道路,我们只是在这条大路上不断前进,整个防火墙的运行过程其实就是,基于iptables的框架,在防火墙收到外界的数据包的时候我们使用第三方库进行解码,接着转码,然后针对里面的内容我们进行一系列判断,对于不同的数据包类型我们做出不同的检测手段,如果是基于modbus的包我们将进行一系列的安全检测,如果是非法操作,我们将记入mongodb并对其进行丢包操作。

5.2 需要进一步完善的内容

其实针对于数据包的拦截只做了一个开始,我们下一步会将代码整理为内核级的,隐藏用户态的低级别操作,并通过外界的客户端去对其进行操作,例如运用tornado的非阻塞式服务器,实现高效的用户与服务器之间的操作,并再将其往硬件方向发展,把他从一个软件做成硬件的形式。实现工业级别的特殊防火墙。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐