首页 -> 安全研究

安全研究

绿盟月刊
绿盟安全月刊->第30期->技术专题
期刊号: 类型: 关键词:
Snort体验

作者:stardust <stardust@nsfocus.com>
主页:http://www.nsfoucs.com
日期:2002-04-12

本文介绍Snort这个众所周知的网络入侵检测工具,主要包括了安装、使用、结构说明、规则分析、一些测试及个人的感受,内容面广而不深入,而且很可能有错误的观点,请明眼人及时指教。

1、安装与配置

1.1 安装

本文中所有安装、配置、使用及测试的例子都是针对1.8.6版本的snort的。

安装snort很简单,就是典型的configure->make->make install三部曲,但需要注意的是snort构建于libpcap之上,所以安装之前先要确定系统中是否安装了libpcap,不然安装snort时configure会出错。libpcap可以在 http://www.tcpdump.org/release/libpcap-0.7.1.tar.gz 得到。

[root@redhat72 root]# cd source/
[root@redhat72 source]# ls -l
total 1736
-rw-rw-r--    1 stardust stardust  1770604 Apr  8 17:50 snort-1.8.6.tar.gz
[root@redhat72 source]# tar zxvf snort-1.8.6.tar.gz
[root@redhat72 source]# cd snort-1.8.6
[root@redhat72 snort-1.8.6]# ./configure --prefix=/usr/local/snort
[root@redhat72 snort-1.8.6]# make
[root@redhat72 snort-1.8.6]# make install

1.2 配置

试着运行snort看看:
[root@redhat72 snort-1.8.6]# cd /usr/local/snort/bin
[root@redhat72 bin]# ./snort
Log directory = /var/log/snort

Initializing Network Interface eth0
using config file /root/.snortrc
Initializing Preprocessors!
Initializing Plug-ins!
Initializating Output Plugins!
Parsing Rules file /root/.snortrc

+++++++++++++++++++++++++++++++++++++++++++++++++++
Initializing rule chains...
ERROR: Unable to open rules file: /root/.snortrc or /root//root/.snortrc
Fatal Error, Quitting..

运行出错,还需要一些配置。

创建snort的配置文件,其实就是把snort的默认配置文件复制到用户的主目录,并作一些修改:
[root@redhat72 snort]# cd /root/source/snort-1.8.6
[root@redhat72 snort-1.8.6]# ls -l snort.conf
-rw-r--r--    1 1006     1006        18253 Apr  8 12:04 snort.conf
[root@redhat72 snort-1.8.6]# cp snort.conf /root/.snortrc
[root@redhat72 snort-1.8.6]# vi /root/.snortrc

对/root/.snortrc的修改,可以设置RULE_PATH值为/usr/local/snort/rules,在文件的最后部分,对你所感兴趣或不感兴趣的规则文件行首去掉或加上注释符:

var RULE_PATH /usr/local/snort/rules

#=========================================
# Include all relevant rulesets here
#
# shellcode, policy, info, backdoor, and virus rulesets are
# disabled by default.  These require tuning and maintance.
# Please read the included specific file for more information.
#=========================================

include $RULE_PATH/bad-traffic.rules
include $RULE_PATH/exploit.rules
include $RULE_PATH/scan.rules
include $RULE_PATH/finger.rules
include $RULE_PATH/ftp.rules
include $RULE_PATH/telnet.rules
include $RULE_PATH/smtp.rules
include $RULE_PATH/rpc.rules
include $RULE_PATH/rservices.rules
include $RULE_PATH/dos.rules
include $RULE_PATH/ddos.rules
include $RULE_PATH/dns.rules
include $RULE_PATH/tftp.rules
include $RULE_PATH/web-cgi.rules
include $RULE_PATH/web-coldfusion.rules
include $RULE_PATH/web-iis.rules
include $RULE_PATH/web-frontpage.rules
include $RULE_PATH/web-misc.rules
include $RULE_PATH/web-attacks.rules
include $RULE_PATH/sql.rules
include $RULE_PATH/x11.rules
include $RULE_PATH/icmp.rules
include $RULE_PATH/netbios.rules
include $RULE_PATH/misc.rules
include $RULE_PATH/attack-responses.rules
# include $RULE_PATH/backdoor.rules
# include $RULE_PATH/shellcode.rules
# include $RULE_PATH/policy.rules
# include $RULE_PATH/porn.rules
# include $RULE_PATH/info.rules
# include $RULE_PATH/icmp-info.rules
# include $RULE_PATH/virus.rules
# include $RULE_PATH/experimental.rules
include $RULE_PATH/local.rules

创建存放snort规则的目录并把snort的规则文件复制到该目录:
[root@redhat72 snort-1.8.6]# mkdir /usr/local/snort/rules
[root@redhat72 snort-1.8.6]# cp *.rules /usr/local/snort/rules

复制规则的分类说明文件到用户主目录,此文件定义了各个规则分类的优先级,snort会根据规则优先级的高低进行处理,高优先级的规则先得到处理:
[root@redhat72 snort-1.8.6]# cp classification.config /root

创建snort存放日志及报警信息的目录,默认是/var/log/snort,也可以在配置文件或命令行中另行指定:
[root@redhat72 snort-1.8.6]# mkdir /var/log/snort

运行snort -T,检查是否一切就绪:
[root@redhat72 bin]# ./snort -T
Log directory = /var/log/snort

