Snort框架分析

下面是snort2.0的框架分析,相比snort之后的版本,其结构比较简单、更容易学习和理解,其次是
本人对此版本相对比较熟悉一些,可以为初次接触和学习snort的朋友提供帮助,能够快速整体全局性地
了解snort的基本框架。下面从四个方面展开描述。
一、snort插件
snort中的插件有3类,输出插件,预处理插件,规则选项检测插件
插件的好处:
灵活地选择使用哪些功能
开发人员很容易开发第三方插件,易于扩展。

1、输出插件
InitOutputPlugins  //输出插件初始化函数注册
1) 注册过程,注册多个插件初始化函数(供用户配置文件选择)
把database、log_tcpdump等关键字及其相对应的初始化函数DatabaseIint、logTcpdumpIint
挂在outputKeywordList链上
2) 初始化函数的执行,通过配置配置文件灵活选择某些插件
在主程序解析snort.conf配置文件时,一旦解析到输出文件中有关键字database就会匹配outputKeywordList链上关键字
执行对应的DatabaseIint函数,DatabaseIint为特定插件初始化函数,会把预定义的Database输出插件函数注册在(挂在)_OutputFucNode链上
3) Database运行的前置条件:当有数据报警时,引擎会轮询_OutputFucNode链上的输出函数,其中Database是链上的一个。
输出插件函数有syslog、logtcpdump、database等,其调用函数有:
CallLogPlugins        //while{ LogList->func()}     日志模式插件输出   
CallLogFuncs                                             检测规则引擎输出
CallAlertPlugins      //while{ AlertList->func()}     报警模式插件输出 
CallAlertFuncs                                           检测规则引擎输出

2、预处理插件初始化
InitPreprocessors
1) 注册过程和初始化过程与输出插件相同
2) Preprocess在detect(规则选项检测)之前,轮询_PreprocessFuncNode链依次
执行预处理函数。
3) 常用的预处理插件有httpDecode Portscan Stream(tcp会话重组) Frag(ip分片重组)
ARPspoof、Flood等插件函数

3、规则选项关键字检测初始化
IinitPlugIns
1) 注册过程和初始化过程与输出插件相同
2) 在分析规则选项时,碰到选项关键字(如dsize),触发检测插件函数
3) 常用的选项关键字检测插件有PatternMatch,模型包括(content、offset、depth、nocase、distance、within)
相结合的匹配函数、dsize、tcpflag、icmptype、ttl、ackcheck等关键字匹配函数

4、插件总结:
1)注册多个关键字与初始化函数,挂在关键字初始化函数链上。
2)根据配置文件中配置选择插件关键字链上的插件初始化函数执行,使预定义的插件函数及其相关参数挂在插件链上。
3)根据插件初始化函数链结点的类型NT_OUTPUT_LOG, NT_OUTPUT_ALERT分别把插件函数注册到全局插件函数链上(AlertList、LogList)

二、规则的初始化
主函数通过调用CreateDefaultRules、ParseRulesFile、ParseRule等函数,最终创建一个三层链表如下


第一层到三层依次为_RuleListNode、_ListHead 、RuleTreeNode ,三个数据结构如下:    

 

typedef struct _RuleTreeNode  //规则头的描述、以协议作为类别,分为ip、tcp、udp、icmp四种规则树链表
{
    RuleFpList *rule_func; /* match functions.. (Bidirectional etc.. ) */  //规则(ip port等)匹配函数链

    int head_node_number;

    int type;                            //RULE_PASS、RULE_ACTIVATE、RULE_ALERT、RULE_DYNAMIC、RULE_LOG    
                                           //fpLogEvent通过判断type值,分别调用ActivateAction{CallAlertFuncs  CallLogFuncs}、LogAction  {CallLogFuncs}
                                          //DynamicAction  {CallLogFuncs}、AlertAction{CallAlertFuncs、CallLogFuncs}函数
                                          //CallAlertFuncs  CallLogFuncs分别轮询全局输出插件函数链AlertList、LogList,执行输出插件函数
    IpAddrSet *sip;
    IpAddrSet *dip;

    int not_sp_flag;     /* not source port flag */

    u_short hsp;         /* hi src port */
    u_short lsp;         /* lo src port */

    int not_dp_flag;     /* not dest port flag */

    u_short hdp;         /* hi dest port */
    u_short ldp;         /* lo dest port */

    u_int32_t flags;     /* control flags */

    /* stuff for dynamic rules activation/deactivation */
    int active_flag;
    int activation_counter;
    int countdown;
    ActivateList *activate_list;

    struct _RuleTreeNode *right;  /* ptr to the next RTN in the list */  //下一条规则

    OptTreeNode *down;   /* list of rule options to associate with this rule node */  //规则的选项部分描述
    struct _ListHead *listhead;

} RuleTreeNode;

//RuleListNode节点有Alert Log  Dynamic Activate pass五种类型,其具体特性通过_ListHead体现
ListHead Alert;         /* Alert Block Header */
ListHead Log;           /* Log Block Header */
ListHead Pass;          /* Pass Block Header */
ListHead Activation;    /* Activation Block Header */
ListHead Dynamic;       /* Dynamic Block Header */

typedef struct _ListHead
{
    RuleTreeNode *IpList;
    RuleTreeNode *TcpList;
    RuleTreeNode *UdpList;
    RuleTreeNode *IcmpList;
    struct _OutputFuncNode *LogList;     //对应全局插件函数链LogList
    struct _OutputFuncNode *AlertList;   //对应全局插件函数链AlertList
    struct _RuleListNode *ruleListNode;
} ListHead;

typedef struct _RuleListNode     //list of Alert Log  Dynamic Activate pass
{
    ListHead *RuleList;         /* 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 (for debugging)  */ Alert Log  Dynamic Activate pass
    struct _RuleListNode *next; /* the next RuleListNode */
} RuleListNode;


//规则选项关键字匹配
typedef struct _OptFpList
{
    /* context data for this test */
    void *context;             //规则选项关键字content部分,待匹配的内容
    int (*OptTestFunc)(Packet *, struct _OptTreeNode *, struct _OptFpList *);//规则选项匹配的执行函数
    struct _OptFpList *next;

} OptFpList;

//规则选项链表节点,是规则的选项部分的描述
typedef struct _OptTreeNode
{
    /* plugin/detection functions go here */
    OptFpList *opt_func;                       //选项匹配处理函数链
    RspFpList *rsp_func;  /* response functions */
    OutputFuncNode *outputFuncs; /* per sid enabled output functions */

    /* the ds_list is absolutely essential for the plugin system to work,
       it allows the plugin authors to associate "dynamic" data structures
       with the rule system, letting them link anything they can come up 
       with to the rules list */?
    void *ds_list[64];   /* list of plugin data struct pointers */检测深度  dsize的大小等都分别存放在不同的结构

    int chain_node_number;

    int type;            /* what do we do when we match this rule */
    int evalIndex;       /* where this rule sits in the evaluation sets */
                            
    int proto;           /* protocol, added for integrity checks 
                            during rule parsing */
    struct _RuleTreeNode *proto_node; /* ptr to head part... */
    int session_flag;    /* record session data */

    char *logto;         /* log file in which to write packets which 
                            match this rule*/
    /* metadata about signature */
    SigInfo sigInfo;

    u_int8_t stateless;  /* this rule can fire regardless of session state */
    u_int8_t established; /* this rule can only fire if it has been marked 
                             as established */
    Event event_data;

    TagData *tag;

    /* stuff for dynamic rules activation/deactivation */
    int active_flag;
    int activation_counter;
    int countdown;
    int activates;
    int activated_by;

    u_int8_t  threshold_type; /* type of threshold we're watching */
    u_int32_t threshold;    /* number of events between alerts */
    u_int32_t window;       /* number of seconds before threshold times out */

    struct _OptTreeNode *OTN_activation_ptr;
    struct _RuleTreeNode *RTN_activation_ptr;

    struct _OptTreeNode *next;
    struct _RuleTreeNode *rtn;

} OptTreeNode;


