END_TEST START_TEST(test_regexextraction) { int i; /* * Please note that all strings are \ escaped */ const char *tests[][15] = { { "123(\\w+\\s+)abc", "123sdf abc", "sdf ", NULL}, { "123(\\w+\\s+)abc", "abc123sdf abc", "sdf ", NULL}, { "123 (\\d+.\\d.\\d.\\d\\d*\\d*)", "123 45.6.5.567", "45.6.5.567", NULL}, { "from (\\S*\\d+.\\d+.\\d+.\\d\\d*\\d*)", "sshd[21576]: Illegal user web14 from ::ffff:212.227.60.55", "::ffff:212.227.60.55", NULL}, { "^sshd[\\d+]: Accepted \\S+ for (\\S+) from (\\S+) port ", "sshd[21405]: Accepted password for root from 192.1.1.1 port 6023", "root", "192.1.1.1", NULL}, { ": \\((\\S+)@(\\S+)\\) [", "pure-ftpd: ([email protected]) [INFO] New connection from enigma.lab.ossec.net", "?", "enigma.lab.ossec.net", NULL}, {NULL,NULL,NULL} }; for(i=0; tests[i][0] != NULL; i++) { OSRegex reg; ck_assert_int_eq(OSRegex_Compile(tests[i][0], ®, OS_RETURN_SUBSTRING), 1); ck_assert_ptr_ne(OSRegex_Execute(tests[i][1], ®), NULL); char **result = reg.sub_strings; int j; int k; for(j = 2, k = 0; tests[i][j] != NULL; j++, k++) { ck_assert_ptr_ne(result[k], NULL); ck_assert_str_eq(result[k], tests[i][j]); } ck_assert_ptr_eq(result[k], NULL); OSRegex_FreePattern(®); } }
/* CheckIfRuleMatch v0.1 * Will check if the currently_rule matches the event information */ RuleInfo *OS_CheckIfRuleMatch(Eventinfo *lf, RuleNode *curr_node) { /* We check for: * decoded_as, * fts, * word match (fast regex), * regex, * url, * id, * user, * maxsize, * protocol, * srcip, * dstip, * srcport, * dstport, * time, * weekday, * status, */ RuleInfo *currently_rule = curr_node->ruleinfo; /* Can't be null */ if(!currently_rule) { merror("%s: Inconsistent state. currently rule NULL", ARGV0); return(NULL); } #ifdef TESTRULE if(full_output && !alert_only) print_out(" Trying rule: %d - %s", currently_rule->sigid, currently_rule->comment); #endif /* Checking if any decoder pre-matched here */ if(currently_rule->decoded_as && currently_rule->decoded_as != lf->decoder_info->id) { return(NULL); } /* Checking program name */ if(currently_rule->program_name) { if(!lf->program_name) return(NULL); if(!OSMatch_Execute(lf->program_name, lf->p_name_size, currently_rule->program_name)) return(NULL); } /* Checking for the id */ if(currently_rule->id) { if(!lf->id) { return(NULL); } if(!OSMatch_Execute(lf->id, strlen(lf->id), currently_rule->id)) return(NULL); #ifdef CDBLOOKUP #endif } /* Checking if any word to match exists */ if(currently_rule->match) { if(!OSMatch_Execute(lf->log, lf->size, currently_rule->match)) return(NULL); } /* Checking if exist any regex for this rule */ if(currently_rule->regex) { if(!OSRegex_Execute(lf->log, currently_rule->regex)) return(NULL); } /* Checking for actions */ if(currently_rule->action) { if(!lf->action) return(NULL); if(strcmp(currently_rule->action,lf->action) != 0) return(NULL); } /* Checking for the url */ if(currently_rule->url) { if(!lf->url) { return(NULL); } if(!OSMatch_Execute(lf->url, strlen(lf->url), currently_rule->url)) { return(NULL); } #ifdef CDBLOOKUP #endif } /* Getting tcp/ip packet information */ if(currently_rule->alert_opts & DO_PACKETINFO) { /* Checking for the srcip */ if(currently_rule->srcip) { if(!lf->srcip) { return(NULL); } if(!OS_IPFoundList(lf->srcip, currently_rule->srcip)) { return(NULL); } #ifdef CDBLOOKUP #endif } /* Checking for the dstip */ if(currently_rule->dstip) { if(!lf->dstip) { return(NULL); } if(!OS_IPFoundList(lf->dstip, currently_rule->dstip)) { return(NULL); } #ifdef CDBLOOKUP #endif } if(currently_rule->srcport) { if(!lf->srcport) { return(NULL); } if(!OSMatch_Execute(lf->srcport, strlen(lf->srcport), currently_rule->srcport)) { return(NULL); } #ifdef CDBLOOKUP #endif } if(currently_rule->dstport) { if(!lf->dstport) { return(NULL); } if(!OSMatch_Execute(lf->dstport, strlen(lf->dstport), currently_rule->dstport)) { return(NULL); } #ifdef CDBLOOKUP #endif } } /* END PACKET_INFO */ /* Extra information from event */ if(currently_rule->alert_opts & DO_EXTRAINFO) { /* Checking compiled rule. */ if(currently_rule->compiled_rule) { if(!currently_rule->compiled_rule(lf)) { return(NULL); } } /* Checking if exist any user to match */ if(currently_rule->user) { if(lf->dstuser) { if(!OSMatch_Execute(lf->dstuser, strlen(lf->dstuser), currently_rule->user)) return(NULL); } else if(lf->srcuser) { if(!OSMatch_Execute(lf->srcuser, strlen(lf->srcuser), currently_rule->user)) return(NULL); } else #ifdef CDBLOOKUP #endif { /* no user set */ return(NULL); } } /* Checking if any rule related to the size exist */ if(currently_rule->maxsize) { if(lf->size < currently_rule->maxsize) return(NULL); } /* Checking if we are in the right time */ if(currently_rule->day_time) { if(!OS_IsonTime(lf->hour, currently_rule->day_time)) { return(NULL); } } /* Checking week day */ if(currently_rule->week_day) { if(!OS_IsonDay(__crt_wday, currently_rule->week_day)) { return(NULL); } } /* Getting extra data */ if(currently_rule->extra_data) { if(!lf->data) return(NULL); if(!OSMatch_Execute(lf->data, strlen(lf->data), currently_rule->extra_data)) return(NULL); } /* Checking hostname */ if(currently_rule->hostname) { if(!lf->hostname) return(NULL); if(!OSMatch_Execute(lf->hostname, strlen(lf->hostname), currently_rule->hostname)) return(NULL); } /* Checking for status */ if(currently_rule->status) { if(!lf->status) return(NULL); if(!OSMatch_Execute(lf->status, strlen(lf->status), currently_rule->status)) return(NULL); } /* Do diff check. */ if(currently_rule->context_opts & SAME_DODIFF) { if(!doDiff(currently_rule, lf)) { return(NULL); } } } /* Checking for the FTS flag */ if(currently_rule->alert_opts & DO_FTS) { /** FTS CHECKS **/ if(lf->decoder_info->fts) { if(lf->decoder_info->fts & FTS_DONE) { /* We already did the fts in here. */ } else if(!FTS(lf)) { return(NULL); } } else { return(NULL); } } /* List lookups */ if(currently_rule->lists != NULL) { ListRule *list_holder=currently_rule->lists; while(list_holder) { switch(list_holder->field) { case RULE_SRCIP: if(!lf->srcip) return(NULL); if(!OS_DBSearch(list_holder,lf->srcip)) return(NULL); break; case RULE_SRCPORT: if(!lf->srcport) return(NULL); if(!OS_DBSearch(list_holder,lf->srcport)) return(NULL); break; case RULE_DSTIP: if(!lf->dstip) return(NULL); if(!OS_DBSearch(list_holder,lf->dstip)) return(NULL); break; case RULE_DSTPORT: if(!lf->dstport) return(NULL); if(!OS_DBSearch(list_holder,lf->dstport)) return(NULL); break; case RULE_USER: if(lf->srcuser) { if(!OS_DBSearch(list_holder,lf->srcuser)) return(NULL); } else if(lf->dstuser) { if(!OS_DBSearch(list_holder,lf->dstuser)) return(NULL); } else { return(NULL); } break; case RULE_URL: if(!lf->url) return(NULL); if(!OS_DBSearch(list_holder,lf->url)) return(NULL); break; case RULE_ID: if(!lf->id) return(NULL); if(!OS_DBSearch(list_holder,lf->id)) return(NULL); break; case RULE_HOSTNAME: if(!lf->hostname) return(NULL); if(!OS_DBSearch(list_holder,lf->hostname)) return(NULL); break; case RULE_PROGRAM_NAME: if(!lf->program_name) return(NULL); if(!OS_DBSearch(list_holder,lf->program_name)) return(NULL); break; case RULE_STATUS: if(!lf->status) return(NULL); if(!OS_DBSearch(list_holder,lf->status)) return(NULL); break; case RULE_ACTION: if(!lf->action) return(NULL); if(!OS_DBSearch(list_holder,lf->action)) return(NULL); break; default: return(NULL); } list_holder = list_holder->next; } } /* If it is a context rule, search for it */ if(currently_rule->context == 1) { if(!currently_rule->event_search(lf, currently_rule)) return(NULL); } #ifdef TESTRULE if(full_output && !alert_only) print_out(" *Rule %d matched.", currently_rule->sigid); #endif /* Search for dependent rules */ if(curr_node->child) { RuleNode *child_node = curr_node->child; RuleInfo *child_rule = NULL; #ifdef TESTRULE if(full_output && !alert_only) print_out(" *Trying child rules."); #endif while(child_node) { child_rule = OS_CheckIfRuleMatch(lf, child_node); if(child_rule != NULL) { return(child_rule); } child_node = child_node->next; } } /* If we are set to no alert, keep going */ if(currently_rule->alert_opts & NO_ALERT) { return(NULL); } hourly_alerts++; currently_rule->firedtimes++; return(currently_rule); /* Matched */ }
/* Use the osdecoders to decode the received event */ void DecodeEvent(Eventinfo *lf) { OSDecoderNode *node; OSDecoderNode *child_node; OSDecoderInfo *nnode; const char *llog = NULL; const char *pmatch = NULL; const char *cmatch = NULL; const char *regex_prev = NULL; node = OS_GetFirstOSDecoder(lf->program_name); if (!node) { return; } #ifdef TESTRULE if (!alert_only) { print_out("\n**Phase 2: Completed decoding."); } #endif do { nnode = node->osdecoder; /* First check program name */ if (lf->program_name) { if (!OSMatch_Execute(lf->program_name, lf->p_name_size, nnode->program_name)) { continue; } pmatch = lf->log; } /* If prematch fails, go to the next osdecoder in the list */ if (nnode->prematch) { if (!(pmatch = OSRegex_Execute(lf->log, nnode->prematch))) { continue; } /* Next character */ if (*pmatch != '\0') { pmatch++; } } #ifdef TESTRULE if (!alert_only) { print_out(" decoder: '%s'", nnode->name); } #endif lf->decoder_info = nnode; child_node = node->child; /* If no child node is set, set the child node * as if it were the child (ugh) */ if (!child_node) { child_node = node; } else { /* Check if we have any child osdecoder */ while (child_node) { nnode = child_node->osdecoder; /* If we have a pre match and it matches, keep * going. If we don't have a prematch, stop * and go for the regexes. */ if (nnode->prematch) { const char *llog2; /* If we have an offset set, use it */ if (nnode->prematch_offset & AFTER_PARENT) { llog2 = pmatch; } else { llog2 = lf->log; } if ((cmatch = OSRegex_Execute(llog2, nnode->prematch))) { if (*cmatch != '\0') { cmatch++; } lf->decoder_info = nnode; break; } } else { cmatch = pmatch; break; } /* If we have multiple regex-only childs, * do not attempt to go any further with them. */ if (child_node->osdecoder->get_next) { do { child_node = child_node->next; } while (child_node && child_node->osdecoder->get_next); if (!child_node) { return; } child_node = child_node->next; nnode = NULL; } else { child_node = child_node->next; nnode = NULL; } } } /* Nothing matched */ if (!nnode) { return; } /* If we have an external decoder, execute it */ if (nnode->plugindecoder) { nnode->plugindecoder(lf); return; } /* Get the regex */ while (child_node) { if (nnode->regex) { int i; /* With regex we have multiple options * regarding the offset: * after the prematch, * after the parent, * after some previous regex, * or any offset */ if (nnode->regex_offset) { if (nnode->regex_offset & AFTER_PARENT) { llog = pmatch; } else if (nnode->regex_offset & AFTER_PREMATCH) { llog = cmatch; } else if (nnode->regex_offset & AFTER_PREVREGEX) { if (!regex_prev) { llog = cmatch; } else { llog = regex_prev; } } } else { llog = lf->log; } /* If Regex does not match, return */ if (!(regex_prev = OSRegex_Execute(llog, nnode->regex))) { if (nnode->get_next) { child_node = child_node->next; nnode = child_node->osdecoder; continue; } return; } /* Fix next pointer */ if (*regex_prev != '\0') { regex_prev++; } for (i = 0; nnode->regex->sub_strings[i]; i++) { if (lf->nfields >= Config.decoder_order_size) { merror("%s: ERROR: Regex has too many groups.", ARGV0); return; } if (nnode->order[i]) nnode->order[i](lf, nnode->regex->sub_strings[i], nnode->fields[i]); else /* We do not free any memory used above */ os_free(nnode->regex->sub_strings[i]); nnode->regex->sub_strings[i] = NULL; } /* If we have a next regex, try getting it */ if (nnode->get_next) { child_node = child_node->next; nnode = child_node->osdecoder; continue; } break; } /* If we don't have a regex, we may leave now */ return; } /* ok to return */ return; } while ((node = node->next) != NULL); #ifdef TESTRULE if (!alert_only) { print_out(" No decoder matched."); } #endif }
/* Look if any of the last events (inside the timeframe) * match the specified rule */ Eventinfo *Search_LastEvents(Eventinfo *my_lf, RuleInfo *rule) { EventNode *eventnode_pt; Eventinfo *lf; /* Last events */ eventnode_pt = OS_GetLastEvent(); if (!eventnode_pt) { /* Nothing found */ return (NULL); } /* Set frequency to 0 */ rule->__frequency = 0; /* Search all previous events */ do { lf = eventnode_pt->event; /* If time is outside the timeframe, return */ if ((c_time - lf->time) > rule->timeframe) { return (NULL); } /* The category must be the same */ else if (lf->decoder_info->type != my_lf->decoder_info->type) { continue; } /* If regex does not match, go to next */ if (rule->if_matched_regex) { if (!OSRegex_Execute(lf->log, rule->if_matched_regex)) { /* Didn't match */ continue; } } /* Check for repetitions on user error */ if (rule->context_opts & SAME_USER) { if ((!lf->dstuser) || (!my_lf->dstuser)) { continue; } if (strcmp(lf->dstuser, my_lf->dstuser) != 0) { continue; } } /* Check for same ID */ if (rule->context_opts & SAME_ID) { if ((!lf->id) || (!my_lf->id)) { continue; } if (strcmp(lf->id, my_lf->id) != 0) { continue; } } /* Check for repetitions from same src_ip */ if (rule->context_opts & SAME_SRCIP) { if ((!lf->srcip) || (!my_lf->srcip)) { continue; } if (strcmp(lf->srcip, my_lf->srcip) != 0) { continue; } } /* Check for different urls */ if (rule->context_opts & DIFFERENT_URL) { if ((!lf->url) || (!my_lf->url)) { continue; } if (strcmp(lf->url, my_lf->url) == 0) { continue; } } /* Check for different from same srcgeoip */ if (rule->context_opts & DIFFERENT_SRCGEOIP) { if ((!lf->srcgeoip) || (!my_lf->srcgeoip)) { continue; } if (strcmp(lf->srcgeoip, my_lf->srcgeoip) == 0) { continue; } } /* We avoid multiple triggers for the same rule * or rules with a lower level. */ else if (lf->matched >= rule->level) { return (NULL); } /* Check if the number of matches worked */ if (rule->__frequency < rule->frequency) { if (rule->__frequency <= 10) { rule->last_events[rule->__frequency] = lf->full_log; rule->last_events[rule->__frequency + 1] = NULL; } rule->__frequency++; continue; } /* If reached here, we matched */ my_lf->matched = rule->level; lf->matched = rule->level; return (lf); } while ((eventnode_pt = eventnode_pt->next) != NULL); return (NULL); }
/** main **/ int main(int argc, char **argv) { char *pattern; char msg[OS_MAXSTR +1]; memset(msg, '\0', OS_MAXSTR +1); OSRegex regex; OSMatch matcher; OS_SetName(ARGV0); /* user arguments */ if(argc != 2) { helpmsg(); return(-1); } /* User options */ if(strcmp(argv[1], "-h") == 0) { helpmsg(); return(-1); } os_strdup(argv[1], pattern); if(!OSRegex_Compile(pattern, ®ex, 0)) { printf("pattern does not compile with OSRegex_Compile\n"); return(-1); } if(!OSMatch_Compile(pattern, &matcher, 0)) { printf("pattern does not compile with OSMatch_Compile\n"); return(-1); } while((fgets(msg, OS_MAXSTR, stdin)) != NULL) { /* Removing new line. */ if(msg[strlen(msg) -1] == '\n') msg[strlen(msg) -1] = '\0'; /* Make sure we ignore blank lines. */ if(strlen(msg) < 2) { continue; } if(OSRegex_Execute(msg, ®ex)) printf("+OSRegex_Execute: %s\n",msg); /* else printf("-OSRegex_Execute: \n"); */ if(OS_Regex(pattern, msg)) printf("+OS_Regex : %s\n", msg); /* else printf("-OS_Regex: \n"); */ if(OSMatch_Execute(msg, strlen(msg), &matcher)) printf("+OSMatch_Compile: %s\n", msg); if(OS_Match2(pattern, msg)) printf("+OS_Match2 : %s\n", msg); } return(0); }