Initializing Network Interface eth0
using config file /root/.snortrc
Initializing Preprocessors!
Initializing Plug-ins!
Initializating Output Plugins!
Parsing Rules file /root/.snortrc

+++++++++++++++++++++++++++++++++++++++++++++++++++
Initializing rule chains...
No arguments to frag2 directive, setting defaults to:
    Fragment timeout: 60 seconds
    Fragment memory cap: 4194304 bytes
Stream4 config:
    Stateful inspection: ACTIVE
    Session statistics: INACTIVE
    Session timeout: 30 seconds
    Session memory cap: 8388608 bytes
    State alerts: INACTIVE
    Scan alerts: ACTIVE
    Log Flushed Streams: INACTIVE
No arguments to stream4_reassemble, setting defaults:
     Reassemble client: ACTIVE
     Reassemble server: INACTIVE
     Reassemble ports: 21 23 25 53 80 143 110 111 513
     Reassembly alerts: ACTIVE
     Reassembly method: FAVOR_OLD
Back Orifice detection brute force: DISABLED
Using LOCAL time
1243 Snort rules read...
1243 Option Chains linked into 152 Chain Headers
0 Dynamic rules
+++++++++++++++++++++++++++++++++++++++++++++++++++

Rule application order: ->activation->dynamic->alert->pass->log

        --== Initializing Snort ==--
Decoding Ethernet on interface eth0

        --== Initialization Complete ==--

-*> Snort! <*-
Version 1.8.6 (Build 105)
By Martin Roesch (roesch@sourcefire.com, www.snort.org)

Snort sucessfully loaded all rules and checked all rule chains!

如果出现类似以上的信息,则说明配置也完成了,接下来就可以开始实际使用了。


2、使用

2.1 snort命令常用命令行选项介绍:

       snort   [-abCdDeGINoOpqsTUvVxXy?]  [-A  alert-mode  ]  [-B
       address-conversion-mask ] [-c rules-file ] [-F bpf-file ]
       [-g grpname ] [-h home-net ] [-i interface ] [-k checksum-
       mode ] [-l log-dir ] [-L bin-log-file ] [-m  umask  ]  [-M
       smb-hosts-file  ] [-n packet-count ] [-P snap-length ] [-r
       tcpdump-file ] [-S variable=value ] [-t chroot_directory ]
       [-u usrname ] [-z connect-status ] expression
       
       -A alert-mode     
      使用指定的报警模式。有效的模式包括fast,full,none
      及unsock。Fast模式只是写一行syslog风格的报警信息到
      默认的“报警”文件中。Full模式除了向报警文件中写入基
      本的报警信息外还会包括完全解码的数据包信息。None模
      式则是关掉报警功能。Unsock是一个实验性的模式,它通
      过一个由其他进程打开的UNIX套接字发送报警信息。

       -a     当解码数据包时候显示ARP数据包。

       -b     以tcpdump的格式记录二进制数据包。所有的数据包都以其
      原始的二进制状态写入到tcpdump格式的记录文件中,文件
      名snort-开始时间戳-.log。这个选项使程序执行更快,因
      为它不需要花时间在从二进制到文本的转换上了。在“-b”
      模式下Snort可以跟得上100Mbps的网络流量。如果想记录
      成其他的文件名,可以使用“-L”选项。

       -B address-conversion-mask            
      把所有home-net的IP地址转换成address-conversion-mask
      指定的内容。用来在二进制记录中隐藏IP地址。用“-h”选项
      指定home-net。需要注意的是这与$HOME_NET指定的内容是
      不一样的。

       -c config-file
      使用config-file文件中的规则。

       -C     只打印数据包负载中的可打印字符(不是十六进制方式)。

       -d     当在详细模式或数据包记录模式下,输出应用层的数据。

       -D     以守护进程的方式运行Snort。除非指定,报警信息被记录
      到/var/log/snort/alert文件中。

       -e     显示/记录数据链路层的数据包头。

       -F bpf-file
      从bpf-file文件中读取BPF过滤器。这对那些把Snort作为
      SHADOW的替代程序和喜欢非常复杂的BPF过滤器的用户有用
      。参看这个文件的“expressions”节以了解更多BPF过滤器
      相关的信息。

       -g groupname
      初始化以后把Snort进程的GID改到groupname。这是作为一
      个安全措施使Snort在经过初始化阶段后放弃root权限。

       -G ghetto-mode
              采用Ghetto向后兼容模式,以1.7的格式打印交叉参考信息
              。可用的模式有basic和url。
              
       -h home-net
              设置“内部网络”为home-net。这个地址的格式是一个网络
              地址前缀加一个CIDR块描述,比如192.168.1.0/24。一旦
              设置了这个变量,所有对解码过的数据包的记录都将相对
              于内部网络的地址空间。从Snort对ASCII日志数据的处理
              方式来看,设置这个变量是有好处的。把这个变量设置成
              本地网络以后,所有解码后的输出都被记录到以外部计算
              机的IP地址命名的目录中,这对进行流量分析很有帮助。

       -i interface
      在interface网络接口监听。

       -I     在报警信息中输出网络接口的名字。

       -k checksum-mode
              细调报警模式相关的校验和验证功能。有效的校验和模式
              为all、noip、notcp、noudp、noicmp和none。All模式支
              持所有的协议。Noip关闭IP校验和验证功能,这对网关路
              由器已经丢弃了校验和不对的数据包的环境中有用。Notcp
              模式关闭TCP校验和验证功能。Noudp关闭UDP校验和验证。
              Noicmp关闭ICMP校验和验证功能。None关闭所有校验和验
              证功能。
              
       -l log-dir
      设置记录目录为log-dir。所有明文报警信息和数据包记录
      都放在这个目录下面。如果没有指定这个选项,默认的记
      录目录是/var/log/snort。

       -L binary-log-file
      设置二进制记录文件的文件名为binary-log-file。如果没
      有指定这个选项,默认的文件名是snort-时间戳.log。

       -M smb-hosts-file
      发送WinPopup信息给smb-hosts-file文件中包含的工作站。
      这个选项要求主机上装有Samba并且在搜索路径内。文件的
      格式很简单,每行为需要向其发送信息的SMB机器名。

       -m umask
      设置创建文件用的umask。

       -n packet-count
      处理packet-count个数据包后退出。
      
       -N     关闭数据包记录功能。程序还是会正常地产生报警信息。

       -o     改变规则被应用于数据包的顺序。从标准的Alert->Pass->
              Log次序,变为Pass->Alert->Log次序。

       -O     在ASCII输出模式中隐藏IP地址。这个选项把向屏幕和日志
              文件输出的IP地址变为"xxx.xxx.xxx.xxx"。如果已设置了
              内部网络地址(-h),只有内部网络的地址会为隐藏,非
              内部网络的地址还是可见的。这样处理是为了方便向一些
              邮件列表张贴,以避免泄露一些内部信息。

       -p     关闭混杂模式监听。

       -P snap-length
      设置数据包的截取长度到snap-length。

       -q     安静执行。不打印banner及初始化信息。

       -r tcpdump-file
      读取tcpdump格式的数据文件tcpdump-file。这会使Snort
      读取和处理提交给它的文件。

       -s     发送报警信息给syslog。在Linux系统下,信息会被记录到
              /var/log/secure文件,在其他系统中会记录到/var/log/
              messages文件。

       -S variable=value
      把“value”值赋给“variable”变量。这个选项可以使你在命
      令行里重置在配置文件中定义的变量的值时有用。例如,
      你在配置文件中设定了HOME_NET变量的值,你可以在命令
      行参数中重置这个变量的值。

       -t chroot
      在初始化以后,改变Snort的root目录为chroot目录,需要
      注意的是在chroot后,所有日志和记录文件名都是相对
      chroot目录的了。

       -T     使Snort以自检的方式启动,检查所有提供给它的命令行参
      数和配置文件,并且指示一切就绪。这个选项对准备以守
      护进程方式运行Snort很有用,它检查Snort将要使用的配
      置情况是否正确,这样就不会在真正要运行时出错。

       -u uname
      在初始化后,改变Snort进程的执行UID到uname。

       -U     把所到的时间戳转成UTC。

       -v     详细模式。把数据包信息打印到控制台,这种方式的最大
              问题是速度慢,如果你是把Snort作为IDS来使用,不要用
              -v模式,不然很容易丢包。

       -V     显示版本号后退出。

       -X     从数据链路层开始输出原始数据包,这个选项覆盖-d选项。
      
       -y     把年信息写进报警和记录文件中。

       -z     此选项与stream4预处理器一起使用,它利用stream3的状
      态相关的检测能力来极大的减少对Snort所能进行的欺骗。
      此选项有两个参数all和est。All模式使Snort在报警时不
      考虑包的TCP状态。Est模式使Snort只对处于某种已知的T
      CP会话的包产生报警信息,这个模式下,Snort会大量减少
      由stick及snot等对抗IDS工具引发的误报的可能。

       -?     显示程序的用法并退出。

