snort 开源网络入侵防御系统(ips)

snort 开源网络入侵防御系统(ips)

目录导航

第一步

Snort 可以配置为执行复杂的数据包处理和深度数据包检查,但最好从简单开始,然后处理更有趣的任务。Snort 不会做任何你没有特别要求它做的事情,所以尝试一下看看会发生什么是安全的。让我们从不带参数运行 Snort 开始:

$ snort

这将输出使用信息,包括一些基本的帮助命令。您现在应该运行所有这些命令以查看可用的内容:

$ snort -V
$ snort -?
$ snort --help

请注意,Snort 有大量可用的命令行帮助,因此如果下面的任何内容不清楚,可能有一种方法可以从命令行获取您需要的确切信息。

现在让我们检查捕获文件 (pcap) 中的数据包:

$ snort -r a.pcap

Snort 会对文件中的数据包进行解码和计数,并输出一些统计信息。请注意,输出不包括非零数字,因此很容易看到那里有什么。

您可能已经注意到,有命令行选项可以限制检查的数据包数量或设置过滤器以选择特定数据包。现在是试验这些选项的好时机。

如果您想查看每个数据包的详细信息,可以像这样将数据包转储到控制台:

$ snort -r a.pcap -L dump

添加 -d 选项以查看 TCP 和 UDP 负载。现在让我们切换到实时流量。将以下命令中的 eth0 替换为可用的网络接口:

$ snort -i eth0 -L dump

除非接口被关闭,否则 Snort 将继续运行,因此输入 Control-C 终止或使用 -n 选项来限制数据包数量。

通常最好捕获数据包以供以后分析,如下所示:

$ snort -i eth0 -L pcap -n 10

Snort 将向 log.pcap.# 写入 10 个数据包,其中 # 是时间戳值。你可以用 -r 读回这些,然后用 -L 转储到控制台或 pcap。你明白了。

请注意,您可以使用其他工具(例如 tcpdump 或 Wireshark)执行类似操作,但是当您想检查 Snort 设置时,这些命令非常有用。

上面的例子使用默认的 pcap DAQ。Snort 还通过 DAQ(数据采集)库支持非 pcap 接口。其他 DAQ 提供额外的功能,例如在线操作和/或更高的性能。甚至还有支持原始文件处理(即无数据包)、套接字处理和纯文本数据包的 DAQ。要加载外部 DAQ 库并查看可用的 DAQ 或选择特定的 DAQ,请使用以下命令之一:

$ snort --daq-dir <path> --daq-list
$ snort --daq-dir <path> --daq <type>

确保将 –daq-dir 选项放在 –daq-list 选项之前,否则外部 DAQ 将不会出现在列表中。

要利用 Snort 的入侵检测功能,您需要提供一些配置详细信息。下一部分分解了必须做的事情。

配置

Snort 的有效配置是通过环境、命令行、Lua 配置文件和一组规则完成的。

请注意,为了获得新的和改进的功能,牺牲了与 Snort 2 的向后兼容性。虽然 Snort 3 利用了 Snort 2 的一些代码库,但还是发生了很多变化。Snort 3 的配置是使用 Lua 完成的,因此您的旧配置将无法按原样工作。规则仍然是基于文本的,但有语法调整,所以你的 2.X 规则必须修正。但是,snort2lua 将帮助您将配置文件和规则转换为新格式。

命令行

一个简单的命令行可能如下所示:

snort -c snort.lua -R cool.rules -r some.pcap -A cmg

要了解它的作用,您可以首先通过运行 snort –help 不带参数地运行 snort。所有配置和规则选项的帮助都可以通过合适的命令行获得。在这种情况下:

-c snort.lua 是主要的配置文件。这是一个加载时执行的 Lua 脚本。

-R cool.rules 包含一些检测规则。您可以自己编写或从 Talos 获取它们(Talos 尚不提供原生 3.0 规则,因此您必须使用 snort2lua 转换它们)。您也可以将规则直接放在配置文件中。

-r some.pcap 告诉 Snort 从给定的数据包捕获文件中读取网络流量。您可以改为使用 -i eth0 从实时界面读取。根据您使用的 DAQ,还有许多其他选项可用。

-A cmg 表示以“cmg”格式输出入侵事件,该格式具有基本的标题详细信息,后跟十六进制和文本形式的有效负载。

请注意,您可以使用 –lua 命令行选项添加和/或覆盖配置文件中的任何内容。例如:

--lua 'ips = { enable_builtin_rules = true }'

将加载内置的解码器和检查器规则。在这种情况下,ips 将被您在上面看到的配置覆盖。如果您只想更改配置文件中给出的配置,您可以这样做:

--lua 'ips.enable_builtin_rules = true'

配置文件

配置文件使您可以完全控制 Snort 处理数据包的方式。从分发中包含的默认 snort.lua 开始,因为它包含一些关键成分。请注意,大多数配置如下所示:

stream = { }

这意味着使用内部默认值启用流模块。要查看它们是什么,您可以运行:

snort --help-config stream

Snort 被组织成一组内置和插件模块。如果模块有参数,则由一个同名的 Lua 表配置。例如,我们可以使用此命令查看活动模块必须提供的内容:

$ snort --help-module active
What: configure responses
Type: basic
Configuration:
int active.attempts = 0: number of TCP packets sent per response (with
varying sequence numbers) { 0:20 }
string active.device: use 'ip' for network layer responses or 'eth0' etc
for link layer
string active.dst_mac: use format '01:23:45:67:89:ab'
int active.max_responses = 0: maximum number of responses { 0: }
int active.min_interval = 255: minimum number of seconds between
responses { 1: }

这表示 active 是一个具有多个参数的基本模块。对于每个,您将看到:

type module.name = default: help { range }

例如,活动模块有一个 max_responses 参数,该参数采用非负整数值并默认为零。我们可以在 Lua 中进行如下更改:

active = { max_responses = 1 }

或者:

active = { }
active.max_responses = 1

如果我们还想将重试限制为至少 5 秒,我们可以这样做:

active = { max_responses = 1, min_interval = 5 }

Lua 变量

当使用 -c 选项通过 lua 配置运行 Snort 时,以下全局 Lua 变量可用。

  • SNORT_VERSION:指向一个包含snort版本的字符串,构建如下:SNORT_VERSION = "3.0.2-x"
  • SNORT_MAJOR_VERSION:Snort 版本的主要编号。SNORT_MAJOR_VERSION = 3
  • SNORT_MINOR_VERSION:Snort 版本的次要编号。SNORT_MINOR_VERSION = 0
  • SNORT_PATCH_VERSION:Snort 版本的补丁号。SNORT_PATCH_VERSION = 2

白名单

当 Snort 使用 –warn-conf-strict 选项运行时,将为配置文件中存在的所有 Lua 表生成警告,这些表未映射到 Snort 模块名称。与其他警告一样,当 Snort 以迂腐模式运行时,这些警告将升级为错误。

为了动态添加应该绕过这种严格验证的异常,在评估 Snort 配置文件期间可以调用两个 Lua 函数:snort_whitelist_append() 和 snort_whitelist_add_prefix()。每个函数都采用一个以空格分隔的列表,前者是一个精确的表名列表,后者是一个允许的表名前缀列表。

示例:snort_whitelist_append(“table1 table2”) snort_whitelist_add_prefix(“local_ foobar_”)

当 Snort 在详细模式 (-v) 下运行时,白名单的累积内容(精确和前缀)将被转储。

规则

规则决定了 Snort 正在寻找什么。它们可以使用 ips 模块直接放在 Lua 配置文件中,使用 –lua 放在命令行中,或放在外部文件中。通常,您会从各种来源(例如 Talos)获得许多规则,加载外部文件是可行的方法,因此我们将在此处进行总结。将此添加到您的 Lua 配置中:

ips = { include = 'rules.txt' }

加载名为 rules.txt 的外部规则文件。您只能以这种方式指定一个文件,但规则文件可以通过 include 语句包含其他规则文件。此外,您可以加载以下规则:

$ sort -c snort.lua -R rules.txt

您可以同时使用这两种方法。

包括

您的配置文件可能包含其他文件,直接通过 Lua 或通过各种参数。Snort 将按以下顺序查找相关的包含:

  1. 如果指定–include-path,将首先尝试此目录。
  2. Snort 将尝试包含包含文件的目录。
  3. Snort 将尝试包含 -c 配置文件的目录。

要记住的一些事情:

  • 如果您使用 Lua dofile 函数,那么您必须指定绝对路径或相对于您的工作目录的路径,因为 Lua 将在 Snort 看到文件内容之前执行包含。
  • 为获得最佳结果,请使用 include 代替 dofile。提供此功能是为了遵循 Snort 的包含逻辑。
  • 截至目前,appid 和信誉路径必须是相对于工作目录的绝对路径或相对路径。这些将在未来的版本中更新。

转换您的 2.X 配置

如果您有可用的 2.X 配置,snort2lua 可以轻松启动和运行 Snort 3。此工具将自动转换您的配置和/或规则文件。您将需要清理结果并仔细检查它是否完全符合您的需要。

snort2lua -c snort.conf

上述命令将根据您的 2.X 配置生成 snort.lua。有关更复杂用例的更多信息和选项,请参阅手册后面的 Snort2Lua 部分。

输出

Snort 可以产生相当多的数据。下面我们将总结核心输出类型的关键方面。后面会介绍其他数据,例如来自 appid 的数据。

基本统计

在关闭时,Snort 将根据配置和处理的流量输出各种计数。通常,您可能会看到:

  • 数据包统计 – 这包括来自 DAQ 和解码器的数据,例如接收到的数据包数量和 UDP 数据包数量。
  • 模块统计 – 每个模块通过一组挂钩计数跟踪活动,这些挂钩计数指示观察或执行某事的次数。这可能包括处理的 HTTP GET 请求的数量和修剪的 TCP 重置数据包的数量。
  • 文件统计 – 在此处查看文件类型、字节、签名的细分。
  • 汇总统计 – 这包括数据包处理的总运行时间和每秒数据包数。如果配置,分析数据也将显示在此处。

请注意,仅输出非零计数。运行此命令以查看可用计数:

$ snort --help-counts

警报

如果您配置了规则,您将需要配置警报以查看检测事件的详细信息。像这样使用 -A 选项:

$ snort -c snort.lua -r a.pcap -A cmg

可能有多种类型的警报输出。这是一个简短的列表:

  • -A cmg 与 -A fast -d -e 相同,将显示有关警报的信息以及数据包标头和有效负载。
  • -A u2 与 -A Unified2 相同,将在二进制文件中记录事件和触发数据包,您可以将其提供给其他工具进行后期处理。请注意,Snort 3 不提供用于 PDU 警报的原始数据包;您将获得警报的实际缓冲区。
  • -A csv 将以逗号分隔值格式输出各种字段。这是完全可定制的,对 pcap 分析非常有用。

要查看可用的警报类型,您可以运行以下命令:

$ snort --list-plugins | grep logger

文件和路径

请注意,输出特定于每个数据包线程。如果您使用 u2 输出运行 4 个数据包线程,您将获得 4 个不同的 u2 文件。基本结构是:

