流关键字 ============= .. role:: example-rule-action .. role:: example-rule-header .. role:: example-rule-options .. role:: example-rule-emphasis flowbits -------- flowbits由两部分组成。第一部分描述要执行的操作,第二部分是flowbit的名称。 一个流包含多个数据包。Suricata将这些流保存在内存中。更多信息请参阅 :ref:`suricata-yaml-flow-settings`。 flowbits可以确保当例如两个不同的数据包匹配时生成警报。只有当两个数据包都匹配时才会生成警报。因此,当第二个数据包匹配时,Suricata需要知道第一个数据包是否也匹配。flowbits会在数据包匹配时标记流,这样Suricata就"知道"当第二个数据包也匹配时应生成警报。 flowbits有不同的操作,包括: flowbits: set, name 如果存在,将在流中设置条件/'名称'。 flowbits: isset, name 可用于规则中,确保当规则匹配且流中设置了该条件时生成警报。 flowbits: toggle, name 反转当前设置。例如,如果条件已设置,则取消设置,反之亦然。 flowbits: unset, name 可用于取消流中的条件设置。 flowbits: isnotset, name 可用于规则中,确保当规则匹配且流中未设置该条件时生成警报。 flowbits: noalert 此规则不会生成警报。 示例: .. image:: flow-keywords/Flowbit_3.png 查看第一条规则时,您会注意到如果没有末尾的'flowbits: noalert',它会在匹配时生成警报。 此规则的目的是检查'userlogin'的匹配并在流中标记。因此,无需生成警报。第二条规则在没有第一条规则时无效。如果第一条规则匹配,flowbit会在流中设置该特定条件。现在可以检查第二条规则,看前一个数据包是否满足第一个条件。如果第二条规则现在匹配,将生成警报。 .. note:: flowbit名称区分大小写。 .. note:: 可以在一条规则中多次使用flowbits并组合不同的功能。 .. note:: 可以使用 `|` (管道)对flowbits执行 `OR` 操作。 .. container:: example-rule alert http any any -> any any (msg:"User1或User2登录"; \ content:"login"; :example-rule-options:`flowbits:isset,user1|user2;` sid:1;) flow ---- flow关键字可用于匹配流的方向,即到/从客户端或到/从服务器。它还可以匹配流是否已建立。flow关键字还可用于表示签名必须仅在流上匹配(only_stream)或仅在数据包上匹配(no_stream)。 使用flow关键字可以匹配: to_client 匹配从服务器到客户端的数据包。 to_server 匹配从客户端到服务器的数据包。 from_client 匹配从客户端到服务器的数据包(与to_server相同)。 from_server 匹配从服务器到客户端的数据包(与to_client相同)。 established 匹配已建立的连接。 not_established 匹配不属于已建立连接的数据包。 stateless 匹配属于流的数据包,无论连接状态如何。(这意味着不被视为流的一部分的数据包不会匹配)。 only_stream 匹配已被流引擎重组的数据包。 no_stream 匹配未被流引擎重组的数据包。不会匹配已被重组的数据包。 only_frag 匹配从片段重组的数据包。 no_frag 匹配未从片段重组的数据包。 可以组合多个flow选项,例如:: flow:to_client, established flow:to_server, established, only_stream flow:to_server, not_established, no_frag *established* 的确定取决于协议: * 对于TCP,连接将在三次握手后建立。 .. image:: flow-keywords/Flow1.png * 对于其他协议(例如UDP),在从连接的两端看到流量后,连接将被视为已建立。 .. image:: flow-keywords/Flow2.png flowint ------- flowint允许使用变量进行存储和数学运算。它的操作类似于flowbits,但增加了数学功能,可以存储和操作整数,而不仅仅是设置标志。我们可以将其用于许多非常有用的用途,例如计数出现次数、增加或减少出现次数,或在流中根据多个因素进行阈值设置。这将很快扩展到全局上下文,以便用户可以在流之间执行这些操作。 语法如下:: flowint: name, modifier[, value]; 定义变量(非必需),或检查是否设置了变量。 :: flowint: name, < +,-,=,>,<,>=,<=,==, != >, value; flowint: name, (isset|notset|isnotset); 比较或修改变量。可用的操作包括加、减、比较大于或小于、大于或等于、小于或等于。比较的对象可以是整数或另一个变量。 ________________________________________ 例如,如果您想计算特定流中用户名出现的次数,并在超过5次时发出警报。 :: alert tcp any any -> any any (msg:"计数用户名"; content:"jonkman"; \ flowint: usernamecount, +, 1; noalert;) 这将计算每次出现并增加变量usernamecount,且不会为每次生成警报。 现在假设我们希望在流中超过五次匹配时生成警报。 :: alert tcp any any -> any any (msg:"超过五个用户名!"; content:"jonkman"; \ flowint: usernamecount, +, 1; flowint:usernamecount, >, 5;) 因此,我们只会在usernamecount超过5时收到警报。 现在假设我们希望如上所述收到警报,但如果该用户名注销的次数更多则不发出警报。假设此特定协议用"jonkman logout"表示注销,让我们尝试: :: alert tcp any any -> any any (msg:"用户名注销"; content:"logout jonkman"; \ flowint: usernamecount, -, 1; flowint:usernamecount, >, 5;) 因此,我们现在只会在该特定用户名有超过五个活动登录时收到警报。 这是一个相当简单的例子,但我相信它展示了这样一个简单功能对规则编写的强大作用。我看到了许多应用,如登录跟踪、IRC状态机、恶意软件跟踪和暴力登录检测。 假设我们正在跟踪一个通常允许每个连接五次登录失败的协议,但我们有一个漏洞,攻击者可以在五次尝试后继续登录,我们需要知道这一点。 :: alert tcp any any -> any any (msg:"开始登录计数"; content:"login failed"; \ flowint:loginfail, notset; flowint:loginfail, =, 1; noalert;) 因此,我们检测初始失败,如果变量尚未设置,则将其设置为1。我们的第一次匹配。 :: alert tcp any any -> any any (msg:"计数登录"; content:"login failed"; \ flowint:loginfail, isset; flowint:loginfail, +, 1; noalert;) 我们现在正在增加计数器,如果它已设置。 :: alert tcp any any -> any any (msg:"流中超过五次登录失败"; \ content:"login failed"; flowint:loginfail, isset; flowint:loginfail, >, 5;) 现在,如果我们在同一流中超过五次登录失败,将生成警报。 但假设我们还需要在两个成功登录后有一个失败登录时发出警报。 :: alert tcp any any -> any any (msg:"计数成功登录"; \ content:"login successful"; flowint:loginsuccess, +, 1; noalert;) 这里我们正在计算成功登录,因此现在我们将计算与失败相关的成功登录: :: alert tcp any any -> any any (msg:"两次成功登录后登录失败"; \ content:"login failed"; flowint:loginsuccess, isset; \ flowint:loginsuccess, =, 2;) 以下是一些其他一般示例: :: alert tcp any any -> any any (msg:"设置flowint计数器"; content:"GET"; \ flowint:myvar, notset; flowint:maxvar,notset; \ flowint:myvar,=,1; flowint: maxvar,=,6;) :: alert tcp any any -> any any (msg:"增加flowint计数器"; \ content:"Unauthorized"; flowint:myvar,isset; flowint: myvar,+,2;) :: alert tcp any any -> any any (msg:"当flowint计数器为3时创建新计数器"; \ content:"Unauthorized"; flowint:myvar, isset; flowint:myvar,==,3; \ flowint:cntpackets,notset; flowint:cntpackets, =, 0;) :: alert tcp any any -> any any (msg:"计数其余部分而不生成警报"; \ flowint:cntpackets,isset; flowint:cntpackets, +, 1; noalert;) :: alert tcp any any -> any any (msg:"当达到6时触发此规则"; \ flowint: cntpackets, isset; \ flowint: maxvar,isset; flowint: cntpackets, ==, maxvar;) stream_size ----------- stream_size选项根据序列号注册的字节数匹配流量。此关键字有几个修饰符: :: > 大于 < 小于 = 等于 != 不等于 >= 大于或等于 <= 小于或等于 格式 :: stream_size:, , ; 规则中stream-size关键字的示例:: alert tcp any any -> any any (stream_size:both, >, 5000; sid:1;) flow.age -------- 流的年龄(秒)(整数) 此关键字不等待流结束,但会在每个数据包上检查。 flow.age使用 :ref:`无符号32位整数 `。 语法:: flow.age: [op] 可以精确匹配时间,或使用_op_设置进行比较:: flow.age:3 # 正好3 flow.age:<3 # 小于3秒 flow.age:>=2 # 大于或等于2秒 签名示例:: alert tcp any any -> any any (msg:"流超过一小时"; flow.age:>3600; flowbits: isnotset, onehourflow; flowbits: onehourflow, name; sid:1; rev:1;) 在此示例中,我们结合 `flow.age` 和 `flowbits` 在流的年龄超过一小时后第一个数据包上获取警报。 flow.pkts --------- 流的数据包数量(整数) 此关键字不等待流结束,但会在每个数据包上检查。 flow.pkts使用 :ref:`无符号32位整数 ` 并支持以下方向: * toclient * toserver * either 语法:: flow.pkts:,[op] 可以精确匹配数据包数量,或使用_op_设置进行比较:: flow.pkts:toclient,3 # 正好3 flow.pkts:toserver,<3 # 小于3 flow.pkts:either,>=2 # 大于或等于2 签名示例:: alert ip any any -> any any (msg:"流在toclient方向有20个数据包"; flow.pkts:toclient,20; sid:1;) .. note:: Suricata还支持 ``flow.pkts_toclient`` 和 ``flow.pkts_toserver`` 关键字分别对应 ``flow.pkts:toclient`` 和 ``flow.pkts:toserver``,但这不是首选语法。 flow.bytes ---------- 流的字节数(整数) 此关键字不等待流结束,但会在每个数据包上检查。 flow.bytes使用 :ref:`无符号64位整数 ` 并支持以下方向: * toclient * toserver * either 语法:: flow.bytes:,[op] 可以精确匹配字节数,或使用_op_设置进行比较:: flow.bytes:toclient,3 # 正好3 flow.bytes:toserver,<3 # 小于3 flow.bytes:either,>=2 # 大于或等于2 签名示例:: alert ip any any -> any any (msg:"流在toserver方向少于2000字节"; flow.bytes:toserver,<2000; sid:1;) .. note:: Suricata还支持 ``flow.bytes_toclient`` 和 ``flow.bytes_toserver`` 关键字分别对应 ``flow.bytes:toclient`` 和 ``flow.bytes:toserver``,但这不是首选语法。