海 洋,徐 魁,李晓辉,曾 涛,陶 军
(1.宝鸡市公安局通信处,陕西 宝鸡 721014;2.宝鸡创天清航科技发展有限责任公司,陕西 宝鸡 721000;3.东南大学 网络空间安全学院,江苏 南京 210096)
随着2010年“震网病毒”[1]的出现,工业控制系统(Industrial Control Systems,ICS)[2]的安全性逐渐受到了全球范围的关注。工业控制系统包括多种类型的控制系统, 这些控制系统对关键基础设施的运行至关重要。工业控制系统由许多的子系统以及相关的组件构成,各组件之间传递一些控制信息或者监控数据,这些信息或者数据的传递均是以工控协议的形式传输,各组件对于工控协议的解析与处理影响着工控系统的安全。
无论是对流量进行解析或者其他操作,第一步都是识别出流量所属协议。而一些协议解析工具或者防火墙针对协议的初步识别主要都是基于固定端口号的,然后再对使用该端口号的协议进行下一步的解析,而一旦协议改变端口号,除非解析工具或者防火墙同步改变配置,否则可能会导致无法识别该协议。Moore等[3]与Madhukar等[4]通过实验证实仅通过端口进行协议识别准确率已经降低到20%以下。
白惠文等[5]提出了一种基于CNN的针对匿名协议的识别方法。他们将数据包序列预处理为二维向量,并将二维向量中的每个值作为像素值,由此把二维向量转换为图像作为LeNet-5网络的输入来训练模型和识别目标流量。对由匿名协议流量和背景流量构成的数据集进行了实验,识别准确率可以达到96%以上。
基于有效载荷的识别技术可以得到较好的性能。该方法主要使用深度包检(DPI)[6]技术。DPI不仅会对数据包的头部字段进行检测,还会对应用层的部分载荷或者所有载荷进行识别,DPI技术首先会对目标协议进行特征提取,找到协议中的特征字符串等特征,组成协议识别特征库,然后通过特征匹配的方式进行协议的识别,如果网络协议中出现相应的特征串,则可以确定协议的类型。例如,“GET”就是HTTP协议的一个特征字符串。
在协议特征准确率较高的情况下,基于有效载荷的协议识别技术是较为准确的一类协议识别方式。因此该方法应用范围广泛,不仅能识别出单协议数据流,还能有效识别出使用端口伪装技术或动态端口技术的流媒体数据以及大多数P2P流量。在工业界应用广泛,是高速网络环境部署的最佳选择[7]。
对于公共协议,可以通过查阅协议规范文档获取协议特征。但对于未知协议,早期的特征提取主要采用人工分析的方式寻找,需要具备一定的专业知识。胡梁眉等[8]利用逆向分析的方法,通过网络报文序列采样对比,对相似性极高的报文合并分析。通过统计报文中的关键字节变化率与取值范围等数据特征,对核电工控系统的私有协议进行了识别。
随着技术的发展,许多数据挖掘[9]技术被用于未知协议的特征提取。Wang等先后提出了Biprominer[10]和ProDecoder[11],将数据挖掘用于协议关键字的提取,利用N-gram之间的潜在关系来推断协议的格式。Luo等[12]提出了一种基于字符串频率的关键字提取方法AutoReEngine,在确定字符串的长度时分别从消息和行的头部、尾部分别进行定位。为了降低二进制逆向协议过程中频繁项提取耗时的问题,Hei等[13]采用Apriori算法生成频繁字节项,然后采用AC算法进行频繁项匹配,并通过位置关联来保证特征候选集的完整性。
Agrawal和Srikant提出的Apriori算法[14]是频繁项挖掘中最具有影响力的算法,后续许多算法都是基于Apriori算法进行改进的。但是其缺点在于得到的结果需要再进行去冗余化处理。
基于此,该文提出了一种自顶向下的频繁字符串挖掘方法。与传统的自底向上式挖掘方法不同,该方法可以直接得到长度最长的频繁字符串,而不用进行去冗余化处理。这一特性,使其能更好地满足利用机器学习方法进行工控协议识别时对于特征字符串的要求。在单协议测试环境和多协议测试环境下,利用识别率、准确率这两个指标对提取的识别特征的正确性和可靠性进行了验证,保证了特征的准确性和完全性。
在进行协议频繁项提取之前,需要给出以下定义。
协议的种类繁多,既有文本型协议,也有二进制协议,但是所有的协议都由整数个字节构成。在此,该文借鉴了AutoReEngine中的定义,将构成协议的字节集合D表示如下:
D={ x00, x01,…, xFF}
(1)
D中的每一个元素代表一个单字节,而由D中的字符构成的序列M可以表示为:
(2)
而由多条同种协议组成的报文集合Z表示如下:
Z=〈M1,M2,…,Mn〉
(3)
定义1 支持度:对于一个字符串str,其支持度Rs(str)定义为包含str的流量数与数据集Z中流量总数的比值,即:
(4)
如果str在一条流中多次出现则按一次计算。
定义2 频繁字符串:在应用层协议中多次出现的字符串序列,位置一般固定,也有部分协议频繁字符串出现的位置不固定。该文将字符串出现频率不低于给定的最小支持度Rmin的字符串作为频繁字符串。也就是说频繁字符串集合表示为:
F={str|Rs(str)≥Rmin}
(5)
也就是说,如果一个字符串是频繁字符串,那么其在整个数据集中出现的频次需要大于一个阈值Threshold,阈值为数据集Z中的流量总数与最小支持度Rmin的乘积,即:
Threshold=|Z|*Rmin
(6)
除此之外,将由所有长度为k的频繁字符串构成的频繁集定义为Fk。
定义3 特征字段:包括协议常量、状态代码、分隔符等,用于标识消息中字段的边界并指示字段语义。例如,在协议S7 COMM中,其应用层数据前两个字节总是为0x 3,0x 0。而第4~6字节总是0x 2,0xf0,0x80。而事实上,这些特征字段正是需要寻找的频繁项。
定义4 完全字符串:如果字符串str是str'的一部分,那么str叫做str'的子字符串,对于字符串str'',如果数据集中没有str''的子字符串,那么str''就叫做完全字符串。
该文尝试对频繁项挖掘算法进行改进,不再使用自底向上的方式进行频繁项的挖掘与构造,而是以空间换时间,采用自顶向下的思路来查找频繁字符串。改进的算法同样基于以下直觉:如果某个项集是频繁的,那么其所有子集也是频繁的。因此若是能够率先找到长度为k的频繁项集Fk,并对Fk中每个频繁字符串的位置信息进行记录,在查找Fk-1时,对Fk中相关位置的序列便不再进行统计。这样的话,既不会导致频繁项出现冗余,也不会导致一些关键信息被忽略。方法描述如下。
在这一步,借鉴了N-gram模型[15]对数据进行划分,N-gram模型的思想是将分组分解为多个长度相等的序列。首先,需要确定一个初始的频繁项长度k,然后,将数据集中所有的序列分别划分为n-k+1个长度为k个字节的子序列。
(7)
算法1:查找频繁项集F
Input:datasetZ,lengthk,minimum supportRmin
Output:frequent items setF
1:F={},Threshold=Rmin*|Z|
2:FOR allMi∈ZDO
3: 将Mi划分为n-k+1个长度为k的序列Si
4:WHILEk≥1 DO
5:Fk={},dict={}
6: FORj∈[0,Si.size)
7: dict.Si[j]+1,dict.Si[j].j+1
8: IF dict.Si[j]>Threshold
9: updateFk.Si[j]=dict.Si[j]
10: END IF
11: END FOR
12: 从所有Si删除相关位置项并将其分裂为长度为k-1的项
13: ADDFktoF
14:k=k-1
15:END WHILE
相关流程示意如图1所示。在图中,以字节为单位,首先取k=3个字节划分序列,假设序列‘000001’为长度为3个字节的频繁项,那么删除以及拆分后的结果如下。可以看到,所说的删除并不是将相关序列从列表中移除,而是将这些序列置为空字符串,因为这样处理不会打乱每个序列在原数据中的位置。最终得到的每一个频繁项的表示如下:
{
Frequent item:
[
Total times,
{position 1: times[,position 2:times]}
]
}
其中,Frequent item表示频繁字符串,Total times 表示该频繁字符串总共在多少个数据包中出现过,positionn代表该字符串在第n个位置出现了times次。
例如,当k=9时,CIP PCCC协议的一个频繁项如下:
{"4b0220672401074d00": [824, {40: 418, 46: 406}]}
表示"4b0220672401074d00"这个字段总共出现了824次,其中在第40个字节出现了418次,第46个字节出现了406次。
在确定了初始的k值后,通过第二步便可以得到长度不同的频繁项集Fk,Fk-1,…,F1,那么,初始的完全频繁项集合如式8所示:
(8)
这样一来,整个频繁项的拆分删除工作可以用图1来表示。
图1 频繁项删除及拆分示意图
上述所有工作中,一切前提都是建立在初始长度k已知。然而实际情况下,初始的k值还需要人工确定。那么应该如何确定初始的k值?显然,k的取值不能过大也不能过小,因为如果初始的k值设置过大,那么在找到第一个频繁项之前,将花费大量无意义的时间在序列的统计与拆分之上,而一旦k的初始值设置过小,则会导致之前提到的数据冗余的问题出现。因此需要找到合适的初始值。该文使用改进的二分查找法来进行初始k值的确定,其思路如下:
(1)对于数据集Z中的所有消息进行扫描,选取其中最短的消息序列的长度lmin作为k取值的右边界R,以1作为左边界L。
(3)如果当前未找到频繁字符串,则更新右边界R=k-1,回到第2步。
(4)如果当前长度的频繁项数目大于等于2且部分频繁项之间存在交叠,则更新左边界L=k+1,同时为了减少查找次数,可以将存在交叠字段的频繁项进行合并,并以合并后的最长序列长度lm更新右边界R,然后回到第2步。
例如,如果查找出长度为4的频繁集为['1234','2345','3456','3214'],那么合并后的结果为['123456','3214'],那么此时R更新为6,L更新为5。
(5)而如果长度为k的频繁集只包含一个元素或者多个无交叠字段的元素,那么当前k值便是最终的k值,算法结束。过程如算法2所描述。
算法2:确定初始长度k
Input: datasetZ, minimum supportRmin
Output: Initialkvalue
1.Initiation:L=0,R=lmin,Threshold=|Z|*Rmin
2.WHILEL<=RDO
4.FORM∈ZDO
5.将M划分为多个长度为k的序列Seq
6.FOR seq∈Seq DO
7.dict[seq]+1
8.IF dict[seq]>=Threshold THEN
9.updateFk[seq]=dict[seq]
10.END IF
11.END FOR
12.END FOR
13.IFFk.size==0 THEN
14.R==k-1
15.ELSE IFFk.size>1 or THEN
16.合并频繁项,计算合并后序列长度lm
17.letL=k+1,R=lm
18.ELSE
19.BREAK
20.END IF
21.END WHILE
在完全频繁项集F中,由于在挖掘过程中便考虑到了去冗余问题,因此不存在冗余问题,但是还是可能存在不可靠的频繁字符串,例如,在二进制协议中长度为1的字节0x 0几乎在每条流量中都有出现,然而出现的位置却不一定固定,甚至可能有很大偏差,而类似于这样的字段显然不适合作为特征字段来进行协议的识别。因此,需要过滤该类弱特征,该文考虑了频繁字符串在所有流量中的位置信息,进而从频繁项集F中推断特征字段。
前文提到,频繁项集中记录了各个频繁字符串在各个位置出现的频次,需要据此来进行频繁项的过滤,筛选出用于识别的特征字段。可以确定的特征字符串如下。
如果该频繁字符串在某个位置出现次数大于阈值Threshold,那么该字符串为位置固定的一个特征字段。
如果某个字符串出现位置虽然不固定,但是各个位置出现次数之和等于或者十分接近该字符串出现总次数,那么该字符串也是特征字符串,虽然其出现位置不固定,但是一般只有有限几个位置,且很少在一个数据包里重复出现。
如果频繁字符串虽然出现位置多变,但是自身长度较长,该文也将其保留对于其他较短的频繁字符串,通过其在数据包中出现位置的方差来进行保留或者过滤。即考虑字符串位置到包含该字符串的消息开头的偏移量,将其表示为P。对于需要保留的关键字,其方差P应当非常小。
至此,便可以得到协议识别的特征字段。
图2为CIP PCCC协议的识别特征中特征字符串的表示。其中表示一个CIP-PCCC识别特征的开始与结束。之间表示具体位置的字节内容,offset表示该特征字段包含多少字节,position表示特征字段起始位置,当同一个之间出现多个position字段时,只要该特征字符串与其中任意一个位置匹配成功即可。如果一条流量与特征中所有字段都匹配成功,便认为这条流属于CIP PCCC协议。
为了验证算法的正确性与性能,主要针对Omron Fins,Modbus,S7 COMM等10种协议进行了分析,对其进行了特征字符串的提取。并将提取出来的特征字符串作为识别特征,进行了协议识别工作,通过识别率、准确率对识别的效果进行了验证。
定义5 识别率:在单协议测试环境下,使用提取得到的某种工控协议的识别特征识别的流量占该协议总流量的百分比。该指标能够度量挖掘的协议识别特征的完全性。
定义6 准确率:在单协议识别环境中,被识别为某种工控协议的流量中真正是该协议的流量所占的百分比。准确率主要用来验证挖掘的协议识别特征的正确性。
针对Omron Fins,Modbus,S7 COMM等10种协议的特征字符串提取结果如表1所示。
表1 不同协议的特征字符串
可以看到,对于每种协议,都提取出了相应的特征字符串。
利用提取出的特征字符串进行协议识别工作,识别结果如图3所示。
(a)协议识别的识别率 (b)协议识别的准确率
对协议识别的结果,对其识别率和准确率进行了统计。识别率如图3(a)所示。可以看到,对于选取的10种协议,其识别率均能达到98%以上。其中除了对IEC104协议的识别率在98%左右,其余9种协议的识别率均达到了99%以上,对于S7COMM和S7COMMON PLUS协议甚至可以达到接近100%。
而协议识别的准确率则如图3(b)所示。可以看到对于选取的10种协议,准确率基本都可以达到99%以上。对CIP,MODBUS,EGD,IEC104等协议的准确率在99%左右,而对Omron Fins,S7COMMOM,S7COMMON PLUS等协议的准确率接近100%。
综合识别率和准确率来看,利用文中算法所提取出的频繁字符串作为特征进行协议识别,可以得到非常准确的结果。对于S7COMMON,S7COMMON PLUS等特征字符串较多的协议,甚至可以得到接近100%的识别率和准确率。这说明文中算法所提取出的频繁字符串确实是协议的特征字符串。
在对工控协议的识别工作中,基于有效载荷的识别方法逐渐成为主流。在这种趋势下,对工控协议中识别特征的选择和提取工作尤为重要。频繁字符串由于其出现频率较高,作为协议识别中的特征字符串极为合适。针对工控协议中的频繁字符串,设计了一种自顶向下的提取算法,使提取出来的字符串无需再进行去冗余化处理。同时针对传统自顶向下算法中的初始数据过大、步骤较多等问题进行了优化。实验数据表明,该算法对大多数协议都能提取出有效的频繁字符串。