<logdir>/[<run_prefix>][<id#>][<X>]<name>

在哪里:

  • logdir 设置为 -l 并默认为 ./
  • run_prefix 设置为 –run-prefix 否则不使用
  • id#是写入文件的数据包线程数;有一个数据包线程,id#(零)被省略,没有 –id-zero
  • X是/如果你使用–id-subdir,否则_如果使用id#
  • 名称基于写入文件的模块名称

其他注意事项:

  • 无法显式配置完整路径以避免多个数据包线程出现问题。
  • 所有文本模式输出默认为 stdout

性能统计

除了上述数​​据,还有更多数据可用。

  • 通过配置 perf_monitor 模块,您可以在运行时捕获一组可配置的挂钩计数。这对于提供给外部程序很有用,因此您可以在不停止 Snort 的情况下查看正在发生的情况。
  • profiler 模块允许您跟踪模块和规则使用的时间和空间。使用此数据来调整您的系统以获得最佳性能。输出将显示在关闭时的汇总统计信息下。

概念

本节提供有关 Snort 操作的基本方面的背景知识。

术语

  • 基本模块:集成到 Snort 中的模块,它不是来自插件。
  • 活页夹:将配置映射到流量的检查器
  • 内置规则:用于内部检测到的异常的编解码器和检查器规则。
  • 编解码器:编码器/解码器的简称。这些插件用于基本协议解码、异常检测和主动响应的构建。
  • 数据模块:用于某些检查器的附加配置插件。
  • 动态规则:在运行时加载的插件规则。参见 SO 规则。
  • 快速模式:搜索引擎必须找到 IPS 规则中的内容,以便对规则进行评估。
  • 快速模式匹配器:参见搜索引擎。
  • hex:向导用来识别二进制协议的一种协议魔法。
  • 检查器:处理数据包的插件(类似于 Snort 2 预处理器)
  • IPS:入侵防御系统,如Snort。
  • IPS 操作:允许您在生成事件时执行自定义操作的插件。与记录器不同,它们在阈值设置之前调用,可用于控制外部代理或发送主动响应。
  • IPS 选项:此插件是 IPS 规则的构建块。
  • logger : 一个执行事件和数据包输出的插件。事件在到达记录器之前被设定阈值。
  • 模块:Snort 组件面向用户的部分。模块主要提供配置参数,但也可能提供命令、内置规则、分析统计、peg 计数等。请注意,并非所有模块都是插件,也不是所有插件都有模块。
  • 挂钩计数:给定事件或条件发生的次数。
  • plugin:Snort 启动时可以从动态库加载的几种软件组件之一。一些插件以这样的方式与主引擎耦合,它们必须静态构建,但可以动态加载更新的版本。
  • 搜索引擎:一个插件,它执行数据包和有效载荷的多模式搜索,以找到应该评估的规则。目前没有特定的模块,尽管有几个搜索引擎插件。相关配置通过基本检测模块完成。又名快速模式匹配器。
  • SO 规则:一个 IPS 规则插件,可以执行文本规则无法完成的自定义检测。这些规则通常没有关联的模块。SO 来自共享对象,即动态库。
  • spell:向导用来识别 ASCII 协议的一种协议魔法。
  • 文本规则:从具有标题和正文的配置加载的规则。标头指定操作、协议、源和目标 IP 地址和端口以及方向。正文指定检测和非检测选项。
  • 向导:应用协议魔术来确定哪些检查器应该绑定到没有端口特定绑定的流量的检查器。见十六进制和拼写。

模块

模块是 Snort 的构建块。它们封装了许多组件需要的数据类型,包括参数、挂钩计数、分析、内置规则和命令。这允许 Snort 通用且一致地处理它们。您可以从命令行中了解很多关于任何给定模块的信息。例如,要查看 stream_tcp 的全部内容,请执行以下操作:

$ snort --help-config stream_tcp

模块使用同名的 Lua 表进行配置。所以 stream_tcp 模块配置了这样的默认值:

stream_tcp = { }

较早的帮助输出显示默认会话跟踪超时为 30 秒。要将其更改为 60 秒,您可以这样配置:

stream_tcp = { session_timeout = 60 }

或者这样:

stream_tcp = { }
stream_tcp.session_timeout = 60

下一节将提供有关参数的更多信息。

关于模块的其他注意事项:

  • 关机输出将显示所有模块的非零挂钉计数。例如,如果 stream_tcp 做了任何事情,你会看到处理的会话数量等等。
  • 提供内置规则允许文档自动包含它们,还允许在启动时自动生成规则。
  • 此时只有少数模块提供命令,最显着的是 snort 模块。

参数

参数以这种格式给出:

type name = default: help { range }

使用以下类型:

  • addr : 任何有效的 IP4 或 IP6 地址或 CIDR
  • addr_list : 一个空格分隔的地址列表
  • bit_list:从 1 到范围最大值的连续整数值列表
  • 布尔:真或假
  • dynamic : 由加载的插件决定的选择类型
  • enum : 从给定范围中选择的字符串
  • 隐含:一个 IPS 规则选项,不带任何值,但表示为真
  • int : 给定范围内的整数
  • 间隔:一组整数(见下文)
  • ip4 : IP4 地址或 CIDR
  • mac : 格式为 01:02:03:04:05:06 的以太网地址
  • multi : 给定范围内的一个或多个空格分隔的字符串
  • port : 0:65535 范围内的 int 表示 TCP 或 UDP 端口号
  • real : 给定范围内的实数
  • select : 从给定范围中选择的字符串
  • string : 任何不超过给定长度的字符串,如果有的话

参数名称可以以各种方式装饰,以指示有关参数类型和用途的附加信息:

  • 对于 Lua 配置(不是 IPS 规则),如果名称以 [] 结尾,则它是一个列表项,可以重复。
  • 仅对于 IPS 规则,以 ~ 开头的名称表示位置参数。此类参数的名称不会出现在规则中。
  • IPS 规则也可能有一个通配符参数,用 * 表示。用于不加引号的逗号分隔列表,例如服务和元数据。
  • snort 模块具有以 – 开头的命令行选项。
  • $ 表示变量名。

一些额外的细节需要注意:

  • 表名和变量名区分大小写;仅使用小写。
  • 字符串值也区分大小写;仅使用小写。
  • 数字范围可以采用低:高的形式,其中低和高是范围内的界限。如果省略其中一个,则没有硬边界。例如 0:表示任何 x,其中 x >= 0。
  • 字符串可能有一个表示长度限制的数字范围;否则没有硬限制。
  • bit_list 通常用于存储一组字节、端口或 VLAN ID 值。
  • 区间采用 [operator]i、j<>k 或 j<⇒k 的形式,其中 i、j、k 是整数,并且 operator 是 =、!、!=(与 !)、<、⇐、> 之一>=。j<>k 表示 j < int < k 和 j<⇒k 表示 j ⇐ int ⇐ k。
  • 范围可以像 { 1:max32 } 一样使用 maxXX,因为 max32 比 4294967295 更容易阅读。要获取 maxXX 的值,请使用 snort –help-limits。

参数限制:

  • max31 = 2147483647
  • max32 = 4294967295
  • max53 = 9007199254740992
  • maxSZ = 9007199254740992

插件

Snort 使用各种插件来实现其大部分处理目标,包括:

  • 编解码器 – 解码和编码数据包
  • 检查器 – 像 Snort 2 预处理器,用于规范化等。
  • IpsOption – 用于检测 Snort 规则
  • IpsAction – 用于自定义操作
  • 记录器 – 用于处理事件
  • Mpse – 用于快速模式匹配
  • 所以 – 对于动态规则

插件的强大之处在于它们具有非常集中的目的,并且可以相对轻松地创建。例如,您可以通过编写自己的 IpsOption 来扩展规则语言,它会像现有选项一样插入和运行。额外的目录包含每种类型插件的示例。

大多数插件可以静态或动态构建。默认情况下,它们都是静态的。静态或动态插件之间的功能没有区别,但动态构建会生成重量稍轻的二进制文件。无论哪种方式,您都可以使用 –plugin-path 添加动态插件,即使是静态构建,新版本也会替换旧版本。

一个动态库可能包含多个插件。例如,检查器通常会与任何关联的规则选项打包在一起。

手术

Snort 是一种基于签名的 IPS,这意味着当它接收网络数据包时,它会重新组合并规范内容,以便可以评估一组规则以检测是否存在任何值得采取进一步行动的重要条件。粗略的处理流程如下:snort2x

步骤是:

  1. 解码每个数据包以确定基本网络特征,例如源地址和目标地址以及端口。一个典型的数据包可能有包含 IP 的以太网,其中包含包含 HTTP 的 TCP(即 eth:ip:tcp:http)。在对数据包进行解码时,会检查各种封装协议的完整性和异常情况。这本质上是一种无状态的努力。
  2. 使用累积状态对每个解码的数据包进行预处理,以确定最内层消息的目的和内容。此步骤可能涉及重新排序和重组 IP 片段和 TCP 片段以生成原始应用协议数据单元 (PDU)。根据需要对此类 PDU 进行分析和标准化,以支持进一步处理。
  3. 检测是一个两步过程。为了提高效率,大多数规则都包含可以搜索的特定内容模式,如果没有找到匹配项,则无需进一步处理。启动时,规则被编译到模式组中,以便可以对组中的所有模式执行单个并行搜索。如果找到任何匹配项,则根据签名的细节检查完整规则。
  4. 日志记录步骤是 Snort 保存从早期步骤产生的任何相关信息的地方。更一般地说,这也是可以采取其他行动的地方,例如阻止数据包。

Snort 2 处理

Snort 2 中的预处理步骤是高度可配置的。任意预处理器可以在启动时动态加载,在 snort.conf 中配置,然后在运行时执行。基本上,预处理器被放入一个列表中,该列表为每个数据包迭代。最近的版本对列表处理进行了一些调整,但相同的基本架构允许 Snort 2 从没有预处理的嗅探器发展为具有大量预处理的成熟 IPS。

虽然这种“插件列表”方法具有相当大的灵活性,但当从一个预处理器到下一个预处理器的数据流取决于流量条件时,它会阻碍未来的开发,这是具有应用程序识别等高级功能的常见情况。在这种情况下,像 HTTP 这样的预处理器可能会提取和规范化最终不使用的数据,或者 appID 可能会重复检查不可用的数据。

回调有助于打破预处理束缚。这是一个预处理器为另一个预处理器提供在某些数据可用时调用的函数的地方。Snort 已经开始采用这种方法将一些 HTTP 和 SIP 预处理器数据传递给 appID。但是,它仍然是一个外围功能,并且仍然需要生成可能不会被消耗的数据。

Snort 3 处理

Snort 3 的目标之一是通过实现事件驱动的方法为数据包处理提供更灵活的框架。另一种方法是仅在需要时生成数据以最小化昂贵的标准化。然而,基本的数据包处理提供了非常相似的功能。

Snort 3 的基本处理步骤与 Snort 2 类似,如下图所示。预处理步骤使用特定的检查器类型而不是通用列表,但基本过程包括两种情况下的无状态数据包解码、TCP 流重组和服务特定分析。(Snort 3 为任意检查器提供钩子,但它们不是基本流程处理的核心,因此未显示。)snort3x

但是,Snort 3 还提供了比回调函数更灵活的机制。通过使用检查事件,检查员可以提供其他检查员可以处理的数据。这被称为观察者模式或发布订阅模式。

请注意,数据实际上并未发布。相反,对数据的访问是公开的,这意味着订阅者可以根据需要访问原始版本或规范化版本。规范化仅在第一次访问时完成,后续访问获取先前规范化的数据。这会导致及时 (JIT) 处理。

额外的 data_log 插件提供了一个基本的例子。它是一个被动检查器,即在收到它订阅的数据之前它什么都不做(上图中的其他)。通过将以下内容添加到您的 snort.lua 配置中,您将获得一个简单的 URI 记录器。

data_log = { key = 'http_raw_uri' }

检查事件与可插入检查器相结合,为实现新功能提供了一个非常灵活的框架。并且 JIT 缓冲区填充器允许 Snort 更聪明地工作,而不是更努力地工作。随着 Snort 开发的继续,这些功能将得到越来越多的利用。

规则

规则告诉 Snort 如何检测有趣的条件,例如攻击,以及在检测到条件时要做什么。这是一个示例规则:

alert tcp any any -> 192.168.1.1 80 ( msg:"A ha!"; content:"attack"; sid:1; )

结构是:

action proto source dir dest ( body )

在哪里:

action – 告诉 Snort 在规则“触发”时(即签名匹配时)要做什么。在这种情况下,Snort 将记录该事件。它还可以在运行内联时执行诸如阻塞流之类的事情。

proto – 告诉 Snort 适用的协议。这可能是 ip、icmp、tcp、udp、http 等。

source – 指定发送IP地址和端口,其中任何一个都可以是关键字any,它是一个通配符。

dir – 必须是如上所示的单向或由 <> 指示的双向。

dest – 与 source 类似,但表示接收端。

body – 括号中包含的检测和其他信息。

有许多规则选项可用于根据需要构建复杂的签名。在这种情况下,我们只是在任何 TCP 数据包中寻找“攻击”。更好的规则可能如下所示:

alert http
(
    msg:"Gotcha!";
    flow:established, to_server;
    http_uri:"attack";
    sid:2;
)

请注意,这些示例有一个 sid 选项,用于指示签名 ID。一般规则由 gid:sid:rev 表示法指定,其中 gid 是生成器 ID,rev 是规则的修订版。默认情况下,文本规则是 gid 1,共享对象 (SO) 规则是 gid 3。Snort 中生成事件的各种组件有 1XX 个 gid,例如解码器是 gid 116。您可以使用这些列出内部 gid 和 sid命令:

$ snort --list-gids
$ snort --list-builtin

有关这些和其他选项的详细信息,请参阅参考部分。

模式匹配

Snort 在两步过程中评估规则,包括快速模式搜索和对签名的全面评估。有关此过程的更多详细信息,请参见下文。

规则组

当 Snort 启动或重新加载配置时,规则按协议、端口和服务分组。例如,所有使用 HTTP_PORTS 变量的 TCP 规则将进入一个组,所有服务 HTTP 规则将进入另一组。这些规则组被编译到多模式搜索引擎 (MPSE) 中,该引擎旨在搜索所有模式,只需通过给定的数据包或缓冲区一次即可。您可以使用 search_engine.search_method 选择用于快速模式搜索的算法,默认为 ac_bnfa,它可以平衡速度和内存。要以显着增加内存为代价进行更快的搜索,请使用ac_full。为获得最佳性能和合理内存,请从 Intel 下载 hyperscan 源。

快速模式

快速模式是具有 fast_pattern 选项或已被 Snort 自动选择用作快速模式的内容字符串。默认情况下,Snort 将选择规则中最长的模式,因为这可能是最独特的。情况并非总是如此,因此将 fast_pattern 添加到适当的内容选项以获得最佳性能。理想的快速模式是一种如果找到就很可能导致规则匹配的模式。频繁匹配不相关流量的快速模式将导致 Snort 努力工作而几乎没有显示出来。

某些内容不能用作快速模式。具体来说,如果一个内容被否定,那么如果它也相对于另一个内容,区分大小写,或者具有非零偏移或深度,那么它就不能用作快速模式。

规则评估

对于每个快速模式匹配,从左到右评估相应的规则。规则评估需要检查规则中的每个检测选项,这是一个相当昂贵的过程,这就是快速模式如此重要的原因。规则评估在第一个不匹配的选项上中止。

当规则评估发生时,如果可能,将自动跳过快速模式匹配。请注意,这与 Snort 2 不同,后者提供了 fast_pattern:only 选项来指定此类情况。这是规则编写者无需担心的一件事。

教程

本节将引导您构建和运行 Snort。它并不详尽,但是,一旦您掌握了这些材料,您应该能够找出更高级的用法。

依赖关系

必需的:

可选的:

建筑

  • 参考部分列出了可选的内置功能。
  • 创建安装路径:export my_path=/path/to/snorty mkdir -p $my_path
  • 如果 LibDAQ 安装到自定义的非系统路径:export PKG_CONFIG_PATH=/libdaq/install/path/lib/pkgconfig:$PKG_CONFIG_PATH
  • 现在执行以下操作之一:
    1. 要使用 cmake 和 make 构建,请运行 configure_cmake.sh。它将自动创建并填充一个名为build的新子目录。./configure_cmake.sh --prefix=$my_path cd build make -j make install ln -s $my_path/conf $my_path/etc
    2. 您还可以指定一个 cmake 项目生成器:./configure_cmake.sh --generator=Xcode --prefix=$my_path
    3. 或者直接使用 ccmake 从任意构建目录配置和生成,如以下之一:ccmake -G Xcode /path/to/Snort++/tree open snort.xcodeprojccmake -G "Eclipse CDT4 - Unix Makefiles" /path/to/Snort++/tree run eclipse and do File > Import > Existing Eclipse Project
  • 要在安装了 clang 的 OS X 上使用 g++ 进行构建,请先执行以下操作:export CXX=g++

跑步

例子:

  • 得到一些帮助:$my_path/bin/snort --help $my_path/bin/snort --help-module suppress $my_path/bin/snort --help-config | grep thread
  • 检查并转储 pcap:$my_path/bin/snort -r <pcap> $my_path/bin/snort -L dump -d -e -q -r <pcap>
  • 使用或不使用规则验证配置:$my_path/bin/snort -c $my_path/etc/snort/snort.lua $my_path/bin/snort -c $my_path/etc/snort/snort.lua -R $my_path/etc/snort/sample.rules
  • 运行 IDS 模式。为了简单起见,请查看每个文件中的前 n 个数据包:$my_path/bin/snort -c $my_path/etc/snort/snort.lua -R $my_path/etc/snort/sample.rules \ -r <pcap> -A alert_test -n 100000
  • 让我们抑制 1:2123。我们可以编辑 conf 或只是这样做:$my_path/bin/snort -c $my_path/etc/snort/snort.lua -R $my_path/etc/snort/sample.rules \ -r <pcap> -A alert_test -n 100000 --lua "suppress = { { gid = 1, sid = 2123 } }"
  • 在具有多个数据包线程的目录上全力以赴:$my_path/bin/snort -c $my_path/etc/snort/snort.lua -R $my_path/etc/snort/sample.rules \ --pcap-filter \*.pcap --pcap-dir <dir> -A alert_fast -n 1000 --max-packet-threads 8

有关更多示例,请参阅用法部分。

提示

Snort 3 的目标之一是让您更轻松地配置传感器。以下是您可能会觉得有用的提示和技巧的摘要。

一般使用

  • Snort 尽量不要太快出错。它会报告多个语义错误。
  • Snort 总是采用最简单的操作模式。例如,如果您不提供数据包源,您可以省略 -T 选项来验证 conf。
  • 除非指定了 –warn-* ,否则不会发出警告。–warn-all 启用所有警告,而 –pedantic 使此类警告致命。
  • 您可以使用 -z 或 –max-threads 选项一次处理多个源。
  • 为方便查找重要数据,关机时不输出零计数。
  • 使用 –plugin-path /path/to/install/lib 从命令行加载插件。
  • 您可以使用 -z 或 –max-threads 选项一次处理多个源。
  • 单元测试使用 –enable-unit-tests 进行配置。然后可以使用 snort –catch-test [tags]|all 运行它们。
  • 基准测试使用 –enable-benchmark-tests 进行配置。然后可以使用 snort –catch-test [tags]|all 运行它们或将它们构建为单独的可执行文件。还首选配置启用优化的非调试版本。

Lua配置

  • 配置向导并根据配置的检查器创建默认绑定。在这种情况下不需要显式绑定端口。
  • 您可以使用 –lua 命令行选项覆盖或添加到您的 Lua 配置中。
  • Lua conf 是一个在加载时执行的实时脚本。您可以添加函数、获取环境变量、计算值等。
  • 您还可以重命名要禁用的符号。例如,将 normalizer 更改为 Xnormalizer(未知符号)将禁用归一化器。在某些情况下,这比评论更容易。
  • 默认情况下,Snort 未知的符号会被静默忽略。您可以使用 –warn-unknown 为它们生成警告。要忽略此类符号,请将它们导出到环境变量 SNORT_IGNORE 中。

编写和加载规则

Snort 规则允许任意空格。为了清晰起见,多行规则可以更轻松地构建规则。有多种方法可以为规则添加注释:

  • # 字符开始注释到行尾。此外,#begin 和#end 之间的所有行都是注释。
  • rem 选项允许您编写随规则传达的注释。
  • 允许使用 C 风格的多行注释,这意味着您可以在测试时注释掉规则的一部分,方法是在 /* 和 */ 之间放置选项。

还有多种加载规则的方法:

  • 设置 ips.rules 或 ips.include。
  • include 语句可以在规则文件中使用。
  • 使用 -R 加载规则文件。
  • 将 –stdin-rules 与命令行重定向一起使用。
  • 使用 –lua 将一个或多个规则指定为命令行参数。

ips 状态类似于 ips 规则,只是它们是在规则之后解析的。这样可以在自定义策略中覆盖规则。

没有启用选项的状态作为存根规则加载,默认为 gid:0, sid:0。用户应该指定gidsidenable选项以避免虚拟规则。

输出文件

为了在使用多个数据包线程运行时配置输出变得简单,未显式配置输出文件。相反,您可以使用以下选项来格式化路径:

<logdir>/[<run_prefix>][<id#>][<X>]<name>
  • logdir 设置为 -l 并默认为 ./
  • run_prefix 设置为 –run-prefix 否则不使用
  • id#是写入文件的数据包线程数;有一个数据包线程,id#(零)被省略,没有 –id-zero
  • X是/如果你使用–id-subdir,否则_如果使用id#
  • 名称基于写入文件的模块名称
  • 所有文本模式输出默认为标准输出

常见错误

PANIC:调用 Lua API 时出现未受保护的错误(无法打开 snort_defaults.lua:没有这样的文件或目录)

  • 导出 SNORT_LUA_PATH 以指向任何 dofile

错误找不到 xyz

  • 如果 xyz 是模块的名称,请确保您没有在需要表的地方分配标量(例如 xyz = 2 应为 xyz = { })。

错误找不到 xy

  • 模块 x 没有名为 y 的参数。检查 –help-module x 以获取可用参数。

错误无效 xy = z

  • z 的值超出了 xy 检查的范围 –help-config xy 对于允许的范围。

错误:x = { y = z } 在 conf 中但没有被应用

  • 确保稍后没有设置 x = { } ,因为它会覆盖之前的设置。xy 也一样

致命: 无法加载 lua/errors.lua: lua/errors.lua:68: =预期在 ‘;’ 附近

  • 这是 Lua 在 errors.lua 的第 68 行向 Snort 报告的语法错误。

错误:规则(2)未知规则关键字:查找。

  • 这是因为不包括 –script-path。

警告:未知符号 x

  • 如果您有任何变量,您可以通过在环境变量 SNORT_IGNORE 中设置它们来消除此类警告。忽略 x、y 和 z:export SNORT_IGNORE="x y z"

陷阱

  • 表中的 nil 键不会被捕获。表中的 nil 值也不会。以下两种情况都不会导致错误,也不会实际设置 http_inspect.request_depth:http_inspect = { request_depth } http_inspect = { request_depth = undefined_symbol }
  • 多次设置一个值不是错误。实际应用的值也可能不是表中的最后一个。最好避免这种情况。http_inspect = { request_depth = 1234, request_depth = 4321 }
  • Snort 无法告诉您语义错误的确切文件名或行号,但它会告诉您完全限定的名称。

已知的问题

  • 除非您使用 –daq-var output=none,否则转储 DAQ 将不适用于多线程。这将在某些时候修复以使用 Snort 日志目录等。
  • 如果您在 OS X 上使用 hyperscan 构建并查看:dyld: Library not loaded: @rpath/libhs.4.0.dylibwhen you try to run src/snort, export DYLD_LIBRARY_PATH with the path to libhs. You can also do:install_name_tool -change @rpath/libhs.4.0.dylib \ /path-to/libhs.4.0.dylib src/snort
  • 在 Ubuntu 17.04/18.04 上使用 tcmalloc 支持 (–enable-tcmalloc) 构建的 Snort 立即崩溃。Workaround: Uninstall gperftools 2.5 provided by the distribution and install gperftools 2.7 before building Snort.

重新加载限制

以下参数在重新加载期间无法更改,需要重新启动:

  • 主动尝试
  • 有源设备
  • alerts.detection_filter_memcap
  • alerts.event_filter_memcap
  • alerts.rate_filter_memcap
  • attribute_table.max_hosts
  • attribute_table.max_services_per_host
  • daq.snaplen
  • 检测.asn1
  • file_id.max_files_cached
  • 进程.chroot
  • 进程守护进程
  • process.set_gid
  • process.set_uid
  • 打鼾。–bpf
  • 打鼾。-l

此外,以下场景需要重启:

  • 首次启用文件捕获
  • 如果之前或当前启用了文件捕获,则更改 file_id.capture_memcap
  • 如果之前或当前启用了文件捕获,则更改 file_id.capture_block_size
  • 如果已经配置了流,则添加/删除 stream_* 检查器

在所有这些情况下,重新加载都会失败并显示以下消息:“重新加载失败 – 需要重新启动”。原始配置将继续使用。

用法

对于以下示例,假定“$my_path”是 Snort 安装目录的路径。此外,假设“$my_path/bin”在您的 PATH 中。

帮助

打印帮助摘要:

snort --help

获取有关特定模块的帮助(例如“流”):

snort --help-module stream

获取有关“-A”命令行选项的帮助:

snort --help-options A

Grep 寻求线程帮助:

snort --help-config | grep thread

以 AsciiDoc 格式输出有关“规则”选项的帮助:

snort --markup --help-options rule
笔记Snort 在“–help- ”和“–list- ”选项之后停止读取命令行选项,因此任何其他选项都应该放在它们之前。

嗅探和记录

阅读 pcap:

snort -r /path/to/my.pcap

将数据包转储到标准输出:

snort -r /path/to/my.pcap -L dump

转储带有应用程序数据和第 2 层标头的数据包

snort -r /path/to/my.pcap -L dump -d -e
笔记命令行选项必须单独指定。“snort -de”不起作用。但是,您仍然可以连接选项及其参数,因此“snort -Ldump”将起作用。

从目录中的所有 pcap 转储数据包:

snort --pcap-dir /path/to/pcap/dir --pcap-filter '*.pcap' -L dump -d -e

将数据包记录到目录:

snort --pcap-dir /path/to/pcap/dir --pcap-filter '*.pcap' -L dump -l /path/to/log/dir

配置

验证配置文件:

snort -c $my_path/etc/snort/snort.lua

验证配置文件和单独的规则文件:

snort -c $my_path/etc/snort/snort.lua -R $my_path/etc/snort/sample.rules

从标准输入读取规则并验证:

snort -c $my_path/etc/snort/snort.lua --stdin-rules < $my_path/etc/snort/sample.rules

为 Lua 配置启用警告并使警告致命:

snort -c $my_path/etc/snort/snort.lua --warn-all --pedantic

告诉 Snort 去哪里寻找额外的 Lua 脚本:

snort --script-path /path/to/script/dir

入侵检测模式

在 IDS 模式下运行 Snort,从 pcap 读取数据包:

snort -c $my_path/etc/snort/snort.lua -r /path/to/my.pcap

使用“-A”选项将任何生成的警报记录到控制台:

snort -c $my_path/etc/snort/snort.lua -r /path/to/my.pcap -A alert_full

捕获单独的 stdout、stderr 和 stdlog 文件(out 有启动和关闭输出,err 有警告和错误,log 有警报):

snort -c $my_path/etc/snort/snort.lua -r /path/to/my.pcap -A csv \
    1>out 2>err 3>log

使用“–lua”选项从命令行添加或修改配置:

snort -c $my_path/etc/snort/snort.lua -r /path/to/my.pcap -A cmg \
    --lua 'ips = { enable_builtin_rules = true }'
笔记可以多次指定“–lua”选项。

在整个 pcaps 目录上以 IDS 模式运行 Snort,在单独的线程上处理每个输入源:

snort -c $my_path/etc/snort/snort.lua --pcap-dir /path/to/pcap/dir \
    --pcap-filter '*.pcap' --max-packet-threads 8

在 eth0 和 eth1 两个接口上运行 Snort:

snort -c $my_path/etc/snort/snort.lua -i "eth0 eth1" -z 2 -A cmg

使用 afpacket DAQ 内联运行 Snort:

snort -c $my_path/etc/snort/snort.lua --daq afpacket -i "eth0:eth1" \
    -A cmg

插件

加载外部插件并使用“ex”警报:

snort -c $my_path/etc/snort/snort.lua \
    --plugin-path $my_path/lib/snort_extra \
    -A alert_ex -r /path/to/my.pcap

测试LuaJIT规则选项发现从标准输入加载:

snort -c $my_path/etc/snort/snort.lua \
    --script-path $my_path/lib/snort_extra \
    --stdin-rules -A cmg -r /path/to/my.pcap << END
alert tcp any any -> any 80 (
    sid:3; msg:"found"; content:"GET";
    find:"pat='HTTP/1%.%d'" ; )
END

输出文件

为了在使用多个数据包线程运行时配置输出变得简单,未显式配置输出文件。相反,您可以使用以下选项来格式化路径:

<logdir>/[<run_prefix>][<id#>][<X>]<name>

登录到统一在当前目录:

snort -c $my_path/etc/snort/snort.lua -r /path/to/my.pcap -A unified2

登录到统一在当前目录下使用不同的前缀:

snort -c $my_path/etc/snort/snort.lua -r /path/to/my.pcap -A unified2 \
    --run-prefix take2

登录统一在/tmp:

snort -c $my_path/etc/snort/snort.lua -r /path/to/my.pcap -A unified2 -l /tmp

运行 4 个数据包线程并使用线程号前缀 (0-3) 记录日志:

snort -c $my_path/etc/snort/snort.lua --pcap-dir /path/to/pcap/dir \
    --pcap-filter '*.pcap' -z 4 -A unified2

运行 4 个数据包线程并登录线程号子目录 (0-3):

snort -c $my_path/etc/snort/snort.lua --pcap-dir /path/to/pcap/dir \
    --pcap-filter '*.pcap' -z 4 -A unified2 --id-subdir
笔记如果需要,会自动创建子目录。日志文件名基于写入文件的模块名称。所有文本模式输出默认为标准输出。这些选项可以组合使用。

数据采集​​替代品

处理来自标准输入的十六进制数据包:

snort -c $my_path/etc/snort/snort.lua \
    --daq-dir $my_path/lib/snort/daqs --daq hext -i tty << END
$packet 10.1.2.3 48620 -> 10.9.8.7 80
"GET / HTTP/1.1\r\n"
"Host: localhost\r\n"
"\r\n"
END

从十六进制文件处理原始以太网:

snort -c $my_path/etc/snort/snort.lua \
    --daq-dir $my_path/lib/snort/daqs --daq hext \
    --daq-var dlt=1 -r <hext-file>

使用 8K 缓冲区的 4 个线程处理纯文件目录(即非 pcap):

snort -c $my_path/etc/snort/snort.lua \
    --daq-dir $my_path/lib/snort/daqs --daq file \
    --pcap-dir path/to/files -z 4 -s 8192

在端口 8000 上桥接两个 TCP 连接并检查流量:

snort -c $my_path/etc/snort/snort.lua \
    --daq-dir $my_path/lib/snort/daqs --daq socket

记录器替代品

以十六进制模式转储 TCP 流负载:

snort -c $my_path/etc/snort/snort.lua -L hext

输出时间戳、pkt_num、proto、pkt_gen、dgm_len、dir、src_ap、dst_ap、规则、每个警报的操作:

snort -c $my_path/etc/snort/snort.lua -A csv

输出旧的测试格式警报:

snort -c $my_path/etc/snort/snort.lua \
    --lua "alert_csv = { fields = 'pkt_num gid sid rev', separator = '\t' }"

贝壳

您必须使用 –enable-shell 进行构建以使命令行 shell 可用。

启用外壳模式:

snort --shell <args>

您将看到 shell 模式命令提示符,如下所示:

o")~

(可以使用 SNORT_PROMPT 环境变量更改提示。)

您可以在加载配置后立即暂停,并在退出之前再次暂停:

snort --shell --pause <args>

在这种情况下,您必须发出 resume() 命令才能继续。输入 quit() 终止 Snort 或 detach() 退出 shell。您可以使用 help() 列出可用命令。

要在端口 12345 上启用本地 telnet 访问:

snort --shell -j 12345 <args>

命令行界面仍在开发中。欢迎提出建议。

信号

笔记以下示例假定 Snort 当前正在运行并且进程 ID 为 <pid>。

修改和重新加载配置:

echo 'suppress = { { gid = 1, sid = 2215 } }' >> $my_path/etc/snort/snort.lua
kill -hup <pid>

将统计信息转储到标准输出:

kill -usr1 <pid>

正常关机:

kill -term <pid>

退出而不刷新数据包:

kill -quit <pid>

列出可用信号:

snort --help-signals
笔记可用信号可能因平台而异。

特征

本节说明如何使用 Snort 的主要功能。

主动响应

通过向关闭违规会话发送主动响应,Snort 可以在保护网络方面发挥更积极的作用。当启用主动响应时,snort 将在丢弃会话时发送 TCP RST 或 ICMP 不可达。

来自 Snort 2.9 的变化

  • stream5_global:max_active_responses 和 min_response_seconds 现在是 active.max_responses 和 active.min_interval。
  • 响应操作已从 IPS 规则正文中删除到标头中的规则操作。这包括反应、拒绝和重写(从替换中分离出来,现在只执行检测部分)。这些 IPS 操作是插件。
  • drop 和 block 在 Snort 2.9 中是同义词,但在 Snort 3.0 中 drop 意味着不只转发当前数据包,而 block 意味着不转发流中的这个或任何后续数据包。

配置活动

通过配置以下 IPS 操作插件之一来启用主动响应:

react = { }
reject = { }

当未配置这些主动响应时,将使用默认配置。

对于拒绝、反应或重写 IPS 规则操作,将执行主动响应,并且响应数据包基于触发数据包进行编码。TTL 将设置为会话拾取时捕获的值。

配置在会话的当前窗口内登陆 TCP RST 的尝试次数(以便它被接收 TCP 接受)。这个序列“扫射”实际上只在被动模式下有用。在内联模式下,重置直接放入流中,而不是触发数据包,因此不需要扫射。

每次尝试(快速连续发送)都有不同的序列号。每个主动响应实际上会导致发送此数量的 TCP 重置。TCP 数据乘法类似。最多发送 1 个 ICMP unreachable,如果尝试 > 0。

设备 IP 将执行网络层注入。指定接口并避免内核路由表等可能是更好的选择。

如果设备是eth0、eth1、eth2等,dst_mac将改变响应目标MAC地址。否则,响应目标MAC地址是从数据包中导出的。

例子:

active =
{
    attempts = 2,
    device = "eth0",
    dst_mac = "00:06:76:DD:5F:E3",
}

拒绝

IPS 操作拒绝执行主动响应以通过注入 TCP 重置(TCP 连接)或 ICMP 无法访问的数据包来关闭恶意网络会话。

例子:

reject = { reset = "both", control = "all" }
local_rules =
[[
reject tcp ( msg:"hostile connection"; flow:established, to_server;
content:"HACK!"; sid:1; )
]]
ips =
{
    rules = local_rules,
}

反应

IPS action react 允许在会话中发送 HTML 页面,然后重置它。

使用的标题是:

"HTTP/1.1 403 Forbidden\r\n" \
"Connection: close\r\n" \
"Content-Type: text/html; charset=utf-8\r\n" \
"Content-Length: 438\r\n" \
"\r\n"

要发送的页面可以从文件中读取:

react = { page = "customized_block_page.html", }

否则使用默认值:

"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"\r\n" \
"    \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\r\n" \
"<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\r\n" \
"<head>\r\n" \
"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\r\n" \
"<title>Access Denied</title>\r\n" \
"</head>\r\n" \
"<body>\r\n" \
"<h1>Access Denied</h1>\r\n" \
"<p>You are attempting to access a forbidden site.<br />" \
"Consult your system administrator for details.</p>\r\n" \
"</body>\r\n" \
"</html>\r\n"

请注意,该文件仅包含消息正文。标题将添加内容长度的更新值。对于 HTTP/2 流量,Snort 会将页面转换为 HTTP/2 格式。

HTTP/2 的限制:

  • 数据包将根据最后收到的流 ID 注入。
  • 不支持在服务器到客户端的流量处于帧中间时触发的注入。流量将被阻止,但不会注入/显示页面。

使用 react 时,还必须配置有效载荷注入器。此外,Snort 应该处于 ips 模式,因此规则是在客户端数据包上触发的,并且不会延迟到服务器发送 ACK。要实现这一点,请使用默认的归一化器。它将设置 normalizer.tcp.ips = true。例子:

react = { page = "my_block_page.html" }
payload_injector = { }
normalizer = { }
local_rules =
[[
react http ( msg:"Unauthorized Access Prohibited!"; flow:established,
to_server; http_method; content:"GET"; sid:1; )
]]
ips =
{
    rules = local_rules,
}

React 具有调试跟踪功能。它可用于在注入不成功的情况下获取跟踪信息。打开它:

trace =
{
    modules = { react = { all = 1 } }
}

改写

IPS 操作“rewrite”启用基于规则中的“replace”选项覆盖数据包内容。请注意,使用没有“替换”选项的“重写”操作将引发相应的规则警报,但不会覆盖数据包有效负载。

例如:

local_rules =
[[
rewrite tcp 10.1.1.87 any -> 10.1.1.0/24 80
(
    sid:1000002;
    msg:"test replace rule";
    content:"index.php", nocase;
    replace:"indax.php";
)
]]
ips =
{
    rules = local_rules,
}

此规则将第一次出现的“index.php”替换为“indax.php”,并且“rewrite”操作会更新该数据包。

内容和替换对齐到匹配内容的右侧,并且不受匹配内容大小的限制,而是受数据包边界的限制。

Example:
rewrite http any any -> any any
(
    msg:"Small replace";
    content:"content";
    replace:"text";
    sid:1000002;
)
this rule replaces "malicious content" to "malicious context".
Example:
rewrite http any any -> any any
(
    msg:"Big replace";
    content:"content";
    replace:"y favorite page!";
    sid:1000002;
)
this rule replaces "malicious content" to "my favorite page!".

请注意,匹配后应该有足够的空间用于匹配数据包中的“替换”内容。如果“替换”内容没有足够的空间,则规则将不匹配。

“替换”仅适用于原始数据包。因此,TCP 数据必须符合“pkt_data”缓冲区要求,或者在重组之前应启用对 TCP 有效负载的检测:search_engine.detect_raw_tcp=true。例如:

Rule that does not require search_engine.detect_raw_tcp=true:
rewrite udp any any -> any any
(
    msg:"TEST 1";
    sid:1000002;
    content:"attack";
    replace:"abc123";
)
Rule that does require search_engine.detect_raw_tcp=true:
rewrite http any any -> any any
(
    msg:"TEST 2";
    content:"/content.html";
    replace:"/replace.html";
    sid:1000002;
)

应用程序ID

网络管理员需要了解应用程序,以便微调他们对不​​断增长的通过网络传输流量的应用程序的管理。应用程序感知允许管理员根据业务需要为应用程序创建规则。规则可用于根据应用程序采取行动,例如阻止、允许或警报。

概述

AppId 检查器通过提供以下功能在管理网络时提供应用程序级别视图:

  • 网络控制:检查器通过向 Snort 规则编写者提供一组应用程序标识符 (AppId) 来处理 Snort 规则。
  • 应用程序使用意识:检查器输出统计数据以显示应用程序在网络上被使用的次数。
  • 自定义应用程序:管理员可以创建自己的应用程序检测器来检测新应用程序。检测器是用 Lua 编写的,并使用定义良好的 C-Lua API 与 Snort 接口。
  • Open Detector Package (ODP):Snort 团队提供了一组预定义的应用程序检测器,可以从 snort.org 下载。

依赖要求

为了 AppId 检查器的正常运行,必须至少启用流跟踪。此外,要识别基于 TCP 或 UDP 的应用程序,必须启用适当的流检查器,例如 stream_tcp 或 stream_udp。

为了识别基于 HTTP 的应用程序,必须启用 HTTP 检查器。否则,只会识别非 HTTP 应用程序。

AppId 订阅其他检查器(例如 HTTP 和 SSL 检查器)发布的检查事件,以访问所需数据。它使用该数据来帮助确定应用程序 ID。

AppId 订阅由 SIP 和 DCE/RPC 检查器发布的事件,以检测预期流上的应用程序。

配置

AppId 功能可以通过配置启用。要使用默认设置启用它,请使用:

appid = { }

要将 AppId 用作 IPS 规则中的匹配参数,请使用appids 关键字。例如,要阻止包含特定标头的 HTTP 流量:

block tcp any any -> 192.168.0.1 any ( msg:"Block Malicious HTTP header";
  appids:"HTTP"; content:"X-Header: malicious"; sid:18000; )

或者,可以指定 HTTP 应用程序代替tcp而不是使用appids关键字。AppId 检查器将在发现服务时设置它,以便它可以在像这样的 IPS 规则中使用。请注意,此规则也未指定默认为any的 IP 或端口。

block http ( msg:"Block Malicious HTTP header";
  content:"X-Header: malicious"; sid:18000; )

可以使用 appids 关键字指定多个应用程序(任意数量)。如果规则上的任何应用程序匹配,则该规则被视为匹配。请注意,此规则不匹配会降低性能的特定内容。

alert tcp any any -> 192.168.0.1 any ( msg:"Alert ";
  appids:"telnet,ssh,smtp,http";

以下是足以阻止基于特定 HTTP 标头的流的最小 Snort 配置:

stream = { }
stream_tcp = { }
binder =
{
    {
        when =
        {
            proto = 'tcp',
            ports = [[ 80 8080 ]],
        },
        use =
        {
            type = 'http_inspect',
        },
    },
}
http_inspect = { }
appid = { }
local_rules =
[[
block http ( msg:"openAppId: test content match for app http";
content:"X-Header: malicious"; sid:18760; rev:4; )
]]
ips =
{
    rules = local_rules,
}

会话应用程序标识符

会话中最多存储四个 AppId,定义如下:

  • serviceAppId – 与会话的服务器端关联的 appId。示例:http 服务器。
  • clientAppId – 与会话客户端上的应用程序关联的 appId。示例:火狐。
  • payloadAppId – 对于像 http 这样的服务,这个 appId 与网络服务器主机相关联。示例:脸书。
  • miscAppId – 对于某些封装的协议,这是最高封装的应用程序。

对于来自客户端的数据包,会话中的 payloadAppid 与规则中列出的所有 AppId 匹配。此后 miscAppId、clientAppId 和 serviceAppId 被匹配。由于警报事件包含一个 AppId,因此只报告第一个匹配项。如果没有 appids 选项的规则匹配,则报告最具体的 appId(按照有效负载、misc、客户端、服务器的顺序)。

除了一个例外,来自服务器的数据包遵循相同的逻辑。更改匹配顺序,使 serviceAppId 在 clientAppId 之前。

AppId 使用统计

AppId 检查器定期在 snort 日志目录中以统一 2 格式打印应用程序网络使用情况。文件名、统计时间间隔和文件翻转由 appId 检查配置控制。

打开检测器包 (ODP) 安装

Snort 团队的应用检测器将在一个名为开放检测器包 (ODP) 的单独包中提供,该包可从 snort.org 下载。ODP 是一个包含以下工件的包:

  • Lua 语言中的应用程序检测器。
  • appMapping.data 文件包含应用程序元数据。不应修改此文件。第一列包含应用程序标识符,第二列包含应用程序名称。其他列包含内部信息。
  • Lua 库文件DetectorCommon.lua。

用户可以在任何目录中安装 ODP 包,并通过 appid 预处理器配置中的 app_detector_dir 选项配置该目录。安装 ODP 不会修改任何名为 custom 的子目录,用户创建的检测器位于该子目录中。

安装后,ODP 将创建以下子目录:

  • odp/lua //Cisco Lua检测器
  • odp/libs //Cisco Lua模块

用户创建的应用程序检测器

用户可以通过添加 Lua 语言的检测器来检测新的应用程序。一份文档将发布在 Snort 网站上,其中包含有关 API 的详细信息。用户还可以复制 Snort 团队提供的检测器并修改它们。用户还可以使用下一节中描述的检测器创建工具。

用户必须通过在 ODP 安装目录下创建以下目录结构来组织他们的 Lua 检测器和库。

  • custom/lua //Lua 检测器
  • custom/libs //Lua 模块

根路径由 snort.conf 的 appid 部分的“app_detector_dir”参数指定:

appid  =
{
    app_detector_dir = '/usr/local/lib/openappid',
}

所以用户创建的 lua 文件的路径将是 /usr/local/lib/openappid/custom/lua/

不会为您添加 /usr/local/lib/openappid/ 下面的任何目录。

应用检测器重新加载

ODP 检测器和用户创建的检测器都可以使用命令 appid.reload_detectors() 重新加载。在发出此命令之前,应在路径 appid.app_detector_dir 中更新检测器。该命令不带任何参数。

应用检测器创建工具

对于基本的 Lua 检测器,提供了一个名为 appid_detector_builder.sh 的工具。这是一个简单的、菜单驱动的 bash 脚本,它根据您的选择和您提供的模式在您的当前目录中创建 .lua 文件。

当您启动脚本时,它会提示您为检测器提供的应用程序 ID。这是具有较小限制的自由格式 ASCII。Lua 检测器文件将根据您的应用程序 ID 命名。如果文件名已存在,系统将提示您覆盖它。

系统还会提示您将检测器的描述放置在 Lua 源代码的注释中。这是可选的。

然后你会被问到一系列问题,这些问题旨在根据模式数据、协议、端口等的类型构建 Lua 代码。

完成后,协议菜单将更改为包括选项“保存检测器”。无需保存文件并退出脚本,您可以为另一种模式提供附加条件,该模式也可能包含在检测方案中。然后,当匹配时,任一模式都将被视为有效检测。

例如,您的第一个选择可能会创建“example.com”的 HTTP 检测模式,下一组选择将添加“example.uk.co”(一个同样虚构的英国对应物)的 HTTP 检测模式。然后它们将共存于 Lua 检测器中,并且会导致使用您为应用程序 ID 指定的名称进行检测。

生成的 .lua 文件将需要放置在目录“custom/lua”中,在上面 README 的前一节中描述,称为“用户创建的应用程序检测器”

粘合剂

Snort 2 和 Snort 3 之间的根本区别之一涉及与​​网络和端口相关的配置。以下是对网络和服务相关组件的 Snort 2 配置的简要回顾:

  • Snort 的配置有一个默认策略和由 VLAN 或网络选择的可选策略(使用配置绑定)。
  • 每个策略包含一组用户定义的预处理器配置。
  • 每个预处理器都有一个默认配置,部分支持网络选择的非默认配置。
  • 大多数预处理器都有端口配置。
  • 默认策略还可能包含要忽略的端口列表。

在 Snort 3 中,上述配置是在称为 binder 的单个模块中完成的。下面是一个例子:

binder =
{
    -- allow all tcp port 22:
    -- (similar to Snort 2 config ignore_ports)
    { when = { proto = 'tcp', ports = '22' }, use = { action = 'allow' } },
-- select a config file by vlan
-- (similar to Snort 2 config binding by vlan)
{ when = { vlans = '1024' }, use = { file = 'vlan.lua' } },
-- use a non-default HTTP inspector for port 8080:
-- (similar to a Snort 2 targeted preprocessor config)
{ when = { nets = '192.168.0.0/16', proto = 'tcp', ports = '8080' },
  use = { name = 'alt_http', type = 'http_inspect' } },
-- use the default inspectors:
-- (similar to a Snort 2 default preprocessor config)
{ when = { proto = 'tcp' }, use = { type = 'stream_tcp' } },
{ when = { service = 'http' }, use = { type = 'http_inspect' } },
    -- figure out which inspector to run automatically:
    { use = { type = 'wizard' } }
}

绑定在会话开始时进行评估,如果在会话上识别出服务,则会再次评估绑定。本质上,绑定是从上到下评估的使用时规则列表。应用第一个匹配的网络和服务配置。binder.when 可以包含标准的任意组合,而 binder.use 可以指定操作、配置文件或检查器配置。

字节规则选项

字节测试

此规则选项针对特定值(使用运算符)测试字节字段。能够测试二进制值或将代表性字节字符串转换为其二进制等效项并对其进行测试。

Snort 对这些运算符中的每一个都使用 C 运算符。如果使用 & 运算符,则与使用相同

如果 (数据和值) {  do_something ();  }

运算符否定基本检查的结果。!<oper>被认为是

!(数据<操作>值)

注意:位掩码选项对转换的字节应用按位 AND 运算符。结果将右移与掩码中尾随零数相等的位数。这也适用于其他规则选项。

例子
alert tcp (byte_test:2, =, 568, 0, bitmask 0x3FF0;)

此示例在偏移量 0 处提取 2 个字节,按位执行并使用位掩码 0x3FF0,将结果移动 4 位并与 568 进行比较。

alert udp (byte_test:4, =, 1234, 0, string, dec;
    msg:"got 1234!";)
alert udp (byte_test:8, =, 0xdeadbeef, 0, string, hex;
    msg:"got DEADBEEF!";)

字节跳转

byte_jump 规则选项允许为长度编码的协议编写规则。通过选择读取部分数据的长度,然后在数据包中向前跳过,可以编写规则,跳过长度编码协议的特定部分并在非常特定的位置执行检测。

例子
alert tcp (content:"Begin";
    byte_jump:0, 0, from_end, post_offset -6;
    content:"end..", distance 0, within 5;
    msg:"Content match from end of the payload";)
alert tcp (content:"catalog";
    byte_jump:2, 1, relative, post_offset 2, bitmask 0x03f0;
    byte_test:2, =, 968, 0, relative;
    msg:"Bitmask applied on the 2 bytes extracted for byte_jump";)

字节提取

byte_extract 关键字是针对长度编码协议编写规则的另一个有用选项。它从数据包有效载荷中读取一定数量的字节并将其保存到一个变量中。这些变量可以在规则的后面引用,而不是使用硬编码值。

使用 byte_extract 变量的其他选项

byte_extract 规则选项本身没有检测到任何内容。它的用途是提取用于其他规则选项的数据包数据。

以下是可以使用 byte_extract 变量的位置列表:

  • 内容/uricontent:偏移量、深度、距离、范围内
  • byte_test:偏移量,值
  • byte_jump:偏移量,post_offset
  • isdataat:偏移量
例子
alert tcp (byte_extract:1, 0, str_offset;
    byte_extract:1, 1, str_depth;
    content:"bad stuff", offset str_offset, depth str_depth;
    msg:"Bad Stuff detected within field";)
alert tcp (content:"START"; byte_extract:1, 0, myvar, relative;
    byte_jump:1, 3, relative, post_offset myvar;
    content:"END", distance 6, within 3;
    msg: "byte_jump - pass variable to post_offset";)

此示例使用两个变量。

第一个变量保持字符串的偏移量,从偏移量 0 处的字节读取。第二个变量保持字符串的深度,从偏移量 1 处的字节读取。这些值用于将模式匹配限制在较小的区域。

alert tcp (content:"|04 63 34 35|", offset 4, depth 4;
    byte_extract: 2, 0, var_match, relative, bitmask 0x03ff;
    byte_test: 2, =, var_match, 2, relative;
    msg:"Test value match, after applying bitmask on bytes extracted";)

字节数学

对提取的值和指定的值或现有变量执行数学运算,并将结果存储在新的结果变量中。这些结果变量可以在规则的后面引用,与 byte_extract 变量位于相同的位置。

此规则选项的语法不同。选项的顺序对于其他规则选项至关重要,不能更改。例如,第一个选项是要提取的字节数。此处明确写入了选项的名称,例如:字节 2。顺序并不重要。

笔记Byte_math 操作在无符号 32 位值上执行。在编写规则时,应考虑避免回绕。
例子
alert tcp ( byte_math: bytes 2, offset 0, oper *, rvalue 10, result area;
   byte_test:2,>,area,16;)

在负载的零偏移处,提取 2 个字节并应用值为 10 的乘法运算。将结果存储在变量区中。area 变量作为 byte_test 值选项的输入。

让我们考虑提取的数据的 2 个字节是 5。右值是 10。结果变量区域是 50 ( 5 * 10 )。区域变量可用于 byte_test 偏移/值选项。

测试数值

编写了规则选项 byte_test 和 byte_jump 以支持具有长度编码数据的协议的编写规则。RPC 是产生这两个规则选项要求的协议,因为 RPC 使用基于简单长度的编码来传递数据。

为了理解为什么字节测试和字节跳转很有用,让我们通过一个针对 sadmind 服务的漏洞利用尝试。

这是漏洞利用的有效载荷:

89 09 9c e2 00 00 00 00 00 00 00 02 00 01 87 88  ................
00 00 00 0a 00 00 00 01 00 00 00 01 00 00 00 20  ...............
40 28 3a 10 00 00 00 0a 4d 45 54 41 53 50 4c 4f  @(:.....metasplo
49 54 00 00 00 00 00 00 00 00 00 00 00 00 00 00  it..............
00 00 00 00 00 00 00 00 40 28 3a 14 00 07 45 df  ........@(:...e.
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00 00 00 00 00 00 00 06 00 00 00 00 00 00 00 00  ................
00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 04  ................
7f 00 00 01 00 01 87 88 00 00 00 0a 00 00 00 04  ................
7f 00 00 01 00 01 87 88 00 00 00 0a 00 00 00 11  ................
00 00 00 1e 00 00 00 00 00 00 00 00 00 00 00 00  ................
00 00 00 00 00 00 00 3b 4d 45 54 41 53 50 4c 4f  .......;metasplo
49 54 00 00 00 00 00 00 00 00 00 00 00 00 00 00  it..............
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00 00 00 00 00 00 00 06 73 79 73 74 65 6d 00 00  ........system..
00 00 00 15 2e 2e 2f 2e 2e 2f 2e 2e 2f 2e 2e 2f  ....../../../../
2e 2e 2f 62 69 6e 2f 73 68 00 00 00 00 00 04 1e  ../bin/sh.......

让我们分解一下,描述每个字段,并弄清楚如何编写规则来捕获这个漏洞。

使用 RPC 有几点需要注意:

数字被写成 uint32s,占用四个字节。数字 26 将显示为 0x0000001a。

字符串被写成一个 uint32,指定字符串的长度,字符串,然后是空字节来填充字符串的长度以在 4 字节边界处结束。字符串bob将显示为 0x00000003626f6200。

89 09 9c e2     - the request id, a random uint32, unique to each request
00 00 00 00     - rpc type (call = 0, response = 1)
00 00 00 02     - rpc version (2)
00 01 87 88     - rpc program (0x00018788 = 100232 = sadmind)
00 00 00 0a     - rpc program version (0x0000000a = 10)
00 00 00 01     - rpc procedure (0x00000001 = 1)
00 00 00 01     - credential flavor (1 = auth_unix)
00 00 00 20     - length of auth_unix data (0x20 = 32)
## the next 32 bytes are the auth_unix data
40 28 3a 10 - unix timestamp (0x40283a10 = 1076378128 = feb 10 01:55:28 2004 gmt)
00 00 00 0a - length of the client machine name (0x0a = 10)
4d 45 54 41 53 50 4c 4f 49 54 00 00  - metasploit
00 00 00 00 - uid of requesting user (0)
00 00 00 00 - gid of requesting user (0)
00 00 00 00 - extra group ids (0)
00 00 00 00 - verifier flavor (0 = auth_null, aka none)
00 00 00 00 - length of verifier (0, aka none)

数据包的其余部分是传递到 sadmind 的过程 1 的请求。

但是,我们知道漏洞在于 sadmind 信任来自客户端的 uid。sadmind 以 root 身份运行客户端 uid 为 0 的任何请求。因此,我们已经解码了足够多的请求来编写我们的规则。

首先,我们需要确保我们的数据包是一个 RPC 调用。

content:"|00 00 00 00|", offset 4, depth 4;

然后,我们需要确保我们的数据包是对 sadmind 的调用。

content:"|00 01 87 88|", offset 12, depth 4;

然后,我们需要确保我们的数据包是对程序 1(易受攻击的程序)的调用。

content:"|00 00 00 01|", offset 20, depth 4;

然后,我们需要确保我们的数据包具有 auth_unix 凭据。

content:"|00 00 00 01|", offset 24, depth 4;

我们不关心主机名,但我们想跳过它并检查主机名后面的数字值。这就是 byte_test 有用的地方。从主机名的长度开始,我们拥有的数据是:

00 00 00 0a 4d 45 54 41 53 50 4c 4f 49 54 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00

我们想要读取 4 个字节,将其转换为一个数字,然后向前跳转那么多字节,确保考虑到 RPC 需要对字符串进行填充。如果我们这样做,我们现在处于:

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00

这恰好是 uid 的确切位置,即我们要检查的值。

在英文中,我们要从数据包的开头读取 4 个字节,36 个字节,并将这 4 个字节转换为整数并向前跳转那么多字节,对齐在 4 字节边界上。为了在 Snort 规则中做到这一点,我们使用:

byte_jump:4,36,align;

那么我们要寻找 0 的 uid。

content:"|00 00 00 00|", within 4;

既然我们拥有规则的所有检测功能,让我们将它们放在一起。

content:"|00 00 00 00|", offset 4, depth 4;
content:"|00 01 87 88|", offset 12, depth 4;
content:"|00 00 00 01|", offset 20, depth 4;
content:"|00 00 00 01|", offset 24, depth 4;
byte_jump:4,36,align;
content:"|00 00 00 00|", within 4;

第三个和第四个字符串匹配彼此相邻,所以我们应该组合这些模式。我们最终得到:

content:"|00 00 00 00|", offset 4, depth 4;
content:"|00 01 87 88|", offset 12, depth 4;
content:"|00 00 00 01 00 00 00 01|", offset 20, depth 8;
byte_jump:4,36,align;
content:"|00 00 00 00|", within 4;

如果 sadmind 服务在读取客户端的主机名时容易受到缓冲区溢出的影响,我们将检查主机名的长度以确保它不会太大,而不是读取主机名的长度并向前跳转那么多字节。

为此,我们将读取 4 个字节,从 36 个字节开始进入数据包,将其转换为一个数字,然后确保它不会太大(假设大于 200 个字节)。在 Snort 中,我们这样做:

byte_test:4,>,200,36;

我们的完整规则是:

content:"|00 00 00 00|", offset 4, depth 4;
content:"|00 01 87 88|", offset 12, depth 4;
content:"|00 00 00 01 00 00 00 01|", offset 20, depth 8;
byte_test:4,>,200,36;

整合配置

配置转储模式生成传递给 Snort 的配置的综合转储。此输出包含配置值以及未配置值的模块默认值。

在转储模式下,Snort 验证配置(类似于选项 -T)并禁止发送到 stdout 的无关消息(配置警告和错误仍会打印到 stderr)。

转储模式由以下选项激活:–dump-config-text、–dump-config=all、–dump-config=top。它们将在下面详细描述。

示例中使用了简单的配置。输出包含应用的配置(默认和配置)。为了简化输出,我们显示了默认选项的简要列表。

snort.lua

stream =
{
    max_flows = 2
}
stream_tcp =
{
    show_rebuilt_packets = true
}
binder =
{
    { when = { nets = '10.1.2.0/24' }, use = { inspection_policy = 'http.lua' } },
    { when = { nets = '192.168.2.0/24' }, use = { inspection_policy = 'sip.lua' } },
}

http.lua

wizard =
{
    spells =
    {
        { service = 'http', proto = 'tcp', client_first = true, to_server = { 'GET' }, to_client = { 'HTTP/' } },
    }
}

lua文件

wizard =
{
    spells =
    {
        { service = 'sip', to_server = { 'INVITE' } },
    }
}

文本格式

–dump-config-text 选项验证配置并将其以文本格式转储到标准输出。输出包含主策略和所有其他包含的子策略的配置。

示例:snort -c snort.lua –dump-config-text

consolidated config for snort.lua
alerts.order="pass reset block drop alert log"
alerts.rate_filter_memcap=1048576
binder[0].when.ips_policy_id=0
binder[0].when.role="any"
binder[0].when.nets="10.1.2.0/24"
binder[0].use.action="inspect"
binder[0].use.inspection_policy="http.lua"
binder[1].when.ips_policy_id=0
binder[1].when.role="any"
binder[1].when.nets="192.168.2.0/24"
binder[1].use.action="inspect"
binder[1].use.inspection_policy="sip.lua"
output.obfuscate=false
output.wide_hex_dump=true
packets.address_space_agnostic=false
packets.limit=0
search_engine.split_any_any=true
search_engine.queue_limit=128
stream.file_cache.idle_timeout=180
stream.file_cache.cap_weight=32
stream.max_flows=2
stream_tcp.small_segments.maximum_size=0
stream_tcp.session_timeout=30
stream_tcp.track_only=false
stream_tcp.show_rebuilt_packets=true
consolidated config for http.lua
wizard.spells[0].proto="tcp"
wizard.spells[0].client_first=true
wizard.spells[0].service="http"
wizard.spells[0].to_client[0].spell="HTTP/"
wizard.spells[0].to_server[0].spell="GET"
consolidated config for sip.lua
wizard.spells[0].proto="tcp"
wizard.spells[0].client_first=true
wizard.spells[0].service="sip"
wizard.spells[0].to_server[0].spell="INVITE"

对于列表,选项名称旁边的索引指定元素解析顺序。

JSON 格式

–dump-config=all 命令行选项验证配置并将其以 JSON 格式转储到标准输出。输出包含主策略和所有其他包含的子策略的配置。Snort 以单行格式转储输出。

有 3rd 方工具jq用于转换为漂亮的打印格式。

示例:snort -c snort.lua –dump-config=all | JQ 

[
    {
        "filename": "snort.lua",
        "config": {
        "alerts": {
            "order": "pass reset block drop alert log",
            "rate_filter_memcap": 1048576
        },
        "binder": [
            {
            "when": {
                "ips_policy_id": 0,
                "role": "any",
                "nets": "10.1.2.0/24"
            },
            "use": {
                "action": "inspect",
                "inspection_policy": "http.lua"
            }
            },
            {
            "when": {
                "ips_policy_id": 0,
                "role": "any",
                "nets": "192.168.2.0/24"
            },
            "use": {
                "action": "inspect",
                "inspection_policy": "sip.lua"
            }
            }
        ],
        "output": {
            "obfuscate": false,
            "wide_hex_dump": true
        },
        "packets": {
            "address_space_agnostic": false,
            "limit": 0
        },
        "process": {
            "daemon": false,
            "dirty_pig": false,
            "utc": false
        },
        "search_engine": {
            "split_any_any": true,
            "queue_limit": 128
        },
        "stream": {
            "file_cache": {
            "idle_timeout": 180,
            "cap_weight": 32
            },
            "max_flows": 2
        },
        "stream_tcp": {
            "small_segments": {
                "maximum_size": 0
            },
            "session_timeout": 30,
            "track_only": false,
            "show_rebuilt_packets": true
        }
        }
    },
    {
        "filename": "http.lua",
        "config": {
        "wizard": {
            "spells": [
            {
                "proto": "tcp",
                "client_first": true,
                "service": "http",
                "to_client": [
                {
                    "spell": "HTTP/"
                }
                ],
                "to_server": [
                {
                    "spell": "GET"
                }
                ]
            }
            ]
        }
        }
    },
    {
        "filename": "sip.lua",
        "config": {
        "wizard": {
            "spells": [
            {
                "proto": "tcp",
                "client_first": true,
                "service": "sip",
                "to_server": [
                {
                    "spell": "INVITE"
                }
                ]
            }
            ]
        }
        }
    }
]

–dump-config=top 命令行选项与 –dump-config=all 类似,不同之处在于它仅为主策略生成转储。它验证配置并将主要策略配置以 JSON 格式转储到标准输出。

示例:snort -c snort.lua –dump-config=top | JQ 

{
    "alerts": {
        "order": "pass reset block drop alert log",
        "rate_filter_memcap": 1048576,
    },
    "binder": [
        {
            "when": {
                "ips_policy_id": 0,
                "role": "any",
                "nets": "10.1.2.0/24"
            },
            "use": {
                "action": "inspect",
                "inspection_policy": "http.lua"
            }
        },
        {
            "when": {
                "ips_policy_id": 0,
                "role": "any",
                "nets": "192.168.2.0/24"
            },
            "use": {
                "action": "inspect",
                "inspection_policy": "sip.lua"
            }
        }
    ],
    "output": {
        "obfuscate": false,
        "wide_hex_dump": true
    },
    "packets": {
        "address_space_agnostic": false,
        "limit": 0,
    },
    "process": {
        "daemon": false,
        "dirty_pig": false,
        "utc": false
    },
    "search_engine": {
        "split_any_any": true,
        "queue_limit": 128
    },
    "stream": {
        "file_cache": {
            "idle_timeout": 180,
            "cap_weight": 32
        }
        "max_flows": 2
    },
    "stream_tcp": {
        "small_segments": {
            "count": 0,
            "maximum_size": 0
        },
        "session_timeout": 30,
        "track_only": false,
        "show_rebuilt_packets": true
    },
}

大商所检查员

这些检查器的主要目的是执行 SMB 去分段和 DCE/RPC 碎片整理,以避免使用这些技术规避规则。

概述

DCE/RPC 支持以下传输:SMB、TCP 和 UDP。已实施新规则选项以提高性能、减少误报并减少基于 DCE/RPC 的规则的数量和复杂性。

与 Snort 2 不同,DCE-RPC 预处理器分为三个检查器 – 每个传输一个:dce_smb、dce_tcp、dce_udp。这包括配置以及检查器模块。Snort 2 服务器配置现在在检查器之间拆分。对所有检查器都有意义的选项,例如策略和碎片整理,被复制到每个检查器配置中。地址/端口映射由绑定器处理。自动检测功能被向导诅咒取代。

快速指南

典型的 dcerpce 配置如下所示:

binder =
{
   {
       when =
       {
           proto = 'tcp',
           ports = '139 445 1025',
        },
       use =
       {
           type = 'dce_smb',
       },
    },
    {
       when =
       {
           proto = 'tcp',
           ports = '135 2103',
       },
       use =
       {
           type = 'dce_tcp',
       },
    },
    {
       when =
       {
           proto = 'udp',
           ports = '1030',
       },
       use =
       {
           type = 'dce_udp',
       },
    }
 }
dce_smb = { }
dce_tcp = { }
dce_udp = { }

在这个例子中,它定义了基于端口的 smb、tcp 和 udp 检查器。所有的配置都是默认的。

基于目标

Windows 和 Samba 版本之间存在足够重要的差异,因此已经实现了基于目标的方法。一些重要的区别:

  • 命名管道实例跟踪
  • 接受的 SMB 命令
  • AndX 命令链
  • 交易追踪
  • 多个绑定请求
  • DCE/RPC 分段请求 – 上下文 ID
  • DCE/RPC 分段请求 – 操作编号
  • DCE/RPC 存根数据字节顺序

由于这些差异,每个检查器都可以配置为不同的策略。以下是支持的策略列表:

  • WinXP(默认)
  • 赢2000
  • WinVista
  • 赢2003
  • 赢2008
  • Win7
  • 桑巴舞
  • Samba-3.0.37
  • Samba-3.0.22
  • Samba-3.0.20

重新组装

SMB 检查器和 TCP 检查器都支持重新组装。重组阈值指定在创建重组数据包以发送到检测引擎之前 DCE/RPC 去分段和碎片整理缓冲区中的最小字节数。此选项在内联模式下很有用,以便在完成完整碎片整理之前尽早捕获漏洞。作为此选项的参数提供的 0 值实际上将禁用此选项。默认为禁用。

中小企业

SMB 检查器是最复杂的检查器之一。除了支持规则选项和大量检查器规则事件外,它还支持 SMB 版本 1、2 和 3 的文件处理。

指纹政策

在 SMB 会话的初始阶段,客户端需要使用 SessionSetupAndX 进行身份验证。对该命令的请求和响应都包含操作系统和版本信息,允许检查器动态设置会话的策略,从而更好地防止 Windows 和 Samba 特定的规避。

档案检查

SMB 检查器支持文件检查。典型的配置如下所示:

binder =
{
   {
       when =
       {
           proto = 'tcp',
           ports = '139 445',
       },
       use =
       {
           type = 'dce_smb',
       },
   },
}
dce_smb =
{
    smb_file_inspection = 'on',
    smb_file_depth = 0,
 }
file_id =
{
    enable_type = true,
    enable_signature = true,
    enable_capture = true,
    file_rules = magics,
}

首先,定义一个 binder 将 tcp 端口 139 和 445 映射到 smb。然后,在 smb 检查中启用文件检查并将文件深度设置为无限制。最后,启用文件检查器来检查文件类型、计算文件签名和捕获文件。文件检查器的详细信息在文件处理部分进行了说明。

SMB 检查器对正常的 SMB 文件传输进行检查。这包括通过文件处理进行文件类型和签名以及为“file_data”规则选项设置指针。请注意,“file_depth”选项仅适用于将为“file_data”规则选项设置指针的最大文件数据量。对于文件类型和签名,它将使用为文件 API 配置的值。如果指定“only”,则检查器将只进行 SMB 文件检查,即不会进行任何 DCE/RPC 跟踪或检查。如果不带参数指定“on”,则默认文件深度为 16384 字节。“file-depth”的参数 -1 将禁用设置“file_data”的指针,从而有效地禁用规则中的 SMB 文件检查。“file_depth”参数为 0 表示无限制。默认为“关闭”,即在检查器中不进行 SMB 文件检查。

TCP

dce_tcp 检查器支持碎片整理、重组和类似于 SMB 的策略。

数据传输协议

dce_udp 是一个非常简单的检查器,只支持碎片整理

规则选项

启用 dcerpc2 检查器支持新的规则选项:

  • dce_iface
  • dce_opnum
  • dce_stub_data

现有 byte_test 和 byte_jump 规则选项的新修饰符:

  • 字节测试:dce
  • byte_jump:dce
dce_iface

对于基于 DCE/RPC 的规则,有必要根据客户端绑定到服务来设置流位以避免误报。客户端必须先绑定到服务,然后才能调用它。但是,当客户端向服务器发送绑定请求时,它可以指定一个或多个要绑定到的服务接口。每个接口都由一个 UUID 表示。每个接口 UUID 都与一个唯一索引(或上下文 id)配对,未来的请求可以使用该索引来引用客户端正在调用的服务。服务器将使用它接受为有效的接口 UUID 进行响应,并允许客户端向这些服务发出请求。当客户端发出请求时,它将指定上下文 ID,以便服务器知道客户端正在向哪个服务发出请求。规则可以简单地询问检查员,而不是使用流位,使用此规则选项,客户端是否已绑定到特定接口 UUID 以及此客户端请求是否正在向它发出请求。这可以消除成功绑定多个服务的误报,因为检查器可以将绑定 UUID 与请求中使用的上下文 ID 相关联。DCE/RPC 请求可以指定数字是表示为大端还是小端。接口 UUID 的表示根据 DCE/RPC 中指定的字节顺序而不同,以前需要两条规则 – 一个用于大端,一个用于小端。检查器通过规范化 UUID 消除了对两个规则的需要。一个接口包含一个版本。某些版本的接口可能不容易受到某种攻击。此外,一个 DCE/RPC 请求可以分解为 1 个或多个片段。在 DCE/RPC 报头中设置标志(和无连接报头中的字段)以指示该片段是第一个、中间的还是最后一个片段。DCE/RPC 请求中的许多数据检查仅在 DCE/RPC 请求是第一个片段(或完整请求)时才相关,因为后续片段将包含更深入 DCE/RPC 请求的数据。正在寻找数据的规则,比如请求中的 5 个字节(可能是一个长度字段),将查看除第一个片段以外的片段上的错误数据,因为后续片段的开头已经偏移了一些长度请求的开始。这可能是碎片化 DCE/RPC 流量中误报的来源。默认情况下,仅评估请求是否为第一个片段(或完整请求)是合理的。但是,如果“any_frag”

例子:

dce_iface: 4b324fc8-1670-01d3-1278-5a47bf6ee188;
dce_iface: 4b324fc8-1670-01d3-1278-5a47bf6ee188,<2;
dce_iface: 4b324fc8-1670-01d3-1278-5a47bf6ee188,any_frag;
dce_iface: 4b324fc8-1670-01d3-1278-5a47bf6ee188,=1,any_frag;

此选项用于指定接口 UUID。可选参数是接口版本和运算符,用于指定版本小于 ( < )、大于 ( > )、等于 ( = ) 或不等于 ( !) 指定的版本。此外,默认情况下,规则将仅针对第一个片段(或完整请求,即不是片段)进行评估,因为大多数规则都是在请求开始时编写的。”any_frag” 参数表示也要评估中间和最后的片段。此选项需要在检查器中跟踪客户端绑定和更改上下文请求以及服务器绑定确认和更改上下文响应以用于面向连接的 DCE/RPC。对于每个绑定和更改上下文请求,客户端指定一个接口 UUID 列表以及每个接口 UUID 的句柄(或上下文 id),这些接口 UUID 将在 DCE/RPC 会话期间用于引用该接口。服务器响应指示它将允许客户端向哪些接口发出请求 – 它接受或拒绝客户端希望绑定到某个接口的愿望。这种跟踪是必需的,以便在处理请求时,可以将请求中使用的上下文 ID 与其作为句柄的接口 UUID 相关联。

hexlong 和 hexshort 将被指定并解释为大端顺序(这通常是界面 UUID 被查看和表示的默认方式)。例如,以下 Messenger 接口 UUID 从一个 little endian Bind 请求中移除:

|f8 91 7b 5a 00 ff d0 11 a9 b2 00 c0 4f b6 e6 fc|

必须写成:

5a7b91f8-ff00-11d0-a9b2-00c04fb6e6fc

相同的 UUID 从大端绑定请求中断开:

|5a 7b 91 f8 ff 00 11 d0 a9 b2 00 c0 4f b6 e6 fc|

必须以相同的方式编写:

5a7b91f8-ff00-11d0-a9b2-00c04fb6e6fc

如果指定的接口 UUID 与 DCE/RPC 请求的接口 UUID(由上下文 id 引用)匹配,则此选项匹配,如果提供,则版本操作为真。如果片段不是第一个片段(或完整请求),则此选项将不匹配,除非提供了“any_frag”选项,在这种情况下,只有接口 UUID 和版本需要匹配。请注意,碎片整理的 DCE/RPC 请求将被视为完整请求。

使用此规则选项将自动将快速模式内容插入到快速模式匹配器中。对于 UDP 规则,大端和小端格式的接口 UUID 将被插入到快速模式匹配器中。对于 TCP 规则,(1) 如果使用规则选项“flow:to_server|from_client”,|05 00 00| 将被插入到快速模式匹配器中,(2) 如果使用规则选项 “flow:from_server|to_client”,|05 00 02| 将被插入到快速模式匹配器中,并且 (3) 如果流未知,|05 00| 将被插入到快速模式匹配器中。请注意,如果规则中已有内容规则选项,则将使用最佳(即最长)模式。如果规则中的内容使用了 fast_pattern 规则选项,它将明确地用于上述模式。

dce_opnum

opnum 代表对接口的特定函数调用。在确定客户端已绑定到特定接口并向其发出请求(见上文 – dce_iface)后,通常我们想知道它正在对该服务进行什么函数调用。漏洞很可能存在于特定的 DCE/RPC 函数调用中。

例子:

dce_opnum: 15;
dce_opnum: 15-18;
dce_opnum: 15,18-20;
dce_opnum: 15,17,20-22;

此选项用于指定 opnum(或操作编号)、opnum 范围或包含 opnum 和/或 opnum-range 之一或两者的列表。DCE/RPC 请求的 opnum 将与此选项指定的 opnum 匹配。如果任何指定的 opnums 与 DCE/RPC 请求的 opnum 匹配,则此选项匹配。

dce_stub_data

由于大多数基于 DCE/RPC 的规则必须进行协议解码才能获得 DCE/RPC 存根数据,即远程过程调用或函数调用数据,此选项将减轻这种需要并将光标置于 DCE/ RPC 存根数据。这减少了规则选项检查的次数和规则的复杂性。

此选项不带参数。

例子:

dce_stub_data;

此选项用于将光标(用于在规则处理中遍历数据包有效负载)放置在 DCE/RPC 存根数据的开头,而不管前面的规则选项如何。此选项没有参数。如果存在 DCE/RPC 存根数据,则此选项匹配。

光标移动到存根数据的开头。所有随后的规则选项都将被视为对该缓冲区的“粘性”。如果 dce_stub_data 之后的第一个规则选项与位置相关,则应使用绝对位置修饰符。如果后续规则选项旨在与存根数据缓冲区中的先前规则选项匹配项相关,则它们应使用相对修饰符。任何未指定相对修饰符的规则选项都将从存根数据缓冲区的开始进行评估。要离开存根数据缓冲区并返回主有效负载缓冲区,请使用“pkt_data”规则选项。

byte_test 和 byte_jump

DCE/RPC 请求可以指定数字是以大端还是小端表示。这些规则选项将作为一个新参数“dce”,并且与正常的 byte_test/byte_jump 基本相同,但由于 DCE/RPC 检查器将知道请求的字节序,因此它能够进行正确的转换。

例子:

byte_test: 4,>,35000,0,relative,dce;
byte_test: 2,!=,2280,-10,relative,dce;

当对 byte_test 使用“dce”参数时,不允许使用以下正常的 byte_test 参数:“big”、“little”、“string”、“hex”、“dec”和“oct”。

例子:

byte_jump:4,-4,relative,align,multiplier 2,post_offset -4,dce;

将 dce 参数用于 byte_jump 时,不允许使用以下正常的 byte_jump 参数:“big”、“little”、“string”、“hex”、“dec”、“oct”和“from_beginning”

文件处理

随着通过网络传输的恶意软件数量不断增加,网络文件检查变得越来越重要。此功能将提供文件类型识别、文件签名创建和文件捕获功能,以帮助用户应对这些挑战。

概述

文件服务有两个部分:文件 API 和文件策略。文件 API 提供所有文件检查功能,例如文件类型识别、文件签名计算和文件捕获。文件策略为用户提供控制文件服务的能力,例如启用/禁用/配置文件类型识别、文件签名或文件捕获。

除了 Snort 2 的所有功能外,我们还支持自定义文件策略和文件事件日志。

  • 支持的协议:HTTP、SMTP、IMAP、POP3、FTP 和 SMB。
  • 支持的文件签名计算:SHA256

快速指南

lua/snort.lua 文件中包含了一个非常简单的配置。典型的文件配置如下所示:

dofile('magic.lua')
my_file_policy =
{
    {  when = { file_type_id = 0 }, use = { verdict = 'log', enable_file_signature = true, enable_file_capture = true } }
    {  when = { file_type_id = 22 }, use = { verdict = 'log', enable_file_signature = true } },
    {  when = { sha256 = "F74DC976BC8387E7D4FC0716A069017A0C7ED13F309A523CC41A8739CCB7D4B6" }, use = { verdict = 'block'} },
}
file_id =
{
    enable_type = true,
    enable_signature = true,
    enable_capture = true,
    file_rules = magics,
    trace_type = true,
    trace_signature = true,
    trace_stream = true,
    file_policy = my_file_policy,
 }
file_log =
{
    log_pkt_time = true,
    log_sys_time = false,
}

启用文件处理有 3 个步骤:

  • 首先,您需要包含文件魔术规则。
  • 然后,定义文件策略并配置检查器
  • 最后启用file_log 获取文件事件的详细信息

预打包文件魔术规则

Snort 打包了一组文件魔术规则。它们可以位于“lua/file_magic.lua”。要使用此功能,建议使用这些预先打包的规则;这样做需要您在 Snort 配置中包含该文件(已经在 snort.lua 中):

dofile('magic.lua')

例子:

{ type = "GIF", id = 62, category = "Graphics", rev = 1,
  magic = { { content = "| 47 49 46 38 37 61 |",offset = 0 } } },
{ type = "GIF", id = 63, category = "Graphics", rev = 1,
  magic = { { content = "| 47 49 46 38 39 61 |",offset = 0 } } },

前两条规则定义了 GIF 格式,因为两个文件魔法不同。文件魔术由内容和偏移量指定,它们查看特定文件偏移量处的内容以识别文件类型。在这种情况下,有两个魔术会查看文件的开头。如果可打印,则可以使用字符或“|”之间的十六进制值。

文件策略

您可以通过配置 file_id 来启用文件类型、文件签名或文件捕获。此外,您可以启用跟踪以查看文件流数据、文件类型和文件签名信息。

最重要的是,您可以配置一个文件策略,该策略可以基于 SHA 阻止/警告某些文件类型或单个文件。这允许您构建文件黑名单或白名单。

例子:

file_policy =
{
    {  when = { file_type_id = 22 }, use = { verdict = 'log', enable_file_signature = true } },
    {  when = { sha256 = "F74DC976BC8387E7D4FC0716A069017A0C7ED13F309A523CC41A8739CCB7D4B6" }, use = { verdict = 'block'} },
    {  when = { file_type_id = 0 }, use = { verdict = 'log', enable_file_signature = true, enable_file_capture = true } }
}

在此示例中,它启用此策略:

  • 对于 PDF 文件,它们将被记录签名。
  • 对于匹配这个SHA的文件,它会被阻止
  • 对于识别出的所有文件类型,它们将通过签名进行记录,并捕获到日志文件夹中。

文件捕获

文件可以被捕获并存储到日志文件夹。我们使用 SHA 作为文件名而不是实际文件名以避免冲突。您可以捕获所有文件、某些文件类型或基于 SHA 的特定文件。

您可以通过此配置启用文件捕获:

enable_capture = true,

或为文件策略中的某些文件或文件类型启用它:

{  when = { file_type_id = 22 }, use = { verdict = 'log', enable_file_capture = true } },

上述规则将启用 PDF 文件捕获。

文件事件

文件检查预处理器还可用作文件事件的动态输出插件。它记录有关文件的基本信息。该日志文件与名称以“file.log”开头的其他日志文件位于同一文件夹中。

例子:

file_log = { log_pkt_time = true, log_sys_time = false }

所有文件事件都将记录在数据包时间中,系统时间不会被记录。

文件事件示例:

08/14-19:14:19.100891  10.22.75.72:33734 -> 10.22.75.36:80,
[Name: "malware.exe"] [Verdict: Block] [Type: MSEXE]
[SHA: 6F26E721FDB1AAFD29B41BCF90196DEE3A5412550615A856DAE8E3634BCE9F7A]
[Size: 1039328]

高可用性

高可用性包括 HA 流同步和 SideChannel 消息传递子系统。

HighAvailability(或 HA)是一个 Snort 模块,它提供两个合作伙伴 snort 实例之间的状态一致性。它使用 SideChannel 进行消息传递。

Snort 和 Snort 插件中可以有多种类型的 HA。HA 实现了一个可扩展的架构,使插件能够订阅基本流 HA 消息传递。然后,这些插件可以包含它们自己的消息以及流缓存 HA 消息。

HA 产生和使用两种类型的消息:

  • 更新 – 更新流状态。插件可以将自己的数据添加到消息中
  • 删除 – 流已从缓存中删除

HA 模块配置了以下项目:

high_availability =
{
    ports = "1",
    enable = true,
    min_age = 0,
    min_sync = 0
}

港口项目映射到侧通道口使用的HA消息。

启动项目控制整个HA操作。

min_age 和 min_sync 项用于流 HA 逻辑。min_age 是在向合作伙伴发送 HA 消息之前,流必须存在于流缓存中的毫秒数。min_sync 是 HA 状态更新之间的最短时间。特定流的 HA 消息的发送速度不会比 min_sync 快。两者都表示为毫秒数。

HA 消息由基本信息加上来自附加模块的任何内容组成。模块订阅 HA 以添加消息内容。所述HA含量始终是存在于所述消息而当通过状态改变请求所请求的辅助模块含量仅为本。

连接器

连接器是一组模块,用于在 Snort 线程和外部世界之间交换面向消息的数据。一个典型的用例是 HA(高可用性)消息交换。连接器用于将消息传输与消息创建/消费分离。连接器为多种形式的消息传输公开了一个通用 API。

连接器是一种 Snort 插件类型。

连接器(父插件类)

连接器既可以是单工通道,也可以执行单向通信。或者可以是双工并执行双向通信。TcpConnector 是双工的,而 FileConnector 是单工的。

连接器的所有子类型都有一个方向配置元素和一个 连接器元素。所述连接器串是用于识别侧通道构成的元素的键。该方向元素可以有一个默认值,比如TcpConnector的是复式

目前有两种连接器的实现:

  • TcpConnector – 通过 tcp 通道交换消息。
  • FileConnector – 将消息写入文件并从文件读取消息。
连接器

TcpConnector 是 Connector 的子类,它实现了 DUPLEX 类型的 Connector,能够通过 tcp 会话发送和接收消息。

TcpConnector 添加了一些会话设置配置元素:

  • setup = callanswer – call用于让 TcpConnector 启动连接。 answer用于让 TcpConnector 接受传入连接。
  • address = <addr> – 用于呼叫建立以指定合作伙伴
  • base_port = port – 用于构造呼叫和 应答模式的实际端口号。实际使用的端口是 (base_port + instance_id)。

TcpConnector 配置的示例段:

tcp_connector =
{
    {
        connector = 'tcp_1',
        address = '127.0.0.1',
        setup = 'call',
        base_port = 11000
    },
}
文件连接器

FileConnector 实现了一个可以从文件读取或写入文件的连接器。FileConnector 是单工的,必须配置为 CONN_TRANSMIT 或 CONN_RECEIVE。

FileConnector 配置添加了两个额外的元素:

  • name = string – 用作消息文件名的一部分
  • 格式 =文本二进制– FileConnector 支持两种文件类型

配置的名称字符串用于构造实际名称,如下所示:

  • file_connector_NAME_transmit 和 file_connector_NAME_receive

一次 Snort 调用的所有消息都被读取并写入一个文件。

在接收 FileConnector 的情况下,所有消息都在数据包处理开始之前从文件中读取。这允许消息为所有处理的数据包建立状态信息。

连接器仅供 SideChannel 使用

FileConnector 配置的示例段:

file_connector =
{
    {
        connector = 'file_tx_1',
        direction = 'transmit',
        format = 'text',
        name = 'HA'
    },
    {
        connector = 'file_rx_1',
        direction = 'receive',
        format = 'text',
        name = 'HA'
    },
}

侧通道

SideChannel 是一个 Snort 模块,它使用连接器来实​​现用于在 Snort 线程和外部世界之间进行通信的消息传递基础结构。

SideChannel 向连接器添加了以下功能:

  • 消息多路复用/多路分解 – 将附加协议层添加到消息中。此端口号用于将消息定向到/来自各种 SideClass 实例。
  • 应用程序接收处理 – 在特定端口上接收消息的处理程序。

SideChannel 始终实现双工(双向)消息传递模型,并且可以映射到单独的发送和接收连接器。

消息处理模型利用底层连接器处理。所以请参考连接器文档。

SideChannel 由各种应用程序实例化。SideChannel 端口号是用于将 SideChannel 映射到应用程序的配置元素。

SideChannel 配置主要用于将端口号映射到一个连接器或一组连接器。每个端口映射最多可以有一个发送加一个接收连接器或一个双工连接器。可以配置和实例化多个 SideChannel 以支持多个应用程序。

SideChannel 配置示例以及相应的连接器配置:

side_channel =
{
    {
        ports = '1',
        connectors =
        {
            {
                connector = 'file_rx_1',
            },
            {
                connector = 'file_tx_1',
            }
        },
    },
}
file_connector =
{
    {
        connector = 'file_tx_1',
        direction = 'transmit',
        format = 'text',
        name = 'HA'
    },
    {
        connector = 'file_rx_1',
        direction = 'receive',
        format = 'text',
        name = 'HA'
    },
}

FTP

给定一个 FTP 命令通道缓冲区,FTP 将解释数据,识别 FTP 命令和参数,以及 FTP 响应代码和消息。它将强制执行参数的正确性,确定何时加密 FTP 命令连接,并确定何时打开 FTP 数据通道。

配置检查器以阻止漏洞利用和攻击

ftp_server 配置
  • ftp_cmds

这指定了检查器中默认检查的那些之外的其他 FTP 命令。检查器可以配置为当它看到它无法识别的命令时生成警报。

除了已识别的默认命令外,可能还需要允许使用 RFC 775 中指定的“X”命令。为此,请使用以下 ftp_cmds 选项。由于这些很少被 FTP 客户端实现使用,因此它们不包含在默认值中。

ftp_cmds = [[ XPWD XCWD XCUP XMKD XRMD ]]
  • def_max_param_len

这指定了所有命令的默认最大参数长度(以字节为单位)。如果 FTP 命令的参数超过该长度,并且检查器配置为这样做,则会生成警报。这用于检查 FTP 服务器中的缓冲区溢出漏洞。

  • cmd_validity

这指定给定命令的参数的有效格式和长度。

  • cmd_validity[].len

这以字节为单位指定指定命令的最大参数长度,覆盖默认值。如果该 FTP 命令的参数超过该长度,并且检查器配置为这样做,则会生成警报。它可用于将特定命令限制为较小的参数值。例如 USER 命令——用户名可能不超过 16 个字节,因此适当的配置是:

cmd_validity =
{
    {
        command = 'USER',
        length = 16,
    }
}
  • cmd_validity[].format

格式如下:

int                 Param must be an integer
number              Param must be an integer between 1 and 255
char <chars>        Param must be a single char, and one of <chars>
date <datefmt>      Param follows format specified where
                    # = Number, C=Char, []=optional, |=OR, {}=choice,
                    anything else=literal (i.e., .+- )
string              Param is string (effectively unrestricted)
host_port           Param must a host port specifier, per RFC 959.
long_host_port      Parameter must be a long host port specified, per RFC 1639
extended_host_port  Parameter must be an extended host port specified, per RFC 2428

cmd_validity 选项的示例如下所示。这些示例是检查员执行的默认检查(根据 RFC 959 和其他)。

cmd_validity =
{
    {
        command = 'CWD',
        length = 200,
    },
    {
        command = 'MODE',
        format = '< char SBC >',
    },
    {
        command = 'STRU',
        format = '< char FRP >',
    },
    {
        command = 'ALLO',
        format = '< int [ char R int ] >',
    },
    {
        command = 'TYPE',
        format = [[ < { char AE [ char NTC ] | char I | char L [ number ]
            } > ]],
    },
    {
        command = 'PORT',
        format = '< host_port >',
    },
}

配置中的 cmd_validity 条目可用于覆盖这些默认值和/或添加对其他命令的检查。下面是几个例子。

这允许其他模式,包括允许 zip 样式压缩的模式 Z:

cmd_validity =
{
    {
        command = 'MODE',
        format = '< char ASBCZ >',
    },
}

允许在 MDTM 命令中输入日期:

cmd_validity =
{
    {
        command = 'MDTM',
        format = '< [ date nnnnnnnnnnnnnn[.n[n[n]]] ] string >',
    },
}

MDTM 是一个值得讨论的奇怪案例……

虽然不是既定标准的一部分,某些 FTP 服务器接受 MDTM 命令来设置文件的修改时间。在这样做的服务器中最常见的是接受使用 YYYYMMDDHHmmss[.uuu] 的格式。其他一些接受使用 YYYYMMDDHHmmss[+|-]TZ 格式的格式。上面的例子是针对第一种情况的。

要检查使用 TZ 格式的服务器的有效性,请使用以下命令:

cmd_validity =
{
    {
        command = 'MDTM',
        format = '< [ date nnnnnnnnnnnnnn[{+|-}n[n]] ] string >',
    },
}
  • chk_str_fmt

这会导致检查器检查对指定命令的字符串格式攻击。

  • telnet_cmds

在 FTP 命令通道上看到 telnet cmds 时检测并发出警报。

  • ignore_telnet_erase_cmds

此选项允许 Snort 在规范化 FTP 命令通道时忽略擦除字符 (TNC EAC) 和擦除行 (TNC EAL) 的 telnet 转义序列。某些 FTP 服务器不处理这些 telnet 转义序列。

  • ignore_data_chan

设置为 true 时,会导致 FTP 检查器强制 snort 的其余部分忽略 FTP 数据通道连接。除了状态(检查器和规则)之外,不会在该数据通道上执行任何检查。可以通过忽略流量来打开它以提高性能 – 特别是对于来自受信任来源的大文件传输。如果您的规则集包括病毒类型规则,建议不要使用此选项。

ftp_client 配置
  • max_resp_len

这指定了所有响应消息的最大长度(以字节为单位)。如果 FTP 响应的消息(3 位数代码之后的所有内容)超过该长度,并且检查器配置为这样做,则会生成警报。这用于检查 FTP 客户端中的缓冲区溢出漏洞。

  • telnet_cmds

在 FTP 命令通道上看到 telnet cmds 时检测并发出警报。

  • ignore_telnet_erase_cmds

此选项允许 Snort 在规范化 FTP 命令通道时忽略擦除字符 (TNC EAC) 和擦除行 (TNC EAL) 的 telnet 转义序列。某些 FTP 客户端不处理这些 telnet 转义序列。

ftp_data

为了启用 ftp 的文件检查,应将以下内容添加到配置中:

ftp_data = {}

HTTP 检查器

Snort 3 的主要任务之一是开发一个全新的 HTTP 检查器。

概述

您可以通过添加以下内容来配置它:

http_inspect = {}

到您的 snort.lua 配置文件。或者您可以在 src/service_inspectors/http_inspect 下的源代码中阅读它。

那么为什么要使用新的 HTTP 检查器呢?

对于初学者来说,它是面向对象的。这对我们有好处,因为我们维护这个软件。但对于开源开发人员来说,它也应该非常好。您可以对 HTTP 处理进行有意义的更改和添加,而无需了解整个过程。事实上,新的 HTTP 检查器的大部分 HTTP 知识都集中在一系列表格中,可以轻松地查看和修改这些表格。仅通过更新这些表就可以进行许多重大更改。

http_inspect 是第一个专门为新的 Snort 3 架构编写的检查器。这提供了对 Snort 3 的最佳功能之一的访问:纯粹基于 PDU 的检查。经典的预处理器处理 HTTP 消息,但即使在这样做的同时,它也会不断了解 IP 数据包以及它们如何划分 TCP 数据流。相同的 HTTP 消息可能会根据发送者(坏人)如何将其划分为 IP 数据包的方式进行不同的处理。

http_inspect 没有这个负担,可以专注于 HTTP。这使得它更简单,更容易测试,并且更不容易出现误报。它还通过调整数据包边界来掩饰不良行为,从而大大减少了攻击者探测检查器弱点的机会。

仅处理 HTTP 消息也为开发主要新功能打开了大门。http_inspect 设计支持真正的有状态处理。想询问涉及客户端请求和服务器响应的问题吗?还是同一会话中的不同请求?这些事情都是可能的。

http_inspect 对 HTTP 标头字段采用了非常不同的方法。经典的预处理器将起始行后面的所有 HTTP 标头划分为 cookie 和其他所有内容。它使用通用过程规范化这两个部分,并将它们放在可以编写规则的缓冲区中。对检查检查器中的单个标题的支持有限,但它非常具体。

新概念是每个标题都应该以适当和特定的方式进行规范化,并单独提供给用户来编写针对它的规则。例如,如果标题应该是日期,则规范化意味着将该日期置于标准格式中。

传统和增强的归一化器

目前,有用于 JavaScript 规范化的 Legacy 和 Enhanced Normalizers。两个归一化器都是独立的,可以单独配置。Legacy 规范化器应被视为已弃用。随着我们不断改进功能和质量,我们鼓励首先将 Enhanced Normalizer 用于 JavaScript 规范化。

传统规范化器

Legacy Normalizer 可以规范化 JavaScript 函数中的混淆数据,例如 unescape、String.fromCharCode、decodeURI 和 decodeURIComponent。它还用单个空格替换连续的空格,并通过连接字符串来规范化加号。有关如何启用 Legacy Normalizer 的更多信息,请查看 http_inspect.normalize_javascript 选项。Legacy Normalizer 已弃用,最好使用 Enhanced Normalizer。在 Enhanced Normalizer 支持向后兼容后,Legacy Normalizer 将被移除。

增强的归一化器

有 ips 选项js_data在规则中自动启用 Enhanced Normalizer。Enhanced Normalizer 可以规范化内联/外部脚本。它支持多个 PDU 上的脚本。它是一个有状态的 JavaScript 空格和标识符规范器。除了那些来自内置标识符列表的 JavaScript 标识符名称之外,所有 JavaScript 标识符名称都将替换为具有以下格式的统一名称:var_0000 → var_ffff。此外,Normalizer 验证有关 ECMA-262 标准的语法,包括范围跟踪,并检查对脚本元素内容的限制(因为它是 HTML 嵌入的 JavaScript)。有关如何额外配置 Enhanced Normalizer 的更多信息,请检查以下 http_inspect 选项:js_normalization_depth、js_norm_identifier_depth、js_norm_max_tmpl_nest、js_norm_max_scope_depth、js_norm_built_in_ident。

配置

配置可以像添加一样简单:

http_inspect = {}

到您的 snort.lua 文件。默认配置提供了彻底的检查,可能就是您所需要的。但是有一些选项可以提供额外的功能、调整工作方式或通过减少工作量来节省资源。

request_depth 和 response_depth

这些替换了旧 HTTP 检查器使用的流深度参数,但它们的工作方式不同。

默认是检查整个 HTTP 消息正文。这是一种非常合理的方法,但如果您的 HTTP 流量包含许多非常大的文件(例如视频),则 Snort 上的负载可能会变得繁重。设置 request_depth 和 response_depth 参数将限制发送到规则引擎的正文数据量。例如:

request_depth = 10000,
response_depth = 80000,

只会检查客户端发送的 POST、PUT 和其他消息正文的前 10000 个字节。来自服务器的响应将被限制为 80000 字节。

这些限制仅适用于邮件正文。HTTP 标头总是被完全检查。

如果您只想检查标题而不检查正文,请将深度设置为 0。如果您想检查整个正文,请将深度设置为 -1 或完全省略深度参数,因为这是默认值。

这些限制对转发给文件处理的数据量没有影响。

脚本检测

脚本检测功能使 Snort 能够更快地检测和阻止包含恶意 JavaScript 的响应消息。当 http_inspect 检测到脚本结束时,它会立即转发消息正文的可用部分以进行早期检测。这使恶意 Javascript 能够被更快地检测到,但会消耗更多的传感器资源。

此功能默认关闭。script_detection = true 将激活它。

压缩包

默认情况下,http_inspect 在检查它们之前解压缩 deflate 和 gzip 消息体。可以通过 unzip = false 关闭此功能。关闭减压提供了显着的性能改进,但代价非常高。不太可能对消息正文进行任何有意义的检查。有效的 HTTP 处理将仅限于标头。

normalize_utf

http_inspect 将根据 Content-Type 标头解码响应消息正文中的 utf-8、utf-7、utf-16le、utf-16be、utf-32le 和 utf-32be。此功能默认开启: normalize_utf = false 将停用它。

解压_pdf

decompress_pdf = true 将启用在响应正文中遇到的 PDF 文件的压缩部分的解压缩。http_inspect 将检查 PDF 文件的响应正文,然后解析这些 PDF 文件以使用单个 /FlateDecode 过滤器定位 PDF 流。压缩的内容通过文件数据规则选项解压并可用。

解压_swf

decompress_swf = true 将启用在响应正文中遇到的压缩 SWF(Adobe Flash 内容)文件的解压缩。可用的解压模式是“deflate”和“lzma”。http_inspect 将搜索 Deflate/ZLIB 的文件签名 CWS 和 LZMA 的 ZWS 文件签名。压缩的内容通过文件数据规则选项解压并可用。压缩后的 SWF 文件签名会转换为 FWS 以指示未压缩的文件。

decompress_vba

decompress_vba ​​= true 将启用 MS Office 文件的 RLE(运行长度编码)压缩的 vba(Visual Basic for Applications)宏数据的解压缩。MS office 文件是 PKZIP 压缩的,经过解析以定位嵌入了包含 RLE 压缩的 vba 宏数据的文件的 OLE(对象链接和嵌入)文件。然后通过 vba_data ips 规则选项使解压缩的 vba 宏数据可用。

normalize_javascript

normalize_javascript = true 将在 HTTP 响应正文中启用 JavaScript 的遗留规范化器。http_inspect 通过搜索没有类型的 <script> 标签来查找 JavaScript。JavaScript 函数中的混淆数据(例如 unescape、String.fromCharCode、decodeURI 和 decodeURIComponent)已标准化。在 unescape、decodeURI 或 decodeURIComponent 中处理的不同编码是 %XX、%uXXXX、XX 和 uXXXXi。http_inspect 还用单个空格替换连续的空格,并通过连接字符串来规范化加号。这种规范化指的是基本的 JavaScript 规范化。

js_normalization_depth

js_normalization_depth = N {-1 : max53} 将设置一些输入 JavaScript 字节来规范化。当达到深度时,将停止归一化。它是按脚本实现的。默认 js_normalization_depth = -1,将设置无限深度。增强的规范化器提供了更精确的 JavaScript 空白规范化,根据 ECMAScript 5.1 标准,从 JavaScript 语法的角度(标识符和标点符号之间,标识符和运算符之间等)删除所有多余的空格和行终止符。此外,它执行 JavaScript 标识符的规范化,使用统一名称表示替换唯一名称:var_0000:var_ffff。标识符是变量和函数名。规范化数据可通过 js_data 规则选项获得。

js_norm_identifier_depth

js_norm_identifier_depth = N {0 : 65536} 将设置一些唯一的 JavaScript 标识符来规范化。当达到深度时,会生成内置警报。每个 HTTP 响应都有自己的标识符替换上下文。因此,来自同一响应的所有脚本都将被规范化,就好像它们是单个脚本一样。默认情况下,该值设置为 65536,这是唯一标识符的最大允许数量。生成的名称范围从 var_0000 到 var_ffff。

js_norm_max_tmpl_nest

js_norm_max_tmpl_nest = N {0 : 255}(默认为 32)是增强型 JavaScript 规范化器的一个选项,用于确定要处理的嵌套模板文字的最深级别。ES6 中引入的模板文字提供了定义文字多行字符串的语法,该字符串可以具有任意 JavaScript 替换,将被评估并插入到字符串中。这种替换可以嵌套,并且需要跟踪每一层以进行适当的规范化。此选项用于限制专用于此跟踪的内存量。

js_norm_max_scope_depth

js_norm_max_scope_depth = N {0 : 65535}(默认为 256)是增强型 JavaScript 规范化器的一个选项,用于确定嵌套范围的最深级别。范围术语包括代码​​段(“{}”)、圆括号(“()”)和方括号(“[]”)。此选项用于限制专用于此跟踪的内存量。

js_norm_built_in_ident

js_norm_built_in_ident = {<内置 JavaScript 标识符名称列表>}。默认列表存在于“snort_defaults.lua”中。

内置 JavaScript 标识符将按原样放置,无需替换。Normalizer 根据配置的内置名称列表跟踪内置标识符表达式。内置标识符表达式是内置名称(函数或对象)及其后的点和括号访问器链,包括函数调用。例如:

console.log("bar")
document.getElementById("id").text
eval("script")
foo["bar"]

该列表必须仅包含对象和函数名称。例如:

http_inspect.js_norm_built_in_ident = { 'console', 'document', 'eval', 'foo' }
xff_headers

此配置支持定义自定义 x-forwarded-for 类型标头。在多供应商的世界中,携带原始客户端 IP 的标头名称很可能是特定于供应商的。这是由于缺乏标准化,否则将标准化标题名称。在这种情况下,此配置提供了一种可以将此类标头引入 HI 的方法。此配置的默认值为“x-forwarded-for true-client-ip”。默认定义引入了两个众所周知的标头,并且在检查员定义的相同顺序中首选,例如,如果两个标头都存在于溪流。标题名称应以空格分隔。

最大主机长度

如果包含可选空格的 Host 标头值超过指定长度,则设置 maximum_host_length 会导致 http_inspect 生成 119:25。在多个 Host 头的异常情况下,使用组合值的总长度。默认值为 -1,表示不执行此检查。

最大块长度

http_inspect 将分块消息正文中的单个块严格限制为小于 4 GB。

可以通过设置maximum_chunk_length 来配置下限。任何超过最大块长度的块都将生成 119:16 警报。

URI处理

HTTP 请求消息中 URI 的规范化和检查是 http_inspect 所做的一个关键方面。规范化 URI 的最佳方法非常依赖于被访问的 HTTP 服务器的特性。目标是以与服务器相同的方式解释 URI,以便服务器将看到的任何内容都无法从规则引擎中隐藏。

默认的 URI 检查参数面向遵循 HTTP RFC——以标准规定的方式读取 URI。大多数服务器都以各种可能被攻击者利用的方式偏离了这一理想。这些选项为用户提供了应对这种情况的工具。

utf8 = true
plus_to_space = true
percent_u = false
utf8_bare_byte = false
iis_unicode = false
iis_double_decode = true

HTTP 检查器将在 URI 中找到的百分比编码标准化。例如,它将“%48%69%64%64%65%6e”转换为“隐藏”。上面列出的所有选项都控制着如何做到这一点。列为 true 的选项是默认解码的相当标准的功能。您不需要在 snort.lua 中列出它们,除非您想通过将它们设置为 false 来关闭它们。但是,除非您知道自己在做什么并且有明确的理由,否则不建议这样做。

其他选项主要用于保护支持不规则解码形式的服务器。这些功能默认是关闭的,但如果需要,您可以通过在 snort.lua 中将它们设置为 true 来激活它们。

bad_characters = "0x25 0x7e 0x6b 0x80 0x81 0x82 0x83 0x84"

这是一个 8 位 Ascii 字符列表,在完成百分比解码后,您不希望这些字符出现在任何规范化 URI 中。例如 0x25 是一个代表%字符的十六进制数(十进制 37)。% 字符合法地用于对 URI 中的特殊字符进行编码。但是如果标准化后仍然有一个百分比,人们可能会得出结论,有些事情是错误的。如果您选择将 0x25 配置为坏字符,则每当发生这种情况时都会发出警报。

另一个示例是 0x00,它表示空字符零。URI 中的空字符通常是错误的并且非常可疑。

默认设置是不对任何 256 个 8 位 Ascii 字符发出警报。如果您想定义一些坏字符,请将此选项添加到您的配置中。

ignore_unreserved = "abc123"

在 HTTP 中没有特殊含义的常见字符(例如字母和数字)的百分比编码是可疑的。这是合法的,但你为什么要这样做,除非你有什么要隐瞒的?http_inspect 将在大写或小写字母、数字、句点、下划线、波浪号或减号被百分比编码时发出警报。但是,如果您环境中的合法应用程序出于某种原因对其中一些字符进行了编码,则您可以为这些字符创建豁免。

在示例中,小写字母 a、b 和 c 以及数字 1、2 和 3 被免除。这些可以是百分比编码而不产生警报。

simplify_path = true
backslash_to_slash = true

HTTP 检查器通过消除使用 .、.. 和 / 的额外遍历来简化 URI 中的目录路径。

例如,我可以采用一个简单的 URI,例如

/very/easy/example

并将其复杂化:

/very/../very/././././easy//////detour/to/nowhere/../.././../example

这可能很难与检测规则匹配。simple_path 默认打开,除非您对 URI 路径不感兴趣,否则不应将其关闭。

backslash_to_slash 是对允许目录由反斜杠分隔的服务器的路径简化的调整:

/this/is/the/normal/way/to/write/a/path
\this\is\the\other\way\to\write\a\path

backslash_to_slash 默认开启。它在规范化期间用斜杠替换所有反斜杠。

连接处理

客户端使用 HTTP CONNECT 方法通过 HTTP 代理服务器建立到目的地的隧道。如果连接成功,服务器将向客户端发送 2XX 成功响应,然后继续在客户端和目的地之间盲目转发流量。该流量属于客户端和目的地之间的新会话,并且可能属于任何协议,因此很明显,HTTP 检查器将无法继续处理 CONNECT 消息之后的流量,就好像它只是原始 HTTP/1.1 会话的延续一样。

因此,在收到对 CONNECT 请求的成功响应后,HTTP 检查器将停止检查会话。下一个数据包将返回到向导,向导将确定合适的检查器以继续处理流。如果隧道协议恰好是 HTTP/1.1,HTTP 检查器将再次开始检查流,但作为一个全新的会话。

有一种情况,尽管对 CONNECT 请求的响应为 2XX 成功,但不会切换到向导。HTTP 允许流水线操作,或发送多个请求而无需等待响应。如果 HTTP 检查器在看到 CONNECT 响应之前在 CONNECT 请求之后看到来自客户端的任何进一步流量,则不清楚该流量是否应被解释为流水线 HTTP 请求或隧道流量,以期待来自服务器的成功响应. 由于这种潜在的规避策略,如果 HTTP 检查器发现任何早期的客户端到服务器流量,它不会切换到向导,但会继续正常的 HTTP 流处理,而不管最终的服务器响应如何。

跟踪消息

当用户需要帮助来整理 HTTP 检查器内部发生的事情时,Trace 模块变得很方便。

$ snort --help-module trace | grep http_inspect

增强的 JavaScript 规范器的消息如下(在调试版本中提供更多详细信息):

trace.module.http_inspect.js_proc

来自脚本处理流程的消息及其详细级别:

  1. 脚本开始标记位置。
  2. 检测到的脚本的属性。
  3. 从 Normalizer 返回代码。
trace.module.http_inspect.js_dump

JavaScript 数据转储和详细级别:

  1. js_data 缓冲区,因为它被传递给检测。
  2. (目前没有可用的消息)
  3. 传递给 Normalizer 的当前脚本。

检测规则

http_inspect 将 HTTP 消息解析为其组件,并通过规则选项将它们提供给检测引擎。让我们从一个例子开始:

alert tcp any any -> any any ( msg:"URI example"; flow:established,
to_server; http_uri; content:"chocolate"; sid:1; rev:1; )

此规则在请求消息的 URI 部分查找巧克力。具体来说,http_uri 规则选项是移除了所有百分比编码的规范化 URI。它会在两者中找到巧克力:

GET /chocolate/cake HTTP/1.1

GET /%63%68$6F%63%6F%6C%61%74%65/%63%61%6B%65 HTTP/1.1

也可以搜索未规范化的 URI

alert tcp any any -> any any ( msg:"Raw URI example"; flow:established,
to_server; http_raw_uri; content:"chocolate"; sid:2; rev:1; )

将匹配第一条消息但不匹配第二条。如果你想发现有人试图隐藏他对巧克力的要求,那么

alert tcp any any -> any any ( msg:"Raw URI example"; flow:established,
to_server; http_raw_uri; content:"%63%68$6F%63%6F%6C%61%74%65";
sid:3; rev:1; )

会做的伎俩。

让我们看看编写规则以匹配 HTTP 响应消息的可能方法,其中 Content-Language 标头设置为“da”(丹麦语)。你可以写:

alert tcp any any -> any any ( msg:"whole header search";
flow:established, to_client; http_header; content:
"Content-Language: da", nocase; sid:4; rev:1; )

这条规则还有很多不足之处。现代标头通常有数千个字节,而且似乎每年都在变长。搜索所有标题会消耗大量资源。此外,这条规则很容易规避:

HTTP/1.1 ... Content-Language:  da ...

“da”之前的额外空间将规则排除在外。或者怎么样:

HTTP/1.1 ... Content-Language: xx,da ...

通过添加编造的第二语言,攻击者再次挫败了比赛。

编写此规则的更好方法是:

alert tcp any any -> any any ( msg:"individual header search";
flow:established, to_client; http_header: field content-language;
content:"da", nocase; sid:4; rev:2; )

field 选项通过将搜索范围缩小到标题的 Content-Language 字段来提高性能。因为它使用 http_inspect 的标头解析能力来查找感兴趣的字段,所以它不会被列表中的额外空格或其他语言抛出。

除了标头之外,HTTP 消息的几乎每个部分都有规则选项。

http_uri 和 http_raw_uri

这些提供请求消息的 URI。原始形式与消息中显示的完全相同,规范化形式由您选择的 URI 规范化选项确定。除了搜索整个 URI 之外,还有六个可以单独搜索的组件:

alert tcp any any -> any any ( msg:"URI path"; flow:established,
to_server; http_uri: path; content:"chocolate"; sid:1; rev:2; )

通过指定“路径”,搜索仅限于 URI 的路径部分。非正式地,这是由目录路径和文件名组成的部分。因此它将匹配:

GET /chocolate/cake HTTP/1.1

但不是:

GET /book/recipes?chocolate+cake HTTP/1.1

问号结束路径并开始 URI 的查询部分。非正式地,查询是设置参数值的地方,通常包含要执行的搜索。

这六个组成部分是:

  1. 路径:目录和文件
  2. 查询:用户参数
  3. 片段:请求的文件的一部分,通常只能在浏览器中找到,不会通过网络传输
  4. 主机:被寻址的服务器的域名
  5. 端口:正在寻址的 TCP 端口号
  6. 方案:通常为“http”或“https”,但也可以使用其他方案,例如“ftp”

这是一个包含所有六个的示例:

GET https://www.samplehost.com:287/basic/example/of/path?with-query
#and-fragment HTTP/1.1\r\n

URI 是第一个空格和最后一个空格之间的所有内容。“https”是方案,“www.samplehost.com”是主机,“287”是端口,“/basic/example/of/path”是路径,“with-query”是查询,“ and-fragment”是片段。

http_uri 表示归一化的 uri,组件的归一化取决于 uri 类型。如果 uri 是绝对类型(包含所有六个组件)或绝对路径(包含路径、查询和片段),则路径和查询组件将被标准化。在这些情况下,http_uri 表示规范化的路径、查询和片段 (/path?query#fragment)。如果 uri 是权限类型(主机和端口),则主机被规范化,http_uri 代表带有端口号的规范化主机。在所有其他情况下,http_uri 与 http_raw_uri 相同。

注意:本节使用非正式语言来解释一些事情。这里没有任何内容与 HTTP RFC 的技术语言冲突,并且实现遵循 RFC。

http_header 和 http_raw_header

这些涵盖了除第一行之外的所有标题行。您可以使用字段选项按名称指定单个标题,如前面的示例所示:

alert tcp any any -> any any ( msg:"individual header search";
flow:established, to_client; http_header: field content-language;
content:"da", nocase; sid:4; rev:2; )

此规则搜索 Content-Language 标头的值。标题名称不区分大小写,可以在规则中以任意大小写混合形式写入。

使用 http_header 以适合该标头的方式对单个标头值进行标准化。

如果您不指定标题,则会获得所有标题。http_raw_header 包括原始消息中出现的未修改的标头名称和值。http_header 是相同的,除了百分比编码和 cookie 被删除并且路径被完全简化,就好像标头是一个 URI。

在大多数情况下,指定单个标题会创建更有效和准确的规则。建议尽可能使用单独的标头编写新规则。

http_trailer 和 http_raw_trailer

HTTP 允许在分块的正文结束后出现标题行。通常,它们包含有关创建标头时不可用的消息内容的信息。为方便起见,我们称它们为拖车。

http_trailer 和 http_raw_trailer 与其对应的标头相同,只是它们适用于这些末端标头。如果您想要一个规则来检查这两种标题,您需要编写两个规则,一个使用标题,一个使用预告片。

它们提供请求消息的 Cookie 标头值和响应消息的 Set-Cookie。如果存在多个 cookie,它们将连接成一个逗号分隔的列表。

http_cookie 的规范化与未指定特定标头时应用于 http_header 的 URI 样式规范化相同。

http_true_ip

这提供了发送请求的客户端的原始 IP 地址,因为它由代理存储在请求消息头中。具体来说,它是 X-Forwarded-For、True-Client-IP 或任何其他自定义 x-forwarded-for 类型标头中列出的最后一个 IP 地址。如果存在多个标头,则考虑在 xff_headers 配置中定义的首选项。

http_client_body

这是请求消息的正文,例如 POST 或 PUT。http_client_body 的规范化与未指定特定标头时应用于 http_header 的类似 URI 的规范化相同。

http_raw_body

这是请求或响应消息的正文。如果适用,它将被解压缩并解压缩,但不会以任何其他方式进行规范化。

http_method

请求消息的方法字段。常见的值为“GET”、“POST”、“OPTIONS”、“HEAD”、“DELETE”、“PUT”、“TRACE”和“CONNECT”。

http_stat_code

响应消息的状态码字段。这通常是 100 到 599 之间的 3 位数字。在本例中为 200。

HTTP/1.1 200 OK
http_stat_msg

响应消息的原因短语字段。这是状态代码之后的可读文本。上例中的“OK”。

http_version

出现在 HTTP 消息第一行的协议版本信息。这通常是“HTTP/1.0”或“HTTP/1.1”。

http_raw_request 和 http_raw_status

这些分别是 HTTP 请求和响应消息的未修改的第一个标题行。这些规则选项是一个安全阀,以防您需要做一些原本无法做的事情。在大多数情况下,最好对第一个标题行的特定部分使用规则选项。对于请求消息,它们是 http_method、http_raw_uri 和 http_version。对于响应消息,它们是 http_version、http_stat_code 和 http_stat_msg。

文件数据

file_data 包含规范化的消息正文。这是上述 gzip、normalize_utf、decompress_pdf、decompress_swf 和 normalize_javascript 下的规范化。

js_data

js_data 包含从整个 PDU(内联或外部脚本)收集的规范化 JavaScript 文本。它需要启用 Enhanced Normalizer:http_inspect = { js_normalization_depth = N },上面描述了 js_normalization_depth 选项。尽管 js_data 有什么,file_data 仍然包含整个 HTTP 主体,其中包含原始 JavaScript。

vba_data

vba_data 将包含嵌入在 MS Office 文件中的解压缩 Visual Basic for Applications (vba) 宏数据。它需要启用 decompress_zip 和 decompress_vba ​​选项。

时间问题和组合规则选项

HTTP 检查器是有状态的。这意味着它知道比它前面的数据包更大的图片。它知道一条消息的所有部分是什么、一条消息和下一条消息之间的分界线、哪个请求消息触发了哪个响应消息、管道以及通过当前连接发送了多少条消息。

一些规则使用单个规则选项:

alert tcp any any -> any any ( msg:"URI example"; flow:established,
to_server; http_uri; content:"chocolate"; sid:1; rev:1; )

每当有新的 URI 可用时,就会评估此规则。没有什么复杂的,但假设我们使用多个规则选项:

alert tcp any any -> any any ( msg:"combined example"; flow:established,
to_server; http_uri: with_body; content:"chocolate"; file_data;
content:"sinister POST data"; sid:5; rev:1; )

http_uri 的 with_body 选项使 URI 与消息正文一起可用。将 with_body 用于还检查邮件正文的规则中与标头相关的规则选项。

with_trailer 选项与此类似,当分块正文之后的预告片到达时,它会在消息的末尾使较早的消息元素可用。

alert tcp any any -> any any ( msg:"double content-language";
flow:established, to_client; http_header: with_trailer, field
content-language; content:"da", nocase; http_trailer: field
content-language; content:"en", nocase; sid:6; rev:1; )

如果内容语言从标题中的丹麦语更改为预告片中的英语,此规则将发出警报。with_trailer 选项对于使此规则起作用至关重要。

也可以编写检查客户端请求和服务器响应的规则。

alert tcp any any -> any any ( msg:"request and response example";
flow:established, to_client; http_uri: with_body; content:"chocolate";
file_data; content:"white chocolate"; sid:7; rev:1; )

此规则在请求的 URI 包含巧克力的响应消息正文中查找白巧克力。请注意,这是一个“to_client”规则,它将警告并可能阻止包含白巧克力的服务器响应,但前提是客户端 URI 请求巧克力。如果规则被重写为“to_server”,那将是无稽之谈并且不起作用。Snort 无法根据服务器响应来阻止客户端请求,因为这还没有发生。

另一点是 http_uri 的“with_body”。这确保规则适用于整个响应正文。如果我们在响应头中寻找白巧克力,这将是不必要的。

响应消息没有 URI,因此 http_uri 在之前的规则中可能只表示一件事。它必须是指请求消息。有时这不是那么清楚。

alert tcp any any -> any any ( msg:"header ambiguity example 1";
flow:established, to_client; http_header: with_body; content:
"chocolate"; file_data; content:"white chocolate"; sid:8; rev:1; )
alert tcp any any -> any any ( msg:"header ambiguity example 2";
flow:established, to_client; http_header: with_body, request; content:
"chocolate"; file_data; content:"white chocolate"; sid:8; rev:2; )

我们对巧克力的搜索已经从 URI 移动到消息标题。请求和响应消息都有标头——我们要问哪一个?歧义总是被解决,以支持查看作为响应的当前消息。第一条规则是寻找在标题中包含巧克力和在正文中包含白巧克力的服务器响应。

第二条规则使用“请求”选项明确说明要搜索的 http_header 是请求头。

让我们把所有这些放在一起。有六种机会可以做检测:

  1. 当请求头到达时。请求行和所有标头同时通过检测。
  2. 当请求消息正文的部分到达时。如果您想将其与请求行或标题中的内容结合起来,您必须使用 with_body 选项。
  3. 当请求拖车到达时。如果您想将其与请求行或标题中的内容结合起来,您必须使用 with_trailer 选项。
  4. 当响应头到达时。状态行和所有标题同时通过检测。这些可以与来自请求行、请求头或请求尾的元素结合。如果出现歧义,请使用请求选项。
  5. 当响应消息正文的部分到达时。如上所述,它们可以与状态行、响应头、请求行、请求头或请求尾组合在一起。
  6. 当响应预告片到达时。同样,这些可以如上所述组合。

消息正文部分只能在收到时进行检测。标题可以与后面的项目组合,但正文不能。

HTTP/2 检查器

Snort 3 中的新增功能,HTTP/2 检查器使 Snort 能够处理 HTTP/2 流量。

概述

尽管名称如此,但最好不要将 HTTP/2 视为 HTTP/1.1 的更新版本,而是将其视为运行在 HTTP/1.1 下和 TLS 或 TCP 之上的单独协议层。它支持多项旨在提高 HTTP 请求性能的新功能,特别是在单个 TCP 连接上多路复用多个请求的能力、HTTP 标头压缩和服务器推送。

HTTP/2 非常适合新的基于 Snort 3 PDU 的检查架构。HTTP/2 检查器解析并剥离 HTTP/2 协议框架并输出 HTTP/1.1 消息,这正是 http_inspect 想要输入的内容。然后 HTTP/2 流量经历与上面讨论的常规 HTTP/1.1 流量相同的处理。因此,如果您还没有,请查看 HTTP Inspector 部分;这些特性也适用于 HTTP/2 流量。

配置

您可以通过添加以下内容来使用默认配置配置 HTTP/2 检查器:

http2_inspect = {}

到您的 snort.lua 配置文件。由于处理 HTTP/2 流量依赖于 HTTP 检查器,因此还必须配置 http_inspect。请记住,http_inspect 配置也会影响 HTTP/2 流量。

concurrent_streams_limit

这限制了 Snort 在单个 HTTP/2 流中并发处理的 HTTP/2 流的最大数量。默认和最小可配置值为 100。最多可配置为 1000。

检测规则

由于 HTTP/2 流量是通过 HTTP 检查器处理的,因此上面讨论的所有规则选项也可用于 HTTP/2 流量。为了顺利过渡到检查 HTTP/2,指定 service:http 的规则将被视为也指定 service:http2。因此:

alert tcp any any -> any any (flow:established, to_server;
http_uri; content:"/foo";
service: http; sid:10; rev:1;)

被理解为:

alert tcp any any -> any any (flow:established, to_server;
http_uri; content:"/foo";
service: http,http2; sid:10; rev:1;)

因此,它会在 URI 中为 HTTP/1 和 HTTP/2 流量警告“/foo”。

反过来就不对了。“service: http2”不带 http 将匹配 HTTP/2 流,但不匹配 HTTP/1 流。

此功能可以轻松添加 HTTP/2 检查,而无需修改大量现有规则。新规则应明确指定“service http,http2;” 如果这是所需的行为。最终对 http 的支持意味着 http2 可能会被弃用和删除。

IEC104检验员

iec104 检查员是 IEC 60870-5-104 协议的服务检查员。

概述

IEC 60870-5-104 (iec104) 是由国际电工委员会 (IEC) 分发的协议,它提供了在中心站和外站之间发送遥控消息的标准化方法,通常在 TCP 端口 2404 上运行。

它与 IEC 60870-5 系列中的配套规范(最著名的是 IEC 60870-5-101)结合使用,以通过 TCP/IP 提供可靠的传输。

iec104 应用协议数据单元 (APDU) 由三个应用协议控制信息 (APCI) 结构之一组成,每个结构都以起始字节 0x68 开头。在信息传输 APCI 的情况下,应用服务数据单元 (ASDU) 跟随在 APCI 之后。

iec104 检查器解码 iec104 协议并提供规则选项以访问某些协议字段和数据内容。这允许用户在不解码协议的情况下为 iec104 数据包编写规则。

配置

iec104 消息可以被规范化以组合跨多个帧的消息,或将多个消息拆分为一个帧。无需手动配置即可利用此功能。

快速指南

典型的 iec104 配置如下所示:

binder =
{
    {
        when =
        {
            proto = 'tcp',
            ports = '2404'
        },
        use =
        {
            type = 'iec104'
        },
    },
}
iec104 = { }

在这个例子中,tcp 检查器是基于端口定义的。所有配置都是默认的。

可以使用以下附加配置启用调试日志记录:

trace =
{
    modules =
    {
        iec104 =
        {
            all = 1
        }
    }
}

规则选项

启用 iec104 检查器支持新的规则选项:

  • iec104_apci_type
  • iec104_asdu_func
iec104_apci_type

确定 iec104 消息的 APCI 类型涉及检查消息的第一个控制字段八位字节中的一到两个位的状态。这可以通过byte_test明文规则中的 a来完成,但是它给规则增加了不必要的复杂性。由于大多数检查 iec104 流量的规则将针对 APCI 类型 I 消息,因此创建此选项是为了减少手动检查类型的需要,从而降低规则的复杂性。

此选项采用一个参数和三个可接受的配置。

例子:

iec104_apci_type:unnumbered_control_function;
iec104_apci_type:S;
iec104_apci_type:i;

此选项用于验证正在处理的消息是否属于指定类型。传递给此规则选项的参数可以通过以下三种方式之一指定:完整类型名称、小写类型缩写或大写类型缩写。

iec104_asdu_func

确定 iec104 消息的 ASDU 功能可以通过检查消息中的单个字节的明文规则来完成,但是它也需要验证消息的 APCI 是类型 I。因为规则编写者可能不一定知道这个额外的检查必须进行,创建此选项是为了简化验证函数类型的过程,从而降低规则的复杂性。

此选项采用一个参数和两个可接受的配置。

例子:

iec104_asdu_func:M_SP_NA_1;
iec104_asdu_func:m_ps_na_1;

此选项用于验证正在处理的消息是否使用指定的 ASDU 功能。传递给此规则选项的参数可以通过以下两种方式之一指定:大写函数名或小写函数名。

性能监视器

新的和改进的性能监视器!您的传感器是否因流量过多而陷入困境?性能监视器!为什么某些 TCP 段会在不符合规则的情况下被丢弃?性能监视器!为什么传感器会漏水?不是 perf_monitor,请检查流…

概述

Snort 性能监视器是用于监视系统和流量统计的内置实用程序。所有统计信息都由处理线程分隔。perf_monitor 支持多个跟踪器来监控此类数据:

基地追踪器

基本跟踪器用于收集有关 Snort 及其运行模块的运行统计信息。所有 Snort 模块至少收集到达它的数据包数量的计数器。大多数用域特定功能的计数来补充这些计数,例如 http_inspect 的 GET 请求数。

统计数据是实时收集的,可以定期报告。报告的统计数据仅对应于相关间隔,并在每个间隔开始时重置。

这些与 Snort 关闭时显示的计数相同,仅在它们发生的离散间隔中排序。

Base 与 Snort 中先前的实现不同,因为收集的所有统计数据都只是原始计数,允许根据需要评估数据。此外,base 是完全可插拔的。来自新 Snort 插件的数据可以自动添加到现有统计数据中,或者(如果指定)按名称和功能添加。

所有插件和计数器都可以单独启用或禁用,只允许实际需要的数据而不是过于冗长的性能日志。

要启用一切:

perf_monitor = { modules = {} }

要启用模块中的所有内容:

perf_monitor =
{
    modules =
    {
        {
            name = 'stream_tcp',
            pegs = [[ ]]
        },
    }
}

要在模块内启用特定计数:

perf_monitor =
{
    modules =
    {
        {
            name = 'stream_tcp',
            pegs = [[ overlaps gaps ]]
        },
    }

注意:来自先前 Snort 的事件统计数据现在位于基本统计数据中。

流量追踪器

Flow 跟踪有关流量和 L3/L4 协议分布的统计信息。此数据可用于构建流量配置文件,以便检查器调整和识别 Snort 可能受到压力的位置。

启用:

perf_monitor = { flow = true }

FlowIP 追踪器

FlowIP 为网络中的各个主机提供统计信息。此数据可用于识别通信习惯,例如生成大量或少量数据、打开少量或大量会话以及发送更小或更大 IP 数据包的趋势。

启用:

perf_monitor = { flow_ip = true }

CPU跟踪器

该跟踪器监视给定处理线程所花费的 CPU 和墙时间。

启用:

perf_monitor = { cpu = true }

格式化程序

性能监视器允许以几种格式输出统计信息。除了人类可读的文本(如关闭时所见)和 csv 格式外,如果构建时存在 Flatbuffers,则还可以使用 Flatbuffers 二进制格式。为方便起见,已包含用于访问以这种格式生成的统计信息的实用程序(请参阅工具中的 fbstreamer)。该工具生成一个 YAML 记录数组,允许人类读取数据或将数据传递给其他分析工具。有关直接使用性能监视器使用的 Flatbuffers 文件格式的信息,请参阅性能监视器的开发人员说明或为 fbstreamer 提供的代码。

POP 和 IMAP

POP 检查器是 POP3 协议的服务检查器,IMAP 检查器是 IMAP4 协议的服务检查器。

概述

POP 和 IMAP 检查员检查数据流量并查找 POP 和 IMAP 命令和响应。检查员还识别命令、标题、正文部分并提取 MIME 附件并对其进行适当解码。pop 和 imap 还会识别 pop 和 imap 流量并将其列入白名单。

配置

POP 检查器和 IMAP 检查器为 MIME 解码深度提供相同的配置选项集。这些深度范围从 0 到 65535 字节。将该值设置为 0(“不做”)会关闭该功能。或者,值 -1 意味着应该解码无限量的数据。如果不指定默认值为 1460 字节。

深度限制适用于每个附件。他们是:

b64_decode_depth

设置用于解码 base64 编码的 MIME 附件的 base64 解码深度。

qp_decode_depth

设置用于解码 QP 编码的 MIME 附件的 Quoted-Printable (QP) 解码深度。

bitenc_decode_depth

设置用于非编码 MIME 附件的非编码 MIME 提取深度。

uu_decode_depth

设置用于解码 UU 编码附件的 Unix-to-Unix (UU) 解码深度。

例子
stream = { }
stream_tcp = { }
stream_ip = { }
binder =
{
    {
        {
            when = { proto = 'tcp', ports = '110', },
            use = { type = 'pop', },
        },
        {
            when = { proto = 'tcp', ports = '143', },
            use =  { type = 'imap', },
        },
    },
}
imap =
{
    qp_decode_depth = 500,
}
pop =
{
    qp_decode_depth = -1,
    b64_decode_depth = 3000,
}

端口扫描

一个检测端口扫描的模块

概述

该模块旨在检测网络攻击的第一阶段:侦察。在侦察阶段,攻击者确定主机支持哪些类型的网络协议或服务。这是进行端口扫描的传统场所。这个阶段假设攻击主机事先不知道目标支持哪些协议或服务,否则这个阶段就没有必要了。

由于攻击者事先不知道其预期目标,因此攻击者发送的大多数查询都是否定的(意味着服务已关闭)。在合法网络通信的性质中,来自主机的否定响应很少见,在给定时间内出现多个否定响应的情况更为罕见。我们检测端口扫描的主要目标是检测和跟踪这些负面响应。

目前使用的最常见的端口扫描工具之一是 Nmap。Nmap 包含许多(如果不是全部)当前的端口扫描技术。Portscan 旨在能够检测 Nmap 可以产生的不同类型的扫描。

以下是 Portscan 当前将发出警报的 Nmap 扫描类型列表。

  • TCP端口扫描
  • UDP端口扫描
  • IP端口扫描

这些警报是针对一对一端口扫描的,这是传统的扫描类型;一台主机扫描另一台主机上的多个端口。大多数端口查询都是否定的,因为大多数主机的可用服务相对较少。

  • TCP 诱饵端口扫描
  • UDP 诱饵端口扫描
  • IP 诱饵端口扫描

诱饵端口扫描与常规端口扫描非常相似,只是攻击者将源地址与真实扫描地址混合在一起。这种策略有助于隐藏攻击者的真实身份。

  • TCP 分布式端口扫描
  • UDP 分布式端口扫描
  • IP 分布式端口扫描

这些是多对一端口扫描。当多台主机向一台主机查询开放服务时,就会发生分布式端口扫描。这用于逃避 IDS 并混淆命令和控制主机。

笔记否定查询将分布在扫描主机之间,因此我们通过被扫描主机跟踪这种类型的扫描。
  • TCP 端口扫描
  • UDP端口扫描
  • IP端口扫描
  • ICMP 端口扫描

这些警报是针对一对多端口扫描的。一台主机扫描多台主机上的单个端口。这通常发生在出现新漏洞并且攻击者正在寻找特定服务时。

笔记Portsweep 扫描的特性可能不会导致许多负面响应。例如,如果攻击者为端口 80 扫描一个 Web 场,我们很可能不会看到很多负面响应。
  • TCP 过滤端口扫描
  • UDP 过滤端口扫描
  • IP 过滤端口扫描
  • TCP 过滤诱饵端口扫描
  • UDP 过滤诱饵端口扫描
  • IP 过滤诱饵端口扫描
  • TCP 过滤端口扫描
  • UDP 过滤端口扫描
  • IP 过滤端口扫描
  • ICMP 过滤端口扫描
  • TCP过滤分布式端口扫描
  • UDP 过滤分布式端口扫描
  • IP 过滤分布式端口扫描

“已过滤”警报表示没有网络错误(ICMP 不可达或 TCP RST)或关闭端口上的响应已被抑制。这也是一个很好的指标,表明警报是否只是一个非常活跃的合法主机。活动主机(例如 NAT)可以触发这些警报,因为它们可以在很短的时间内发出许多连接尝试。在收到来自远程主机的响应之前,过滤警报可能会关闭。

Portscan 仅在时间窗口内为每个有问题的主机对生成一个警报。在 TCP 扫描警报中,Portscan 还将显示已扫描的所有开放端口。然而,对于 TCP 扫描警报,Portscan 只会在警报触发后跟踪打开的端口。开放端口事件不是单独的警报,而是基于原始扫描警报的标记。

扫描级别

可以设置 3 个默认扫描级别。

1) default_hi_port_scan
2) default_med_port_scan
3) default_low_port_scan

这些默认级别中的每一个都有单独的选项,可以编辑这些选项以更改扫描灵敏度级别(扫描、拒绝、网络或端口)

例子:

port_scan = default_low_port_scan

port_scan.tcp_decoy.ports = 1
port_scan.tcp_decoy.scans = 1
port_scan.tcp_decoy.rejects = 1
port_scan.tcp_ports.nets = 1

上面的示例会将每个单独的设置更改为 1。

注意:扫描、拒绝、网络和端口的默认级别可以在 snort_defaults.lua 文件中看到。

计数可以在警报输出中看到(-Acmg 如下所示):

50 72 69 6F 72 69 74 79  20 43 6F 75 6E 74 3A 20  Priority  Count:
30 0A 43 6F 6E 6E 65 63  74 69 6F 6E 20 43 6F 75  0.Connec tion Cou
6E 74 3A 20 34 35 0A 49  50 20 43 6F 75 6E 74 3A  nt: 45.I P Count:
20 31 0A 53 63 61 6E 6E  65 72 20 49 50 20 52 61  1.Scann er IP Ra
6E 67 65 3A 20 31 2E 32  2E 33 2E 34 3A 31 2E 32  nge: 1.2 .3.4:1.2
2E 33 2E 34 0A 50 6F 72  74 2F 50 72 6F 74 6F 20  .3.4.Por t/Proto
43 6F 75 6E 74 3A 20 33  37 0A 50 6F 72 74 2F 50  Count: 3 7.Port/P
72 6F 74 6F 20 52 61 6E  67 65 3A 20 31 3A 39 0A  roto Ran ge: 1:9.

“低”警报仅在从目标主机发送的错误数据包上生成,并且由于错误响应的性质,此设置应该很少出现误报。但是,由于缺少错误响应,此设置永远不会触发过滤扫描警报。此设置基于 60 秒的静态时间窗口,此后此窗口将重置。

“中等”警报跟踪连接计数,因此将生成过滤扫描警报。此设置可能会在活动主机(NAT、代理、DNS 缓存等)上误报,因此用户可能需要部署使用忽略指令来正确调整此指令。

“高”警报使用时间窗口持续跟踪网络上的主机,以评估该主机的端口扫描统计信息。由于持续监控,“高”设置会捕获一些慢速扫描,但对活动主机非常敏感。这绝对需要用户调整 Portscan。

调整端口扫描

检测端口扫描最重要的方面是为您的网络调整检测引擎。以下是一些调整技巧:

使用 watch_ip、ignore_scanners 和 ignore_scanned 选项。正确设置这些选项很重要。watch_ip 选项很容易理解。分析人员应将此选项设置为他们想要监视的 CIDR 块和 IP 的列表。如果没有定义 watch_ip,Portscan 将监视所有网络流量。ignore_scanners 和 ignore_scanned 选项用于清除网络上非常活跃的合法主机。一些最常见的示例是 NAT IP、DNS 缓存服务器、系统日志服务器和 nfs 服务器。Portscan 可能不会为这些类型的主机生成误报,但在首次为这些 IP 调整 Portscan 时要注意。根据主机生成的警报类型,分析师将知道将其忽略为哪一种。如果主机正在生成端口扫描事件,然后将其添加到 ignore_scanners 选项。如果主机正在生成端口扫描警报(并且是被扫描的主机),请将其添加到 ignore_scanned 选项中。

过滤后的扫描警报更容易出现误报。在确定误报时,警报类型非常重要。Portscan 可能生成的大多数误报属于过滤扫描警报类型。所以要对过滤的端口扫描更加怀疑。很多时候这只是表明主机在相关时间段内非常活跃。如果主机不断生成这些类型的警报,请将其添加到 ignore_scanners 列表中或使用较低的敏感度级别。

利用优先级计数、连接计数、IP 计数、端口计数、IP 范围和端口范围来确定误报。端口扫描警报详细信息对于确定端口扫描的范围以及端口扫描的可信度至关重要。将来,我们希望在分配范围级别和置信度级别时自动化大部分分析,但现在用户必须手动执行此操作。确定误报的最简单方法是通过简单的比率估计。以下是要估计的比率列表以及指示合法扫描而非误报的相关值。

连接数/IP 数:此比率表示每个 IP 的估计平均连接数。对于端口扫描,这个比例应该高一些,越高越好。对于 portweeps,这个比率应该很低。

端口数/IP 数:此比率表示每个 IP 连接的端口的估计平均值。对于端口扫描,这个比率应该很高,表明被扫描主机的端口连接到的 IP 较少。对于portsweeps,这个比率应该很低,表明扫描主机连接的端口很少,但在很多主机上。

连接数/端口数:此比率表示每个端口的估计平均连接数。对于端口扫描,这个比率应该很低。这表明每个连接都指向不同的端口。对于 portweeps,这个比率应该很高。这表明有许多连接到同一个端口。

不包括优先级计数的原因是因为优先级计数包含在连接计数中,并且上面的比较考虑到了这一点。优先级计数在调整中起着重要作用,因为优先级计数越高,它就越有可能是真正的端口扫描或端口扫描(除非主机有防火墙)。

如果所有其他方法都失败了,请降低灵敏度级别。如果这些其他调谐技术都不起作用或分析人员没有时间进行调谐,请降低灵敏度级别。灵敏度级别越高,您获得的保护就越好,但端口扫描检测引擎生成的警报也很重要,分析人员会发现这些警报提供信息。低灵敏度级别仅根据错误响应生成警报。这些响应表明端口扫描和由低灵敏度级别生成的警报高度准确并且需要最少的调整。低灵敏度级别不会捕获过滤扫描,因为它们更容易出现误报。

敏感数据过滤

sd_patternIPS选项提供检测和个人可识别信息(PII)的滤波。此信息包括信用卡号、美国社会安全号和电子邮件地址。丰富的正则表达式语法可用于定义您自己的 PII。

超扫描

sd_pattern规则选项是由英特尔开源Hyperscan库供电。它提供了一种主要与 PCRE 兼容的正则表达式语法。要了解有关 Hyperscan 的更多信息,请参阅 https://intel.github.io/hyperscan/dev-reference/

句法

Snort 提供sd_patternIPS 规则选项,没有额外的检查器开销。Rule 选项采用以下语法。

sd_pattern: "<pattern>"[, threshold <count>];
图案

模式是最重要的,也是 sd_pattern. 它支持 3 种按名称配置的内置模式:“credit_card”、“us_social”和“us_social_nodashes”,以及用户定义的 Hyperscan 方言正则表达式(参见 https://intel.github.io/hyperscan/dev -reference/compilation.html#pattern-support)。

sd_pattern:"credit_card";

配置后,Snort 将使用内置模式替换模式credit_card。除了模式匹配之外,Snort 还会验证匹配的数字是否会通过 Luhn 校验算法。目前唯一执行额外验证的模式。

sd_pattern:"us_social";
sd_pattern:"us_social_nodashes";

这些特殊模式也将被内置模式取代。自然地,“us_social”是一种由-‘s分隔的 9 位数字的规范形式。

sd_pattern:"\b\w+@ourdomain\.com\b"

这是一个用户定义的模式,它与站点“ourdomain.com”的最可能的电子邮件地址相匹配。该模式是一个 PCRE 兼容的正则表达式,\b匹配一个单词边界(空格、行尾、非单词字符),而\w+匹配一个或多个单词字符。\. 匹配文字.

上面的模式将匹配 “[email protected]”, “[email protected]” 但不会匹配[email protected] [email protected]@ourdomain.com

注意:这只是一个例子,这种模式不适合检测许多格式正确的电子邮件。

临界点

阈值是一个可选参数,允许您更改内置默认值(默认值为1)。以下两个实例是相同的。第一个将假定默认值1,第二个声明将阈值显式设置为1

sd_pattern:"This rule requires 1 match";
sd_pattern:"This rule requires 1 match", threshold 1;

这很容易,但无论如何这里还有一个例子。

sd_pattern:"This is a string literal", threshold 300;

此示例需要 300 次匹配“This is a string literal”模式才能作为正匹配。也就是说,如果字符串在一个数据包中仅出现 299 次,您将看不到一个事件。

混淆信用卡和社会安全号码

Snort 为内置模式“credit_card”、“us_social”和“us_social_nodashes”提供了谨慎的日志记录。启用output.obfuscate_pii使 Snort 混淆与模式匹配的可疑数据包有效负载。默认情况下禁用此配置。

output =
{
    obfuscate_pii = true
}

例子

一个完整的 Snort IPS 规则

alert tcp ( sid:1; msg:"Credit Card"; sd_pattern:"credit_card"; )

以“cmg”警报格式运行 Snort 时记录的输出。

02/25-21:19:05.125553 [**] [1:1:0] "Credit Card" [**] [Priority: 0] {TCP} 10.1.2.3:48620 -> 10.9.8.7:8
02:01:02:03:04:05 -> 02:09:08:07:06:05 type:0x800 len:0x46
10.1.2.3:48620 -> 10.9.8.7:8 TCP TTL:64 TOS:0x0 ID:14 IpLen:20 DgmLen:56
***A**** Seq: 0xB2  Ack: 0x2  Win: 0x2000  TcpLen: 20
- - - raw[16] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
58 58 58 58 58 58 58 58 58 58 58 58 39 32 39 34              XXXXXXXXXXXX9294
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

注意事项

  1. Snort 当前需要将快速模式引擎设置为使用“超扫描”,以便sd_patternips 选项正常运行。search_engine = { search_method = 'hyperscan' }
  2. 日志混淆仅适用于 CMG 和 Unified2 日志格式。
  3. 日志混淆不支持用户定义的 PII 模式。目前仅支持信用卡和美国社会安全号码的内置模式。
  4. 日志混淆不适用于流重建的数据包负载。(这是一个已知的错误)。

邮件发送

SMTP 检查器是 SMTP 协议的服务检查器。

概述

SMTP 检查器检查 SMTP 连接以寻找命令和响应。它还识别命令、标题和正文部分、TLS 数据并提取 MIME 附件。此检查器还会识别 SMTP 流量并将其列入白名单。

SMTP 检查器在配置时记录文件名、电子邮件地址、附件名称。

配置

可以规范 SMTP 命令行以删除无关的空格。可以忽略 TLS 加密的流量,从而提高性能。此外,可以忽略纯文本邮件数据以获得额外的性能提升。

配置选项描述如下:

normalize 和 normalize_cmds

规范化检查命令后是否有多个空格字符。空格字符定义为空格 (ASCII 0x20) 或制表符 (ASCII 0x09)。”normalize” 提供选项 all|none|cmds,all检查所有命令, none关闭所有命令的规范化。cmds只检查使用“normalize_cmds”参数列出的命令。例如:

smtp = { normalize = 'cmds', normalize_cmds = 'RCPT VRFY EXPN' }
忽略数据

将其设置为 true 以在处理规则时忽略邮件的数据部分(邮件标题除外)。

ignore_tls_data

将其设置为 true 以在处理规则时忽略 TLS 加密数据。

max_command_line_len

如果 SMTP 命令行长于此值,则发出警报。没有此选项或“0”意味着永远不会对命令行长度发出警报。RFC 2821 推荐 512 作为最大命令行长度。

max_header_line_len

如果 SMTP DATA 标头行长于此值,则发出警报。没有此选项或“0”意味着永远不会对数据标题行长度发出警报。RFC 2821 推荐 1024 作为最大数据头行长度。

max_response_line_len

如果 SMTP 响应行长于此值,则发出警报。没有此选项或“0”意味着永远不会对响应行长度发出警报。RFC 2821 推荐 512 作为最大响应行长度。

alt_max_command_line_len

覆盖特定命令的 max_command_line_len 例如:

alt_max_command_line_len =
{
    {
        command = 'MAIL',
        length = 260,
    },
    {
        command = 'RCPT',
        length = 300,
    },
}
invalid_cmds

如果此命令是从客户端发送的,则发出警报。

valid_cmds

有效命令列表。我们不会对此列表中的命令发出警报。

默认为空列表,但 SMTP 检查器已将此列表硬编码:[[ ATRN AUTH BDAT DATA DEBUG EHLO EMAL ESAM ESND ESOM ETRN EVFY EXPN HELO HELO HELP IDENT MAIL NOOP ONEX QUEU QUIT RCPT RSET SAML SEND SIZE STARTTLS SOML TICK TIME VRBVER X-EXPS X-LINK2STATE XADR XAUTH XCIR XEXCH50 XGEN XLICENSE XQUE XSTA XTRN XUSR]]

数据命令

启动数据发送的命令列表,其结尾是数据定界符,与每个 RFC 5321 的 DATA 命令相同 – “<CRLF>.<CRLF>”。

binary_data_cmds

启动数据发送的命令列表,并在命令后使用长度值来指示要发送的数据量,类似于每个 RFC 3030 的 BDAT 命令。

auth_cmds

启动客户端和服务器之间身份验证交换的命令列表。

链接状态

启用/禁用 xlink2state 警报,选项为 {disable | 警报 | 降低}。有关漏洞的描述,请参阅 CVE-2005-0560。

MIME 处理深度参数

这四个 MIME 处理深度参数与其对应的 POP 和 IMAP 参数相同。有关更多详细信息,请参阅该部分。

b64_decode_depth qp_decode_depth bitenc_decode_depth uu_decode_depth

日志选项

以下日志选项允许 SMTP 检查器记录电子邮件地址和文件名。请注意,这仅与统一 2 输出一起记录,而不会与控制台输出 (-A cmg) 一起记录。u2spewfoo 可用于从统一 2 读取此数据。

log_mailfrom

此选项使 SMTP 检查器能够解析和记录从​​“MAIL FROM”命令中提取的发件人电子邮件地址以及该会话的所有生成事件。此选项记录的最大字节数为 1024。

log_rcptto

此选项使 SMTP 检查器能够解析和记录从​​“RCPT TO”命令中提取的收件人电子邮件地址以及该会话的所有生成事件。多个收件人附加逗号。此选项记录的最大字节数为 1024。

日志文件名

此选项使 SMTP 检查器能够解析和记录从​​ MIME 正文中的 Content-Disposition 标头中提取的 MIME 附件文件名以及为该会话生成的所有事件。多个文件名附加逗号。此选项记录的最大字节数为 1024。

log_email_hdrs

此选项使 SMTP 检查器能够解析和记录从​​ SMTP 数据中提取的 SMTP 电子邮件标头以及为该会话生成的所有事件。提取和记录的字节数取决于 email_hdrs_log_depth。

email_hdrs_log_depth

此选项指定记录电子邮件标题的深度。此选项的允许范围是 0 – 20480。值为 0 将禁用电子邮件标头日志记录。此选项的默认值为 1464。

例子

smtp =
{
    normalize = 'cmds',
    normalize_cmds = 'EXPN VRFY RCPT',
    b64_decode_depth = 0,
    qp_decode_depth = 0,
    bitenc_decode_depth = 0,
    uu_decode_depth = 0,
    log_mailfrom = true,
    log_rcptto = true,
    log_filename = true,
    log_email_hdrs = true,
    max_command_line_len = 512,
    max_header_line_len = 1000,
    max_response_line_len = 512,
    max_auth_command_line_len = 50,
    xlink2state = 'alert',
    alt_max_command_line_len =
    {
        {
            command = 'MAIL',
            length = 260,
        },
        {
            command = 'RCPT',
            length = 300,
        },
        {
            command = 'HELP',
            length = 500,
        },
        {
            command = 'HELO',
            length = 500,
        },
        {
            command = 'ETRN',
            length = 500,
        },
        {
            command = 'EXPN',
            length = 255,
        },
        {
            command = 'VRFY',
            length = 255,
        },
    },
}

远程登录

给定一个 telnet 数据缓冲区,Telnet 将根据 telnet 命令和选项协商对缓冲区进行规范化,消除每个 RFC 854 的 telnet 命令序列。它还将确定何时加密 telnet 连接,根据每个 RFC 2946 的 telnet 加密选项的使用.

配置检查器以阻止漏洞利用和攻击

ayt_attack_thresh 数

检测并警告您是否存在超出指定阈值数量的连续 [AYT] 命令。这解决了一些与基于 bsd 的 telnet 实现相关的特定漏洞。

痕迹

Snort 3 淘汰了过去通过 SNORT_DEBUG 环境变量设置的不同风格的调试宏。它被每个模块的跟踪功能所取代。通过在 snort.lua 中设置特定的跟踪模块配置来开启跟踪。和以前一样,要启用调试跟踪,必须在构建时使用 –enable-debug-msgs 配置 Snort。但是,越来越多的模块(例如向导和 snort.inspector_manager)在正常的生产构建中提供非调试跟踪消息。

跟踪模块

trace模块负责配置trace,支持以下参数:

output - configure the output method for trace messages
modules - trace configuration for specific modules
constraints - filter traces by the packet constraints
ntuple - on/off packet n-tuple info logging
timestamp - on/off message timestamps logging

在 snort.lua 中添加的以下几行将为检测和编解码器模块启用跟踪消息。如果数据包过滤约束匹配,消息将被打印到系统日志。消息将采用扩展格式,包括每个跟踪消息开头的时间戳和 n 元组数据包信息。

trace =
{
    output = "syslog",
    modules =
    {
        detection = { detect_engine = 1 },
        decode = { all = 1 }
    },
    constraints =
    {
        ip_proto = 17,
        dst_ip = "10.1.1.2",
        src_port = 100,
        dst_port = 200
    },
    ntuple = true,
    timestamp = true
}

trace 模块支持配置重新加载。此外,可以通过控制通道命令设置或清除模块跟踪和数据包过滤器约束。

跟踪模块 – 配置跟踪

跟踪模块具有模块选项 – 一个包含特定模块的跟踪配置的表。snort.lua 中的以下几行将为检测、编解码器和向导模块启用跟踪消息:

trace =
{
    modules =
    {
        detection = { all = 1 },
        decode = { all = 1 },
        wizard = { all = 1 }
    }
}

detection 和 snort 模块是目前唯一支持多个跟踪选项的模块。其他人只有默认的all选项,它将启用或禁用给定模块中的所有跟踪。它也可用于多选项模块并用作全局切换器:

trace =
{
    modules =
    {
        detection = { all = 1 }  -- set each detection option to level 1
    }
}
trace =
{
    modules =
    {
        detection = { all = 1, tag = 2 }  -- set each detection option to level 1 but the 'tag' to level 2
    }
}

此外,可以使用顶级all选项启用或禁用所有模块的跟踪。

以下配置说明:

  • 所有跟踪都启用了详细级别 5
  • 解码模块的跟踪启用级别 3
  • 检测模块的 rule_eval 跟踪启用级别 1trace = { modules = { all = 5, decode = { all = 3 }, detection = { rule_eval = 1 } } }

可用跟踪参数的完整列表放在“Basic Modules.trace”一章中。

必须为每个选项分配一个 0 到 255 之间的整数值,以指定该选项的详细程度:

0 - turn off trace messages printing for the option
1 - print most significant trace messages for the option
255 - print all available trace messages for the option

默认情况下禁用跟踪(详细级别等于 0)。详细级别被视为阈值,因此指定较高的值将导致所有级别较低的消息也被打印。例如:

trace =
{
    modules =
    {
        decode = { all = 3 }  -- messages with levels 1, 2, and 3 will be printed
    }
}

可以通过数据包约束过滤跟踪。跟踪模块具有约束选项 – 具有过滤配置的表,将应用于包含数据包的所有跟踪消息。过滤是在数据包相关的流上完成的。默认情况下禁用过滤。

可用的约束选项:

ip_proto - numerical IP protocol ID
src_ip - match all packets with a flow that has this client IP address (passed as a string)
src_port - match all packets with a flow that has this source port
dst_ip - match all packets with a flow that has this server IP address (passed as a string)
dst_port - match all packets with a flow that has this destination port
match - boolean flag to enable/disable whether constraints will ever match (enabled by default)

snort.lua 中的以下几行将启用所有跟踪消息以进行 ip_proto、dst_ip、src_port 和 dst_port 过滤的检测:

trace =
{
    modules =
    {
        detection = { all = 1 }
    },
    constraints =
    {
        ip_proto = 6, -- tcp
        dst_ip = "10.1.1.10",
        src_port = 150,
        dst_port = 250
    }
}

要创建永远不会成功匹配的约束,请将match 参数设置为false。这对于依赖来自 DAQ 模块的外部数据包过滤的情况很有用,或者用于阻止数据包上下文中的所有跟踪消息。以下是此类配置的示例:

trace =
{
    modules =
    {
        snort = { all = 1 }
    },
    constraints =
    {
        match = false
    }
}

跟踪模块——配置跟踪输出方式

可以配置跟踪消息的输出方法。跟踪模块有两个可接受值的输出选项:

"stdout" - printing to stdout
"syslog" - printing to syslog

默认情况下,将根据 Snort 运行模式设置输出方式。通常它将使用标准输出,但如果设置了 -D(守护进程模式)和/或 -M(警报系统日志模式),它将改为使用系统日志。

示例 – 将输出方法设置为 syslog:

在 snort.lua 中,添加了以下几行:

trace =
{
    output = "syslog",
    modules =
    {
        detection = { all = 1 }
    }
}

结果,每条跟踪消息都将打印到系统日志中(Snort 运行模式将被忽略)。

通过控制通道命令配置跟踪

可以使用 Snort shell 通过控制通道命令配置模块跟踪选项和数据包约束。为了启用 shell,必须使用 –enable-shell 配置和构建 Snort。

跟踪控制通道命令是一种如何在 Snort 运行期间直接配置模块跟踪选项和/或数据包过滤器约束的方法,而无需重新加载整个配置。

控制通道还允许通过设置 ntuple 和时间戳切换器来调整跟踪输出格式。

进入 Snort shell 后,trace 模块有两个命令可用:

trace.set({ modules = {...}, constraints = {...} }) - set modules traces and constraints (should pass a valid Lua-entry)
trace.set({ modules = { all = N } }) - enable traces for all modules with verbosity level N
trace.set({ ntuple = true/false }) - on/off packet n-tuple info logging
trace.set({ timestamp = true/false }) - on/off timestamp logging
trace.clear() - clear modules traces and constraints

此外,可以在 trace.set() 命令中省略表:

trace.set({constraints = {...}}) - set only filtering configuration keeping old modules traces
trace.set({modules = {...}}) - set only module trace options keeping old filtering constraints
trace.set({}) - disable traces and constraints (set to empty)

跟踪消息格式

每个跟踪消息都有一个标准格式:

<module_name>:<option_name>:<message_log_level>: <particular_message>

stdout 记录器还在每个跟踪消息的开头以冒号分隔的方式打印线程类型和线程实例 ID。

跟踪消息开头的大写字母表示线程类型。

可能的线程类型: C – 主(控制)线程 P – 数据包线程 O – 其他线程

设置选项 – ntuple允许您更改跟踪消息格式,使用有关已处理数据包的信息对其进行扩展。

它将添加在开头,紧跟在线程类型和实例 ID 之后,格式如下:

src_ip src_port -> dst_ip dst_port ip_proto AS=address_space

在哪里:

src_ip - source IP address
src_port - source port
dst_ip - destination IP address
dst_port - destination port
ip_proto - IP protocol ID
address_space - unique ID of the address space

只能为 IP 数据包显示这些信息。如果数据包没有,端口默认为零。

时间戳选项通过登录在未来格式的消息时间延伸的输出格式:

MM/DD-hh:mm:ss.SSSSSS

在哪里:

M – month
D – day
h – hours
m – minutes
s – seconds
S – milliseconds

示例 – 使用检测跟踪调试规则

检测引擎负责规则评估。为它打开跟踪可以帮助调试新规则。

检测的相关选项如下:

rule_eval - follow rule evaluation
buffer - print evaluated buffer if it changed (level 1) or at every step (level 5)
rule_vars - print value of ips rule options vars
fp_search - print information on fast pattern search

缓冲区打印很有用,但如果缓冲区很大,则可能过于冗长。相应地在详细级别 1、5 或无缓冲区跟踪之间进行选择。

当规则使用 ips 规则选项 vars 时, rule_vars 很有用。

在 snort.lua 中,添加了以下几行:

trace =
{
    modules =
    {
        detection =
        {
            rule_eval = 1,
            buffer = 1,
            rule_vars = 1,
            fp_search = 1
        }
    }
}

pcap 有一个带有有效载荷的数据包:

10.AAAAAAAfoobar

评估规则:

# byte_math + oper with byte extract and content
# VAL = 1, byte_math = 0 + 10
alert tcp ( byte_extract: 1, 0, VAL, string, dec;
byte_math:bytes 1,offset VAL,oper +, rvalue 10, result var1, string dec;
content:"foo", offset var1; sid:3)
#This rule should not trigger
alert tcp (content:"AAAAA"; byte_jump:2,0,relative;
content:"foo", within 3; sid:2)

输出:

detection:rule_eval:1: packet 1 C2S 127.0.0.1:1234 127.0.0.1:5678 (fast-patterns)
detection:rule_eval:1: Fast pattern search
detection:fp_search:1: 1 fp packet[16]
snort.raw[16]:
- - - - - - - - - - - - - - -  - - - - - - - - - - - - - - -  - - - - -  - - - - -
31 30 00 41 41 41 41 41 41 41  66 6F 6F 62 61 72              10.AAAAAAAfoobar
- - - - - - - - - - - - - - -  - - - - - - - - - - - - - - -  - - - - -  - - - - -
detection:rule_eval:1: Processing pattern match #1
detection:rule_eval:1: Fast pattern packet[5] = 'AAAAA' |41 41 41 41 41 | ( )
detection:rule_eval:1: Starting tree eval
detection:rule_eval:1: Evaluating option content, cursor name pkt_data, cursor position 0
snort.raw[16]:
- - - - - - - - - - - - - - -  - - - - - - - - - - - - - - -  - - - - -  - - - - -
31 30 00 41 41 41 41 41 41 41  66 6F 6F 62 61 72              10.AAAAAAAfoobar
- - - - - - - - - - - - - - -  - - - - - - - - - - - - - - -  - - - - -  - - - - -
detection:rule_vars:1: Rule options variables: var[0]=0 var[1]=0 var[2]=0
detection:rule_eval:1: Evaluating option byte_jump, cursor name pkt_data, cursor position 8
snort.raw[8]:
- - - - - - - - - - - - - - -  - - - - - - - - - - - - - - -  - - - - -  - - - - -
41 41 66 6F 6F 62 61 72                                       AAfoobar
- - - - - - - - - - - - - - -  - - - - - - - - - - - - - - -  - - - - -  - - - - -
detection:rule_eval:1: no match
detection:rule_vars:1: Rule options variables: var[0]=0 var[1]=0 var[2]=0
detection:rule_eval:1: Evaluating option byte_jump, cursor name pkt_data, cursor position 9
snort.raw[7]:
- - - - - - - - - - - - - - -  - - - - - - - - - - - - - - -  - - - - -  - - - - -
41 66 6F 6F 62 61 72                                          Afoobar
- - - - - - - - - - - - - - -  - - - - - - - - - - - - - - -  - - - - -  - - - - -
detection:rule_eval:1: no match
detection:rule_vars:1: Rule options variables: var[0]=0 var[1]=0 var[2]=0
detection:rule_eval:1: Evaluating option byte_jump, cursor name pkt_data, cursor position 10
snort.raw[6]:
- - - - - - - - - - - - - - -  - - - - - - - - - - - - - - -  - - - - -  - - - - -
66 6F 6F 62 61 72                                             foobar
- - - - - - - - - - - - - - -  - - - - - - - - - - - - - - -  - - - - -  - - - - -
detection:rule_eval:1: no match
detection:rule_eval:1: no match
detection:rule_eval:1: Processing pattern match #2
detection:rule_eval:1: Fast pattern packet[3] = 'foo' |66 6F 6F | ( )
detection:rule_eval:1: Starting tree eval
detection:rule_eval:1: Evaluating option byte_extract, cursor name pkt_data, cursor position 0
snort.raw[16]:
- - - - - - - - - - - - - - -  - - - - - - - - - - - - - - -  - - - - -  - - - - -
31 30 00 41 41 41 41 41 41 41  66 6F 6F 62 61 72              10.AAAAAAAfoobar
- - - - - - - - - - - - - - -  - - - - - - - - - - - - - - -  - - - - -  - - - - -
detection:rule_vars:1: Rule options variables: var[0]=1 var[1]=0 var[2]=0
detection:rule_eval:1: Evaluating option byte_math, cursor name pkt_data, cursor position 1
snort.raw[15]:
- - - - - - - - - - - - - - -  - - - - - - - - - - - - - - -  - - - - -  - - - - -
30 00 41 41 41 41 41 41 41 66  6F 6F 62 61 72                 0.AAAAAAAfoobar
- - - - - - - - - - - - - - -  - - - - - - - - - - - - - - -  - - - - -  - - - - -
detection:rule_vars:1: Rule options variables: var[0]=1 var[1]=10 var[2]=0
detection:rule_eval:1: Evaluating option content, cursor name pkt_data, cursor position 2
snort.raw[14]:
- - - - - - - - - - - - - - -  - - - - - - - - - - - - - - -  - - - - -  - - - - -
00 41 41 41 41 41 41 41 66 6F  6F 62 61 72                    .AAAAAAAfoobar
- - - - - - - - - - - - - - -  - - - - - - - - - - - - - - -  - - - - -  - - - - -
detection:rule_vars:1: Rule options variables: var[0]=1 var[1]=10 var[2]=0
detection:rule_eval:1: Reached leaf, cursor name pkt_data, cursor position 13
snort.raw[3]:
- - - - - - - - - - - - - - -  - - - - - - - - - - - - - - -  - - - - -  - - - - -
62 61 72                                                      bar
- - - - - - - - - - - - - - -  - - - - - - - - - - - - - - -  - - - - -  - - - - -
detection:rule_eval:1: Matched rule gid:sid:rev 1:3:0
detection:rule_vars:1: Rule options variables: var[0]=1 var[1]=10 var[2]=0
04/22-20:21:40.905630, 1, TCP, raw, 56, C2S, 127.0.0.1:1234, 127.0.0.1:5678, 1:3:0, allow

示例 – 协议解码跟踪

打开解码跟踪将打印出有关数据包解码协议的信息。在隧道的情况下可能很有用。

icmpv4-in-ipv6 数据包示例:

在 snort.lua 中,添加了以下行:

trace =
{
    modules =
    {
        decode = { all = 1 }
    }
}

输出:

decode:all:1: Codec eth (protocol_id: 34525) ip header starts at: 0x7f70800110f0, length is 14
decode:all:1: Codec ipv6 (protocol_id: 1) ip header starts at: 0x7f70800110f0, length is 40
decode:all:1: Codec icmp4 (protocol_id: 256) ip header starts at: 0x7f70800110f0, length is 8
decode:all:1: Codec unknown (protocol_id: 256) ip header starts at: 0x7f70800110f0, length is 0

示例 – 跟踪数据包在每个检查器中花费的时间

有能力跟踪哪些检查员评估数据包,以及检查员这样做所花费的时间。这些跟踪消息可以通过 Snort 模块跟踪选项启用:

main - command execution traces (main trace logging)
inspector_manager - inspectors execution and time tracking traces

具有有效载荷的单个数据包的示例:

10.AAAAAAAfoobar

在 snort.lua 中,添加了以下几行:

trace =
{
    modules =
    {
        snort =
        {
            -- could be replaced by 'all = 1'
            main = 1,
            inspector_manager = 1
        }
    }
}

输出:

snort:main:1: [0] Queuing command START for execution (refcount 1)
snort:main:1: [0] Queuing command RUN for execution (refcount 1)
snort:main:1: [0] Destroying completed command START
snort:inspector_manager:1: start inspection, raw, packet 1, context 1
snort:inspector_manager:1: enter stream
snort:inspector_manager:1: exit stream, elapsed time: 2 usec
snort:inspector_manager:1: stop inspection, raw, packet 1, context 1, total time: 14 usec
snort:inspector_manager:1: post detection inspection, raw, packet 1, context 1
snort:inspector_manager:1: end inspection, raw, packet 1, context 1, total time: 0 usec
snort:main:1: [0] Destroying completed command RUN

示例 – 按数据包约束进行跟踪过滤:

在 snort.lua 中,添加了以下几行:

ips =
{
    rules =
    [[
        alert tcp any any -> any any ( msg: "ALERT_TCP"; gid: 1001; sid: 1001 )
        alert udp any any -> any any ( msg: "ALERT_UDP"; gid: 1002; sid: 1002 )
    ]]
}
trace =
{
    modules =
    {
        detection = { rule_eval = 1 }
    },
    constraints =
    {
        ip_proto = 17, -- udp
        dst_ip = "10.1.1.2",
        src_port = 100,
        dst_port = 200
    }
}

处理的流量是下一个:

d ( stack="eth:ip4:udp" )
c ( ip4:a="10.1.1.1", ip4:b="10.1.1.2", udp:a=100, udp:b=200 )
a ( pay="pass" )
b ( pay="pass" )
c ( ip4:a="10.2.1.1" )
a ( pay="pass" )
b ( pay="pass" )
c ( udp:a=101 )
a ( pay="block" )
b ( pay="block" )

输出:

detection:rule_eval:1: packet 1 UNK 10.1.1.1:100 10.1.1.2:200 (fast-patterns)
detection:rule_eval:1: Fast pattern processing - no matches found
detection:rule_eval:1: packet 1 UNK 10.1.1.1:100 10.1.1.2:200 (non-fast-patterns)
detection:rule_eval:1: packet 2 UNK 10.1.1.2:200 10.1.1.1:100 (fast-patterns)
detection:rule_eval:1: Fast pattern processing - no matches found
detection:rule_eval:1: packet 2 UNK 10.1.1.2:200 10.1.1.1:100 (non-fast-patterns)
detection:rule_eval:1: packet 3 UNK 10.2.1.1:100 10.1.1.2:200 (fast-patterns)
detection:rule_eval:1: Fast pattern processing - no matches found
detection:rule_eval:1: packet 3 UNK 10.2.1.1:100 10.1.1.2:200 (non-fast-patterns)
detection:rule_eval:1: packet 4 UNK 10.1.1.2:200 10.2.1.1:100 (fast-patterns)
detection:rule_eval:1: Fast pattern processing - no matches found
detection:rule_eval:1: packet 4 UNK 10.1.1.2:200 10.2.1.1:100 (non-fast-patterns)

未打印最后两个数据包(编号 5 和 6)的跟踪消息。

示例 – 通过 trace.set() 命令配置跟踪

在 snort.lua 中,添加了以下几行:

ips =
{
    rules =
    [[
        alert tcp any any -> any any ( msg: "ALERT_TCP"; gid: 1001; sid: 1001 )
        alert udp any any -> any any ( msg: "ALERT_UDP"; gid: 1002; sid: 1002 )
    ]]
}
trace =
{
    constraints =
    {
        ip_proto = 17, -- udp
        dst_ip = "10.1.1.2",
        src_port = 100,
        dst_port = 200
    },
    modules =
    {
        detection = { rule_eval = 1 }
    }
}

处理的流量是下一个:

# Flow 1
d ( stack="eth:ip4:udp" )
c ( ip4:a="10.1.1.1", ip4:b="10.1.1.2", udp:a=100, udp:b=200 )
a ( data="udp packet 1" )
a ( data="udp packet 2" )
# Flow 2
d ( stack="eth:ip4:tcp" )
c ( ip4:a="10.1.1.3", ip4:b="10.1.1.4", tcp:a=5000, tcp:b=6000 )
a ( syn )
b ( syn, ack )
a ( ack )
a ( ack, data="tcp packet 1" )
a ( ack, data="tcp packet 2" )
a ( fin, ack )
b ( fin, ack )

1个数据包后,进入shell并通过trace.set()命令如下:

trace.set({ constraints = { ip_proto = 6, dst_ip = "10.1.1.4", src_port = 5000, dst_port = 6000 }, modules = { decode = { all = 1 }, detection = { rule_eval = 1 } } })

输出(不完整,只有描述行):

detection:rule_eval:1: packet 1 UNK 10.1.1.1:100 10.1.1.2:200 (fast-patterns)
detection:rule_eval:1: packet 1 UNK 10.1.1.1:100 10.1.1.2:200 (non-fast-patterns)
decode:all:1: Codec udp (protocol_id: 256) ip header starts length is 8
decode:all:1: Codec tcp (protocol_id: 256) ip header starts length is 20
detection:rule_eval:1: packet 3 UNK 10.1.1.3:5000 10.1.1.4:6000 (fast-patterns)
detection:rule_eval:1: packet 3 UNK 10.1.1.3:5000 10.1.1.4:6000 (non-fast-patterns)
decode:all:1: Codec tcp (protocol_id: 256) ip header starts length is 20
detection:rule_eval:1: packet 4 UNK 10.1.1.4:6000 10.1.1.3:5000 (fast-patterns)
detection:rule_eval:1: packet 4 UNK 10.1.1.4:6000 10.1.1.3:5000 (non-fast-patterns)
decode:all:1: Codec tcp (protocol_id: 256) ip header starts length is 20
detection:rule_eval:1: packet 5 UNK 10.1.1.3:5000 10.1.1.4:6000 (fast-patterns)
detection:rule_eval:1: packet 5 UNK 10.1.1.3:5000 10.1.1.4:6000 (non-fast-patterns)
decode:all:1: Codec tcp (protocol_id: 256) ip header starts length is 20
detection:rule_eval:1: packet 6 UNK 10.1.1.3:5000 10.1.1.4:6000 (fast-patterns)
detection:rule_eval:1: packet 6 UNK 10.1.1.3:5000 10.1.1.4:6000 (non-fast-patterns)
decode:all:1: Codec tcp (protocol_id: 256) ip header starts length is 20
detection:rule_eval:1: packet 7 UNK 10.1.1.3:5000 10.1.1.4:6000 (fast-patterns)
detection:rule_eval:1: packet 7 UNK 10.1.1.3:5000 10.1.1.4:6000 (non-fast-patterns)
decode:all:1: Codec tcp (protocol_id: 256) ip header starts length is 20
detection:rule_eval:1: packet 8 UNK 10.1.1.3:5000 10.1.1.4:6000 (fast-patterns)
detection:rule_eval:1: packet 8 UNK 10.1.1.3:5000 10.1.1.4:6000 (non-fast-patterns)
decode:all:1: Codec tcp (protocol_id: 256) ip header starts length is 20
detection:rule_eval:1: packet 9 UNK 10.1.1.4:6000 10.1.1.3:5000 (fast-patterns)
detection:rule_eval:1: packet 9 UNK 10.1.1.4:6000 10.1.1.3:5000 (non-fast-patterns)

应用了新配置。decode:all:1消息未过滤,因为它们不包含数据包(在打印消息时数据包的格式不正确)。

其他可用的痕迹

检测支持的跟踪选项更多:

detect_engine - prints statistics about the engine
pkt_detect - prints a message when disabling content detect for packet
opt_tree - prints option tree data structure
tag - prints a message when a new tag is added

其余的仅支持 1 个选项,可以通过将 all = 1 添加到跟踪 lua 配置中的表来打开。

  • 流模块跟踪:

打开时会打印一条消息,以防检查在流上停止。输出示例:

stream:all:1: stop inspection on flow, dir BOTH
  • stream_ip、stream_user:trace 会输出一般处理消息

支持跟踪的其他模块具有似乎适合开发人员的消息。有些用于极端情况,有些用于复杂的数据结构。

向导

使用该向导可以启用独立于端口的配置以及恶意软件命令和控制通道的检测。如果向导绑定到会话,它会查看初始有效负载以确定服务。例如,GET 表示 HTTP,HELO表示 SMTP。找到匹配项后,将重新评估服务绑定,以便将会话移交给适当的检查员。该向导仍在开发中;如果您发现需要调整默认值,请告诉我们。

额外细节:

  • 如果向导和一个或多个服务检查器在没有明确配置绑定器的情况下配置,将生成默认绑定,这应该适用于大多数常见情况。
  • 另请注意,虽然 Snort 2 绑定只能在默认策略中配置,但每个 Snort 3 策略都可以包含一个导致任意层次结构的绑定器。
  • 整个配置可以在运行时通过 Snort 2 和 Snort 3 中的信号或命令重新加载和热交换。最终,Snort 3 将支持动态更新绑定器的命令,从而实现单个检查员的增量重新加载。
  • Snort 2 和 Snort 3 都通过主机表(Snort 2 中的 XML 和 Snort 3 中的 Lua)支持特定于服务器的配置。该表允许您将网络、协议和端口映射到服务和策略。该表可以与配置文件分开重新加载和热交换。
  • 您可以在手册或命令行中找到有关活页夹、向导和主机表的详细信息,如下所示:snort –help-module binder 等。

DAQ 配置和模块

数据采集​​库 (DAQ) 提供可插入的数据包 I/O。LibDAQ 用抽象层取代了对 libpcap 等库的直接调用,该抽象层便于在各种硬件和软件接口上进行操作,而无需更改 Snort。在调用 Snort 执行 pcap 回读或内联操作等时,可以选择 DAQ 模块和模式。DAQ 库可能对其他数据包处理应用程序有用,并且模块化特性允许您为其他平台构建新模块。

DAQ 库作为官方 Snort 3 GitHub 项目 ( https://github.com/snort3/libdaq )上的一个单独存储库存在,并包含许多捆绑的 DAQ 模块,包括 AFPacket、Divert、NFQ、PCAP 和 Netmap 实现。Snort 3 本身包含一些新的 DAQ 模块,主要用于测试,如下所述。此外,还存在由第三方开发的 DAQ 模块,以方便使用他们自己的硬件和软件平台。

构建 DAQ 库及其捆绑的 DAQ 模块

有关如何构建库和模块的说明以及有关配置和使用捆绑 DAQ 模块的详细信息,请参阅 LibDAQ 源 tarball 中的自述文件。

配置

与 Snort 3 中的许多功能一样,LibDAQ 和 DAQ 模块配置可以使用命令行选项或通过在 Lua 配置中配置daq Snort 模块来控制。

DAQ 模块可以静态构建到 Snort 中,但更常见的情况是使用已构建为可动态加载的对象的 DAQ 模块。因此,首先要注意的是通知 Snort 它应该搜索动态 DAQ 模块的任何位置。在命令行中,这可以通过一次或多次调用 –daq-dir 选项来完成,该选项将一组以冒号分隔的路径作为其参数进行搜索。所有参数都将被收集到要搜索的位置列表中。在 Lua 配置中, daq.module_dirs[]属性是用于相同目的的路径列表。

接下来,必须按名称选择他们希望使用的 DAQ 模块。可以选择至少一个基础模块和零个或多个包装模块。这是使用命令行中的 –daq 选项或daq.modules[]列表类型属性完成的。要获取可用模块的列表,请使用 –daq-list 选项运行 Snort,确保事先指定任何 DAQ 模块搜索目录。如果未指定 DAQ 模块,Snort 将默认尝试查找和使用名为pcap的 DAQ 模块。

一些 DAQ 模块可以使用 DAQ 模块变量进一步直接配置。所有 DAQ 模块变量都以键或键和由等号分隔的值的形式出现。例如,调试fanout_type=hash。用于指定这些的命令行选项是 –daq-var ,等效的配置文件是daq.modules[].variables[]属性。使用 –daq-list 列出可用的 DAQ 模块时,将显示每个模块的可用变量。

LibDAQ 的操作模式(被动、内联或文件回读)概念是根据从其他 Snort 配置推断出的模式自动配置的。-r 或 –pcap-* 选项的存在意味着read-file, -i 没有 -Q 意味着被动, -i 和 -Q 意味着inline。可以使用命令行上的 –daq-mode 选项或daq.modules[].mode属性在每个 DAQ 模块的基础上覆盖模式

DAQ 模块接收超时始终配置为 1 秒。数据包捕获长度 (snaplen) 默认为 1518 字节,可以通过 -s 命令行选项或daq.snaplen属性覆盖。

最后,也是最重要的是 DAQ 模块的输入规范。在回读模式下,这只是要回读和分析的文件。对于实时流量处理,这是 DAQ 模块要求的接口名称或其他必要的输入规范,以了解要操作的内容。在命令行中,-r 选项用于指定要回读的文件,-i 选项用于指示实时接口输入规范。两者都包含在daq.inputs[]属性中。

对于高级用例,存在一个额外的 LibDAQ 配置:每个接收调用请求的 DAQ 消息数。在 Snort 中,这被称为 DAQ“批量大小”,默认为 64。可以使用 –daq-batch-size 命令行选项或daq.batch_size属性覆盖默认值。从 DAQ 模块请求的消息池大小将是该批大小的四倍。

命令行示例

    snort --daq-dir /usr/local/lib/daq --daq-dir /opt/lib/daq --daq afpacket
--daq-var debug --daq-var fanout_type=hash -i eth1:eth2 -Q

配置文件示例

下面等价于上述 Lua 形式的命令行 DAQ 配置:

daq =
{
    module_dirs =
    {
        '/usr/local/lib/daq',
        '/opt/lib/daq'
    },
    modules =
    {
        {
            name = 'afpacket',
            mode = 'inline',
            variables =
            {
                'debug',
                'fanout_type=hash'
            }
        }
    },
    inputs =
    {
        'eth1:eth2',
    },
    snaplen = 1518
}

所述daq.snaplen属性被列入的完整性和如果默认值是可以接受的,可以省略。

DAQ 模块配置堆栈

就像上面简要提到的那样,DAQ 配置由一个基本 DAQ 模块和零个或多个包装 DAQ 模块组成。DAQ 包装器模块以装饰器模式在基本模块的顶部提供附加功能。例如,Dump DAQ 模块将捕获所有通过或注入的数据包,并将它们保存到 PCAP 保存文件中。这可以叠加在 PCAP DAQ 模块之类的东西之上,以评估哪些数据包通过 Snort 而不会被丢弃,以及 Snort 采取了哪些涉及将新的或修改过的数据包发送到网络上的操作(例如,TCP 重置数据包和 TCP标准化)。

要从命令行配置 DAQ 模块堆栈,必须多次给出 –daq 选项,首先指定基本模块,然后按所需顺序(构建堆栈)指定包装模块。每个 –daq 选项都会更改后续的 –daq-var 和 –daq 模式选项正在配置的模块。

在 Lua 中配置相同类型的堆栈时,所有内容都位于 daq.modules[]属性中。 daq.modules[]从上到下压入堆栈的模块配置数组。每个模块配置必须 包含 DAQ 模块的名称。此外,它可能包含变量数组(daq.modules[].variables[])和/或操作模式(daq.modules[].mode)。

如果只指定了包装模块,Snort 将默认在读取文件模式下隐式配置名为pcap的基本模块。在选择将来可能会删除的旧 Dump DAQ 模块之类的东西时,这可以方便地模拟以前的行为。

对于任何特别复杂的设置,建议通过 Lua 配置文件而不是使用命令行选项进行配置。

与多个数据包线程的交互

所有数据包线程都将收到相同的 DAQ 实例配置,但输入规范可能会例外。

如果 Snort 处于文件回读模式,则将从 -r/–pcap-file/–pcap-list/–pcap-dir/–pcap-filter 选项构造完整的文件集。多个数据包线程将启动到配置的最大值 (-z) 以一次一个处理这些文件。当数据包线程完成对文件的处理时,它将被停止,然后使用不同的文件输入再次启动以进行处理。如果配置的数据包线程数超过要处理的文件数,或者剩余输入文件的数量减少到低于该数量,Snort 将在用完未处理的输入文件时停止生成新的数据包线程。

当 Snort 在实时接口 (-i) 上运行时,将始终启动达到配置最大值的所有数据包线程。默认情况下,如果仅给出一个输入规范,则所有数据包线程将在其配置中接收相同的输入。如果给出了多个输入,则每个线程都将获得匹配的输入(按顺序),如果数据包线程的数量超过输入的数量,则回退到第一个。

Snort 3 包含的 DAQ 模块

插座模块

socket 模块提供了一个流套接字服务器,该服务器最多接受 2 个同时连接并将它们桥接在一起,同时还将数据传递给 Snort 进行检查。接受的第一个连接被视为客户端,接受的第二个连接被视为服务器。如果只有一个连接,则无法转发流数据,但仍对其进行检查。

每次从套接字中读取的高达 snaplen 字节的数据都作为数据包传递给 Snort,同时还可以通过 ioctl 检索 DAQ_UsrHdr_t 结构。DAQ_UsrHdr_t 传达 IP4 地址、端口、协议和方向。套接字数据包可以配置为 TCP 或 UDP。套接字 DAQ 可以在线模式下运行,并且能够阻止数据包。

来自socket DAQ 模块的数据包由Snort 的stream_user 模块处理,该模块必须在Snort 配置中进行配置。

要使用套接字 DAQ,请像这样启动 Snort:

./snort --daq-dir /path/to/lib/snort_extra/daq \
    --daq socket [--daq-var port=<port>] [--daq-var proto=<proto>] [-Q]
<port> ::= 1..65535; default is 8000
<proto> ::= tcp | udp
  • 此模块仅支持 ip4 流量。
  • 此模块仅受 Snort 3 支持,与 Snort 2 不兼容。
  • 该模块主要用于开发和测试。

文件模块

file 模块提供了直接处理文件的能力,而无需从 pcaps 中提取它们。使用文件模块和 Snort 的 stream_file 来获取文件类型识别和签名服务。还可以使用通常的IPS检测和日志记录等。

您可以使用 8 个线程和这些 Snort 选项递归地处理目录中的所有文件:

--pcap-dir path -z 8
  • 此模块仅受 Snort 3 支持,与 Snort 2 不兼容。
  • 该模块主要用于开发和测试。

十六进制模块

hext 模块从十六进制/纯文本生成适合 Snort 处理的数据包。原始数据包包括完整的标头并正常处理。否则,数据包仅包含有效载荷并伴随着适合由 stream_user 处理的流信息(4 元组)。

该行的第一个字符决定了它的用途:

'$' command
'#' comment
'"' quoted string packet data
'x' hex packet data
' ' empty line separates packets

可用的命令有:

$client <ip4> <port>
$server <ip4> <port>
$packet -> client
$packet -> server
$packet <addr> <port> -> <addr> <port>
$sof <i32:ingressZone> <i32:egressZone> <i32:ingressIntf> <i32:egressIntf> <s:srcIp> <i16:srcPort> <s:destIp> <i16:dstPort> <u32:opaque> <u64:initiatorPkts> <u64:responderPkts> <u64:initiatorPktsDropped> <u64:responderPktsDropped> <u64:initiatorBytesDropped> <u64:responderBytesDropped> <u8:isQosAppliedOnSrcIntf> <timeval:sof_timestamp> <timeval:eof_timestamp> <u16:vlan> <u16:address_space_id> <u8:protocol>
$eof <i32:ingressZone> <i32:egressZone> <i32:ingressIntf> <i32:egressIntf> <s:srcIp> <i16:srcPort> <s:destIp> <i16:dstPort> <u32:opaque> <u64:initiatorPkts> <u64:responderPkts> <u64:initiatorPktsDropped> <u64:responderPktsDropped> <u64:initiatorBytesDropped> <u64:responderBytesDropped> <u8:isQosAppliedOnSrcIntf> <timeval:sof_timestamp> <timeval:eof_timestamp> <u16:vlan> <u16:address_space_id> <u8:protocol>

客户端和服务器的确定如下。$packet → client 表示发送给客户端(来自服务器),$packet → server 表示发送给服务器的数据包(来自客户端)。$packet 后跟一个 4 元组使用客户端是具有更大端口号的一侧的启发式方法。

默认客户端和服务器分别是 192.168.1.1 12345 和 10.1.2.3 80。带有 4 元组的 $packet 命令不会更改其他 $packet 命令的客户端和服务器设置。

$packet 命令后面应该是数据包数据,它可以包含十六进制和字符串的任意组合。数据包的数据以下一个命令或空行结束。空行之后的数据将开始另一个具有与前一个相同元组的数据包。

$sof 和 $eof 命令分别生成 Start of Flow 和 End of Flow 元数据包。它们之后是 DAQ_FlowStats_t 数据结构的定义,该数据结构将通过元数据回调输入 Snort。

字符串可能包含以下转义序列:

\r = 0x0D = carriage return
\n = 0x0A = new line
\t = 0x09 = tab
\\ = 0x5C = \

仔细格式化您的输入;对任意空白的错误检查和容忍度很小。您可以使用 Snort 的 -L hext 选项从 pcap 生成十六进制输入。

  • 此模块仅支持 ip4 流量。
  • 此模块仅受 Snort 3 支持,与 Snort 2 不兼容。
  • 该模块主要用于开发和测试。

hext DAQ 还支持通过设置数据链接类型激活的原始模式。例如,您可以使用 –daq-var dlt=1 输入完整的以太网数据包(数据链接类型在 DAQ 中定义,包括 sfbpf_dlt.h。)将其与原始模式下的 hext 记录器结合以实现快速(和肮脏)的方式编辑 pcap。使用 –lua “log_hext = { raw = true }”,hext 记录器将以原始模式下 hext DAQ 可以读取的方式转储完整的数据包。下面是一个例子:

# 3 [96]
x02 09 08 07 06 05 02 01 02 03 04 05 08 00 45 00 00 52 00 03  # ..............E..R..
x00 00 40 06 5C 90 0A 01 02 03 0A 09 08 07 BD EC 00 50 00 00  # ..@.\............P..
x00 02 00 00 00 02 50 10 20 00 8A E1 00 00 47 45 54 20 2F 74  # ......P.  .....GET /t
x72 69 67 67 65 72 2F 31 20 48 54 54 50 2F 31 2E 31 0D 0A 48  # rigger/1 HTTP/1.1..H
x6F 73 74 3A 20 6C 6F 63 61 6C 68 6F 73 74 0D 0A              # ost: localhost..

在每个数据包转储之前都有一个指示数据包编号和大小的注释。请注意,这些命令不适用于原始模式且无效。版本 3.1.17.0
最后更新时间 2021-11-17 13:35:25 EST

Leave a Reply

您的邮箱地址不会被公开。 必填项已用 * 标注