expression
      表达式,用于过滤想查看的数据包,用法与TCPDUMP的基本
      一致,详细可以参看tcpdump的手册页。

2.2 snort工具的使用方式

Snort并不是一个单纯的网络入侵检测工具,实际上它有三种基本的使用方式。

2.2.1 作为一个类似tcpdump的抓包工具

Snort和tcpdump一样是基于libpcap的网络工具,snort支持几乎与tcpdump完全一样的BPF包过滤语法,甚至可以把snort看作一个具有搜索匹配数据包中数据内容能力的tcpdump,因此在一般的IP网络环境下,snort完全可以代替tcpdump用于进行抓包分析。例如:

[root@redhat72 bin]# ./snort -qvd -A none  host xxx.xxx.xxx.xxx and port 23
04/10-00:57:24.339805 yyy.yyy.yyy.yyy:3221 -> xxx.xxx.xxx.xxx:23
TCP TTL:128 TOS:0x0 ID:47808 IpLen:20 DgmLen:48 DF
******S* Seq: 0xDB7320DD  Ack: 0x0  Win: 0x4000  TcpLen: 28
TCP Options (4) => MSS: 1460 NOP NOP SackOK

=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+

04/10-00:57:24.339805 xxx.xxx.xxx.xxx:23 -> yyy.yyy.yyy.yyy:3221
TCP TTL:64 TOS:0x0 ID:0 IpLen:20 DgmLen:48 DF
***A**S* Seq: 0x1F6B22C2  Ack: 0xDB7320DE  Win: 0x16D0  TcpLen: 28
TCP Options (4) => MSS: 1460 NOP NOP SackOK

=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+

...

=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+

04/10-00:57:24.439805 xxx.xxx.xxx.xxx:23 -> yyy.yyy.yyy.yyy:3221
TCP TTL:64 TOS:0x10 ID:38843 IpLen:20 DgmLen:112 DF
***AP*** Seq: 0x1F6B22E4  Ack: 0xDB73210F  Win: 0x16D0  TcpLen: 20
FF FE 01 FF FB 01 0D 0A 52 65 64 20 48 61 74 20  ........Red Hat
4C 69 6E 75 78 20 72 65 6C 65 61 73 65 20 37 2E  Linux release 7.
31 20 28 53 65 61 77 6F 6C 66 29 0D 0A 4B 65 72  1 (Seawolf)..Ker
6E 65 6C 20 32 2E 34 2E 32 2D 32 20 6F 6E 20 61  nel 2.4.2-2 on a
6E 20 69 36 38 36 0D 0A                          n i686..

=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+

04/10-00:57:24.449805 yyy.yyy.yyy.yyy:3221 -> xxx.xxx.xxx.xxx:23
TCP TTL:128 TOS:0x0 ID:47881 IpLen:20 DgmLen:43 DF
***AP*** Seq: 0xDB73210F  Ack: 0x1F6B232C  Win: 0x4407  TcpLen: 20
FF FC 01                                         ...

=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+

2.2.2 作为一个数据包记录工具

Snort默认就会在日志目录记录下数据包,结合BPF的数据包过滤语法,可以非常有针对性、选择性地记录网络数据包。它能以tcpdump的那种二进制格式,也能以经过解码后的文本文件的格式记录。

当以文本文件格式记录时,snort会在日志目录下创建以“外部IP”为目录名的子目录,在那些目录下对于每个连接创建一个文本文件进行记录。

如以下的命令可以记录所有来自xxx.xxx.xxx.xxx主机的非22端口的TCP数据包的解码文本信息记录到/var/log/snort/xxx.xxx.xxx.xxx目录下:

[root@redhat72 bin]# ./snort -qd -l /var/log/snort tcp and port '!22' and src host 'xxx.xxx.xxx.xxx'

程序执行一段时间后,查看日志:

