bro框架--签名框架

原文地址:https://www.bro.org/sphinx/frameworks/signatures.html

Bro主要依赖它的可扩展的脚本语言来定义和分析探测策略。此外,Bro也提供了一种独立的可用于低层次的,snort风格的模式匹配的签名语言。尽管Bro不是很喜欢把签名作为惯用探测工具,但签名易于上手且更容易为那些熟悉别的网络入侵检测系统的人员所使用。本文就Bro的签名和一些相关技巧作出一点简单的介绍。

基础(Basics)
我们先看一个签名的例子:

signature my-first-sig {
    ip-proto == tcp
    dst-port == 80
    payload /.*root/
    event "Found root!"
}

这条签名要求Bro在所有到80端口的TCP连接中,匹配有.*root的正则表达式。当此签名触发的时候,Bro会发起一个具有以下形式的叫做signature_match的事件:

event signature_match(state: signature_state, msg: string, data: string)

这里,state包含了触发了这个事件的连接的更多的信息,msg是由签名的事件语句指定的字符串(找到root!),data是触发这个模式匹配的最后一条有效载荷。

为了将这样的signature_match事件转换为实际的警告,你可以加载Bro的base/frameworks/signatures/main.bro脚本。这个脚本包含了一个默认的事件处理(发出Signatures::Sensitive_Signature   通知)(其他的也是一样的,看一下脚本的开头部分)。

由于签名独立于Bro的策略脚本,它们置于它们自己的文件中。有三种方法来指定哪些文件包含签名:当你调用bro的时候使用-s标识位,或者通过+=操作符来拓展Bro变量signature_files,或者是在Bro脚本中使用@load-sigs指令。如果一个签名文件没有给出完整路径,我们会在BROPATH那边搜索它。此外,@load-sigs指令可以用来加载于bro脚本所处位置而言的相对路径那里的签名文件。比如@load-sigs ./mysigs.sig会要求那个签名文件和Bro脚本放在同级目录下。文件的默认拓展名是.sig,Bro会在必要时加上它。

网络流量的签名语言(Signature Language for Network Traffic)
我们再仔细看一下签名的格式。每个签名都有signature <id> { <attributes> },这样的格式。<id>是签名的唯一标识。有两种类型的属性,条件(conditions)和动作(actions)。状况定义了签名什么时候匹配,动作声明了在这种匹配下做什么。状况还可以细分为四种类型:头部,内容,依赖和上下文。接下来我们详细讨论一下这些内容。

条件(condition)(不知道是不是翻译为“条件”好一点?后面给出了一些逻辑表达式)
头部条件(condition)
头部条件限制了对一个子网(该子网包含匹配的包头部)的流量的签名的应用。这种类型的匹配仅仅对一条连接的第一个包施行。

对某些最常用的头部字段,已经有预定义的头部条件。它们都有形同<keyword> <cmp> <value-list>的格式,其中<keyword>表示头部字段,cmp是==,!=,<,<=,>,>=这些符号之一,<value-list>是一个由逗号分隔的列表。定义了如下的关键字:


src-ip/dst-ip <cmp> <address-list>
    Source and destination address, respectively. Addresses can be given as IPv4 or IPv6 addresses or CIDR masks. For IPv6 addresses/masks the colon-hexadecimal representation of the address must be enclosed in square brackets (e.g. [fe80::1] or [fe80::0]/16).
src-port/dst-port <cmp> <int-list>
    Source and destination port, respectively.
ip-proto <cmp> tcp|udp|icmp|icmp6|ip|ip6
    IPv4 header’s Protocol field or the Next Header field of the final IPv6 header (i.e. either Next Header field in the fixed IPv6 header if no extension headers are present or that field from the last extension header in the chain). Note that the IP-in-IP forms of tunneling are automatically decapsulated by default and signatures apply to only the inner-most packet, so specifying ip or ip6 is a no-op. 

这个多值的列表,将它们与对应的头部字段顺序地比较下来。如果至少有一个比较结果为真的话,整个头部状况匹配就算满足了(除了!=这种情况,所有的值都不一样的话,匹配成功)。
除了那些预定义的头部关键子,一般的头部状况会像下面这样定义:

header <proto>[<offset>:<size>] [& <integer>] <cmp> <value-list>

这会将包头部的某个指定位置的值和一个值列表中的值做比较。offset定义了由proto定义的协议头部中的值(用于比较的那个值,可以使ip,ip6,tcp,udp,icmp或者icmp6)的位置。size是1,2或者4并指明这个值有这么多字节的大小。如果给出了可选字段&<integer>,这个包的值会在与值列表中的值做比较之前就用这个整数作了标识。cmp是==, !=, <, <=, >, >= 之一。value-list是类似于前面所描述的,由逗号分隔的一系列整数。列表中的整数可能跟着一个/mask标识,其中mask是一个在0和32之间的整数。这个和网络的CIDR(无类别域间路由,Classless Inter-Domain Routing)标识相类似,并且会被翻译为对应的位掩码,这个位掩码可以用于前面的包的值(比较之前,类似于可选的&interger)。IPv6地址值不允许在值列表中出现,但你可以用这个关键字来在一个IPv6头部中查找1,2,4字节的部分。

