YARA & Suricata 入侵检测规则

YARA规则

Yara 简介

yara是一个用于帮助恶意软件研究人员识别和分类恶意软件样本的开源工具,其每条描述、规则都由一系列字符串和一个布尔类型表达式构成,并用于阐述其逻辑。其可以用于对于文件进行匹配,进而来判断是否出现在已经进行过规则描述的某恶意软件。

IDAFind Cryptos插件也运用到了yara规则来进行匹配对应密码学相关特征数据字段,通过对固定密码盒的识别来尝试性提醒用户存在对应的加密规则。对于yara可能更多的像是一种正则表达式来对目标数据进行匹配。

项目地址:https://github.com/VirusTotal/yara,(yara64.exe , yarac64.exe )

python:https://github.com/VirusTotal/yara-python

官方文档:https://yara.readthedocs.io/

Yara 规则编写

从官方文档来看yara的开头必须为rule,随后跟着一个定义名,其命名规则同样遵循与C 语言类似的规则,可以包含任意字母数字或是下划线,但是需要注意的是第一个字符不能够是数字。与此同时,yara中有一些预定义的关键字,命名不能够与其相同

image-20231010231609126

下面我们举出一个编写的例子

1
2
3
4
5
6
7
8
9
10
11
12
rule ExampleRule
{
meta:
description = "This is just an example"
thread_level = 3
in_the_wild = true
strings:
$my_text_string = "text here"
$my_hex_string = { E2 34 A1 C8 23 FB }
condition:
$my_text_string or $my_hex_string
}

其中meta描述的是规则信息,我们可以添加作者信息,威胁等级,在野情况,文件MD5之类的信息,string则是规则字段,中间我们可以插入一些关键的判断字段如一些HEX值或是恶意URLcondition字段则是对应我们的条件判断部分,通过对应的布尔运算进行连接。

需要注意的是对应的变量需要以$开头,代表其为一个变量,而在我们的meta描述信息中则不需要(因为其不是变量)

Strings

HEX

在我们之前的例子中有一个HEX String,在其中我们可以使用正则表达式进行进行通用匹配

1
2
$hex_string = { E2 34 ?? C8 A? FB }
$hex_string = { F4 23 8[4-6] 62 B4 }

yara2.0之后可以使用无界跳转

一般的正则表达式是线性匹配,一旦开始便是从头开始逐步匹配,直到到达模式的结尾。但是无界跳转可以让我们在代码的执行中的任意位置进行跳转,而不仅仅限于按顺序执行。

1
2
$hex_string = { FE 39 45 [10-] 89 00 }
$hex_string = { FE 39 45 [-] 89 00 }

在上述中[10-]可以匹配11 12 13 14 ...多个16进制串,同理[-]可以匹配00 01 02 ...

或者我们可以给定有一部分的替换方案:

1
$hex_string = { F4 23 ( 62 B4 | 56 ) 45 }

他会匹配:F42362B445或是F4235645

Text strings

当我们需要对字符串进行匹配时我们有以下关键字来帮助我们进一步细化

不区分大小写: nocase

1
$text_string = "abc" nocase

宽字节:wide

1
$text_string = "abc" wide

相当于我们在匹配Unicode字符串

如果我们要同时搜索ASCII以及宽字节格式的字符串,我们可以将ascii修饰符与wide结合使用,使用顺序无所谓

1
$wide_and_ascii_string = "abc" ascii wide

一般情况下的text都是ascii的

异或:xor

当我们的一个字符串可能发生各种异或时我们对其添加修饰符xor便可以匹配对应单字节在不同情况下的异或值

1
$xor_string = "This program cannot" xor

其则可以匹配下面类似的值:

1
2
$xor_string_01 = "Uihr!qsnfs`l!b`oonu"
$xor_string_02 = "Vjkq\"rpmepco\"acllmv"

同样的我们可以结合修饰符wideascii使用

Base64编码:base64

对于一个可能被编码为base64的字符串,我们可以使用关键字base64来对其进行进行匹配

1
$xor_string = "This program cannot" base64

对应的可以匹配类似下面的值

1
VGhpcyBwcm9ncmFtIGNhbm5vd [A-Za-z0-9-_]

对于上面结果我们也可以使用wide来将编码后的结果转换为宽字节匹配

上述的base64编码我们也可以自定义码表,其长度必须为 64

1
$a = "This program cannot" base64("!@#$%^&*(){}[].,|ABCDEFGHIJ\x09LMNOPQRSTUVWXYZabcdefghijklmnopqrstu")

全字匹配:fullword

比如我们在对域名进行匹配时,我们对domain添加了fullword修饰符,那么www.mydomain.com不会被匹配,但是www.my-domain.com and www.domain.com这样会被匹配

