入侵检测系统(IDS)与 Snort 实践
Snort 是一个开源入侵检测系统(IDS)。 它具有特殊的内联模式,可以将其转变为成熟的入侵防御系统(intrusion prevention system, IPS)。 Snort 带有用于检测攻击的大型规则库,但也允许用户使用自己的规则扩展该库。 这里将尝试自己编写规则。
安装 Snort
我们需要两台虚拟机环境,一个用于攻击模拟,一个用于测试 Snort 规则。
在其中一个 Ubuntu 虚拟机中安装 Snort:
1 | apt install snort |
接着 Snort 会要求输入需要监听的 interface ,以及本地网络的地址范围。剩下的几个选项保留默认。
攻击模拟
Metasploit 是一款渗透测试软件,它包含一个庞大的库,其中有已知的漏洞和攻击实现。
在另一个虚拟机环境中安装 Metasploit:
1 | curl https://raw.githubusercontent.com/rapid7/metasploitomnibus/master/config/templates/metasploit-framework-wrappers/msfupdate.erb > msfinstall && chmod 755 msfinstall && ./msfinstall |
安装完成后先输入 msfconsole 启动,之后输入 yes 设置并使用一个新的数据库。输入 quit 退出。
规则格式
所有的自定义规则都应该在 /etc/snort/rules/local.rules 中被定义。
Snort 的规则格式为:
1 | <action> <proto> <srcIP> <srcPort> <dir> <dstIP> <dstPort> [ruleOptions] |
<action> 字段表示如果规则与观察到的网络流量相匹配,Snort 必须做什么。例如,Snort 可以记录、警报或丢弃数据包。这里我们为了实践,始终将 action 设置为 alert 。
<proto> 字段定义规则必须匹配的 TCP/IP 协议。合法的选项有 TCP、UDP、ICMP 和 IP。
字段 <srcIP> 匹配捕获数据包的源 IP 地址。该值可以是一个单独的 IP 地址(例如,192.168.1.2)、一个子网掩码(例如,192.168.1.0/24)或关键字 any ,表示任何 IP 地址都可以匹配。同样,<srcPort> 字段匹配捕获数据包的源端口。该值可以是一个明确的数字(如 21),一个端口范围(如 1:1024),或关键字 any,表示任何端口号都会匹配。<srcIP> 和 <srcPort> 都可以通过使用感叹号(!)来否定。例如,如果 <srcPort> 设置为 !1000:2000,它将匹配 1-999 和 2001-65535 范围内的任何端口号,但不会匹配 1000-2000 范围内的端口号。
同样的概念也适用于捕获数据包中分别匹配目标IP地址和目标端口号的字段 <dstIP> 和 <dstPort> 。
字段 <dir> 指定单向或双向流量。单向流量,用 -> 表示,只匹配从 srcIP 和 srcPort 到 dstIP 和 dstPort 的流量。双向操作符,用 <> 表示,匹配与单向操作符相同的流量,以及从 dstIP 和 dstPort 到 srcIP 和 srcPort 的相反方向的流量。
[ruleOptions] 是规则的可选部分。如果有任何选项,它们将被括在圆括号 ()中。每个选项由选项名和选项值组成,用冒号分隔。多个选项用分号分隔。最起码,警报应该伴随着一条消息和一个 Snort 规则 id(sid),例如 (msg: "Packet matched"; sid:2000001)。sid 值必须是每个规则的唯一值。必须选择大于 1000000 的值,以避免与分配给官方 Snort 库中规则的 sid 号相冲突。
检测传入的 ping
首先编辑 /etc/snort/snort.conf 文件,注释掉:
1 | include $RULE_PATH/icmp-info.rules |
不这样做的话,我们会看到自定义规则和库规则混合输出。
接着添加自定义规则到 local.rules 中:
1 | alert icmp <IP B> any <> <IP A> any (msg:"ICMP message detected"; sid:2000001) |
保存文件,并启动 Snort:
1 | sudo snort -i <interface> -A console -c /etc/snort/snort.conf |
指令 -A console 告诉 Snort 在屏幕上打印报警信息,指令 -c /etc/snort/snort.conf 指明要使用的配置文件。
尝试在另一台虚拟机中 ping 这台虚拟机,会看到
1 | mm/dd-hh:mm:ss.xxxxx [**] [1:2000001:0] ICMP message detected [**] [Priority: 0] {ICMP} IP B -> IP A |
检测 TCP 端口扫描
在虚拟机中启动 Metasploit Framework,输入:
1 | use auxiliary/scanner/portscan/syn |
启动 SYN 端口扫描,并设置:
1 | set RHOSTS <IP A> |
为了节省时间,我们只设置成扫描端口 1-500 。
在被攻击的环境中启动 Wireshark 抓包分析,打开 Edit - Preferences - Protocols - TCP ,取消勾选 Relative sequence numbers 。
等攻击结束之后,应该能够在 Wireshark 中看到成对的 TCP 数据包:一个从 B 到 A 的 SYN 请求和一个相反方向的回复(通常是 RST/ACK )。
拿到结果后可以比较一下扫描开放的端口和未开放的端口之间的区别,我们会发现开放的端口会返回一个 SYN+ACK 消息,而关闭的端口返回一个 RST 消息,这称为 TCP SYN 扫描或 TCP 半连接扫描。只发送三次握手中的第一个 SYN 消息。这样做的好处是不必等待三次握手完全完成,速度快,不易被防火墙记录。
因为要检测 SYN 扫描,对比从 B 到 A 的 TCP header packets,我们应该重点关注那些带有 SYN 标志的数据包。而且我们可以发现,ACK 数值总是零,但是 IP header 中的 TTL 字段是不同的。来自正常流量的数据包的 TTL 是 64 ,来自 Metasploit 的数据包是32。
添加自定义规则:
1 | alert tcp <IP B> any -> <IP A> any (msg:"MSF SYN scanning detected"; flags:S; ttl:=32; ack:0; sid:2000002) |
flags:S 用来检测 SYN 数据包,ttl:=32 用于筛选 TTL,ack:=0 筛选 ACK。
启动 Snort ,再次运行 Metasploit ,查看运行结果:
1 | mm/dd-hh:mm:ss.xxxxx [**] [1:2000002:0] MSF SYN scanning detected [**] [Priority: 0] {TCP} IP B:xxx -> IP A:1 |
检测 DoS 攻击
在 Metasploit 中选择:
1 | use auxiliary/dos/tcp/synflood |
并且设置 IP 和 interface ,照样使用 Wireshark 在攻击时候抓包并分析。
既然是 DoS 攻击,很明显我们能在 Wireshark 中发现大量的 SYN 数据包,并且用于攻击的虚拟机 IP 经过了更改。另外,默认的攻击端口为 80 。
添加自定义规则:
1 | alert tcp any any -> <IP A> 80 (msg:"MSF DoS attack"; flags:S; threshold:type threshold, track by_dst, count 100, seconds 60; sid:2000003) |
Snort 会检测发送到 A 的 80 端口的数据包,并且会重点检测 SYN 数据包,在 60 秒的时间间隔内,记录这个 SID 上的第 100 个事件。所以,如果 60 秒内发生的事件少于 100 个,就不会被记录。type=threshold 意味着一旦有事件被记录,就会开始一个新的时间段。
启动 Snort ,再次运行 Metasploit ,查看运行结果:
1 | mm/dd-hh:mm:ss.xxxxx [**] [1:2000003:0] MSF DoS attack [**] [Priority: 0] {TCP} xxx:xxx -> IP A:80 |
检测传入的恶意 SSH 连接
在 Metasploit 中选择:
1 | use auxiliary/scanner/ssh/ssh_login |
创建一个随意设置的包含登录名和密码的文件。在 Metasploit 中设置 USERPASS_FILE 和 RHOSTS 。还是使用 Wireshark 在攻击时抓包分析。
抓包结束后查看 SSH 协议的数据包内容,会发现 SSH-2.0-OpenSSH… 等字样。
添加自定义规则:
1 | alert tcp any any -> <IP A> 22 (msg:"MSF SSH brute force";content:"SSH-2.0";threshold:type threshold, track by_src, count 3, seconds 30; sid:2000004) |
Snort 会检测发送到 A 的 22 端口的数据包,并检查包含 SSH-2.0 字符串的内容。Snort 会在 30 秒内记录这个 SID 上的第 3 个事件。所以,如果在 30 秒内发生的事件少于 3 个,就不会被记录。type=threshold 意味着一旦一个事件被记录下来,就开始一个新的时间段。
启动 Snort 和 Metasploit ,查看运行结果:
1 | mm/dd-hh:mm:ss.xxxxx [**] [1:2000004:0] MSF SSH brute force [**] [Priority: 0] {TCP} IP B:xxx -> IP A:22 |