Snort的特点
Snort是一个强大的清量级的网络入侵检测系统。它具有实时数据流量分析和日志Ip网络数据包的能力,能够进行协议分析,对内容搜索/匹配。它能够检测各种不同的攻击方式,对攻击进行实时警报。此外,Snort具有很好的扩展性和可移植性。
还有,这个软件遵循公用许可GPL,所以只要遵守GPL任何组织和个人都可以自由使用。
Snort是一个轻量级的入侵检测系统。
1.Snort虽然功能强大,但是其代码极为简洁,短小,其源代码压缩包只有200KB不到。Snort可移植性非常好。Snort的跨平台性能极佳,目前已经支持Linux系列, Solaris,BSD系列,IRIX,HP-UX,Windows系列,ScoOpenserver,Unixware等。
Snort的功能非常强大,
2.Snort具有实时流量分析和日志Ip网数据包的能力。能够快速地检测网络攻击,及时地发出警报。Snort的警报机制很丰富。
例如:Syslog,用户指定文件,UnixSocket,还有使用SAMBA协议向Windows客户程序发出WinPopup消息。利用XML插件,Snort可以使用SNML(简单网络标记语言.simple network markup language)把日志存放在一个文件或者适时警报。
3.Snort能够进行协议分析,内容的搜索/匹配。现在Snort能够分析的协议有TCP,UDP和ICMP。将来的版本,将提供对ARP.ICRP,GRE,OSPF,RIP,ERIP,IPX,APPLEX等协议的支持。它能够检测多种方式的攻击和探测,例如:缓冲区溢出,CGI攻击,SMB检测,探测操作系统质问特征的企图等等。
4.Snort的日至格式既可以是Tcpdump的二进制格式,也可以编码成ASCII字符形式,更便于拥护尤其是新手检查,使用数据库输出插件,Snort可以把日志记入数据库,当前支持的数据库包括:Postagresql,MySQL,任何UnixODBC数据库,MicrosoftMsSQL,还有Oracle等数据库。
5.使用TCP流插件(TCPSTREAM),Snort可以对TCP包进行重组。Snort能够对IP包的内容进行匹配,但是对于TCP攻击,如果攻击者使用一个程序,每次发送只有一个字节的数据包,完全可以避开Snort的模式匹配。而被攻击的主机的TCP西医栈会重组这些数据,将其发送给目标端口上监听的进程,从而使攻击包逃过Snort的监视。使用TCP流插件,可以对TCP包进行缓冲,然后进行匹配,使Snort具备对付上面攻击的能力。
6.使用Spade(Statistical Packet Anomaly Detection Engine)插件,Snort能够报告非正常的可以包,从而对端口扫描进行有效的检测。
7.Snort还有很强的系统防护能力。如:是用其IPTables,IPFilter插件可以使入侵检测主机与防火墙联动,通过FlexResp功能,Snort能够命令防火墙主动短开恶意连接。
8.扩展性能较好,对于新的攻击威胁反应迅速。
作为一个轻量级的网络入侵检测系统,Snort有足够的扩展能力。它使用一种简单的规则描述语言(很多商用入侵检测系统都兼容Snort的规则语言)。最基本的规则知识包含四个域:处理动作,协议,方向,端口。
例如 Log Tcp Any any -> 10.1.1.0/24 80(谁都看得明白)
9.Snort支持插件,可以使用具有特定功能的报告,检测子系统插件对其功能进行扩展。Snort当前支持的插件包括:数据库日志输出插件,破碎数据包检测插件,断口扫描检测插件,HTTP URI插件,XML网页生成等插件。
10.Snort的规则语言非常简单,能够对新的网络攻击做出很快的反应。发现新攻击后,可以很快地根据Bugtrag邮件列表,找到特征码,写出新的规则文件。
总之,对于世界上各安全组织来讲,Snort入侵检测都是一个优秀入侵检测系统的一个标准的标准。通过研究它,我们可以学到到所有入侵检测系统的内部框架及工作流程(也包括同类型的商业入侵检测系统的框架及工作流程)。
7.2 Snort系统各程序模块代码分析
系统架构分析Snort主工作流函数为SnortMain()流程大体如下:
Snort2.0系列主工作图
图7.1 Snort主函数模块
相关函数解释:
1) 命令行参数解析函数ParseCmdLine(),解析个中命令参数,并将其放入全局PV类型的变量PV中。数据类型PV包含各种标示字段,用来知识个中系统的参数设置。
例如:规则文件,系统运行模式,显示模式,插件激活等。
2)检测引擎初始化fpInitDetectinEngine(),用于制定快速规则匹配模块的配置参数,包括模式搜索算法等(Snort可使用的算法有Aho-Corasick , Wu-Manber , Boyer-Moore 等算法,缺省Snort使用Byer-More算法。)。并负责在协议解析过程中产生警报信息。
3)取得从网络截取到的数据流的主要进程OpenPcap()。起主要作用是根据命令行参数分析结果,分别调用Libpcap函数库Pcap_open_live()—通过网卡驱动实时截取网络数据 和 Pcap_open_offline()—通过文件来访问以前网卡驱动截取数据保存成为的文件,并获得相对应的数据包数据结构。
4)各种插件初始化主要包括输入/输出插件初始化,检测插件初始化和预处理插件初始化等。主要就是将各种插件的关键字与对应的初始化处理函数相调用,然后注册到对应的关键字链表结构中,随后逐个弹出以便规则解析模块使用。
例如:预处理模块插件. 链表结构PreprocessKeyWordList定义如下:
typedef struct_preprocessKeywordNode
{
char *keyword;
void(*func)(u_char*);
}PreprocessKeywordNode;
typedef struct_preprocessKeywordList
{
PreprocessNode entry;
Struct_PreprocessKeywordList *next;
}PreprocessKeywordlist;
预处理插件的初始化函数 void (*func)(u_char *)并非插件的直接工作模块,而是由规则解释模块负责调用,然后将对应的插件处理模块连接到预处理工作数据链表结构中。
预处理工作函数链表结构PreprocessFuncNode定义如下:
typedef struct_PreprocessFuncNode
{
void (*func)(Packet *);
struct_PreprocessFuncNode *next;
} PreprocessFuncNode;
函数void (*func)(Packet *)才是真正进行预处理的工作模块,将被检测模块Preprocess() 在遍历预处理插件链表时调用。
4)规则结构初始化和解析
CreateDefaultRules()负责进行初始的规则结果建设。
我们学习到的规则链表模型结构多是多个二维链表结构(前面描述过)。而Snort是新三维链表结构形式,涉及到关键数据结构RuleListNode如下:
typedef struct_RuleListNode
{
ListHead *RuList; /* The rule list associated with this node*/
int mode; /* The rule mode */
int rval; /* 0—no detection , 1 –detection event */
int evalIndex ; /* eval index for this rule set */
char *name; /* Name of this rule list */
struct_RuleListNode Next; /* Rhe next RuleListNode */
} RuleListNode;
数据结构RuleListNode链表代表了系统支持的规则类型,包括Alert,Log,Pass,Activate,Dynamic。每链表节电又通过ListHead结构类型字段RuleList指向下面的规则链表。
第二层数据结构ListHead,定义如下:
typedef struct_ListHead
{
RuleTreeNode *IpList;
RuleTreeNode *TcpList;
RuleTreeNode *UdpList;
RuleTreeNode *IcmpList;
Struct_OutputFuncNode *LogList;
Struct_OutputFuncNode *AlertList;
Struct_RuleListNode *ruleListNode;
} ListHead;
数据结构ListHead中若干字段IpList , TcpList , UdpList , IcmpList等又分别指向各协议类型划分的规则链表,同时,可能有一个回指针去对应RuleListNode节点。
最基础的数据结构包括RuleTreeNode和OptTreeNode,分别代表最基本的规则链表头和规则节点,并分别定义。
应用这个链表来解决实例问题并说明此链表结构与工作过程.
函数CreatDefaultRules()此时并没有执行规则解析的任务,只是负责上层规则构架,代码如下:
ListHead Alert; /*Alert Block Header*/
ListHead Log; /*Log Block Header*/
ListHead Pass; /*Pass Blok Header*/
ListHead Activation; /*Activation Block Header*/
ListHead Dynamic; /*Dynamic Block Header*/
Void CreateDefaultRules()
{
CreateRuleType(“activation”,RULE_ACTIVATE,1,&Activation);
CreateRuleType(“dynamic”,RULE_DYNAMIC,1,&Dynamic);
CreateRuleType(“alert”,RULE_ALERT,1,&Alert);
CreateRuleType(“Pass”,RULE_PASS,0,&Pass);
CreateRuleType(“log”,RULE_LOG,1,&Log); }
链表头动作(5种):
图7.2 Snort 二维规则检测树
说明:以上举的两个例子一个是对WEB服务的CGI攻击,另一个是telnet攻击。还有很多应用层上的攻击,就不举例了。其中字符:Flow: 链接到检测插件。
Content: 用特定算法检查的字符串。
5)规则优化及快速匹配模块是Snort2.0版本中引入的最重要的组件。在SnortMain()函数中,主要涉及调用了建立和初始化规则优化和快速匹配数据结构的类型。包含有2个主要函数:OtnXMatchInfoInitialize(),fpCreateFastPacketDetection()
OtnXMatchInfoInitialize()主要是对数据类型OTNX_MATCH_DATA数据结构类型的全局变量omd,为它而申请空间。OTNX_MATCH_DATA数据结构中包括快速匹配时所需要的重要信息。而fpCreateFastPacketDetection()是建立快速匹配引擎的主要接口函数,严厉是读入有规则解析模块建立的规则链表中的所有规则链表头(上图所显示的RuleTreeNode类型)和规则选项节点(OptTreeNode类型),一边快速匹配之用。
6)数据包处理模块InterfaceThread()。
InterfaceThread()中功能简单,主要调用Libpcap库函数Pcap_loop()。Libpcap 库函数Pcap_loop()的接口函数,
接口函数ProcessPacket()主要功能包括:
1) 调用数据包协议解码模块,并将解码结果存储在特定的Packet类型数据结构中。
2) 根据Snort的运行模式,调用不同的处理模块。
3) 对入侵检测的运行模式,调用Preprocess()模块。
ProcessPacket()函数代码如下显示:
void ProcessPacket(char *user, struct pcap_pkthdr * pkthdr, u_char * pkt)
{
Packet p; /* reset the packet flags for each packet */
p.packet_flags = 0;
pc.total++;
/* reset the thresholding subsystem checks for this packet */
sfthreshold_reset();
#if defined(WIN32) && defined(ENABLE_WIN32_SERVICE)
if( pv.terminate_service_flag || pv.pause_service_flag )
{
ClearDumpBuf(); /* cleanup and return without processing */
return;
}
#endif /* WIN32 && ENABLE_WIN32_SERVICE */
/* call the packet decoder */
(*grinder) (&p, pkthdr, pkt);
/* print the packet to the screen */
if(pv.verbose_flag)
{
if(p.iph != NULL)
PrintIPPkt(stdout, p.iph->ip_proto, &p);
else if(p.ah != NULL)
PrintArpHeader(stdout, &p);
else if(p.eplh != NULL)
{
PrintEapolPkt(stdout, &p);
}
else if(p.wifih && pv.showwifimgmt_flag)
{
PrintWifiPkt(stdout, &p); } }
switch(runMode)
{
case MODE_PACKET_LOG:
CallLogPlugins(&p, NULL, NULL, NULL);
break;
case MODE_IDS: /* allow the user to throw away TTLs that won't apply to the
detection engine as a whole. */
if(pv.min_ttl && p.iph != NULL && (p.iph->ip_ttl < pv.min_ttl))
{
DEBUG_WRAP(DebugMessage(DEBUG_DECODE,
"MinTTL reached in main detection loop\n");
return;
} /* start calling the detection processes */
Preprocess(&p);
break;
default:
break;
}
ClearDumpBuf(); }
接口函数Process() 主要功能:
1) 遍历所有的预处理器模块。
2) 如果满足进行规则检测的条件,调用规则调用模块Detect()。
7.3几个重要的数据结构
Snort系统中最重要的全局数据结构就是Packet结构,Packet数据结构控制着整个系统正常工作的关键信息。所以,该数据结构在代码中出现的频率最高。
Packet数据结构如下(代码太长,截取部分):
Typedef struct_Packet
{
struct pcap_pkthdr pkth; /*BPF data*/
u_int8_t *pkt; /*base pointer to the raw packet data*/
Fddi_hdr fddihdr; /*FDDI support headers*/
…………
}
7.4规则检测组件
Snort2.0系统的快速匹配模块有最重要的设计特色,其在初始规则链表的基础上,重新构造了一套快速匹配的数据结构,宾采用了多模式匹配搜索引擎。
Snort2.0快速规则检测模块,其功能主要涉及三步骤:
1. 构造初始的规则链表结构,主要由ParseRulesFile()和ParseRule()两个函数完成。
2. 读入规则链表各节点,并构造用快速匹配的新数据结构,该步骤由fpCreateFastPacketDetection()完成。
3. 对当前数据包执行具体的快速规则匹配任务,主要在fpEvalPacket()上。
图7.3 检测组建的主要函数
7.4.1构造规则链表ParseRulesFile()和ParseRule()
ParseRulesFile()在主函数SnortMain()中调用。但是实际上ParseRulesFile()只是一个过渡接口,主要功能是读取规则配置文件并送实际的规则解析模块ParseRule()最后解析。规则解析模块ParseRule()其功能是解析所有的系统配置规则,包括插件配置,检测规则配置,变量定义,类定义等。
Snort系统的检测规则格式如下:
Alert Tcp any any ->192.168.1.0/24
ParseRule()基本算法流程图:
7.4.2结构快速匹配规则引擎fpCreateFastPacketDetection()
Snort2.0系统快速匹配规则引擎的设计基础是如何更有效地划分规则集合。系统采用的基本思想是通过规则中的目的端口和源断口值来划分类别。
1) 如果源端口值为特定值,目的端口为任意值(ANY),则该规则加入到源端口值对应的子集合中。如果目的端口的值为特定值,则该规则同时加入到目的端口对应的子集合中。
2) 如果源端口值为特定值,目的端口为任意值(ANY),则该规则加入到源端口值对应的子集合中。如果目的端口的值也为任意值(ANY),则该规则同时加入到目的端口对应的子集合中。
3) 如果目的端口和源端口都为任意值(ANY),则该规则加入到通用子集合中。
4) 对于规则中端口值求反操作或者指定值范围的情况,等于端口值为ANY情况。
在构建快速规则匹配引擎中所涉及到的主要数据结构如下:
最高层数据结构是Port_Lule_Map数据结构,其定义如下:
#define Max_PORTS 64*1024
#define ANYPORT –1
Typedef struct{
Int prmNumDstRules;
Int prmNumSrcRules;
Int prmNumGenericRules;
Int prmNumDstGroups;
Int prmNumSrcGroups;
PORT_GROUP *prmSrcPort[MAX_PORTS];
PORT_GROUP *prmDrcPort[MAX_PORTS];
PORT_GROUP *prmGeneric;
}PORT_RULE_MAP;
对于通用规则节点链表而言,在构建快速规则匹配引擎中,它仅是作为一个过渡性的函数结构。对于未来的规则检测任务而言,每个数据包都有特定的源/目的端口值。
为了达成根据端口进行快速规则匹配的任务,函数fpCreateFastPacketDetection()在完成遍历操作后,对各个PORT_RULE_MAP结构中的通用规则链表进行了进一步处理,调用prmCompileGroups().该函数功能将通用规则链表中的各个规则节点加入到另外对应于特定端口值的两个规则链表中,前提条件是目标规则链表中已经存在节点,既在Port_Rule_Map结构中的Port_Group数组中每个非空元素中加入。
函数prmAddRule()根据端口值,选定当前RULE_PORT_MAP中对应的PORT_GROUP结构,然后实际调用prmxAddPortRule()来具体执行在指定PORT_GROUP结构中的对应规则节点连表中加入的OTNX结构变量。
快速匹配规则引擎结构图中,函数fpCreateFastPacketDetection()在完成规则链表的遍历操作后,既完成了哥哥规则子集合的划分,所有的规则节点都已经加入了如下三种类型之一的子集合里:
1) 对应于特定源端口值的PORT_GROUP结构的规则链表
2) 对应于特定目的端口值的PORT_GROUP结构的规则链表
3) 通用一般的规则节点链表。
最后,为适应多模式引擎算法,fpCreateFastPacketDetection调用BuildMultiPaternGroups()在每个Port_Group结构中构建多模式搜索引擎所需的数据结构。
Typedef struct_otnx_
{
OptTreeNode *otn;
RuleTreeNode *rtn;
}OTNX;
7.5预处理模块
预处理模块的作用是对当前截获的数据包进行预先处理,以便后续处理模块对数据包的处理操作。之所以最后讲是因为,有些入侵检测系统没有此模块,此模块是嵌入在数据截取部分中的。
Snort2.0以上系统中预处理模块按功能分三种:
1) 数据包分片重组及数据流重组
在正常情况下,数据包在网络上由于最大数据传输单元可能有限制MTU及网络延迟等问题,路由器会对数据包进行分片处理。但是恶意攻击者也会故意发送经过软件加工过的数据包,以便把一个带有攻击性的数据包分散到各个小的数据包中,并有可能打乱数据包传输次序,分多次传输到目标主机。这样做的好处是减少被检测到的概率。为此,入侵检测系统有专门针对数据包上DM字段(第四章重点讲述过)标示为分段数据流的处理,此模块对这些分段数据包可以进行正确的从组(即使包的发送次序被打乱)。
2) 协议编码
协议编码是指有些协议是比较灵活的,如HTTP等协议。它支持多种编码,如ASCII码等,这就需要预处理模块进行处理,以便后续模块进行操作。同时,还有可能发现一些特定攻击类型。如:
http://Domain.com/scripts/..%c1%c...../cmd.exe?/c+dir
就是我们熟悉的目录遍历漏洞特征
/default.ida?NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN.. ..NNNNNNNNNNNNNNNN%u9090%6858%ucbd3…
就是我们熟悉的红色代码蠕虫特征
其中包含了ASCII码来标示。
更如:http://www.xxxx.com/%73%63%72%69%70...二进制表示URI为
HTTP://www.xxxx.com/scripts/hackme.exe的危险程序。
3) 协议异常检测
这指的是给予异常行为统计检查功能,能够针对一些异常的网络行为发出报警。如端口及特定服务(finger x.500等服务)的搜索。
7.5.1预处理器的基本框架
所涉及到的函数如下:(在Spp_template.c/h中)
SetupTemplate() //注册函数,由InitPreprocessors调用
TemplateInit(u_char *) //预处理模块的初始化
ParseTemplateArgs(char *) //参数解析
PreproFunction(Packet *) //根据预处理模块的不同,执行不同
PreproRestartFunction(int)
PreproCleanExitFunction(int) //退出清理函数
重点介绍协议处理中的Http规范Spp_Http_Decode模块,与拒绝服务DOS 紧密相关的检测分段模块Spp_frag2.
7.5.2 Spp_Http_Decode模块
该模块主要负责对HTTP协议中URL字符进行规范化编码处理,避免攻击者通过某些特殊的字符编码方式来逃避后续的规则检测。对与IIS 等可以接受同URL字符串的多个编码形式:
http://www.xxx.com/%73%63%72%69%70%...6D%65.%65%78%65
http://www.xxx.com%73%63%72%69%70%...6D%65.%65%78%65
HTTP://www.xxxx.com/scripts/hackme.exe
对于IIS会认为上面是一个请求。
该模块参数格式如下:
preprocedssor http_decode : var1 var2
如:
preprocedssor http_decode: 80 8080 8000 unicode iis_alt_Unicode
double_encode iis_flip_slash
7.5.3 Spp_frag2模块
Spp_frag2模块能够检测到若干种基于IP数据包分片技术的Dos攻击方法。这些类型的拒绝服务攻击经常利用操作系统协议栈(IP堆栈)的弱点,通过发送经过精心设计的异常数据包分片来对目标进行攻击。
该模块参数如:
preprocedssor frag2: var1 , var2
Spp_frag2预处理模块使用Frag2Data结构来存储当前模块的参数配置情况,其结构如下:
Typedef struct_frag2Data
{
u_int8_t os_flags;
u_int32_t memcap; // 内存
………
u_int8_t min_ttl //最小的生存值ttl
char frag2_alert; //*frag2 的警报是否打开
……..
SPMemControl frag_sp_data; //内存使用控制
…..
}Frag2Data
关于frag2的数据格式就不在多写了,这里简要分析一下Spp_frag2模块中的主功能模块Frag2Defrag().代码如下: (只列出重点代码,代码经过处理)
//主功能模块处理函数
void Frag2Defrag(Packet *p)
{
//如果表示字段显示不用分片处理操作,立即返回
if( !( p->preprocessors & pp_FRAG2 ))
{
return;
}
/*确定了数据包类型后,对只有分片的数据包进行种组处理,P->packet_flags & PKT_REBULT_FRAG的处理。 Snort会调用此函数。*/
if(p == NULL || p->iph == NULL || !p->frag_flag )
{
return;
}
if(p->packet_flags & PKT_REBUILT_FRAG)
{
return;
}
…….
//主二叉树中进行查询,是否存在满足当强数据包所指示IP源/目的地址条件的二叉树节点。返回Frag2Tracker结构变量。
Ft=GetFragTracker(p);
If(ft==Null)
{
//如果主树中不存在满足条件的节点,则表明当前数据包是一个新出现的IP分段数据包
if((f2_emergency.status == OPS_NORMAL)||(p->mf && p->frag_offset == 0)
{
//调用NewFragTracker()插入新节点。构造新节点的一个主要限制条件是当新出现的IP分段一定要为一个首分片才可以。此点主要防止泛滥IP分片数据,对IDS系统产生新的拒绝服务攻击
ft=NewFragTracker(p);
}
//如果不满足限制条件,则不进行后续的规则处理
else
DisableDetect(p);
Return;
//返回调用模块
}
}
7.6 Snort网络检测模块总流程