正则表达式

如果我们对于某内容需要进行正则匹配时我们需要带上两个斜线如:/xxx/,其中xxx为我们的内容,对于正则语法则和常规的差不多

其对应可以匹配的元字符:

\ 引用下一个元字符
^ 匹配文件的开头,或在用作左括号后的第一个字符时,对字符类求反
$ 匹配文件的结尾
. 匹配除换行符以外的任何单个字符
` 用于对正则表达式进行定界
() Grouping
[] Bracketed character class

以下量词也可以识别:

* Match 0 or more times
+ Match 1 or more times
? Match 0 or 1 times
{n} Match exactly n times(精确匹配)
{n,} Match at least n times(至少匹配n次)
{,m} Match at most m times(最多匹配n次)
{n,m} Match n to m times

以下转义字符可识别:

\t Tab (HT, TAB)
\n New line (LF, NL)
\r Return (CR)
\f Form feed (FF)换页
\a Alarm bell
\xNN 序号为给定十六进制数的字符

公认字符类:

\w 匹配单词字符 (alphanumeric plus “_”)
\W 匹配非单词字符
\s 匹配空白字符
\S Match a non-whitespace character
\d 匹配十进制数字字符
\D Match a non-digit character

Conditions

conditions即布尔表达式,andornot,关运算符,算数运算符,位运算等。

需要注意的是整数的长度始终为 64 位,在使用位运算符是需要注意

如 ~0x01 不是 0xFE 而是 0xFFFFFFFFFE

Counting strings

假如我们需要对一个字符串进行计数,我们使用的则是井号来计数

1
2
3
4
5
6
7
8
9
rule CountExample
{
strings:
$a = "dummy1"
$b = "dummy2"

condition:
#a == 6 and #b > 10
}

yara 4.2.0后我们可以使用 in 来判断某个区间是否出现了指定个数的字符

1
2
#a in (filesize-500..filesize) == 2
// 文件最后500个字节中的 a 所代表的字符串数必须正好等于2。
String offset or Virtual address

当我们需要判断对应的字符串是否在指定的偏移时,我们可以使用关键字at

1
2
3
4
5
6
7
8
9
rule AtExample
{
strings:
$a = "dummy1"
$b = "dummy2"

condition:
$a at 100 and $b at 200
}

at运算符允许在文件或进程内存空间中的虚拟地址的某个固定偏移量处搜索字符串,而in运算符允许在偏移量或地址范围内搜索字符串

1
2
3
4
5
6
7
8
9
rule InExample
{
strings:
$a = "dummy1"
$b = "dummy2"

condition:
$a in (0..100) and $b in (100..filesize)
}

与此同时我们可以使用@a[i]获得字符串$a第 i 次出现的偏移量或虚拟地址

其中索引是基于1的,因此第一次出现是@a[1],第二次出现是@a[2],依此类推。如果提供的索引大于字符串的出现次数,则结果将是一个NaN(不是数字)值

File Size

我们判断文件大小时可以直接使用关键字filesize

1
2
3
4
rule FileSizeExample{
condition:
filesize > 100kb
}
Executable entry point

对于一个PE文件我们可以使用entrypoint关键字来对目标的入口点进行判断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
rule EntryPointExample1
{
strings:
$a = { E8 00 00 00 00 }

condition:
$a at entrypoint
}

rule EntryPointExample2
{
strings:
$a = { 9C 50 66 A1 ?? ?? ?? 00 66 A9 ?? ?? 58 0F 85 }

condition:
$a in (entrypoint..entrypoint + 10)
}
对于偏移处数据的访问判断

对于这种类型判断我们需要使用int8int16int32…等关键字,其中指明的内容为对应的文件偏移或者是对应的虚拟地址

1
2
3
4
5
6
7
8
rule IsPE
{
condition:
// MZ signature at offset 0 and ...
uint16(0) == 0x5A4D and
// ... PE signature at offset stored in MZ header at 0x3C
uint32(uint32(0x3C)) == 0x00004550
}
字符串集

我们可以使用of关键字来表示至少存在字符串集中的一部分

1
2
3
4
5
6
7
8
9
10
rule OfExample1
{
strings:
$a = "dummy1"
$b = "dummy2"
$c = "dummy3"

condition:
2 of ($a,$b,$c)
}

当出现几个名字有着相同构成的变量名我们同样可以使用正则表达式对其进行选中,对于字符串需要全选中时我们可以使用($*)来进行匹配或是使用them关键字来表示

1
2
3
4
5
6
7
8
9
10
rule OfExample4
{
strings:
$a = "dummy1"
$b = "dummy2"
$c = "dummy3"

condition:
1 of them // equivalent to 1 of ($*)
}

还有以下几种方式进行表示:

1
2
3
4
5
6
all of them       // all strings in the rule
any of them // any string in the rule
all of ($a*) // all strings whose identifier starts by $a
any of ($a,$b,$c) // any of $a, $b or $c
1 of ($*) // same that "any of them"
none of ($b*) // zero of the set of strings that start with "$b"
对多个字符串应用相同的条件

当我们需要对多个字符串使用相同的条件的时候,我们可以使用for..of

1
for expression of string_set : (boolean_expression)

对于字符串我们可以使用$来做占位符

1
2
for any of ($a,$b,$c) : ( $ at pe.entry_point  )
// $a、$b、$c中有一个在 PE 文件的入口点

在yara 4.0后for..of得到了改善

1
2
3
for any section in pe.sections : ( section.name == ".text" )
//等价
for any i in (0..pe.number_of_sections-1) : ( pe.sections[i].name == ".text" )
迭代字符串出现的次数
1
2
3
4
5
6
7
8
9
10
11
12
rule Occurrences
{
strings:
$a = "dummy1"
$b = "dummy2"

condition:
for all i in (1,2,3) : ( @a[i] + 10 == @b[i] )
//也可以这样写
// for all i in (1..3) : ( @a[i] + 10 == @b[i] )
// a 前 3 次出现的位置 +10 得到 b 前 3 次出现的位置
}

More rules

Global rules

我们可以添加一些全局的规则,这些规则会在所有规则中添加限制。全局规则可以有多个,我们只需要在原先的rule前加一个global即可

1
2
3
4
5
global rule SizeLimit
{
condition:
filesize < 2MB
}
Tag

我们可以在meta中添加一些tag,当我们在导出结果时可以对其更好的组织管理

1
2
3
4
5
6
7
8
9
10
11
12
13
rule Example
{
meta:
description = "This is an example rule"
author = "John Doe"
tags = "malware, trojan"

strings:
$str = "Hello World"

condition:
$str
}

Other Modules

PE

PE module — yara 4.4.0 documentation

其可以通过导入pe来完成PE文件的相关判断

1
import "pe"

其中包含许多方法,我们就简单的举几个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import "pe"

rule single_section
{
condition:
pe.number_of_sections == 1
}

rule control_panel_applet
{
condition:
pe.exports("CPlApplet")
}

rule is_dll
{
condition:
pe.characteristics & pe.DLL
}

rule is_pe
{
condition:
pe.is_pe
}
ELF

相似的对于elf我们也有同样的方法来对其进行分析

1
2
3
4
5
6
7
8
9
10
11
12
13
import "elf"

rule single_section
{
condition:
elf.number_of_sections == 1
}

rule elf_64
{
condition:
elf.machine == elf.EM_X86_64
}
Hash

常见的hash加密在yara中也有对应的支持

1
2
hash.md5(0, filesize) == "feba6c919e3797e7778e8f2e85fa033d" // md5(offset, size)
hash.md5("dummy") == "275876e34cf609db118f3d84b799a790"

Suricata规则

suricata简介

Suricata是一款高性能的开源入侵检测系统(IDS)和入侵防御系统(IPS),它专门设计用于监测和保护计算机网络免受各种网络攻击。

特点和功能:

  1. 多线程支持: Suricata是一种多线程应用程序,能够有效利用多核处理器,提供高性能的网络流量分析和处理。
  2. 规则引擎: Suricata使用规则引擎来检测网络流量中的恶意行为。规则可以根据特定的网络流量模式、签名、协议等来定义。
  3. 协议支持: Suricata支持多种网络协议,包括但不限于TCP、UDP、ICMP、HTTP、FTP等,使其能够检测各种不同类型的网络攻击。
  4. 文件MD5检测: Suricata可以检测文件的MD5哈希值,从而识别已知的恶意文件。
  5. TLS/SSL解密: Suricata能够进行TLS/SSL解密,使其能够检测加密流量中的潜在威胁。
  6. 流量日志: Suricata能够生成详细的流量日志,帮助安全管理员了解网络中的活动,同时用于事后分析和调查。
  7. IPv6支持: Suricata具有对IPv6的完整支持,使其能够监控和防御IPv6网络。

suricata安装

1
2
3
4
sudo apt-get install software-properties-common
sudo add-apt-repository ppa:oisf/suricata-stable
sudo apt-get update
sudo apt-get install suricata

或者GCC编译安装,参考如下https://docs.suricata.io/en/suricata-6.0.10/install.html

规则的构成

Suricata规则包含以下几个部分:

Action 规则匹配后所执行的操作。常用的有drop、alert、reject等。 drop用于ips模式
alert用于ids/ips模式
reject用于ips模式
Protocol 规则所匹配的协议。常用的有TCP、UDP、ICMP等。 协议识别引擎通过特征端口/特征字符决定流量协议类型
Source IP/Port 规则所匹配的源IP地址和端口号。
Destination IP/Port 规则所匹配的源IP地址和端口号。
Direction 规则所匹配的数据流方向,通常有inbound和outbound两种。 通过<>-符号筛选需要检测的流量
Options 规则匹配所需的选项。常用的有content、flow、metadata等。 根据各种关键字组合决定动作触发条件

其中,content是最重要的选项之一,它用于匹配数据包的负载。Flow用于匹配数据包的流量方向,metadata用于提供额外的信息,比如协议版本等。除此之外,还有一些其他的选项,比如pcre、threshold、classtype等,它们可以帮助Suricata更加准确地匹配网络流量并进行分析。

示例规则分析1

sid:2100498:

1
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;)

一条规则的标题部分的一般格式是:

1
<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端口为目的地:

1
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流量,解释警报的内容:

1
alert ssh any any -> 203.0.113.0/24 !22 (msg:"SSH TRAFFIC on non-SSH port"; sid:1000000;)

关于如何在Suricata规则中使用每个选项的完整解释,从第6.2节开始的Suricata规则文档详细描述了每个关键词选项。

关键字: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的数据包,并生成一个警报:

1
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;关键字。

1
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部分,你将了解到参考选项,你可以用它来链接到关于签名和它所要检测的问题的更多信息。

关键字 sidrev

每个Suricata签名都需要一个唯一的签名ID(sid)。如果两个规则具有相同的sid(在下面的输出示例中是sid:10000000),Suricata将不会启动,而会产生一个类似下面的错误:

1
2
3
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流量:

1
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中找到,包含如下条目:

1
2
3
4
5
6
7
8
#
# 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_ipdest_ip。这个选项的目的是为了在Suricata的警报日志中正确识别源主机和目标主机

例如,本教程前面的SSH签名可以用target:dest_ip;选项来加强:

1
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部分出现以下额外字段:

1
2
3
4
5
6
7
8
9
10
. . .
"source": {
"ip": "127.0.0.1",
"port": 35272
},
"target": {
"ip": "203.0.113.1",
"port": 2022
}
. . .

有了Suricata日志中的这些条目,它们可以被发送到安全信息和事件管理(SIEM)工具中,以便更容易地搜索可能来自普通主机的警报,或针对网络上特定目标的攻击。

常见的规则

Suricata常见规则分类可以分为以下几类:

基础规则(Base rules):包括协议分析、流量检测、服务识别等基本的规则。
恶意软件规则(Malware rules):主要是检测恶意软件、恶意代码的规则。
漏洞规则(Vulnerability rules):主要是检测系统或软件存在的漏洞。
检测规则(Detection rules):主要是根据攻击的特征来检测是否存在安全威胁,如检测SQL注入、XSS等攻击。
告警规则(Alert rules):主要是根据攻击行为发现安全事件并进行告警。
检测规则(Thresholding rules):主要是基于一定的时间窗口来判断是否存在攻击。
收集规则(Collection rules):主要是用于收集网络信息,如收集DNS信息、HTTP信息等。
文件规则(File inspection rules):主要是用于检测文件的特征,如文件名、文件类型、文
件大小等。
协议规则(Protocol rules):主要是用于检测协议的使用情况,如检测FTP、SMTP、DNS等
协议的使用情况。
以上分类并不是严格的划分,不同的规则可能会包含多种不同的分类。

编写suricata规则的技巧

针对漏洞,而不要漏洞利用

避免编写检测特定漏洞工具包的规则,因为同样的漏洞有无数个漏洞,而且我们可以肯定,在你读到这篇文章的时候,新的漏洞正在被编写。例如,许多早期检测缓冲区超限攻击的签名是这样的:

1
alert tcp $EXTERNAL_NET any -> $HOME_NET 80 (content:"AAAAAAAAAAAAAA", msg:"Buffer overrun detected.")

其原因当然是为了成功地发起缓冲区超限攻击,攻击者需要填充某个变量的缓冲区,并在最后添加他的恶意有效载荷,使其成为可执行文件。他选择用来填充缓冲区的字符是完全不重要的,事实上,在这种签名出现后,许多攻击工具箱只是用不同的字母来填充缓冲区,完全逃避了这种签名检测。一个更好的方法是试图通过检测基于字段类型和长度的不正确输入来检测这类攻击。

示例规则分析2

有如下规则,下面对其进行解释

1
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使用方法