将它们放在一起,这是一个示例条件,等价于dst-ip == 1.2.3.4/16, 5.6.7.8/24:

header ip[16:4] == 1.2.3.4/16, 5.6.7.8/24

注意IPv6的类似的例子目前还不行,因为4字节已经是比较值的最大长度了。 

内容条件(Content Conditions)
内容条件是由正则表达式定义的。我们区分两种不同的条件:第一,表达式可以由payload语句来定义,在这种情况下,匹配一个连接(重组的TCP流)或者包(ICMP,UDP和未重组的TCP)的原始有效载荷。第二,前面可以添加一个分析其指定的标签,在这种情况下表达式会和从对应分析器中取出的数据匹配。
一个playload条件具有以下形式:

payload /<regular expression>/

 现在,下面的定义了特定分析其的内容条件(注意对应的分析器需要通过加载这个策略脚本激活):


http-request /<regular expression>/
    The regular expression is matched against decoded URIs of HTTP requests. Obsolete alias: http.
http-request-header /<regular expression>/
    The regular expression is matched against client-side HTTP headers.
http-request-body /<regular expression>/
    The regular expression is matched against client-side bodys of HTTP requests.
http-reply-header /<regular expression>/
    The regular expression is matched against server-side HTTP headers.
http-reply-body /<regular expression>/
    The regular expression is matched against server-side bodys of HTTP replys.
ftp /<regular expression>/
    The regular expression is matched against the command line input of FTP sessions.
