From: Russ Combs Date: Tue, 1 Jul 2014 12:43:56 +0000 (-0400) Subject: implemented default fp selection X-Git-Tag: 3.0.0-233~1450^2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=9684e3efa077b4756fd69fdc0ad9de310f2fb9fe;p=thirdparty%2Fsnort3.git implemented default fp selection --- diff --git a/ChangeLog b/ChangeLog index fb75589fe..51468945e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +96 +-- finished default fp selection +-- added NHttpInspect::get_buf() and related + 95 -- added some wizard module foo -- fixed cmake build with static inspectors for wizard and binder diff --git a/configure.ac b/configure.ac index e3677261d..b343d2311 100644 --- a/configure.ac +++ b/configure.ac @@ -25,7 +25,7 @@ # initialization #-------------------------------------------------------------------------- -AC_INIT([snort], [2.10.095]) +AC_INIT([snort], [2.10.096]) AC_PREREQ([2.68]) AC_CONFIG_SRCDIR([src/main.h]) diff --git a/lua/snort.lua b/lua/snort.lua index 8838df330..5bca86a5a 100644 --- a/lua/snort.lua +++ b/lua/snort.lua @@ -328,7 +328,7 @@ hi_x = post_depth = 65495, } ---nhttp_inspect = { } +nhttp_inspect = { } --------------------------------------------------------------------------- -- ftp / telnet normalization and anomaly detection @@ -560,9 +560,10 @@ default_rules = #alert tcp any any -> any any ( sid:412; pcre:"/ABA/"; pcre:"/AC/"; ) #alert tcp any any -> any any ( sid:414; pcre:"/ABA/"; pcre:"/C/R"; ) -alert ( gid:134; sid:1; ) -alert ( gid:134; sid:2; ) -alert ( gid:134; sid:3; ) +#alert ( gid:134; sid:1; ) +#alert ( gid:134; sid:2; ) +#alert ( gid:134; sid:3; ) +alert tcp any any -> any 80 ( sid:2; rev:3; http_uri; content:"evil", nocase, fast_pattern; ) ]] network = @@ -573,9 +574,9 @@ network = -- put classic rules and includes in the include file and/or rules string ips = { - include = '../active.rules', + --include = '../active.rules', rules = default_rules, - enable_builtin_rules = false + enable_builtin_rules = true } --[[ @@ -637,30 +638,30 @@ telnet_commands = '|FF FC|', '|FF FD|', '|FF FE|', '|FF FF|' } -xwizard = +wizard = { spells = { { service = 'ftp', proto = 'tcp', client_first = false, - to_client = ftp_commands, to_server = { '220*FTP' } }, + to_server = ftp_commands, to_client = { '220*FTP' } }, { service = 'http', proto = 'tcp', client_first = true, to_server = default_http_methods, to_client = { 'HTTP/' } }, { service = 'imap', proto = 'tcp', client_first = false, - to_client = { 'LOGIN', 'AUTHENTICATE', 'STARTTLS' }, - to_server = { '**OK', '**BYE' } }, + to_server = { 'LOGIN', 'AUTHENTICATE', 'STARTTLS' }, + to_client = { '**OK', '**BYE' } }, { service = 'pop', proto = 'tcp', client_first = false, - to_client = { 'USER', 'APOP' }, - to_server = { '+OK', '-ERR' } }, + to_server = { 'USER', 'APOP' }, + to_client = { '+OK', '-ERR' } }, { service = 'sip', proto = 'tcp', client_first = true, to_server = sip_methods, to_client = { 'SIP/' } }, { service = 'smtp', proto = 'tcp', client_first = false, - to_client = { 'HELO', 'EHLO' }, - to_server = { '220*SMTP', '220*MAIL' } }, + to_server = { 'HELO', 'EHLO' }, + to_client = { '220*SMTP', '220*MAIL' } }, { service = 'ssh', proto = 'tcp', client_first = true, to_server = { '*SSH' }, to_client = { '*SSH' } } @@ -733,8 +734,8 @@ binder = --{ when = target_x, use = { type = 'http_server', name = 'hi_x' } }, -- classic ports only config - { when = { proto = 'tcp', ports = HTTP_PORTS }, use = { type = 'http_server' } }, - --{ when = { proto = 'tcp', ports = HTTP_PORTS }, use = { type = 'nhttp_inspect' } }, + --{ when = { proto = 'tcp', ports = HTTP_PORTS }, use = { type = 'http_server' } }, + { when = { proto = 'tcp', ports = HTTP_PORTS }, use = { type = 'nhttp_inspect' } }, { when = { proto = 'tcp', ports = FTP_PORTS }, use = { type = 'ftp_server' } }, { when = { proto = 'tcp', ports = RPC_PORTS }, use = { type = 'rpc_decode' } }, diff --git a/src/detection/fpcreate.cc b/src/detection/fpcreate.cc index cd481804a..dee986f7d 100644 --- a/src/detection/fpcreate.cc +++ b/src/detection/fpcreate.cc @@ -81,16 +81,14 @@ static void fpDeletePortGroup(void *); static void fpDeletePMX(void *data); static int fpGetFinalPattern(FastPatternConfig *fp, PatternMatchData *pmd, char **ret_pattern, int *ret_bytes); -static PatternMatchData * GetLongestPmdContent(OptTreeNode *otn); -static int fpFinishPortGroupRule(SnortConfig *sc, PORT_GROUP *pg, PmType pm_type, +static int fpFinishPortGroupRule(SnortConfig *sc, PORT_GROUP *pg, OptTreeNode *otn, PatternMatchData *pmd, FastPatternConfig *fp); static int fpFinishPortGroup(SnortConfig *sc, PORT_GROUP *pg, FastPatternConfig *fp); static int fpAllocPms(SnortConfig *sc, PORT_GROUP *pg, FastPatternConfig *fp); static int fpAddPortGroupRule(SnortConfig *sc, PORT_GROUP *pg, OptTreeNode *otn, FastPatternConfig *fp); static int fpAddPortGroupPrmx(PORT_GROUP *pg, OptTreeNode *otn, int cflag); -static inline int IsPmdFpEligible(PatternMatchData *content); static void PrintFastPatternInfo(OptTreeNode *otn, PatternMatchData *pmd, - const char *pattern, int pattern_length, PmType pm_type); + const char *pattern, int pattern_length); static const char *pm_type_strings[PM_TYPE__MAX] = { @@ -859,48 +857,94 @@ static int FLP_Trim( char * p, int plen, char ** buff ) return size; } -static inline int IsPmdFpEligible(PatternMatchData *content) +static bool pmd_can_be_fp(PatternMatchData* pmd, CursorActionType cat) { - if (content == NULL) - return 0; + if ( !pmd->pattern_buf || !pmd->pattern_size ) + return false; - if ((content->pattern_buf != NULL) && (content->pattern_size != 0)) - { - if (content->negated) - { - /* Negative contents can only be considered if they are not relative - * and don't have any offset or depth. This is because the pattern - * matcher does not take these into consideration and may find the - * content in a non-relevant section of the payload and thus disable - * the rule when it shouldn't be. - * Also case sensitive patterns cannot be considered since patterns - * are inserted into the pattern matcher without case which may - * lead to false negatives */ - if (content->relative || !content->no_case - || (content->offset != 0) || (content->depth != 0)) - { - return 0; - } - } + if ( pmd->relative ) + return false; - return 1; - } + if ( cat <= CAT_SET_OTHER ) + return false; - return 0; + if ( !pmd->negated ) + return true; + + /* Negative contents can only be considered if they are not relative + * and don't have any offset or depth. This is because the pattern + * matcher does not take these into consideration and may find the + * content in a non-relevant section of the payload and thus disable + * the rule when it shouldn't be. + * Also case sensitive patterns cannot be considered since patterns + * are inserted into the pattern matcher without case which may + * lead to false negatives */ + if ( pmd->relative || !pmd->no_case || + pmd->offset || pmd->depth ) + return false; + + return true; } -static PatternMatchData * GetLongestPmdContent(OptTreeNode *otn) +struct FpFoo { - PatternMatchData *pmd = NULL; - PatternMatchData *pmd_not = NULL; - PatternMatchData *pmd_zero = NULL; - PatternMatchData *pmd_zero_not = NULL; + CursorActionType cat; + PatternMatchData* pmd; + int size; - OptFpList *ofl; - int max_size = 0, max_zero_size = 0; + FpFoo() + { cat = CAT_NONE; pmd = nullptr; size = 0; }; + + FpFoo(CursorActionType c, PatternMatchData* p) + { + cat = c; + pmd = p; + size = FLP_Trim(pmd->pattern_buf, pmd->pattern_size, nullptr); + }; + bool is_better(FpFoo& rhs) + { + if ( size && !rhs.size ) + return true; + + if ( !pmd->negated && rhs.pmd->negated ) + return true; + + if ( cat > rhs.cat ) + return true; + + if ( cat < rhs.cat ) + return false; - CursorActionType last_cat = CAT_SET_RAW; // default is raw packet - CursorActionType curr_cat = CAT_NONE; // selected for fast pattern + if ( size > rhs.size ) + return true; + + return false; + }; +}; + +static PmType get_pm_type(CursorActionType cat) +{ + switch ( cat ) + { + case CAT_SET_RAW: + return PM_TYPE__CONTENT; + case CAT_SET_BODY: + return PM_TYPE__HTTP_CLIENT_BODY_CONTENT; + case CAT_SET_HEADER: + return PM_TYPE__HTTP_HEADER_CONTENT; + case CAT_SET_COMMAND: + return PM_TYPE__HTTP_URI_CONTENT; + default: + break; + } + return PM_TYPE__MAX; +} + +static PatternMatchData * get_fp_content(OptTreeNode *otn) +{ + OptFpList *ofl; + CursorActionType curr_cat = CAT_SET_RAW; + FpFoo best; for (ofl = otn->opt_func; ofl != NULL; ofl = ofl->next) { @@ -909,11 +953,8 @@ static PatternMatchData * GetLongestPmdContent(OptTreeNode *otn) CursorActionType cat = IpsOption::get_cat(ofl->context); - if ( cat == CAT_NONE ) - continue; - - if ( cat > CAT_SET_RAW ) - last_cat = cat; + if ( cat > CAT_ADJUST ) + curr_cat = cat; if ( ofl->type != RULE_OPTION_TYPE_CONTENT ) continue; @@ -921,56 +962,24 @@ static PatternMatchData * GetLongestPmdContent(OptTreeNode *otn) PatternMatchData* tmp = get_pmd(ofl); assert(tmp); + tmp->pm_type = get_pm_type(curr_cat); + if (tmp->fp) return tmp; - if ( !IsPmdFpEligible(tmp) ) + if ( !pmd_can_be_fp(tmp, curr_cat) ) continue; - int size = FLP_Trim(tmp->pattern_buf, tmp->pattern_size, NULL); + FpFoo curr(curr_cat, tmp); - /* In case we get all zeros patterns */ - if ((size == 0) && ((int)tmp->pattern_size > max_zero_size)) - { - if (tmp->negated) - { - pmd_zero_not = tmp; - } - else - { - max_zero_size = tmp->pattern_size; - pmd_zero = tmp; - } - } - else if ( last_cat > curr_cat || size > max_size ) - { - if (tmp->negated) - { - pmd_not = tmp; - } - else - { - max_size = size; - pmd = tmp; - } - curr_cat = last_cat; - } + if ( curr.is_better(best) ) + best = curr; } - - if (pmd != NULL) - return pmd; - else if (pmd_zero != NULL) - return pmd_zero; - else if (pmd_not != NULL) - return pmd_not; - else if (pmd_zero_not != NULL) - return pmd_zero_not; - - return NULL; + return best.pmd; } static int fpFinishPortGroupRule( - SnortConfig *sc, PORT_GROUP *pg, PmType pm_type, + SnortConfig *sc, PORT_GROUP *pg, OptTreeNode *otn, PatternMatchData* pmd, FastPatternConfig *fp) { PMX * pmx; @@ -982,27 +991,15 @@ static int fpFinishPortGroupRule( if ((pg == NULL) || (otn == NULL) || (fp == NULL)) return -1; - switch (pm_type) + if ( !pmd ) { - case PM_TYPE__CONTENT: - if (pmd == NULL) - return -1; - pg_type = PGCT_CONTENT; - break; - case PM_TYPE__HTTP_URI_CONTENT: - case PM_TYPE__HTTP_HEADER_CONTENT: - case PM_TYPE__HTTP_CLIENT_BODY_CONTENT: - if (pmd == NULL) - return -1; - pg_type = PGCT_URICONTENT; - break; - case PM_TYPE__MAX: - default: - if (pmd != NULL) - return -1; - fpAddPortGroupPrmx(pg, otn, PGCT_NOCONTENT); - return 0; /* Not adding any content to pattern matcher */ + fpAddPortGroupPrmx(pg, otn, PGCT_NOCONTENT); + return 0; /* Not adding any content to pattern matcher */ } + if (pmd->pm_type == PM_TYPE__CONTENT ) + pg_type = PGCT_CONTENT; + else + pg_type = PGCT_URICONTENT; { if (pmd->negated) @@ -1023,9 +1020,9 @@ static int fpFinishPortGroupRule( pmx->PatternMatchData = pmd; if (fpDetectGetDebugPrintFastPatterns(fp)) - PrintFastPatternInfo(otn, pmd, pattern, pattern_length, pm_type); + PrintFastPatternInfo(otn, pmd, pattern, pattern_length); - pg->pgPms[pm_type]->add_pattern( + pg->pgPms[pmd->pm_type]->add_pattern( sc, pattern, pattern_length, @@ -1137,34 +1134,12 @@ static int fpAllocPms( return 0; } -#if 0 -// FIXIT fast_pattern -static PmType GetPmType (HTTP_BUFFER hb_type) -{ - switch ( hb_type ) - { - case HTTP_BUFFER_URI: - return PM_TYPE__HTTP_URI_CONTENT; - - case HTTP_BUFFER_HEADER: - return PM_TYPE__HTTP_HEADER_CONTENT; - - case HTTP_BUFFER_CLIENT_BODY: - return PM_TYPE__HTTP_CLIENT_BODY_CONTENT; - - default: - break; - } - return PM_TYPE__CONTENT; -} -#endif - static int fpAddPortGroupRule( SnortConfig *sc, PORT_GROUP *pg, OptTreeNode *otn, FastPatternConfig *fp) { PatternMatchData *pmd = NULL; - if ((pg == NULL) || (otn == NULL)) + if ( !pg || !otn ) return -1; // skip builtin rules @@ -1175,11 +1150,18 @@ static int fpAddPortGroupRule( if ( !otn->enabled ) return -1; - pmd = GetLongestPmdContent(otn); + pmd = get_fp_content(otn); - if ((pmd != NULL) && pmd->fp) + if ( pmd && pmd->fp) { - if (fpFinishPortGroupRule(sc, pg, PM_TYPE__CONTENT, otn, pmd, fp) == 0) + if ( + pmd->fp && !pmd->relative && !pmd->negated && + !pmd->offset && !pmd->depth && pmd->no_case ) + { + pmd->fp_only = 1; + } + + if (fpFinishPortGroupRule(sc, pg, otn, pmd, fp) == 0) { if (pmd->pattern_size > otn->longestPatternLen) otn->longestPatternLen = pmd->pattern_size; @@ -1190,7 +1172,7 @@ static int fpAddPortGroupRule( /* If we get this far then no URI contents were added */ - if (fpFinishPortGroupRule(sc, pg, PM_TYPE__CONTENT, otn, pmd, fp) == 0) + if ( pmd && fpFinishPortGroupRule(sc, pg, otn, pmd, fp) == 0) { if (pmd->pattern_size > otn->longestPatternLen) otn->longestPatternLen = pmd->pattern_size; @@ -1198,7 +1180,7 @@ static int fpAddPortGroupRule( } /* No content added */ - if (fpFinishPortGroupRule(sc, pg, PM_TYPE__MAX, otn, NULL, fp) != 0) + if (fpFinishPortGroupRule(sc, pg, otn, NULL, fp) != 0) return -1; return 0; @@ -2681,13 +2663,13 @@ const char * PatternRawToContent(const char *pattern, int pattern_len) } static void PrintFastPatternInfo(OptTreeNode *otn, PatternMatchData *pmd, - const char *pattern, int pattern_length, PmType pm_type) + const char *pattern, int pattern_length) { if ((otn == NULL) || (pmd == NULL)) return; LogMessage("%u:%u\n", otn->sigInfo.generator, otn->sigInfo.id); - LogMessage(" Fast pattern matcher: %s\n", pm_type_strings[pm_type]); + LogMessage(" Fast pattern matcher: %s\n", pm_type_strings[pmd->pm_type]); LogMessage(" Fast pattern set: %s\n", pmd->fp ? "yes" : "no"); LogMessage(" Fast pattern only: %s\n", pmd->fp_only ? "yes" : "no"); LogMessage(" Negated: %s\n", pmd->negated ? "yes" : "no"); diff --git a/src/ips_options/ips_content.cc b/src/ips_options/ips_content.cc index 3066ef516..2a07ac96a 100644 --- a/src/ips_options/ips_content.cc +++ b/src/ips_options/ips_content.cc @@ -279,20 +279,10 @@ static int32_t parse_int( } static void validate_content( - SnortConfig*, PatternMatchData *pmd, OptTreeNode* otn) + SnortConfig*, PatternMatchData*, OptTreeNode* otn) { if ( fast_pattern_count(otn, RULE_OPTION_TYPE_CONTENT) > 1 ) ParseError("Only one content per rule may be used for fast pattern matching."); - - if ( - pmd->fp && !pmd->relative && !pmd->negated && - !pmd->offset && !pmd->depth && pmd->no_case ) - { - // this is provisional; will be disabled later if there - // is a relative rule option following this one - // see parse_rule.cc::ValidateFastPattern() - pmd->fp_only = 1; - } } static void make_precomp(PatternMatchData * idx) diff --git a/src/ips_options/ips_content.h b/src/ips_options/ips_content.h index f4b886bdc..f6e3edcdf 100644 --- a/src/ips_options/ips_content.h +++ b/src/ips_options/ips_content.h @@ -69,6 +69,7 @@ struct PatternMatchData uint16_t fp_length; uint8_t negated; /* search for "not this pattern" */ + uint8_t pm_type; // FIXIT wasting some memory here: // - this is not used by content option logic directly @@ -79,7 +80,6 @@ struct PatternMatchData but the rule option specifies a negated content. Only applies to negative contents that are not relative */ PmdLastCheck* last_check; - }; PatternMatchData* content_get_data(void*); diff --git a/src/ips_options/ips_raw_data.cc b/src/ips_options/ips_raw_data.cc index adef361f7..3aaaa4786 100644 --- a/src/ips_options/ips_raw_data.cc +++ b/src/ips_options/ips_raw_data.cc @@ -60,6 +60,10 @@ class RawDataOption : public IpsOption { public: RawDataOption() : IpsOption(s_name) { }; + + CursorActionType get_cursor_type() const + { return CAT_SET_RAW; }; + int eval(Cursor&, Packet*); }; diff --git a/src/service_inspectors/nhttp_inspect/nhttp_api.cc b/src/service_inspectors/nhttp_inspect/nhttp_api.cc index 477c89ce8..68d6cd092 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_api.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_api.cc @@ -95,6 +95,21 @@ void NHttpApi::nhttp_reset() { } +static const char* buffers[] = +{ + "http_client_body", + "http_cookie", + "http_header", + "http_method", + "http_raw_cookie", + "http_raw_header", + "http_raw_uri", + "http_stat_code", + "http_stat_msg", + "http_uri", + nullptr +}; + const InspectApi NHttpApi::nhttp_api = { { @@ -107,7 +122,7 @@ const InspectApi NHttpApi::nhttp_api = }, IT_SERVICE, PROTO_BIT__TCP, - nullptr, // buffers + buffers, "http", NHttpApi::nhttp_init, NHttpApi::nhttp_term, diff --git a/src/service_inspectors/nhttp_inspect/nhttp_inspect.cc b/src/service_inspectors/nhttp_inspect/nhttp_inspect.cc index 5b13c8d72..ee0a8be0c 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_inspect.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_inspect.cc @@ -76,6 +76,18 @@ bool NHttpInspect::configure (SnortConfig *) return true; } +bool NHttpInspect::get_buf(unsigned id, Packet*, InspectionBuffer& b) +{ + const HttpBuffer* h = GetHttpBuffer((HTTP_BUFFER)id); + + if ( !h ) + return false; + + b.data = h->buf; + b.len = h->length; + return true; +} + int NHttpInspect::verify(SnortConfig*) { return 0; // 0 = good, -1 = bad diff --git a/src/service_inspectors/nhttp_inspect/nhttp_inspect.h b/src/service_inspectors/nhttp_inspect/nhttp_inspect.h index d36a3668c..1117bc5e8 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_inspect.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_inspect.h @@ -45,6 +45,7 @@ public: NHttpInspect(bool test_input, bool _test_output); ~NHttpInspect(); + bool get_buf(unsigned, Packet*, InspectionBuffer&); bool configure(SnortConfig*); int verify(SnortConfig*); void show(SnortConfig*);