📄 spp_anomsensor.c
字号:
/* snort config file line: preprocessor spade-stats: {<stat-option>} where <stat-option> is one of: "entropy" (to display the known entropies and conditional entropies) "uncondprob" (to display the known non-0 simple (joint) probabilities) "condprob" (to display the known non-0 conditional (joint)probabilities) */ /* vars to store what the stats module should report */int print_entropy= 0;int print_condprob= 0;int print_uncondprob= 0;/* Spade Stat module init function: set up the print_* variables */void SpadeStatInit(u_char *args){ char **toks; int numToks; int i; if (as_debug) printf("Preprocessor: SpadeStat Initialized\n"); /* parse the argument list from the rules file */ toks = mSplit(args, " ", 20, &numToks, '\\'); for (i= 0; i < numToks; i++) { if (!(strcmp(toks[i],"entropy"))) { print_entropy= 1; } else if (!(strcmp(toks[i],"condprob"))) { print_condprob= 1; } else if (!(strcmp(toks[i],"uncondprob"))) { print_uncondprob= 1; } else { fprintf(stderr,"Anomaly Sensor Stat: option \"%s\" not recognized\n",toks[i]); } }}/*========================================================================*//*======================== SpadeThreshlearn module =======================*//*========================================================================*//* Given a packet count and a length of time, this module reports a reporting threshold that would have been effective in producing that number of alerts in that time interval. The idea is that one might use this as a threshold for future runs. The module quietly watches the network for the length of time, adding events to the tree and calculating anomaly scores. When the time period is up, the module calls exit() after reporting the top anomaly scores seen to the log file. */ /* snort config file line: preprocessor spade-threshlearn: [ <num-scores> [ <obs-time> ]] where: <num-scores> is the number of packets to report for (default 200) <obs-time> is the number of hours to run for (default 24)*//* variables used in the threshold learning module */int tl_obs_size=0; // the number of anomalous packets desiredtime_t tl_obs_secs; // how long to observe forll_double *top_anom_list; // the start of the list of anomaly scores we // maintain; the scores are the highest we've // observed; this list can be up to tl_obs_size+1 // long and is orderd by increasing score; the // list is initialized to 0 -> 0 in case we never // see enough packetsint top_anom_list_size; // the number of scores on the list (0-based)time_t obs_start_time=(time_t)0; // the start time of the observation, set // after the first packet we see/* Spade threshold learning module init function: set up threshold learning module per args and register its preprocessor function */void SpadeThreshlearnInit(u_char *args){ pp_active++; need_anom= 1; /* parse the argument list from the rules file */ ParseSpadeThreshlearnArgs(args); /* Set the preprocessor function into the function list */ AddFuncToPreprocList(PreprocSpadeThreshlearn); /* init list to contain just 0; this is to let us assume the list is not empty elsewhere */ top_anom_list= (ll_double *)malloc(sizeof(ll_double)); top_anom_list->val= 0.0; top_anom_list_size= 1; if (as_debug) printf("Preprocessor: SpadeThreshlearn Initialized\n");}/* Spade 'spade-thesshlearn' argument parsing function */void ParseSpadeThreshlearnArgs(char *args){ char **toks; int numToks; double hours; toks = mSplit(args, " ", 20, &numToks, '\\'); if (numToks > 0) { tl_obs_size = atoi(toks[0]); } else { tl_obs_size= 200; } if (as_debug) printf("observation size is %d\n",tl_obs_size); if (numToks > 1) { hours = atof(toks[1]); tl_obs_secs= (long)(hours*3600); } else { tl_obs_secs= 24*3600; } if (as_debug) printf("seconds of observation is %d\n",(int)tl_obs_secs);}/* Spade threshold learning module routine that is called with each packet */void PreprocSpadeThreshlearn(Packet *p){ size_t packet_time= p->pkth->ts.tv_sec; double anom; ll_double *new,*prev,*l; static int alldone=0; if (alldone) return; if (obs_start_time == 0) { /* first packet */ obs_start_time= packet_time; } else if ((long)packet_time > (obs_start_time + tl_obs_secs)) { CleanUpSpade(SIGUSR1); alldone=1; } if (record_maybe_skip(p)) return; /* accepted packets only past here; anom score is last_anom_score */ anom= last_anom_score; if (top_anom_list_size <= tl_obs_size) { new= (ll_double *)malloc(sizeof(ll_double)); top_anom_list_size++; } else if (anom > top_anom_list->val) { if (top_anom_list->next != NULL && anom < top_anom_list->next->val) { top_anom_list->val= anom; /* can just replace first */ return; } new= top_anom_list; top_anom_list= top_anom_list->next; } else { return; } new->val= anom; for (prev= top_anom_list, l=top_anom_list->next; l != NULL && anom > l->val; prev=l,l=l->next); /* add between prev and l */ prev->next= new; new->next= l; } /*========================================================================*//*=========================== SpadeAdapt module ==========================*//*========================================================================*//* Given a report count target and a length of time, this module tries to keep the reporting threshold at a level that would produce that number of alerts in that time interval based on what was observed in the last interval. To support this, a list of the most anomalous scores seen in the current interval is maintained. At the end of the interval, an ideal threshold is calculated based on the interval's scores. This is combined linearly with the current threshold to produce the threshold for the next interval. As a default option, the interval can implemented in terms of a count of packets, where this count is the average number of packets seen during the specified time interval length; this tends to make the transitions more smooth and reliable since a more constant number of anomaly scores is used in finding the topmost anamolous ones. *//* snort config file line: preprocessor spade-adapt: [ <target-count> [ <adapt-time> [ <new-weight> [ <interval-by-count> ]]]] where: <target-count> is the number of packets to aim for (default 20) <adapt-time> is the number of hours in the interval (default 2) <new-weight> is the part of new threshold based on the observed ideal for the previous interal (where the rest depends on the previous threshold) (default 0.5) <interval-by-count> is whether to measure intervals by count (0 to measure strictly by time, 1 to do it by count) (default 1)*//* global-scope variables used in the adapt module */// the number of alerts that is ideal for the given length of timeint adapt_target=0;// the length of time in which to ideally produce the given number of alerts;// also the interval at which to adjust the report thresholdtime_t adapt_period;// the weight to give to the new observation ideal cutoff in determining the// new weightfloat new_obs_weight;// adapt by count or by time onlyint adapt_by_count;// the head of the list of anomaly scores. This list is like the one in the// threshold learning module abovell_double *top_adapt_list;// the current size of this list (0-based)int top_adapt_list_size;/* Spade adapt module init function: set up the adapt module per its args and register its preprocessor function */void SpadeAdaptInit(u_char *args){ if (adapting) { fprintf(stderr,"Anomoly sensor threshold adapting repeadly specified, ignoring later specification: %s\n",args); return; } adapting= 1; pp_active++; need_anom= 1; /* parse the argument list from the rules file */ ParseSpadeAdaptArgs(args); /* Set the preprocessor function into the function list */ AddFuncToPreprocList(PreprocSpadeAdapt); /* init list to contain 0 and 0; this is to let us assume the list has a bottom and runner-up elsewhere */ top_adapt_list= (ll_double *)malloc(sizeof(ll_double)); top_adapt_list->val= 0.0; top_adapt_list->next= (ll_double *)malloc(sizeof(ll_double)); top_adapt_list->next->val= 0.0; top_adapt_list->next->next= NULL; top_adapt_list_size= 1; if (as_debug) printf("Preprocessor: SpadeAdapt Initialized\n");}/* Spade 'spade-adapt' argument parsing function */void ParseSpadeAdaptArgs(char *args){ char **toks; int numToks; double hours; toks = mSplit(args, " ", 20, &numToks, '\\'); if (numToks > 0) { adapt_target = atoi(toks[0]); } else { adapt_target= 20; } if (numToks > 1) { hours = atof(toks[1]); } else { hours= 2; } adapt_period= (long)(hours*3600); if (as_debug) printf("adapt target count is %d\n",adapt_target); if (as_debug) printf("adapt target period is %d\n",(int)adapt_period); if (numToks > 2) { new_obs_weight = (float)atof(toks[2]); } else { new_obs_weight= 0.5; } if (numToks > 3) { adapt_by_count = atoi(toks[3]); } else { adapt_by_count= 1; }}/* Spade adapt module routine that is called with each packet */void PreprocSpadeAdapt(Packet *p){ /* see if time to adjust the rate and if so, do so, and reset */ size_t packet_time= p->pkth->ts.tv_sec; ll_double *new,*prev,*l; // when the time interval is time-based, this is when the current interval // started; otherwise this is the last time the packets per interval // was updated average static time_t last_adapt_time=(time_t)0; // the time period #, starting with 1 for the first interval static int time_period_num= 1; // the average number of packets per time interval as most recently // calculated static float average_pkt_rate; if ((long)packet_time > (last_adapt_time + adapt_period)) { if (last_adapt_time == 0) { /* first packet */ last_adapt_time= packet_time; time_period_num= 1; } else { if (!adapt_by_count || time_period_num <= 1) { /* adapt by time since not doing count or since this is first period */ if (as_debug) { printf("%d alerts in last time period (of %d)\n",recent_alert_count,recent_packets); } do_adapt(); } if (adapt_by_count) { /* collect packet rate stats */ average_pkt_rate= tot_packets/(float)time_period_num; if (as_debug) { static int last_repcount; printf("End of time period %d: ave pkt rate is now %.2f\n",time_period_num,average_pkt_rate); printf(" %d alerts in last time period; ave alert rate is %.2f\n",(alert_count-last_repcount),alert_count/(float)time_period_num); last_repcount= alert_count; } time_period_num++; } last_adapt_time+= adapt_period; } } if (record_maybe_skip(p)) return; /* accepted packets only past here; anom score is last_anom_score */ if (adapt_by_count) { /* we are adapting by count */ if (time_period_num > 1 && recent_packets > average_pkt_rate) { /* time to adapt; note that average_pkt_rate can be adjusted any time in our counting */ if (as_debug) { printf("%d alerts in last packet period (of %d)\n",recent_alert_count,recent_packets); } do_adapt(); } } /* add anomaly score to list if it is high enough */ if (top_adapt_list_size <= adapt_target) { new= (ll_double *)malloc(sizeof(ll_double)); top_adapt_list_size++; } else if (last_anom_score > top_adapt_list->val) { if (last_anom_score < top_adapt_list->next->val) { top_adapt_list->val= last_anom_score; /* can just replace first */ return; } new= top_adapt_list; top_adapt_list= top_adapt_list->next; } else { return; } new->val= last_anom_score; for (prev= top_adapt_list, l=top_adapt_list->next; l != NULL && last_anom_score > l->val; prev=l,l=l->next); /* add between prev and l */ prev->next= new; new->next= l;} void do_adapt() { ll_double *l; double obs_thresh= (top_adapt_list->val + top_adapt_list->next->val)/2; if (as_debug) printf("observed recent ideal threshold is %.4f\n",obs_thresh); if (report_anom_thres < 0.0) { /* started up with no reporting */ set_new_threshold(obs_thresh); } else { set_new_threshold((1-new_obs_weight)*report_anom_thres + new_obs_weight*obs_thresh); } if (as_debug) printf("new threshold is %.4f\n",report_anom_thres); for (l=top_adapt_list; l != NULL; l=l->next) l->val= 0.0; recent_alert_count= 0; recent_packets= 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -