本文在Linux环境下,利用Snort和Iptables 构建了一个小型网络防御系统,由PHP页面提供了一个远程管理工具,并给出关键程序的实现和说明。
引言
Snort 是目前十分流行的轻型入侵检测系统。但是目前人们对Snort检测结果的处理大都停留在记录日志或简单通知网络管理员,由管理员进行审计再决定网络防御策略的阶段。Snort的检测结果并没有及时地用来抵御网络入侵。本文通过为Snort的报警输出模块提供一个服务监听程序的办法,及时获取Snort的报警信息并对其进行解析,根据解析结果向iptables添加相应的防火墙规则,达到实时阻止网络攻击的目的。服务程序同时监听来自PHP的管理请求,并进行相应的操作。由于服务程序独立于Snort而运行,故不会影响到Snort的运行效率。管理员可以通过PHP页面对服务程序阻塞的主机进行监控和管理,如查看当前阻塞的主机IP地址、事件发生时间、阻塞时间、阻塞原因,修改阻塞时间等。
总体思想
Snort的输出plugin为我们提供了丰富的报警输出方式:输出到文件,syslog,数据库,Unix域Socket等。其中当Snort的报警输出到Unix域Socket时,输出模块相当于一个报警的客户端,Snort的用户可以通过编写服务器端代码,获取Snort的报警输出消息,并根据这些消息采取相应的对策。本文基于这种思想,并利用Linux下自带的防火墙Iptables,构建了一个网络防御系统,系统总体结构如下:
服务处理程序是该系统的核心部分,包括报警输出处理子程序(AO_Handler)和PHP请求处理子程序(Web_Handler)两个部分。报警输出处理子程序主要负责接收Snort报警,解析报警信息,并通过向iptables加规则的方式对攻击主机进行阻塞;而PHP请求处理子程序主要负责与PHP管理页面通信,并根据页面的请求做出相应的处理。
服务程序中维护了一个规则相关信息表,这个表以队列(报警队列和阻塞队列)的数据结构进行组织,其中报警队列中记录的是经Snort报警输出解析得到的攻击主机信息(即报警结点,由AO_Handler生成), 而阻塞队列中记录了正在被阻塞的攻击主机信息(即阻塞结点)。如果报警结点不在阻塞队列中,程序将对这个结点所代表的主机进行阻塞操作,并把该结点加入到阻塞队列中。对每个阻塞操作所对应的阻塞结点设定一个有效期,当阻塞时间超过这个有效期时,程序将该阻塞结点从阻塞队列中删除,并删除iptables中对应的阻塞规则,对该阻塞主机放行。采用两个列队来维护报警和阻塞信息可以防止程序在多次收到有关同一个主机地址的报警时,添加重复的阻塞规则而为规则管理和取消阻塞操作时所带来的混乱。另外阻塞信息的维护使得程序可以为终端用户提供当前被系统自动阻塞的主机的所有信息:报警时间,阻塞时间,阻塞原因等,为用户了解和管理这些信息提供了接口。
具体实现
服务程序实现方式
服务程序需要同时处理三种事件:监听Snort报警输出、维护规则相关信息表(即报警队列和阻塞队列)、处理来自PHP页面的请求。因此,服务程序采用多线程并发模式。由主线程监听来自Snort的报警数据,解析该数据、创建报警结点并将其加入报警队列,另外主线程还执行服务程序的初始化工作;由两个线程来专门维护规则相关信息表,一个线程(AlertHandler)用于检测报警队列,当其中有符合要求的报警结点时,将其加入阻塞队列,执行阻塞操作,另一个(BlockHanlder)用于监测阻塞队列,将其中到达阻塞有效期的阻塞节点删除;对于来自PHP页面的请求,服务程序采用建立一个线程池的办法,对PHP请求做出相应操作,如:列表阻塞主机,删除某阻塞主机,修改阻塞有效时间等。
主线程和规则维护线程构成了报警输出处理子程序, 而PHP请求处理线程构成了PHP请求处理子程序。由于这些线程都涉及到对规则相关信息表的读写操作,因此,需要一定的同步机制来保证操作的正确性。本文中的程序采用了建立互斥锁和条件变量的办法来达到这个目的。程序主要数据结构默认情况下,Snort的报警套接字以数据报方式向path为/var/log/snort_alert的Unix域套接字发送报警数据,报警数据被封装在一个Alertpkt的结构体中(在Snort源码包的Spo_alert_unixsock.h中定义),Alertpkt的定义如下:
typedef struct _Alertpkt
{
u_int8_t alertmsg[ALERTMSG_LENGTH]; /* 报警消息 */
struct pcap_pkthdr pkth;
u_int32_t dlthdr; /* datalink header offset. (ethernet, etc.. ) */
u_int32_t nethdr; /* network header offset. (ip etc...) */
u_int32_t transhdr; /* transport header offset (tcp/udp/icmp ..) */
u_int32_t data;
u_int32_t val; /*指出有效的字段*/
……
Event event; /* 报警事件的相关信息 */
} Alertpkt;