suricata规则分析
Suricata 签名的结构
在高层次上,Suricata签名由三部分组成:
- Action:当流量符合规则时采取的行动
- Header:一个标题,描述主机、IP地址、端口、协议和流量方向(传入或传出)
- Options:选项,指定诸如签名ID(sid)、日志信息、匹配数据包内容的正则表达式、分类类型,以及其他可以帮助缩小识别合法和可疑流量的修饰语
签名的一般结构如下:
ACTION HEADER OPTIONS
示例规则分析1
sid:2100498:
alert ip any any -> any any (msg:"GPL ATTACK_RESPONSE id check returned root"; content:"uid=0|28|root|29|";
签名的alert部分是ACTION,ip any -> any any部分是HEADER,签名的其余部分从(msg:GPL ATTACK_RESPONSE...)开始包含了规则的OPTIONS。
Actions
sid:2100498
签名的第一部分是Actions,在这里是alert。Suricata签名的Actions部分指定了当数据包符合规则时要采取的动作。根据Suricata是在IDS还是IPS模式下运行,行动还可以是以下之一:
- Pass - Suricata将停止扫描该数据包,并允许其通过,但不产生警报。
- Drop - 当在IPS模式下工作时,Suricata将立即停止处理该数据包并产生警报。如果产生数据包的连接使用的是TCP,则会超时。
- Reject - 当Suricata运行IPS模式时,将发送一个TCP重置包,Suricata将放弃匹配的数据包。
- Alert - Suricata将生成一个警报,并将其记录下来以便进一步分析。
Headers
每个Suricata签名都有一个Headers部分,描述了网络协议、源和目的IP地址、端口和流量方向。参考示例 sid:2100498
签名,该规则的头部分是突出显示的ip any any -> any any
部分:
alert ip any any -> any any (msg:"GPL ATTACK_RESPONSE id check returned root"; content:"uid=0|28|root|29|"; classtype:bad-unknown; sid:2100498; rev:7; metadata:created_at 2010_09_23, updated_at 2010_09_23;)
一条规则的标题部分的一般格式是:
<PROTOCOL> <SOURCE IP> <SOURCE PORT> -> <DESTINATION IP> <DESTINATION PORT>
PROTOCOL协议可以是以下之一:
- TCP
- UDP
- ICMP
- IP
- 其他一些应用协议
来源和目的地字段可以是IP地址或网络范围,或者是特殊值any,它将匹配所有的IP地址和网络。
箭头->表示流量的方向。
注意:签名也可以使用非方向性标记<>,它将匹配两个方向的流量。然而,Suricata关于方向性标记的文档指出,大多数规则将使用->右侧的匹配箭头。
如果你想对恶意的出站流量(即离开你的网络的流量)发出警报,那么源字段将是你的系统的IP地址或网络范围。目的地可以是一个远程系统的IP或网络,或特殊的任何值。
反过来说,如果你想对传入的恶意流量产生警报,源字段可以设置为任何,而目的地可以是你系统的IP地址或网络范围。
你还可以使用端口字段指定要检查的TCP或UDP端口。一般来说,来自一个系统的流量会被分配一个随机的端口,所以任何值对->指标的左边是合适的。如果你打算检查每个传入数据包的内容,目标端口也可以是任何,或者你可以限制一个签名,只扫描个别端口的数据包,如22用于SSH流量,或443用于HTTPS。
sid:2100498的ip any -> any any
头是一个通用的头,将匹配所有的流量,无论协议、源或目标IP或端口。当你想确保入站和出站流量被检查出可疑的内容时,这种捕获所有的头是有用的。
请注意,源、目的和端口字段也可以使用特殊的 !否定操作符,它将处理与该字段值不匹配的流量。
例如,以下签名将使Suricata对所有来自任何网络的SSH数据包发出警报,这些数据包的目的地是你的网络(由203.0.113.0/24 IP块代表),而不是以22端口为目的地:
alert ssh any any -> 203.0.113.0/24 !22 (sid:1000000;)
这种警报并不那么有用,因为它不包含任何关于数据包的信息,也不包含分类类型。为了给警报添加额外的信息,以及根据更具体的标准进行匹配,Suricata规则有一个OPTIONS部分,你可以为一个签名指定一些额外的设置。
OPTIONS
在Suricata签名中的括号(...)内的参数包含各种选项和关键字修改器,你可以用它们来匹配数据包的特定部分,对规则进行分类,或记录自定义信息。规则的header参数是针对IP、端口和协议级别的数据包标题,而OPTIONS则是针对数据包中的数据进行匹配。
Suricata规则中的OPTIONS必须用分号隔开,并且通常使用key:value格式。有些选项没有任何设置,只需要在规则中指定名称。
使用上一节的签名示例,你可以添加msg选项(即触发规则后返回的提示信息),其值为在非SSH端口检测到的SSH流量,解释警报的内容:
alert ssh any any -> 203.0.113.0/24 !22 (msg:"SSH TRAFFIC on non-SSH port"; sid:1000000;)
关于如何在Suricata规则中使用每个选项的完整解释,从第6.2节开始的Suricata规则文档详细描述了每个关键词选项。
然而,有一些核心选项,如内容关键字和各种Meta关键字,在大多数签名中都会用到,我们将在下面的章节中研究:
关键字:Content
任何规则最重要的选项之一是Content内容关键词。回顾一下sid:2100498签名的例子:
alert ip any any -> any any (msg:"GPL ATTACK_RESPONSE id check returned root"; content:"uid=0|28|root|29|"; classtype:bad-unknown; sid:2100498; rev:7; metadata:created_at 2010_09_23, updated_at 2010_09_23;)
突出显示的内容: "uid=0|28|root|29|";
部分包含Content关键字,以及Suricata将在数据包内寻找的值。在这个签名示例中,来自任何端口的任何IP地址的所有数据包都将被检查,以确保它们不包含字符串值uid=0|28|root|29|(在以前的教程中,它被用作表示被攻击的主机的例子)
Content关键字可以与Suricata中的大多数其他关键字一起使用。你可以使用头文件的组合来创建非常具体的签名,以及针对特定应用协议的选项,然后使用正则表达式检查数据包内容的单个字节、字符串或匹配。
例如,下面的签名检查DNS流量,寻找任何内容为your_domain.com的数据包,并生成一个警报:
alert dns any any -> any any (msg:"DNS LOOKUP for your_domain.com"; dns.query; content:"your_domain.com"; sid:1000001;)
然而,如果DNS查询使用域名YOUR_DOMAIN.COM,则此规则将无法匹配,因为Suricata默认为大小写内容匹配。要使内容匹配对大小写不敏感,请在规则中添加nocase;
关键字。
alert dns any any -> any any (msg:"DNS LOOKUP for your_domain.com"; dns.query; content:"your_domain.com"; nocase; sid:1000001;)
现在,小写或大写字母的任何组合仍将与内容关键词相匹配。
关键字msg
本教程中的签名示例都包含了带有签名信息的msg关键字。虽然msg选项不是必须的,但留空的话,在检查Suricata的日志时,就很难理解为什么会发生警报或删除动作。
msg选项的设计是对一个警报的可读文本描述。它应该是描述性的,并为警报添加上下文,以便您或其他正在分析日志的人理解为什么警报被触发。在本教程的reference Keyword部分,你将了解到参考选项,你可以用它来链接到关于签名和它所要检测的问题的更多信息。
关键字 sid
和 rev
每个Suricata签名都需要一个唯一的签名ID(sid)。如果两个规则具有相同的sid(在下面的输出示例中是sid:10000000),Suricata将不会启动,而会产生一个类似下面的错误:
Example Duplicate sid Error. . .
19/11/2021 -- 01:17:40 - <Error> - [ERRCODE: SC_ERR_DUPLICATE_SIG(176)] - Duplicate signature "drop ssh any any -> 127.0.0.0/8 !22 (msg:"blocked invalid ssh"; sid:10000000;)"
. . .
当你创建自己的签名时,1000000-1999999的范围被保留给自定义规则。Suricata的内置规则的范围是2200000-2299999。其他边框范围在新出现的威胁SID分配页面上有记录。
sid选项通常是Suricata规则的最后部分。然而,如果一个签名有多个版本,并随着时间的推移而变化,则有一个rev选项,用于指定规则的版本。例如,本教程早期的SSH警报可以改为只扫描2022端口的SSH流量:
alert ssh any any -> 203.0.113.0/24 2022 (msg:"SSH TRAFFIC on non-SSH port"; sid:1000000; rev:2;)
更新后的签名现在包括rev:2选项,表明它已经从以前的版本更新。
关键字reference
reference参考关键词在签名中用来描述在哪里可以找到更多关于规则所要检测的攻击或问题的信息。例如,如果一个签名是为了检测一种新的漏洞或攻击方法,参考字段可以用来链接到一个安全研究员或公司的网站,记录这个问题。
OpenSSL中的Heartbleed漏洞就是一个被广泛宣传和研究的漏洞的例子。Suricata带有签名,旨在检查不正确的TLS数据包,并包括对Heartbleed CVE主条目的参考:
alert tls any any -> any any (msg:"SURICATA TLS invalid heartbeat encountered, possible exploit attempt (heartbleed)"; flow:established; app-layer-event:tls.invalid_heartbeat_message; flowint:tls.anomaly.count,+,1; classtype:protocol-command-decode; reference:cve,2014-0160; sid:2230013; rev:1;)
请注意签名中突出显示的参考:cve,2014-0160;
部分。这个参考选项告诉您或正在检查Suricata警报的分析师,在哪里可以找到有关该特定问题的更多信息。
参考选项可以使用/etc/suricata/reference.config
文件中的任何前缀。例如,在前面的例子中,可以用url来代替cve,用一个直接指向Heartbleed网站的链接来代替2014-0160 CVE标识。
关键字classtype
Suricata可以根据一套预先配置好的类别对流量进行分类,这些类别在你用Linux发行版的软件包管理器安装Suricata软件包时就已经包含了。默认的分类文件通常在/etc/suricata/classification.config
中找到,包含如下条目:
#
# config classification:shortname,short description,priority
#
config classification: not-suspicious,Not Suspicious Traffic,3
config classification: unknown,Unknown Traffic,3
config classification: bad-unknown,Potentially Bad Traffic, 2
. . .
如文件头所示,每个分类条目有三个字段:
- shortname:一个简短的、机器可读的名字,在上面的例子中分别是:not-suspicious、unknown和bad-unknown
- short description:用于警报的分类描述,例如:Not Suspicious Traffic
- priority:一个优先级字段,它决定了签名将被Suricata处理的顺序。最高的优先级是值1。当Suricata处理一个数据包时,使用更高优先级的分类器的签名将被首先检查。
在 sid:2100498
签名的例子中,classtype 是classtype:bad-unknown;
alert ip any any -> any any (msg:"GPL ATTACK_RESPONSE id check returned root"; content:"uid=0|28|root|29|"; classtype:bad-unknown; sid:2100498; rev:7; metadata:created_at 2010_09_23, updated_at 2010_09_23;)
签名的隐含优先级是2,因为这是在/etc/suricata/classification.config
中分配给 **bad-unknown classtype **的值。如果你想覆盖一个 classtype 的默认优先级,你可以在签名中添加一个priority:n
选项,其中n是一个从1到255的值。
关键字 target
Suricata签名中另一个有用的选项是target目标选项。它可以被设置为两个值之一:src_ip和dest_ip。这个选项的目的是为了在Suricata的警报日志中正确识别源主机和目标主机。
例如,本教程前面的SSH签名可以用target:dest_ip;选项来加强:
alert ssh any any -> 203.0.113.0/24 2022 (msg:"SSH TRAFFIC on non-SSH port"; target:dest_ip; sid:1000000; rev:3;)
这个例子使用dest_ip是因为这个规则被设计为检查进入我们的例子网络的SSH流量,所以它是目标。在规则中添加目标选项将导致在 **eve.json **日志条目的alert部分出现以下额外字段:
. . .
"source": {
"ip": "127.0.0.1",
"port": 35272
},
"target": {
"ip": "203.0.113.1",
"port": 2022
}
. . .
有了Suricata日志中的这些条目,它们可以被发送到安全信息和事件管理(SIEM)工具中,以便更容易地搜索可能来自普通主机的警报,或针对网络上特定目标的攻击。
示例规则分析2
有如下规则,下面对其进行解释
alert tcp $EXTERNAL_NET any -> 10.200.0.0/24 80 (msg:"WEB-IIS CodeRed v2 root.exe access"; flow:to_server,established; uricontent:"/root.exe"; nocase; classtype:web application-attack; reference:url,www.cert.org/advisories/CA-2001 19.html; sid:1255; rev:7;)
alert:告诉Suricata将此行为作为警报报告(在为STA创建的规则中是强制性的)。
tcp: 表示此规则只适用于TCP的流量。
$EXTERNAL_NET:这是在Suricata中定义的一个变量。
默认情况下,变量HOME_NET被定义为这些范围内的任何IP:192.168.0.0/16,10.0.0.0/8,172.16.0.0/12,而EXTERNAL_NET则定义为这些范围之外的任何IP。
你可以通过指定单个IP如10.200.0.0、IP CIDR范围如192.168.0.0/16或IP列表如[192.168.0.0/16,10.0.0.8]来指定IP地址。请注意,列表中的空格是不允许的。
any:在这种情况下,它意味着 "来自任何源端口",然后有一个箭头'->',意味着 "连接到"(没有'<-'操作符,但你可以简单地翻转操作符周围的参数。你可以使用'<>'操作符来表示连接方向与此规则无关),然后是一个IP范围,表示目标IP地址,然后是端口。你可以用冒号来表示一个端口范围,比如0:1024表示0-1024。在圆括号中,有一些指令用于设置警报信息、关于规则的元数据,以及额外的检查。
msg: 是一个指令,它简单地设置了在检测到匹配流量的情况下将发送的信息(在STA情况下发送到Coralogix)。
flow: 是一个指令,表示我们即将定义为签名的内容是否需要出现在与服务器("to_server")或与客户("to_client")的通信中。这可能非常有用,例如,如果我们想检测服务器的响应,该项可表明它已被攻破。
established: 是一个指令,它将导致Suricata限制其搜索匹配此签名的数据包,只搜索属于已建立连接的数据包。这对于尽量减少Suricata的负载是很有用的。
uricontent: 是一个指令,指示Suricata在规范化的HTTP URI内容中寻找某个文本。在这个例子中,我们要寻找的url正是"/root.exe "这样的文本。
nocase:是一个指令,表示我们希望Suricata进行不区分大小写的搜索。
classtype:是一个指令,它是一个元数据属性,表明该规则检测的活动类型。
reference:是一个指令,是一个元数据属性,链接到另一个系统以获取更多信息。在我们的例子中,值url,https://....链接到互联网上的一个URL。
sid: 是一个指令,是一个元数据属性,表示签名的ID。如果你正在创建你自己的签名(即使你只是替换一个内置的规则),请使用一个高于9,000,000的值,以防止与另一个预先存在的规则发生碰撞。
rev: 是一个指令,表示规则的版本。
编写suricata规则的技巧
针对漏洞,而不要漏洞利用
避免编写检测特定漏洞工具包的规则,因为同样的漏洞有无数个漏洞,而且我们可以肯定,在你读到这篇文章的时候,新的漏洞正在被编写。例如,许多早期检测缓冲区超限攻击的签名是这样的:
alert tcp $EXTERNAL_NET any -> $HOME_NET 80 (content:"AAAAAAAAAAAAAA", msg:"Buffer overrun detected.")
其原因当然是为了成功地发起缓冲区超限攻击,攻击者需要填充某个变量的缓冲区,并在最后添加他的恶意有效载荷,使其成为可执行文件。他选择用来填充缓冲区的字符是完全不重要的,事实上,在这种签名出现后,许多攻击工具箱只是用不同的字母来填充缓冲区,完全逃避了这种签名检测。一个更好的方法是试图通过检测基于字段类型和长度的不正确输入来检测这类攻击。