[root@redhat72 snort]# pwd
/var/log/snort
[root@redhat72 snort]# ls -l
total 6
drwx------    2 root     root         8192 Apr 10 10:38 xxx.xxx.xxx.xxx
[root@redhat72 snort]# cd xxx.xxx.xxx.xxx
[root@redhat72 xxx.xxx.xxx.xxx]# ls
TCP:10282-80     TCP:26169-80     TCP:40969-9617   TCP:54872-80
TCP:10760-53     TCP:26335-80     TCP:41003-79     TCP:54889-80
TCP:10991-80     TCP:26816-23     TCP:41770-8888   TCP:55071-80
[root@redhat72 xxx.xxx.xxx.xxx]# cat TCP:54889-80
04/10-10:38:24.519805 xxx.xxx.xxx.xxx:54889 -> yyy.yyy.yyy.yyy:80
TCP TTL:247 TOS:0x0 ID:24743 IpLen:20 DgmLen:414
***A**** Seq: 0x9FF92979  Ack: 0xA92A8370  Win: 0x7703  TcpLen: 20
FA 33 22 79 B1 91 38 F0 4C 60 CD 09 A0 E2 0A 45  .3"y..8.L`.....E
EC 23 9C 1B 3B 03 5D 96 9E BD BC 6E 76 E7 CF 72  .#..;.]....nv..r
1B F1 6B 4C 84 23 BD 50 84 0B 5A A4 EE E3 6A DB  ..kL.#.P..Z...j.
86 07 F6 C1 89 D3 D7 28 12 14 16 88 FB 65 7A 96  .......(.....ez.
58 66 E3 5C 09 A1 2C 8D AC 86 B2 9B 6B 1D 77 71  Xf.\..,.....k.wq
24 ED 34 2D 42 8B 55 54 A0 EA 5C 9C 51 57 B3 29  $.4-B.UT..\.QW.)
BD 97 05 C6 B8 31 D4 65 B8 87 81 A3 24 F8 15 C7  .....1.e....$...
67 C8 F4 A9 55 C9 7D 75 B4 59 12 06 B0 45 AE ED  g...U.}u.Y...E..
DC B3 35 95 E5 0A 7B 1E 11 FC 41 B4 F5 56 7C DC  ..5...{...A..V|.
20 F0 86 F4 3A 83 6A EE DD FB 75 0E 42 24 FC 9E   ...:.j...u.B$..
58 32 35 3E BB B0 DB CC AD 1D 81 23 73 7D 01 13  X25>.......#s}..
ED 07 2F 73 63 72 69 70 74 73 2F 73 61 6D 70 6C  ../scripts/sampl
65 73 2F 73 65 61 72 63 68 2F 77 65 62 68 69 74  es/search/webhit
73 2E 65 78 65 59 7F 2E E4 77 5E 15 6A 2D 9D 11  s.exeY...w^.j-..

为了加强snort的记录处理能力,可以使用tcpdump的二进制格式记录数据包,因为snort不需要花时间在二进制数据到文本文件的转换上,所以能处理更多的数据包。所有的数据将都被记录到一个文件中,文件名可以自己指定,如果未指定默认的文件名为snort-时间戳.log。以下的命令将以二进制格式记录所有来自主机xxx.xxx.xxx.xxx 23端口相关的数据包到telnet.log文件。

[root@redhat72 bin]# ./snort -qb -L telnet.log port 23 and src host 'xxx.xxx.xxx.xxx'

程序执行一段时间后,查看日志:
[root@redhat72 snort]# ls -l
total 32
-rw-------    1 root     root          954 Apr 10 11:10 telnet.log

可以使用snort -r命令读取文件中的内容:
[root@redhat72 snort]# snort -qr telnet.log
No run mode specified, defaulting to verbose mode
04/10-11:10:33.439805 xxx.xxx.xxx.xxx:1516 -> yyy.yyy.yyy.yyy:23
TCP TTL:128 TOS:0x0 ID:30948 IpLen:20 DgmLen:48 DF
******S* Seq: 0x5761EDF  Ack: 0x0  Win: 0x4000  TcpLen: 28
TCP Options (4) => MSS: 1460 NOP NOP SackOK

=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+

04/10-11:10:33.439805 xxx.xxx.xxx.xxx:1516 -> yyy.yyy.yyy.yyy:23
TCP TTL:128 TOS:0x0 ID:30949 IpLen:20 DgmLen:40 DF
***A**** Seq: 0x5761EE0  Ack: 0x2A020557  Win: 0x4470  TcpLen: 20

=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+

04/10-11:10:33.459805 xxx.xxx.xxx.xxx:1516 -> yyy.yyy.yyy.yyy:23
TCP TTL:128 TOS:0x0 ID:30950 IpLen:20 DgmLen:46 DF
***AP*** Seq: 0x5761EE0  Ack: 0x2A020563  Win: 0x4464  TcpLen: 20
FF FB 18 FF FB 1F                                ......

=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+

当然你也可以在记录时不指定BPF过滤器,在读取时通过指定BPF过滤器选择需要的数据包信息,这样会记录大量的数据。

Snort还可以由特定的规则触发进行记录操作,这个功能对于某些蜜罐系统很有用,比如攻击者可能利用某个溢出攻击得到了主机的访问权限,snort可以检测到这个攻击并启动一定的记录操作。下面是一个很简单的例子,我们设定一个规则,当有连接到23端口时,我们就作相应的记录。

[root@redhat72 bin]# cat /root/test.rules
alert tcp any any -> any 23 (flags: S;tag: session, 20, packets; msg: "incoming telnet session";)
[root@redhat72 bin]# ./snort -q -c /root/testrc

程序执行一段时间后,查看日志:
[root@redhat72 snort]# ls -l
total 8
drwx------    2 root     root         4096 Apr 10 14:41 xxx.xxx.xxx.xxx
-rw-------    1 root     root          259 Apr 10 11:47 alert
[root@redhat72 snort]# cat alert
[**] [1:0:0] incoming telnet session [**]
04/10-11:47:25.829805 xxx.xxx.xxx.xxx:1533 -> yyy.yyy.yyy.yyy:23
TCP TTL:128 TOS:0x0 ID:34819 IpLen:20 DgmLen:48 DF
******S* Seq: 0x269C3C35  Ack: 0x0  Win: 0x4000  TcpLen: 28
TCP Options (4) => MSS: 1460 NOP NOP SackOK
[root@redhat72 snort]# cd xxx.xxx.xxx.xxx
[root@redhat72 xxx.xxx.xxx.xxx]# ls -l
total 8
-rw-------    1 root     root         5447 Apr 10 11:47 TCP:1533-23
[root@redhat72 xxx.xxx.xxx.xxx]# head -20 TCP\:1533-23
[**] incoming telnet session [**]
04/10-11:47:25.829805 xxx.xxx.xxx.xxx:1533 -> yyy.yyy.yyy.yyy:23
TCP TTL:128 TOS:0x0 ID:34819 IpLen:20 DgmLen:48 DF
******S* Seq: 0x269C3C35  Ack: 0x0  Win: 0x4000  TcpLen: 28
TCP Options (4) => MSS: 1460 NOP NOP SackOK
=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+

04/10-11:47:25.829805 yyy.yyy.yyy.yyy:23 -> xxx.xxx.xxx.xxx:1533
TCP TTL:64 TOS:0x0 ID:0 IpLen:20 DgmLen:48 DF
***A**S* Seq: 0xB5CFDC6C  Ack: 0x269C3C36  Win: 0x16D0  TcpLen: 28
TCP Options (4) => MSS: 1460 NOP NOP SackOK
=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+

04/10-11:47:25.829805 xxx.xxx.xxx.xxx:1533 -> yyy.yyy.yyy.yyy:23
TCP TTL:128 TOS:0x0 ID:34820 IpLen:20 DgmLen:40 DF
***A**** Seq: 0x269C3C36  Ack: 0xB5CFDC6D  Win: 0x4470  TcpLen: 20
=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+

04/10-11:47:25.839805 yyy.yyy.yyy.yyy:23 -> xxx.xxx.xxx.xxx:1533
TCP TTL:64 TOS:0x10 ID:58376 IpLen:20 DgmLen:52 DF

2.2.3 作为一个全功能的网络入侵检测系统

Snort的主要功能是作为一个入侵检测工具,snort有一个相对完整的规则集用于对各种攻击特征进行匹配,可以用带以下选项的snort来使程序启动到入侵检测状态。

[root@redhat72 bin]# ./snort -Dd -c /root/.snortrc

查看日志:
[root@redhat72 snort]# ls -l
total 240
drwx------    2 root     root         4096 Apr 10 16:01 yyy.yyy.yyy.yyy
drwx------    2 root     root        12288 Apr 10 16:01 xxx.xxx.xxx.xxxx
-rw-------    1 root     root       200012 Apr 10 16:01 alert

alert文件里记录的是报警信息,以IP地址为名的目录中存放的是报警相关的数据包解码信息。
[root@redhat72 snort]# head alert
[**] [1:324:2] FINGER null request [**]
[Classification: Attempted Information Leak] [Priority: 2]
04/10-16:01:31.999805 xxx.xxx.xxx.xxxx:31714 -> yyy.yyy.yyy.yyy:79
TCP TTL:176 TOS:0x0 ID:45170 IpLen:20 DgmLen:433
***A**** Seq: 0xFAD2A66A  Ack: 0x47272F00  Win: 0xF414  TcpLen: 20
[Xref => http://www.whitehats.com/info/IDS377]

[**] [1:651:4] SHELLCODE x86 stealth NOOP [**]
[Classification: Executable code was detected] [Priority: 1]
04/10-16:01:32.019805 xxx.xxx.xxx.xxxx:301 -> yyy.yyy.yyy.yyy:5277

如果想让snort尽可能快地处理数据包,可以使用“-b”选项只记录二进制数据,“-A fast”或“-s”只记录一条简短的报警信息到日志文件。
[root@redhat72 bin]# ./snort -Db -A fast -c /root/.snortrc

在机器上跑起snort后,每天都会产生大量的日志和报警信息,其中的大多数其实是误报,管理员人工的去分辨处理这些日志是不能忍受的,因此需要配合Snortsnarf这样的日志分析工具来帮助管理员进行日志审核。

3、Snort的结构

从模块结构上看,snort可以分为四个组成部分,数据包解码器、检测引擎、记录和报警系统、预处理器。

3.1 数据包解码器

解码器构建于libpcap的混杂模式程序库之上,有很好的可移植性。对以太网上的原始包从数据链路层开始逐层解码到传输层,最后到应用层。在解码器里比较强调速度,而且在数据包里为以后的检测引擎的工作设置了一些指针。

3.2 检测引擎

Snort在真正执行检测之前会对规则集进行初始化,它会把规则按头部信息(主要是动作、源目标IP、源目标端口信息)及选项信息初始化成规则头信息链和规则选项链。Snort作者提供的图示如下:

Rule Chain logical structure
-------------------------------------------------------------------------------
  ------------------------            ------------------------            -----
| Chain Header           |          | Chain Header           |          | Chai
|                        |          |                        |          |
| Source IP Address      |          | Source IP Address      |          | Sour
| Destination IP Address |--------->| Destination IP Address |--------->| Dest
| Source Port            |          | Source Port            |          | Sour
| Destination Port       |          | Destination Port       |          | Dest
|                        |          |                        |          |
  ------------------------            ------------------------            -----
             |                                   |
             |                                   |
             |                                   |
            \|/                                 \|/
  -----------V---------               -----------V---------
| Chain Option        |             | Chain Option        |
|                     |             |                     |
| Content             |
| TCP Flags           |
| ICMP Codes/types    |
| Payload Size        |
| etc.                |
|                     |
  ---------------------
             |
             |
             |
            \|/
  -----------V---------
| Chain Option        |
|                     |
| Content             |
| TCP Flags           |
| ICMP Codes/types    |
| Payload Size        |
| etc.                |
|                     |
  ---------------------
             |

这样做的好处是所有规则头信息相同的规则都被链入同一个规则链,比如所有CGI漏洞的攻击很可能都有相同的规则头信息(可能都是"alert any any -> HOME-NET 80"这种模式),一个包的一旦匹配了这种规则头模式,就会顺着相应的链继续匹配选项部分,这样就极大的减少了匹配的次数,提高了效率。

据说Snort还支持模块化的plugins与规则中的关键字绑定,以实现方便地加入新的检测方法和能力,用户可以编写自己的检测模块。这个功能还没时间加以研究。
          
3.3 记录和报警子系统

Snort实现了模块化的实时报警和记录引擎,包括了一些报警和记录插件,当前版本的snort(1.8.6)支持5种报警功能和7种记录选项,可以在运行snort时在命令行或配置文件中指定。具体支持哪些选项可以在snort的手册里找到,这里不多做介绍了。

3.4 预处理器

Snort的预处理器是介于解码器与检测引擎之间的可插入模块,提供对一些对解码后的数据包及一些应用层协议的附加处理及解码功能,如IP分片包的重组、TCP数据流状态的检定、HTTP协议的十六进制串及Unicode的解码。

4、Snort的规则集

4.1 规则简介

关于规则的详细信息可以在Snort的主站找到:
http://www.snort.org/docs/writing_rules/chap2.html#tth_chAp2

简单介绍一下Snort规则,下面是规则的一个例子:

alert tcp $EXTERNAL_NET any -> $HTTP_SERVERS 80 (msg:"WEB-CGI mmstdod.cgi access"; uricontent:"/mmstdod.cgi"; nocase; flags:a+;classtype:attempted-recon; sid:819; rev:1;)

一条snort规则可以从逻辑上分为两个部分,规则头和后面的选项部分。之所以这样分开与snort的实现方式有密切关系,因为snort在初始化规则集时会把所有规则按规则头和选项部分分别初始化两条规则链。每个数据包对应的特征都在这两条链上递归搜索。

规则头包含有匹配后的动作命令、协议类型、源IP及端口、数据包方向、目标IP及端口。目前snort支持5种动作方式,其中最常用的就是alert动作,它会向报警日志中写入报警信息。源及目标IP可以被指定为一个CIDR的地址块,端口也可以指定一个范围。

规则的选项部分是由一个或几个选项的符合,选项之间是并且的关系。选项之间可能有一定的依赖关系,比如nocase、offset、depth选项其实是content选项的修饰,是对其的一些说明。目前稳定版的snort(1.8.6)支持35种选项(在最新的开发版中加入了一种新的重要的Flow选项的支持),主要可以分为四类,第一类是数据包相关各种特征的说明选项,比如:content、flags、dsize、ttl等;第二类是规则本身相关一些说明选项,比如:reference、sid、classtype、priority等;第三类是规则匹配后的动作选项,比如:msg、resp、react、session、logto、tag等;第四类是选项它们并不是独立的,而是对某些选项的修饰,比如nocase、offset、depth、regex等。具体这些选项的含义请参看上面提到的链接或snort的手册,在这就不再深入了。

4.2 Snort规则的优点

总的看起来,snort的规则有如下特点:

4.2.1 简单

体现在规则选项概念清楚明确,选项之间没什么从属关系,规则之间除了启动与被启动之外没有什么其它的关系。

4.2.2 高效

规则所提供的选项基本上能完全描述一个数据包的特征,通过对选项加以组合基本上就能清楚地描述出基于单包的攻击,绝大多数规则只需要一行代码就行,这样也使规则匹配引擎能够高效地实现,完成高速的处理。

4.2.3 灵活

Snort的规则从技术类型、攻击类型、威胁类型等角度被分了类,而且对相应的分类定义优先级,虽然从理论上并不太科学完整(我认为比较科学的分类应该是层次性的,每个层次都应该是一个统一的标准),但在实现运用中还是相当实用的,可以比较方便地针对各种网络环境作出调整,对规则集加以剪裁。

4.2.4 规则更新迅速

由于snort开放源码的特性,网上有相当多的人关心这个项目的进展,热心地提供支持维护,因此规则的更新非常迅速,往往一有新的攻击出来在几个小时以内就会有相应的检测规则出现。这能使用户在第一时间就能获得发现攻击的能力,使其很快能补上漏洞。

Snort的设计架构是简单、高效、灵活,这在它规则的设计上也得到了很大程度的体现,snort规则很容易被理解,容易书写,不容易出错,也便于程序处理,能使新手很快上手。

4.3 Snort规则的缺点

Snort规则简单的特点既构成了它的优点,也衍生出了结构性的缺陷。

4.3.1 Snort规则的设计是面向单包的。

虽然它能很有效地描述单包的特征,但它基本上没有能力描述一些状态相关的特性,所以很难用来探测一些与状态相关的攻击。

4.3.2 Snort的规则基本上一条规则只能匹配一个攻击而不是一类攻击。

比如对于80端口的CGI漏洞扫描攻击,snort所采用的依然是一条规则匹配一个CGI漏洞探测请求的手段,其实这些CGI漏洞的攻击除了提交的漏洞脚本不同外其他方面的属性都是一致的,虽然snort检测引擎的特点可以在一定程度弥补效率上的下降,但也造成规则数量的猛增,不利于维护。

4.3.2 规则本身相关的描述信息严重不全。

用户往往只能看到规则的本身,甚至这条规则是干什么的都搞不清楚,找不到规则是如何探测攻击的原理描述、相关漏洞的描述,解决方案等等。因此,这样的规则集其实对于用户的要求相对高得多,要求用户本身就比较熟悉安全相关的一些概念,对网上最近出现的一些漏洞有及时地了解,这样的用户才能真正知道规则的用意。

Snort的开发小组也意识到这个问题,在snort的主站上提供了规则数据库的维护界面,鼓励热心人给规则数据库添加信息,详细的说明可以在下面的链接访问到:
http://www.snort.org/snort-db/help-us.html

4.3.3 规则缺少广泛的测试和分析,规则的可用性有时值得怀疑。

Snort毕竟不是一个商业产品,规则的维护很大程度上依靠一些非专业人员的支持,因此规则的有效性很多时候并未得到有效地测试与分析,某些规则的可用性欠佳,可能会产生可以避免的误报和漏报。

比如一条检测phpupload溢出攻击的规则是这样的:
alert tcp $EXTERNAL_NET any -> $HOME_NET 80 (msg:"EXPERIMENTAL php content-disposition"; flags:A+; content:"Content-Disposition\:"; content:"form-data\;"; classtype:web-application-attack; reference:bugtraq,4183; sid:1425; rev:2;)

它判断提交给服务器的HTTP请求中是否包含"Content-Disposition:"及"form-data;"字串,其实只要是有PHP上传操作都会在请求中出现这两个字串,会造成很多误报。

再如一条检测SNMP口令串溢出漏洞规则是这样的:
alert udp $EXTERNAL_NET any -> $HOME_NET 161:162 (msg:"EXPERIMENTAL SNMP community string buffer overflow attempt"; content:"|02 01 00 04 82 01 00|"; offset:4; reference:url,www.cert.org/advisories/CA-2002-03.html; reference:cve,CAN-2002-0012; reference:cve,CAN-2002-0013; classtype:misc-attack; sid:1409; rev:2;)

它判断发往SNMP服务端口的数据包中是否包含"|02 01 00 04 82 01 00|"二进制串,此串对应SNMP操作的分支的位置。事实上由于SNMP协议的灵活性,对同一分支位置在SNMP包里可能有不同的表示,"|02 80 01 80 00 80 04 80 82 80 01 80 00|"就可能表示的是同一分支,更糟的是还有更多的表示方法,攻击者完全可以利用这种协议表示上的灵活性逃过snort的检测,造成漏报。要完全解决这个问题,单纯靠搜索特定串是不行的,看来唯一可行的方法是做协议解码。

5 几个小测试

5.1 snot/stick压力测试

snot/stick是一种IDS的压力测试工具,它们读取snort的规则集,按规则的选项描述生成相应的数据包发送给IDS,这样短时间内大量地假攻击可能会使IDS处理能力溢出,造成崩溃或失去工作能力。此类工具刚出现时,曾让很多IDS产品无法应付,经过改进以后,现在大多数的IDS产品已经能处理这种情况了。各个产品对付此类攻击的实现方法不同,当前版本的snort也应该解决了这个问题,至少实现方法我还没仔细研究,但做了一个简单的测试:

测试机的CPU情况:
[root@redhat72 snort]# cat /proc/cpuinfo
processor       : 0
vendor_id       : GenuineIntel
cpu family      : 6
model           : 7
model name      : Pentium III (Katmai)
stepping        : 3
cpu MHz         : 551.258

使用详细报警,不记录数据包模式后台启动snort:
[root@redhat72 snort]# snort -D -N -A full

并从100M局域网内另一台机器用snot进行攻击,测试期间snort的CPU平均占用率为10%-20%左右,看来从处理能力上snort还是完全能应付的,但产生了大量的误报:
[root@redhat72 snort]# ls -l
total 12232
-rw-------    1 root     root     12500352 Apr 12 10:56 alert

使用详细报警,记录数据包并解码模式后台启动snort:
[root@redhat72 snort]# snort -Dd -A full
相同的环境下,snort在snot的攻击下CPU占用率在30%-60%之间波动。

5.2 状态相关的TCP攻击的检测

新版的snort加入了stream4预处理器,它可以跟踪TCP连接的建立情况,利用stream4的状态检测能力可以使snort只对那些通过正常TCP三次握手后建立连接的数据流中的数据包产生报警信息,这样就可以比较有效地对抗那些如stick和snot这样的“无状态”反IDS发包工具的攻击。在snort的命令行指定“-z est”选项就可以让snort忽略那些“无状态”的数据包,作了如下简单的测试:

用一般方式启动snort:
[root@redhat72 bin]# ./snort -Dd -N -A full
用snot攻击几秒钟后,看看产生的日志文件大小,可以看到产生了相当多的报警信息。
[root@redhat72 snort]# ls -l
total 584
-rw-------    1 root     root       585935 Apr 11 23:33 alert

加入“-z”参数,启动snort
[root@redhat72 bin]# ./snort -D -N -A full -z est
用snot攻击相同的时间,查看日志文件的大小:
[root@redhat72 snort]# ls -l
total 232
-rw-------    1 root     root       207595 Apr 11 23:41 alert
可以看到报警信息少了许多,通过查看alert文件里的具体报警信息,发现snort只对UDP的攻击和那些本来就与状态无关的TCP端口秘密扫描攻击报了警,其他需要建立真正TCP连接的snot产生的假攻击都已经被忽略了。

5.3 测试过程中发现的问题

a、如果在snort后台运行过程中强行删除alert报警文件,snort不会重新建立之,报警信息不再记录。
b、用stick进行测试时,发现snort在处理很多源IP与目标IP相同的畸形包时,CPU占用率会达到100%。
c、Snort规则的通配符匹配regex选项很多时候并不能正常工作。

6、一些个人的结论

Snort正如它的作者描述的那样是一个简洁、高效、灵活的入侵检测系统,它在单个结点上的安装与配置都很容易,检测能力方面能对付绝大多数基于单包的网络攻击。因此snort适合用于那些流量不高的简单网络,在那些环境下可以很大程度上作为商业IDS产品的免费替代方案。

但是,与一些商业化的IDS产品相比,当前版本的snort的缺陷也是很明显的。Snort的整体设计都是面向单包的,而且完全由规则驱动,它所做的只是对到网络接口的数据包做生硬的规则匹配,虽然通过预处理器比如stream4引入一些底层数据包相关的状态检测,但还远远不够,因此基本上不能检测一些高层协议状态相关的攻击。Snort虽然对某些应用广泛的应用层协议如HTTP、TELNET等提供了解码插件,能对特定端口上的数据进行解码分析,但并没有达到对高层协议的状态进行跟踪的程度。从目前版本的snort的实现情况来看,其实只是实现了探测器部分,还没有一个管理平台对多个探测器进行统一的,实时的管理,因此对于复杂网络多结点探测器的网络环境,探测器的启动、关闭、选项的修改、规则集的分发都是相当麻烦的,可管理性很差。还有,snort的规则数据库还极不完善,每条规则的相关说明文档非常不完整,某些规则的创建并没有经过严格的测试,会带来不少可以避免的漏报和误报。

7、参考资料

http://www.snort.org/docs/writing_rules/
http://www.snort.org/docs/lisapaper.txt
man snort
感谢小四对SNMP协议的深入分析和支持。

版权所有,未经许可,不得转载