finger /<regular expression>/
    The regular expression is matched against finger requests. 

 举个例子,http-request /.*(etc/(passwd|shadow)/会匹配所有包含etc/passwd或者etc/shadow的URL。针对需要的类型过滤,比如GET,就用payload /GET /。

注意HTTP流水线(在一个TCP连接上的多个HTTP事务)对签名匹配有一些副作用。如果在一个签名中指定了多个条件,这个签名会匹配在一个流水线连接中是否所有的条件对任意的HTTP事务都满足(它们未必总是相同的)。

依赖条件(Dependency Conditions)
定义签名之间的依赖,有以下两个条件:


requires-signature [!] <id>
    Defines the current signature to match only if the signature given by id matches for the same connection. Using ! negates the condition: The current signature only matches if id does not match for the same connection (using this defers the match decision until the connection terminates).
requires-reverse-signature [!] <id>
    Similar to requires-signature, but id has to match for the opposite direction of the same connection, compared to the current signature. This allows to model the notion of requests and replies. 

上下文条件(Context Conditions)
上下文条件将匹配的选择传递给Bro的其他组件。它们仅当所有其它条件都满足的时候才有效。下面定义了一些上下文条件:


eval <policy-function>
    The given policy function is called and has to return a boolean confirming the match. If false is returned, no signature match is going to be triggered. The function has to be of type function
    cond(state: signature_state, data: string): bool. Here, data may contain the most recent content chunk available at the time the signature was matched. If no such chunk is available, data will be the empty string. See signature_state for its definition.
payload-size <cmp> <integer>
    Compares the integer to the size of the payload of a packet. For reassembled TCP streams, the integer is compared to the size of the first in-order payload chunk. Note that the latter is not very well defined.
same-ip
    Evaluates to true if the source address of the IP packets equals its destination address.
tcp-state <state-list>
    Imposes restrictions on the current TCP state of the connection. state-list is a comma-separated list of the keywords established (the three-way handshake has already been performed), originator (the current data is send by the originator of the connection), and responder (the current data is send by the responder of the connection). 

 动作(Actions)
动作定义了在匹配到了签名的时候做什么。现在,下面定义了两个动作:


event <string>

    Raises a signature_match event. The event handler has the following type:

    event signature_match(state: signature_state, msg: string, data: string)

    The given string is passed in as msg, and data is the current part of the payload that has eventually lead to the signature match (this may be empty for signatures without content conditions).
enable <string>
    Enables the protocol analyzer <string> for the matching connection ("http", "ftp", etc.). This is used by Bro’s dynamic protocol detection to activate analyzers on the fly. 

 文件内容的签名语言(Signature Language for File Content)
签名框架可以用于确认文件的MIME类型(不考虑文件是在哪个协议/连接上传输的)。可以为此写一个特殊类型的签名,自动地由文件框架调用,或者是使用Bro脚本通过内置的file_magic函数调用。

条件(Conditions)
文件签名使用一种简单的内容条件的类型,以正则表达式的形式呈现:

file-magic /<regular expression>/

和上面描述的网络流量签名语言payload内容条件相似。区别在于payload签名可以应用于网络连接的有效载荷,但是file-magic可以应用到任何数据上去,它不需要和某个网络协议/连接相关联。

动作(Action)
一旦匹配到大量数据,文件签名就会用下面的动作来获取关于数据的MIME类型信息:

file-mime <string> [, <integer>]

 参数包括与file magic(不知道怎么说)正则表达式相关的MIME类型字符串以及可选的带符号整形类型的"strength"。由于多重文件魔法签名可能与给定的大量数据匹配,这个强度值(strength)可能会用于帮助选择一个“胜者”。这个值越高越强大。

写签名的时候请记住这些(Things to keep in mind when writing signatures)
在每条连接上,每个签名最多汇报一次,对同一个签名的多个匹配(从第二个开始)就不要了,忽视它。
内容条件是在从应用协议会话中获取的元素上进行模式匹配的。举个例子,http /.*passwd/在HTTP会话中扫描URL。这里需要记住的是,所有的这些条件仅仅当对应的应用分析器对这个连接是处于活动状态的时候才会开展匹配。请注意,在默认情况下,如果对应的Bro脚本没有被加载的话,分析器是没有被激活的。一种很好的检验分析器是否“看见了”某条连接的方法,是检查对应的入口的日志文件。如果你在分析器的日志中找不到这条连接,那么很可能是这个签名引擎尚未看到任何应用数据。
顾名思义,payload关键字仅匹配包的有效载荷。你不能用它来对包头部进行匹配,请使用头部条件。
对于TCP连接,头部条件仅仅对每个端点来的第一个包感兴趣。如果头部连接没有匹配到这些初始包,那么这个签名就不会触发。Bro在此处优化了最常用的应用,(这个应用作为)头部条件来选择与有效载荷陈述更加密切的连接来检验。
对于UDP和ICMP流,有效载荷的匹配是基于一个一个包(匹配)的形式的,比如超过包界限的内容就找不到了。对于TCP连接而言,匹配的语义(意义,semantics)依赖于Bro是否在重组(reassembling)连接(比如,将某个连接的所有包都放在一个序列里面)。在默认情况下,Bro重组每个TCP连接的前1K的内容,这意味着在这个范围(1K)内,不论包的次序或者边界是什么样的,都可以实现匹配(举个例子,stream-wise匹配)。
由于性能的原因,默认情况下,在看到1K的有效载荷之后Bro就不会在一个连接上继续匹配了,可以看看下面的选项(讲述了怎么改变这种行为)。默认是把Bro的主用户的签名记住,即便只检查了连接头部,动态协议探测也可以很好地运作。
毫无疑问,正则表达式是固定(anchored,不知道在这边是不是固定的意思)的,比如他们前面跟着^操作符。对于重组的TCP连接,它们在有效载荷流的第一个字节就固定了。对于所有的其它连接,它们在每个包的第一个有效载荷字节处就固定了。为了在任何地方都能匹配,你可以在正则表达式的前面加上.*,正如上面的例子所做的那样。
为了匹配非ASCII字符,Bro的正则表达式支持\x<hex>操作符。CRs/LFs不由签名引擎专门处理,可以分别由\r和\n来匹配。一般地,Bro和flex的正则表达式的语法相同。看看base/frameworks/dpd/dpd.sig这里的DPD签名,这儿有更多的复杂的有效载荷模式。
signature_match处理(方法)的数据参数可能不会带上由正则表达式匹配到的完整文本。Bro随着数据包的增多,随之进行匹配,签名最终发出(fire在这里是什么意思?)的时候,它只能传送最近的大量数据。

选项(Options)
下面的选项控制Bro匹配过程的细节:


dpd_reassemble_first_packets: bool (default: T)
    If true, Bro reassembles the beginning of every TCP connection (of up to dpd_buffer_size bytes, see below), to facilitate reliable matching across packet boundaries. If false, only connections are reassembled for which an application-layer analyzer gets activated (e.g., by Bro’s dynamic protocol detection).
dpd_match_only_beginning : bool (default: T)
    If true, Bro performs packet matching only within the initial payload window of dpd_buffer_size. If false, it keeps matching on subsequent payload as well.
dpd_buffer_size: count (default: 1024)
    Defines the buffer size for the two preceding options. In addition, this value determines the amount of bytes Bro buffers for each connection in order to activate application analyzers even after parts of the payload have already passed through. This is needed by the dynamic protocol detection capability to defer the decision which analyzers to use. 

 

所以,在Bro上使用Snort签名怎么样?(So, how about using Snort signatures with Bro?)
有一个叫做snort2bro的脚本,将Snort的签名自动转换为Bro的签名语法。然而,根据我们的经验,这不是一个有效的途径。因为使用Snort签名不能从Bro提供的其它功能中受益,这两种系统的方法差别太大了。因此,我们不再维护snort2bro脚本,有很多它所不支持的新的Snort选项。在以后的Bro发布版中都不会再提供这个脚本。

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值