diff options
Diffstat (limited to 'framework/src/suricata/src/detect-engine-content-inspection.c')
-rw-r--r-- | framework/src/suricata/src/detect-engine-content-inspection.c | 588 |
1 files changed, 0 insertions, 588 deletions
diff --git a/framework/src/suricata/src/detect-engine-content-inspection.c b/framework/src/suricata/src/detect-engine-content-inspection.c deleted file mode 100644 index 17df02ce..00000000 --- a/framework/src/suricata/src/detect-engine-content-inspection.c +++ /dev/null @@ -1,588 +0,0 @@ -/* Copyright (C) 2007-2011 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Anoop Saldanha <anoopsaldanha@gmail.com> - * - * Performs content inspection on any buffer supplied. - */ - -#include "suricata-common.h" -#include "suricata.h" - -#include "decode.h" - -#include "detect.h" -#include "detect-engine.h" -#include "detect-parse.h" -#include "detect-content.h" -#include "detect-pcre.h" -#include "detect-isdataat.h" -#include "detect-bytetest.h" -#include "detect-bytejump.h" -#include "detect-byte-extract.h" -#include "detect-replace.h" -#include "detect-engine-content-inspection.h" -#include "detect-uricontent.h" -#include "detect-urilen.h" -#include "detect-lua.h" -#include "detect-base64-decode.h" -#include "detect-base64-data.h" - -#include "app-layer-dcerpc.h" - -#include "util-spm.h" -#include "util-spm-bm.h" -#include "util-debug.h" -#include "util-print.h" - -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-profiling.h" - -#ifdef HAVE_LUA -#include "util-lua.h" -#endif - -/** - * \brief Run the actual payload match functions - * - * The following keywords are inspected: - * - content, including all the http and dce modified contents - * - isdaatat - * - pcre - * - bytejump - * - bytetest - * - byte_extract - * - urilen - * - - * - * All keywords are evaluated against the buffer with buffer_len. - * - * For accounting the last match in relative matching the - * det_ctx->buffer_offset int is used. - * - * \param de_ctx Detection engine context - * \param det_ctx Detection engine thread context - * \param s Signature to inspect - * \param sm SigMatch to inspect - * \param f Flow (for pcre flowvar storage) - * \param buffer Ptr to the buffer to inspect - * \param buffer_len Length of the payload - * \param stream_start_offset Indicates the start of the current buffer in - * the whole buffer stream inspected. This - * applies if the current buffer is inspected - * in chunks. - * \param inspection_mode Refers to the engine inspection mode we are currently - * inspecting. Can be payload, stream, one of the http - * buffer inspection modes or dce inspection mode. - * \param data Used to send some custom data. For example in - * payload inspection mode, data contains packet ptr, - * and under dce inspection mode, contains dce state. - * - * \retval 0 no match - * \retval 1 match - */ -int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, SigMatch *sm, - Flow *f, - uint8_t *buffer, uint32_t buffer_len, - uint32_t stream_start_offset, - uint8_t inspection_mode, void *data) -{ - SCEnter(); - KEYWORD_PROFILING_START; - - det_ctx->inspection_recursion_counter++; - - if (det_ctx->inspection_recursion_counter == de_ctx->inspection_recursion_limit) { - det_ctx->discontinue_matching = 1; - KEYWORD_PROFILING_END(det_ctx, sm->type, 0); - SCReturnInt(0); - } - - if (sm == NULL || buffer_len == 0) { - KEYWORD_PROFILING_END(det_ctx, sm->type, 0); - SCReturnInt(0); - } - - /* \todo unify this which is phase 2 of payload inspection unification */ - if (sm->type == DETECT_CONTENT) { - - DetectContentData *cd = (DetectContentData *)sm->ctx; - SCLogDebug("inspecting content %"PRIu32" buffer_len %"PRIu32, cd->id, buffer_len); - - /* we might have already have this content matched by the mpm. - * (if there is any other reason why we'd want to avoid checking - * it here, please fill it in) */ - //if (cd->flags & DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED) { - // goto match; - //} - - /* rule parsers should take care of this */ -#ifdef DEBUG - BUG_ON(cd->depth != 0 && cd->depth <= cd->offset); -#endif - - /* search for our pattern, checking the matches recursively. - * if we match we look for the next SigMatch as well */ - uint8_t *found = NULL; - uint32_t offset = 0; - uint32_t depth = buffer_len; - uint32_t prev_offset = 0; /**< used in recursive searching */ - uint32_t prev_buffer_offset = det_ctx->buffer_offset; - - do { - if ((cd->flags & DETECT_CONTENT_DISTANCE) || - (cd->flags & DETECT_CONTENT_WITHIN)) { - SCLogDebug("det_ctx->buffer_offset %"PRIu32, det_ctx->buffer_offset); - - offset = prev_buffer_offset; - depth = buffer_len; - - int distance = cd->distance; - if (cd->flags & DETECT_CONTENT_DISTANCE) { - if (cd->flags & DETECT_CONTENT_DISTANCE_BE) { - distance = det_ctx->bj_values[cd->distance]; - } - if (distance < 0 && (uint32_t)(abs(distance)) > offset) - offset = 0; - else - offset += distance; - - SCLogDebug("cd->distance %"PRIi32", offset %"PRIu32", depth %"PRIu32, - distance, offset, depth); - } - - if (cd->flags & DETECT_CONTENT_WITHIN) { - if (cd->flags & DETECT_CONTENT_WITHIN_BE) { - if ((int32_t)depth > (int32_t)(prev_buffer_offset + det_ctx->bj_values[cd->within] + distance)) { - depth = prev_buffer_offset + det_ctx->bj_values[cd->within] + distance; - } - } else { - if ((int32_t)depth > (int32_t)(prev_buffer_offset + cd->within + distance)) { - depth = prev_buffer_offset + cd->within + distance; - } - - SCLogDebug("cd->within %"PRIi32", det_ctx->buffer_offset %"PRIu32", depth %"PRIu32, - cd->within, prev_buffer_offset, depth); - } - - if (stream_start_offset != 0 && prev_buffer_offset == 0) { - if (depth <= stream_start_offset) { - goto no_match; - } else if (depth >= (stream_start_offset + buffer_len)) { - ; - } else { - depth = depth - stream_start_offset; - } - } - } - - if (cd->flags & DETECT_CONTENT_DEPTH_BE) { - if ((det_ctx->bj_values[cd->depth] + prev_buffer_offset) < depth) { - depth = prev_buffer_offset + det_ctx->bj_values[cd->depth]; - } - } else { - if (cd->depth != 0) { - if ((cd->depth + prev_buffer_offset) < depth) { - depth = prev_buffer_offset + cd->depth; - } - - SCLogDebug("cd->depth %"PRIu32", depth %"PRIu32, cd->depth, depth); - } - } - - if (cd->flags & DETECT_CONTENT_OFFSET_BE) { - if (det_ctx->bj_values[cd->offset] > offset) - offset = det_ctx->bj_values[cd->offset]; - } else { - if (cd->offset > offset) { - offset = cd->offset; - SCLogDebug("setting offset %"PRIu32, offset); - } - } - } else { /* implied no relative matches */ - /* set depth */ - if (cd->flags & DETECT_CONTENT_DEPTH_BE) { - depth = det_ctx->bj_values[cd->depth]; - } else { - if (cd->depth != 0) { - depth = cd->depth; - } - } - - if (stream_start_offset != 0 && cd->flags & DETECT_CONTENT_DEPTH) { - if (depth <= stream_start_offset) { - goto no_match; - } else if (depth >= (stream_start_offset + buffer_len)) { - ; - } else { - depth = depth - stream_start_offset; - } - } - - /* set offset */ - if (cd->flags & DETECT_CONTENT_OFFSET_BE) - offset = det_ctx->bj_values[cd->offset]; - else - offset = cd->offset; - prev_buffer_offset = 0; - } - - /* update offset with prev_offset if we're searching for - * matches after the first occurence. */ - SCLogDebug("offset %"PRIu32", prev_offset %"PRIu32, offset, prev_offset); - if (prev_offset != 0) - offset = prev_offset; - - SCLogDebug("offset %"PRIu32", depth %"PRIu32, offset, depth); - - if (depth > buffer_len) - depth = buffer_len; - - /* if offset is bigger than depth we can never match on a pattern. - * We can however, "match" on a negated pattern. */ - if (offset > depth || depth == 0) { - if (cd->flags & DETECT_CONTENT_NEGATED) { - goto match; - } else { - goto no_match; - } - } - - uint8_t *sbuffer = buffer + offset; - uint32_t sbuffer_len = depth - offset; - uint32_t match_offset = 0; - SCLogDebug("sbuffer_len %"PRIu32, sbuffer_len); -#ifdef DEBUG - BUG_ON(sbuffer_len > buffer_len); -#endif - - /* \todo Add another optimization here. If cd->content_len is - * greater than sbuffer_len found is anyways NULL */ - - /* do the actual search */ - if (cd->flags & DETECT_CONTENT_NOCASE) - found = BoyerMooreNocase(cd->content, cd->content_len, sbuffer, sbuffer_len, cd->bm_ctx); - else - found = BoyerMoore(cd->content, cd->content_len, sbuffer, sbuffer_len, cd->bm_ctx); - - /* next we evaluate the result in combination with the - * negation flag. */ - SCLogDebug("found %p cd negated %s", found, cd->flags & DETECT_CONTENT_NEGATED ? "true" : "false"); - - if (found == NULL && !(cd->flags & DETECT_CONTENT_NEGATED)) { - goto no_match; - } else if (found == NULL && (cd->flags & DETECT_CONTENT_NEGATED)) { - goto match; - } else if (found != NULL && (cd->flags & DETECT_CONTENT_NEGATED)) { - SCLogDebug("content %"PRIu32" matched at offset %"PRIu32", but negated so no match", cd->id, match_offset); - /* don't bother carrying recursive matches now, for preceding - * relative keywords */ - if (DETECT_CONTENT_IS_SINGLE(cd)) - det_ctx->discontinue_matching = 1; - goto no_match; - } else { - match_offset = (uint32_t)((found - buffer) + cd->content_len); - SCLogDebug("content %"PRIu32" matched at offset %"PRIu32"", cd->id, match_offset); - det_ctx->buffer_offset = match_offset; - - /* Match branch, add replace to the list if needed */ - if (cd->flags & DETECT_CONTENT_REPLACE) { - if (inspection_mode == DETECT_ENGINE_CONTENT_INSPECTION_MODE_PAYLOAD) { - /* we will need to replace content if match is confirmed */ - det_ctx->replist = DetectReplaceAddToList(det_ctx->replist, found, cd); - } else { - SCLogWarning(SC_ERR_INVALID_VALUE, "Can't modify payload without packet"); - } - } - if (!(cd->flags & DETECT_CONTENT_RELATIVE_NEXT)) { - SCLogDebug("no relative match coming up, so this is a match"); - goto match; - } - - /* bail out if we have no next match. Technically this is an - * error, as the current cd has the DETECT_CONTENT_RELATIVE_NEXT - * flag set. */ - if (sm->next == NULL) { - goto no_match; - } - - SCLogDebug("content %"PRIu32, cd->id); - KEYWORD_PROFILING_END(det_ctx, sm->type, 1); - - /* see if the next buffer keywords match. If not, we will - * search for another occurence of this content and see - * if the others match then until we run out of matches */ - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm->next, f, buffer, buffer_len, stream_start_offset, inspection_mode, data); - if (r == 1) { - SCReturnInt(1); - } - - if (det_ctx->discontinue_matching) - goto no_match; - - /* set the previous match offset to the start of this match + 1 */ - prev_offset = (match_offset - (cd->content_len - 1)); - SCLogDebug("trying to see if there is another match after prev_offset %"PRIu32, prev_offset); - } - - } while(1); - - } else if (sm->type == DETECT_ISDATAAT) { - SCLogDebug("inspecting isdataat"); - - DetectIsdataatData *id = (DetectIsdataatData *)sm->ctx; - if (id->flags & ISDATAAT_RELATIVE) { - if (det_ctx->buffer_offset + id->dataat > buffer_len) { - SCLogDebug("det_ctx->buffer_offset + id->dataat %"PRIu32" > %"PRIu32, det_ctx->buffer_offset + id->dataat, buffer_len); - if (id->flags & ISDATAAT_NEGATED) - goto match; - goto no_match; - } else { - SCLogDebug("relative isdataat match"); - if (id->flags & ISDATAAT_NEGATED) - goto no_match; - goto match; - } - } else { - if (id->dataat < buffer_len) { - SCLogDebug("absolute isdataat match"); - if (id->flags & ISDATAAT_NEGATED) - goto no_match; - goto match; - } else { - SCLogDebug("absolute isdataat mismatch, id->isdataat %"PRIu32", buffer_len %"PRIu32"", id->dataat, buffer_len); - if (id->flags & ISDATAAT_NEGATED) - goto match; - goto no_match; - } - } - - } else if (sm->type == DETECT_PCRE) { - SCLogDebug("inspecting pcre"); - DetectPcreData *pe = (DetectPcreData *)sm->ctx; - uint32_t prev_buffer_offset = det_ctx->buffer_offset; - uint32_t prev_offset = 0; - int r = 0; - - det_ctx->pcre_match_start_offset = 0; - do { - Packet *p = NULL; - if (inspection_mode == DETECT_ENGINE_CONTENT_INSPECTION_MODE_PAYLOAD) - p = (Packet *)data; - r = DetectPcrePayloadMatch(det_ctx, s, sm, p, f, - buffer, buffer_len); - if (r == 0) { - goto no_match; - } - - if (!(pe->flags & DETECT_PCRE_RELATIVE_NEXT)) { - SCLogDebug("no relative match coming up, so this is a match"); - goto match; - } - KEYWORD_PROFILING_END(det_ctx, sm->type, 1); - - /* save it, in case we need to do a pcre match once again */ - prev_offset = det_ctx->pcre_match_start_offset; - - /* see if the next payload keywords match. If not, we will - * search for another occurence of this pcre and see - * if the others match, until we run out of matches */ - r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm->next, - f, buffer, buffer_len, stream_start_offset, inspection_mode, data); - if (r == 1) { - SCReturnInt(1); - } - - if (det_ctx->discontinue_matching) - goto no_match; - - det_ctx->buffer_offset = prev_buffer_offset; - det_ctx->pcre_match_start_offset = prev_offset; - } while (1); - - } else if (sm->type == DETECT_BYTETEST) { - DetectBytetestData *btd = (DetectBytetestData *)sm->ctx; - uint8_t flags = btd->flags; - int32_t offset = btd->offset; - uint64_t value = btd->value; - if (flags & DETECT_BYTETEST_OFFSET_BE) { - offset = det_ctx->bj_values[offset]; - } - if (flags & DETECT_BYTETEST_VALUE_BE) { - value = det_ctx->bj_values[value]; - } - - /* if we have dce enabled we will have to use the endianness - * specified by the dce header */ - if (flags & DETECT_BYTETEST_DCE) { - DCERPCState *dcerpc_state = (DCERPCState *)data; - /* enable the endianness flag temporarily. once we are done - * processing we reset the flags to the original value*/ - flags |= ((dcerpc_state->dcerpc.dcerpchdr.packed_drep[0] & 0x10) ? - DETECT_BYTETEST_LITTLE: 0); - } - - if (DetectBytetestDoMatch(det_ctx, s, sm->ctx, buffer, buffer_len, flags, - offset, value) != 1) { - goto no_match; - } - - goto match; - - } else if (sm->type == DETECT_BYTEJUMP) { - DetectBytejumpData *bjd = (DetectBytejumpData *)sm->ctx; - uint8_t flags = bjd->flags; - int32_t offset = bjd->offset; - - if (flags & DETECT_BYTEJUMP_OFFSET_BE) { - offset = det_ctx->bj_values[offset]; - } - - /* if we have dce enabled we will have to use the endianness - * specified by the dce header */ - if (flags & DETECT_BYTEJUMP_DCE) { - DCERPCState *dcerpc_state = (DCERPCState *)data; - /* enable the endianness flag temporarily. once we are done - * processing we reset the flags to the original value*/ - flags |= ((dcerpc_state->dcerpc.dcerpchdr.packed_drep[0] & 0x10) ? - DETECT_BYTEJUMP_LITTLE: 0); - } - - if (DetectBytejumpDoMatch(det_ctx, s, sm->ctx, buffer, buffer_len, - flags, offset) != 1) { - goto no_match; - } - - goto match; - - } else if (sm->type == DETECT_BYTE_EXTRACT) { - - DetectByteExtractData *bed = (DetectByteExtractData *)sm->ctx; - uint8_t endian = bed->endian; - - /* if we have dce enabled we will have to use the endianness - * specified by the dce header */ - if ((bed->flags & DETECT_BYTE_EXTRACT_FLAG_ENDIAN) && - endian == DETECT_BYTE_EXTRACT_ENDIAN_DCE) { - - DCERPCState *dcerpc_state = (DCERPCState *)data; - /* enable the endianness flag temporarily. once we are done - * processing we reset the flags to the original value*/ - endian |= ((dcerpc_state->dcerpc.dcerpchdr.packed_drep[0] == 0x10) ? - DETECT_BYTE_EXTRACT_ENDIAN_LITTLE : DETECT_BYTE_EXTRACT_ENDIAN_BIG); - } - - if (DetectByteExtractDoMatch(det_ctx, sm, s, buffer, - buffer_len, - &det_ctx->bj_values[bed->local_id], - endian) != 1) { - goto no_match; - } - - goto match; - - /* we should never get here, but bail out just in case */ - } else if (sm->type == DETECT_AL_URILEN) { - SCLogDebug("inspecting uri len"); - - int r = 0; - DetectUrilenData *urilend = (DetectUrilenData *) sm->ctx; - - switch (urilend->mode) { - case DETECT_URILEN_EQ: - if (buffer_len == urilend->urilen1) - r = 1; - break; - case DETECT_URILEN_LT: - if (buffer_len < urilend->urilen1) - r = 1; - break; - case DETECT_URILEN_GT: - if (buffer_len > urilend->urilen1) - r = 1; - break; - case DETECT_URILEN_RA: - if (buffer_len > urilend->urilen1 && - buffer_len < urilend->urilen2) { - r = 1; - } - break; - } - - if (r == 1) { - goto match; - } - - det_ctx->discontinue_matching = 0; - - goto no_match; -#ifdef HAVE_LUA - } - else if (sm->type == DETECT_LUA) { - SCLogDebug("lua starting"); - /* for flowvar gets and sets we need to know the flow's lock status */ - int flow_lock = LUA_FLOW_LOCKED_BY_PARENT; - if (inspection_mode <= DETECT_ENGINE_CONTENT_INSPECTION_MODE_STREAM) - flow_lock = LUA_FLOW_NOT_LOCKED_BY_PARENT; - - if (DetectLuaMatchBuffer(det_ctx, s, sm, buffer, buffer_len, - det_ctx->buffer_offset, f, flow_lock) != 1) - { - SCLogDebug("lua no_match"); - goto no_match; - } - SCLogDebug("lua match"); - goto match; -#endif /* HAVE_LUA */ - } else if (sm->type == DETECT_BASE64_DECODE) { - if (DetectBase64DecodeDoMatch(det_ctx, s, sm, buffer, buffer_len)) { - if (s->sm_arrays[DETECT_SM_LIST_BASE64_DATA] != NULL) { - KEYWORD_PROFILING_END(det_ctx, sm->type, 1); - if (DetectBase64DataDoMatch(de_ctx, det_ctx, s, f)) { - /* Base64 is a terminal list. */ - goto final_match; - } - } - } - } else { - SCLogDebug("sm->type %u", sm->type); -#ifdef DEBUG - BUG_ON(1); -#endif - } - -no_match: - KEYWORD_PROFILING_END(det_ctx, sm->type, 0); - SCReturnInt(0); - -match: - /* this sigmatch matched, inspect the next one. If it was the last, - * the buffer portion of the signature matched. */ - if (sm->next != NULL) { - KEYWORD_PROFILING_END(det_ctx, sm->type, 1); - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm->next, f, buffer, buffer_len, stream_start_offset, inspection_mode, data); - SCReturnInt(r); - } -final_match: - KEYWORD_PROFILING_END(det_ctx, sm->type, 1); - SCReturnInt(1); -} |