/* * Content Option processing function * * p: packet data structure, same as the one found in snort. * content: data defined in the detection plugin for this rule content option * cursor: updated to point the 1st byte after the match * * Returns: * > 0 : match found * = 0 : no match found * < 0 : error * * Predefined constants: * (see sf_snort_plugin_api.h for more values) * CONTENT_MATCH - if content specifier is found within buffer * CONTENT_NOMATCH - if content specifier is not found within buffer * * Notes: * For multiple URI buffers, we scan each buffer, if any one of them * contains the content we return a match. This is essentially an OR * operation. * * Currently support: * options: * nocase * offset * depth * buffers: * normalized(alt-decode) * raw * uri * post * */ ENGINE_LINKAGE int contentMatch(void *p, ContentInfo* content, const u_int8_t **cursor) { const u_int8_t * q = NULL; const u_int8_t * buffer_start; const u_int8_t * buffer_end = NULL; u_int buffer_len; int length; int i; char relative = 0; SFSnortPacket *sp = (SFSnortPacket *) p; if (content->flags & CONTENT_RELATIVE) { if( !cursor || !(*cursor) ) { return CONTENT_NOMATCH; } relative = 1; } if (content->flags & (CONTENT_BUF_URI | CONTENT_BUF_POST)) { for (i=0;i<sp->num_uris; i++) { if ((content->flags & CONTENT_BUF_URI) && (i != HTTP_BUFFER_URI)) { /* Not looking at the "URI" buffer... * keep going. */ continue; } if ((content->flags & CONTENT_BUF_POST) && (i != HTTP_BUFFER_CLIENT_BODY)) { /* Not looking at the "POST" buffer... * keep going. */ continue; } if (relative) { if (checkCursorInternal(p, content->flags, content->offset, *cursor) <= 0) { /* Okay, cursor is NOT within this buffer... */ continue; } buffer_start = *cursor + content->offset; } else { buffer_start = _ded.uriBuffers[i]->uriBuffer + content->offset; } if (_uri_buffer_end) { buffer_end = _uri_buffer_end; } else { buffer_end = _ded.uriBuffers[i]->uriBuffer + _ded.uriBuffers[i]->uriLength; } length = buffer_len = buffer_end - buffer_start; if (length <= 0) { continue; } /* Don't bother looking deeper than depth */ if ( content->depth != 0 && content->depth < buffer_len ) { buffer_len = content->depth; } q = hbm_match((HBM_STRUCT*)content->boyer_ptr,buffer_start,buffer_len); if (q) { if (content->flags & CONTENT_END_BUFFER) { _uri_buffer_end = q; } if (cursor) { *cursor = q + content->patternByteFormLength; } return CONTENT_MATCH; } } return CONTENT_NOMATCH; } if (relative) { if (checkCursorInternal(p, content->flags, content->offset, *cursor) <= 0) { return CONTENT_NOMATCH; } if ((content->flags & CONTENT_BUF_NORMALIZED) && (sp->flags & FLAG_ALT_DECODE)) { if (_alt_buffer_end) { buffer_end = _alt_buffer_end; } else { buffer_end = _ded.altBuffer + sp->normalized_payload_size; } } else { if (_buffer_end) { buffer_end = _buffer_end; } else { buffer_end = sp->payload + sp->payload_size; } } buffer_start = *cursor + content->offset; } else { if ((content->flags & CONTENT_BUF_NORMALIZED) && (sp->flags & FLAG_ALT_DECODE)) { buffer_start = _ded.altBuffer + content->offset; if (_alt_buffer_end) { buffer_end = _alt_buffer_end; } else { buffer_end = _ded.altBuffer + sp->normalized_payload_size; } } else { buffer_start = sp->payload + content->offset; if (_buffer_end) { buffer_end = _buffer_end; } else { buffer_end = sp->payload + sp->payload_size; } } } length = buffer_len = buffer_end - buffer_start; if (length <= 0) { return CONTENT_NOMATCH; } /* Don't bother looking deeper than depth */ if ( content->depth != 0 && content->depth < buffer_len ) { buffer_len = content->depth; } q = hbm_match((HBM_STRUCT*)content->boyer_ptr,buffer_start,buffer_len); if (q) { if (content->flags & CONTENT_END_BUFFER) { if ((content->flags & CONTENT_BUF_NORMALIZED) && (sp->flags & FLAG_ALT_DECODE)) { _alt_buffer_end = q; } else { _buffer_end = q; } } if (cursor) { *cursor = q + content->patternByteFormLength; } return CONTENT_MATCH; } return CONTENT_NOMATCH; }
/* ** Search a body of text or data for paterns */ int mwmSearch( void * pv, unsigned char * T, int n, int(*match)( void * id, int index, void * data ), void * data ) { MWM_STRUCT * ps = (MWM_STRUCT*)pv; unsigned char *s; iPatCount += n; ConvCaseToUpperEx( S, T, n ); /* Copy and Convert to Upper Case */ if( ps->msMethod == MTH_BM ) { /* Boyer-Moore */ int i,nfound=0; unsigned char * Tx = NULL; for( i=0; i<ps->msNumPatterns; i++ ) { s = &S[0]; /* Init this for each pattern we search */ do { Tx = hbm_match( ps->msPatArray[i].psBmh, s, n ); if( Tx ) { /* If we are case sensitive, do a final exact match test */ if( !ps->msPatArray[i].psNoCase ) { if( memcmp(ps->msPatArray[i].psPatCase,&T[Tx-S],ps->msPatArray[i].psLen) ) { if (++Tx < s + n) { n--; s++; } else { n = 0; } continue; /* no match, continue with this pattern, or next if n == 0 */ } } nfound++; if( match(ps->msPatArray[i].psID, (int)(Tx-S),data) ) return nfound; } break; /* on to next pattern */ } while (n >= 0); } return nfound; } else /* MTH_MWM */ { /* Wu-Manber */ return ps->search( ps, S, n, T, match, data ); } }
static int contentMatchCommon(ContentInfo* content, const uint8_t *start_ptr, int dlen, const uint8_t **cursor) { const uint8_t *q; const uint8_t *base_ptr; const uint8_t *end_ptr = start_ptr + dlen; int depth; char relative = (content->flags & CONTENT_RELATIVE) ? 1 : 0; if (relative) { // Sanity check to make sure the cursor isn't NULL and is within the // buffer we're searching. It could be at the very end of the buffer // due to a previous match, but may have a negative offset here. if ((cursor == NULL) || (*cursor == NULL) || (*cursor < start_ptr) || (*cursor > end_ptr)) return CONTENT_CURSOR_ERROR; base_ptr = *cursor; depth = dlen - (*cursor - start_ptr); } else { base_ptr = start_ptr; depth = dlen; } // Adjust base_ptr and depth based on offset/depth parameters. if (relative && ((content->offset != 0) || (content->depth != 0))) { if (content->offset != 0) { base_ptr += content->offset; depth -= content->offset; } // If the offset is negative and puts us before start_ptr // set base_ptr to start_ptr and adjust depth based on depth. if (base_ptr < start_ptr) { int delta = (int)content->depth - (start_ptr - base_ptr); base_ptr = start_ptr; depth = ((content->depth == 0) || (delta > dlen)) ? dlen : delta; } else if ((content->depth != 0) && ((int)content->depth < depth)) { depth = (int)content->depth; } } else if ((content->offset != 0) || (content->depth != 0)) { if (content->offset != 0) { base_ptr += content->offset; depth -= content->offset; } if ((content->depth != 0) && ((int)content->depth < depth)) depth = content->depth; } // If the pattern size is greater than the amount of data we have to // search, there's no way we can match, so return error, however, return // CONTENT_NOMATCH here for the case where the match is inverted and there // is at least some data. if ((int)content->patternByteFormLength > depth) { if ((content->flags & NOT_FLAG) && (depth > 0)) return CONTENT_NOMATCH; // This will get inverted on return return CONTENT_CURSOR_ERROR; } q = hbm_match((HBM_STRUCT*)content->boyer_ptr, base_ptr, depth); if (q) { if (content->flags & CONTENT_END_BUFFER) { if ( HTTP_CONTENT(content->flags) ) _uri_buffer_end = q; else if ((content->flags & CONTENT_BUF_NORMALIZED) && _ded.Is_DetectFlag(SF_FLAG_ALT_DETECT) ) _alt_detect_end = q; else if ((content->flags & CONTENT_BUF_NORMALIZED) && _ded.Is_DetectFlag(SF_FLAG_ALT_DECODE) ) _alt_buffer_end = q; else _buffer_end = q; } if (cursor) *cursor = q + content->patternByteFormLength; return CONTENT_MATCH; } return CONTENT_NOMATCH; }
/* * Content Option processing function * * p: packet data structure, same as the one found in snort. * content: data defined in the detection plugin for this rule content option * cursor: updated to point the 1st byte after the match * * Returns: * > 0 : match found * = 0 : no match found * < 0 : error * * Predefined constants: * (see sf_snort_plugin_api.h for more values) * CONTENT_MATCH - if content specifier is found within buffer * CONTENT_NOMATCH - if content specifier is not found within buffer * * Notes: * For multiple URI buffers, we scan each buffer, if any one of them * contains the content we return a match. This is essentially an OR * operation. * * Currently support: * options: * nocase * offset * depth * buffers: * normalized(alt-decode) * raw * uri * post * */ static int contentMatchInternal(void *p, ContentInfo* content, const uint8_t **cursor) { const uint8_t * q = NULL; const uint8_t * buffer_start = NULL; const uint8_t * buffer_end = NULL; u_int buffer_len; int length; int i; char relative = 0; SFSnortPacket *sp = (SFSnortPacket *) p; /* This content is only used for fast pattern matching and * should not be evaluated */ if (content->flags & CONTENT_FAST_PATTERN_ONLY) return CONTENT_MATCH; if (content->flags & CONTENT_RELATIVE) { if( !cursor || !(*cursor) ) { return CONTENT_NOMATCH; } relative = 1; } /* Check for byte_extract variables and use them if present. */ if (content->offset_location) { content->offset = *content->offset_location; } if (content->depth_location) { content->depth = *content->depth_location; } if (content->flags & URI_CONTENT_BUFS) { for (i=0; i<sp->num_uris; i++) { switch (i) { case HTTP_BUFFER_URI: if (!(content->flags & CONTENT_BUF_URI)) continue; /* Go to next, not looking at URI buffer */ break; case HTTP_BUFFER_HEADER: if (!(content->flags & CONTENT_BUF_HEADER)) continue; /* Go to next, not looking at HEADER buffer */ break; case HTTP_BUFFER_CLIENT_BODY: if (!(content->flags & CONTENT_BUF_POST)) continue; /* Go to next, not looking at POST buffer */ break; case HTTP_BUFFER_METHOD: if (!(content->flags & CONTENT_BUF_METHOD)) continue; /* Go to next, not looking at METHOD buffer */ break; case HTTP_BUFFER_COOKIE: if (!(content->flags & CONTENT_BUF_COOKIE)) continue; /* Go to next, not looking at COOKIE buffer */ break; case HTTP_BUFFER_RAW_URI: if (!(content->flags & CONTENT_BUF_RAW_URI)) continue; /* Go to next, not looking at RAW URI buffer */ break; case HTTP_BUFFER_RAW_HEADER: if (!(content->flags & CONTENT_BUF_RAW_HEADER)) continue; /* Go to next, not looking at RAW HEADER buffer */ break; case HTTP_BUFFER_RAW_COOKIE: if (!(content->flags & CONTENT_BUF_RAW_COOKIE)) continue; /* Go to next, not looking at RAW COOKIE buffer */ break; case HTTP_BUFFER_STAT_CODE: if (!(content->flags & CONTENT_BUF_STAT_CODE)) continue; /* Go to next, not looking at STAT CODE buffer */ break; case HTTP_BUFFER_STAT_MSG: if (!(content->flags & CONTENT_BUF_STAT_MSG)) continue; /* Go to next, not looking at STAT MSG buffer */ break; default: /* Uh, what buffer is this? */ return CONTENT_NOMATCH; } if (!_ded.uriBuffers[i]->uriBuffer || (_ded.uriBuffers[i]->uriLength == 0)) continue; if (relative) { if (checkCursorInternal(p, content->flags, content->offset, *cursor) <= 0) { /* Okay, cursor is NOT within this buffer... */ continue; } buffer_start = *cursor + content->offset; } else { buffer_start = _ded.uriBuffers[i]->uriBuffer + content->offset; } buffer_end = _ded.uriBuffers[i]->uriBuffer + _ded.uriBuffers[i]->uriLength; length = buffer_len = buffer_end - buffer_start; if (length <= 0) { continue; } /* Don't bother looking deeper than depth */ if ( content->depth != 0 && content->depth < buffer_len ) { buffer_len = content->depth; } q = hbm_match((HBM_STRUCT*)content->boyer_ptr,buffer_start,buffer_len); if (q) { if (content->flags & CONTENT_END_BUFFER) { _uri_buffer_end = q; } if (cursor) { *cursor = q + content->patternByteFormLength; } return CONTENT_MATCH; } } return CONTENT_NOMATCH; } if (relative) { if (checkCursorInternal(p, content->flags, content->offset, *cursor) <= 0) { return CONTENT_NOMATCH; } if ((content->flags & CONTENT_BUF_NORMALIZED) && _ded.Is_DetectFlag(SF_FLAG_DETECT_ALL)) { if(_ded.Is_DetectFlag(SF_FLAG_ALT_DETECT)) { if (_alt_detect_end) { buffer_end = _alt_detect_end; } else { buffer_end = _ded.altDetect->data + _ded.altDetect->len; } } else if(_ded.Is_DetectFlag(SF_FLAG_ALT_DECODE)) { if (_alt_buffer_end) { buffer_end = _alt_buffer_end; } else { buffer_end = _ded.altBuffer->data + _ded.altBuffer->len; } } } else { if(sp->normalized_payload_size) { buffer_end = sp->payload + sp->normalized_payload_size; } else if (_buffer_end) { buffer_end = _buffer_end; } else { buffer_end = sp->payload + sp->payload_size; } } buffer_start = *cursor + content->offset; } else { if ((content->flags & CONTENT_BUF_NORMALIZED) && _ded.Is_DetectFlag(SF_FLAG_DETECT_ALL)) { if(_ded.Is_DetectFlag(SF_FLAG_ALT_DETECT)) { buffer_start = _ded.altDetect->data + content->offset; if (_alt_detect_end) { buffer_end = _alt_detect_end; } else { buffer_end = _ded.altDetect->data + _ded.altDetect->len; } } else if(_ded.Is_DetectFlag(SF_FLAG_ALT_DECODE)) { buffer_start = _ded.altBuffer->data + content->offset; if (_alt_buffer_end) { buffer_end = _alt_buffer_end; } else { buffer_end = _ded.altBuffer->data + _ded.altBuffer->len; } } } else { buffer_start = sp->payload + content->offset; if(sp->normalized_payload_size) { buffer_end = sp->payload + sp->normalized_payload_size; } else if (_buffer_end) { buffer_end = _buffer_end; } else { buffer_end = sp->payload + sp->payload_size; } } } length = buffer_len = buffer_end - buffer_start; if (length <= 0) { return CONTENT_NOMATCH; } /* Don't bother looking deeper than depth */ if ( content->depth != 0 && content->depth < buffer_len ) { buffer_len = content->depth; } q = hbm_match((HBM_STRUCT*)content->boyer_ptr,buffer_start,buffer_len); if (q) { if (content->flags & CONTENT_END_BUFFER) { if((content->flags & CONTENT_BUF_NORMALIZED) && _ded.Is_DetectFlag(SF_FLAG_ALT_DETECT)) { _alt_detect_end = q; } else if ((content->flags & CONTENT_BUF_NORMALIZED) && _ded.Is_DetectFlag(SF_FLAG_ALT_DECODE)) { _alt_buffer_end = q; } else { _buffer_end = q; } } if (cursor) { *cursor = q + content->patternByteFormLength; } return CONTENT_MATCH; } return CONTENT_NOMATCH; }