三、数据包处理流程
ProcessPacket
 (*grinder) (&p, pkthdr, pkt);   //DecodeEthPkt、DecodeIP、DecodeIP从链路层到传输层逐层分析解码,
                     //将eth头地址、ip头地址、负载大小等信息保存到全局结构Packet*p中,供Detect等解析使用
  CallLogPlugins(p)              //runMode=MODE_PACKET_LOG
  Preprocess(&p);                //runMode=MODE_IDS 
    //轮询预处理插件函数链,执行tcp重组、ip分片重组、后门发现等插件函数
    Frag2Defrag
    PortscanPreprocFunction
    BoFind    
  Detect(p);//检测规则引擎
     fpEvalPacket
      fpEvalHeaderUdp
      fpEvalHeaderTcp
        fpEvalHeaderSW
         mpseSearch->otnx_match->fpEvalRTNSW->fpEvalOTN->(opt_func->OptTestFunc)//可通过gdb bt命令查看调用栈
         fpLogEvent
           AlertAction-> {CallAlertFuncs、CallLogFuncs} ->{ AlertList->func()、{ LogList->func()} } //输出检测结果 报警日志
   

四、快速规则匹配初始化流程
fpCreateFastPacketDetection
 prmAddRule
 prmAddRuleUri
 prmAddRuleNC
  prmxAddPortRule
   p->pgHead->rnRuleData  = otnx;

总结
追踪程序函数栈,可以使用gdb bt命令输出函数栈。要弄清楚整个程序的功能,主要先搞清楚整个框架模型,程序都是围绕这个框架
进行工作。snort是以两个模型开展工作,第一个模型Packet存放协议解码、包括预处理后的数据信息,作为数据模型,第二个模型是规则的三层链表,
存放解析后的所有检测规则信息,作为检测模型。Detect作为检测引擎,调用规则(ip port等)匹配函数链检测规则头,调用选项检测插件链进行选项字段匹配,
匹配成功最终以注册的输出插件函数进行报警和记录。

snort的编程风格非常优秀,代码阅读起来并不困难,整个程序结构清晰,函 数调用关系也不算复杂。但是,snort的源文件不少,函数总数也很多,所以不太 容易讲清楚。因此,最好把代码完整看一两遍,能更清楚点。 下面对源代码文件分组说明。 snort.c(.h)是主程序所在的文件,实现了main函数和一系列辅助函数。 decode.c(.h)把数据包层层剥开,确定该包属于何种协议,有什么特征。并 标记到全局结构变量pv中。 log.c(.h)实现日志和报警功能。snort有多种日志格式,一种是按tcpdump二进制的格式存储,另一种按snort编码的ascii格式存储在日志目录下,日志目录的名字根据"外"主机的ip地址命名。报警有不同的级别和方式,可以记录到syslog中,或者记录到用户指定的文件,另外还可以通过unix socket发送报警消息,以及利用SMB向Windows系统发送winpopup消息。 mstring.c(.h)实现字符串匹配算法。在snort中,采用的是Boyer-Moore算法。算法书上一般都有。 plugbase.c(.h)实现了初始化检测以及登记检测规则的一组函数。snort中的检测规则以链表的形式存储,每条规则通过登记(Register)过程添加到链表中。 response.c(.h)进行响应,即向攻击方主动发送数据包。这里实现了两种响应。一种是发送ICMP的主机不可到达的假信息,另一种针对TCP,发送RST包,断开连接。 rule.c(.h)实现了规则设置和入侵检测所需要的函数。规则设置主要的作用是 把一个规则文件转化为实际运作中的规则链表。检测函数根据规则实施攻击特征的检测。 sp_*_check.c(.h)是不同类型的检测规则的具体实现。很容易就可以从文件名得知所实现的规则。例如,sp_dsize_check针对的是包的数据大小,sp_icmp_type_check针对icmp包的类型,sp_tcp_flag_check针对tcp包的标志位。不再详述。 spo_*.c(.h)实现输出(output)规则。spo_alert_syslog把事件记录到syslog中;spo_log_tcpdump利用libpcap中的日志函数,进行日志记录。 spp_*.c(.h)实现预处理(preprocess)规则。包括http解码(即把http请求中的%XX这样的字符用对应的ascii字符代替,避免忽略了恶意的请求)、最小片断检查(避免恶意利用tcp协议中重组的功能)和端口扫描检测。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值