From a2b0b3ab836e0c93a9f213b603c72f47c8b434be Mon Sep 17 00:00:00 2001 From: Anoop Saldanha Date: Wed, 23 Jun 2010 01:00:35 +0530 Subject: [PATCH] add pcre with U modifiers to the umatch sigmatch list. fix for bug 155 --- src/detect-engine-uri.c | 205 ++++++++++++++++++++++++++++++++++++++++------- src/detect-engine-uri.h | 6 +- src/detect-pcre.c | 37 ++++++++- src/suricata.c | 2 + 4 files changed, 215 insertions(+), 35 deletions(-) diff --git a/src/detect-engine-uri.c b/src/detect-engine-uri.c index 138a68d..9580698 100644 --- a/src/detect-engine-uri.c +++ b/src/detect-engine-uri.c @@ -28,12 +28,16 @@ #include "decode.h" #include "detect.h" +#include "detect-engine.h" +#include "detect-parse.h" +#include "detect-engine-state.h" #include "detect-uricontent.h" #include "detect-pcre.h" #include "detect-isdataat.h" #include "detect-bytetest.h" #include "detect-bytejump.h" +#include "flow-util.h" #include "util-spm.h" #include "util-debug.h" #include "util-print.h" @@ -53,24 +57,26 @@ #include "app-layer-htp.h" #include "app-layer-protos.h" -/** \brief Run the actual payload match function for uricontent +/** + * \brief Run the actual payload match function for uricontent. * - * For accounting the last match in relative matching the - * det_ctx->uricontent_payload_offset int is used. + * For accounting the last match in relative matching the + * det_ctx->payload_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 payload ptr to the uricontent payload to inspect - * \param payload_len length of the uricontent payload + * \param de_ctx Detection engine context. + * \param det_ctx Detection engine thread context. + * \param s Signature to inspect. + * \param sm SigMatch to inspect. + * \param payload Ptr to the uricontent payload to inspect. + * \param payload_len Length of the uricontent payload. * - * \retval 0 no match - * \retval 1 match + * \retval 0 no match. + * \retval 1 match. */ static int DoInspectPacketUri(DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, Signature *s, SigMatch *sm, - uint8_t *payload, uint32_t payload_len) + DetectEngineThreadCtx *det_ctx, + Signature *s, SigMatch *sm, + uint8_t *payload, uint32_t payload_len) { SCEnter(); @@ -102,7 +108,7 @@ static int DoInspectPacketUri(DetectEngineCtx *de_ctx, ud->flags & DETECT_URICONTENT_WITHIN) { SCLogDebug("det_ctx->uricontent_payload_offset %"PRIu32, det_ctx->uricontent_payload_offset); - offset = det_ctx->uricontent_payload_offset; + offset = det_ctx->payload_offset; depth = payload_len; if (ud->flags & DETECT_URICONTENT_DISTANCE) { @@ -116,17 +122,17 @@ static int DoInspectPacketUri(DetectEngineCtx *de_ctx, } if (ud->flags & DETECT_URICONTENT_WITHIN) { - if ((int32_t)depth > (int32_t)(det_ctx->uricontent_payload_offset + ud->within)) { - depth = det_ctx->uricontent_payload_offset + ud->within; + if ((int32_t)depth > (int32_t)(det_ctx->payload_offset + ud->within)) { + depth = det_ctx->payload_offset + ud->within; } - SCLogDebug("ud->within %"PRIi32", det_ctx->uricontent_payload_offset %"PRIu32", depth %"PRIu32, - ud->within, det_ctx->uricontent_payload_offset, depth); + SCLogDebug("ud->within %"PRIi32", det_ctx->payload_offset %"PRIu32", depth %"PRIu32, + ud->within, det_ctx->payload_offset, depth); } if (ud->depth != 0) { - if ((ud->depth + det_ctx->uricontent_payload_offset) < depth) { - depth = det_ctx->uricontent_payload_offset + ud->depth; + if ((ud->depth + det_ctx->payload_offset) < depth) { + depth = det_ctx->payload_offset + ud->depth; } SCLogDebug("ud->depth %"PRIu32", depth %"PRIu32, ud->depth, depth); @@ -196,7 +202,7 @@ static int DoInspectPacketUri(DetectEngineCtx *de_ctx, } else { match_offset = (uint32_t)((found - payload) + ud->uricontent_len); SCLogDebug("uricontent %"PRIu32" matched at offset %"PRIu32"", ud->id, match_offset); - det_ctx->uricontent_payload_offset = match_offset; + det_ctx->payload_offset = match_offset; if (!(ud->flags & DETECT_URICONTENT_RELATIVE_NEXT)) { SCLogDebug("no relative match coming up, so this is a match"); @@ -220,6 +226,16 @@ static int DoInspectPacketUri(DetectEngineCtx *de_ctx, } } while(1); + } else if (sm->type == DETECT_PCRE) { + SCLogDebug("inspecting pcre"); + + int r = DetectPcrePayloadMatch(det_ctx, s, sm, /* no packet */NULL, + NULL, payload, payload_len); + if (r == 1) { + goto match; + } + + SCReturnInt(0); } else { /* we should never get here, but bail out just in case */ BUG_ON(1); @@ -230,7 +246,8 @@ match: /* this sigmatch matched, inspect the next one. If it was the last, * the payload portion of the signature matched. */ if (sm->next != NULL) { - int r = DoInspectPacketUri(de_ctx,det_ctx,s,sm->next, payload, payload_len); + int r = DoInspectPacketUri(de_ctx, det_ctx, s, sm->next, payload, + payload_len); SCReturnInt(r); } else { SCReturnInt(1); @@ -259,11 +276,6 @@ int DetectEngineInspectPacketUris(DetectEngineCtx *de_ctx, int r = 0; HtpState *htp_state = NULL; - if (!(det_ctx->sgh->flags & SIG_GROUP_HAVEURICONTENT)) { - SCLogDebug("no uricontent in sgh"); - SCReturnInt(0); - } - htp_state = (HtpState *)alstate; if (htp_state == NULL) { SCLogDebug("no HTTP state"); @@ -278,6 +290,7 @@ int DetectEngineInspectPacketUris(DetectEngineCtx *de_ctx, goto end; } + det_ctx->de_have_httpuri = TRUE; /* If we have the uricontent multi pattern matcher signatures in signature list, then search the received HTTP uri(s) in the htp state against those patterns */ @@ -288,8 +301,8 @@ int DetectEngineInspectPacketUris(DetectEngineCtx *de_ctx, /* only consider uri sigs if we've seen at least one match */ /** \warning when we start supporting negated uri content matches * we need to update this check as well */ - if (cnt > 0) { - det_ctx->de_have_httpuri = TRUE; + if (cnt <= 0) { + det_ctx->de_have_httpuri = FALSE; } SCLogDebug("uricontent cnt %"PRIu32"", cnt); @@ -306,7 +319,7 @@ int DetectEngineInspectPacketUris(DetectEngineCtx *de_ctx, goto end; } - if (det_ctx->de_mpm_scanned_uri == TRUE) { + if ((s->flags & SIG_FLAG_MPM_URI) && (det_ctx->de_mpm_scanned_uri == TRUE)) { if (det_ctx->pmq.pattern_id_bitarray != NULL) { /* filter out sigs that want pattern matches, but * have no matches */ @@ -321,7 +334,7 @@ int DetectEngineInspectPacketUris(DetectEngineCtx *de_ctx, sm = s->umatch; - det_ctx->uricontent_payload_offset = 0; + det_ctx->payload_offset = 0; #ifdef DEBUG DetectUricontentData *co = (DetectUricontentData *)sm->ctx; @@ -356,3 +369,133 @@ end: SCReturnInt(r); } +/***********************************Unittests**********************************/ + +#ifdef UNITTESTS + +static int UriTestSig01(void) +{ + int result = 1; + Flow f; + HtpState *http_state = NULL; + uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; + uint32_t http_buf1_len = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = "POST /oneself HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; + uint32_t http_buf2_len = sizeof(http_buf2) - 1; + TcpSession ssn; + Packet p; + Signature *s = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&p, 0, sizeof(Packet)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p.src.family = AF_INET; + p.dst.family = AF_INET; + p.payload = http_buf1; + p.payload_len = http_buf1_len; + p.proto = IPPROTO_TCP; + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.src.family = AF_INET; + f.dst.family = AF_INET; + + p.flow = &f; + p.flowflags |= FLOW_PKT_TOSERVER; + p.flowflags |= FLOW_PKT_ESTABLISHED; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + FlowL7DataPtrInit(&f); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->mpm_matcher = MPM_B2G; + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Test pcre U option\"; " + "uricontent:one; sid:1;)"); + if (s == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)]; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, &p); + + if (!PacketAlertCheck(&p, 1)) { + printf("sig 1 alerted, but it should not: "); + goto end; + } + + r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)]; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + if (!PacketAlertCheck(&p, 1)) { + printf("sig 1 alerted, but it should not: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, &p); + + result = 1; + +end: + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + return result; +} + +#endif /* UNITTESTS */ + +void UriRegisterTests(void) +{ + +#ifdef UNITTESTS + UtRegisterTest("UriTestSig01", UriTestSig01, 1); +#endif /* UNITTESTS */ + + return; +} diff --git a/src/detect-engine-uri.h b/src/detect-engine-uri.h index e68c695..1eb886c 100644 --- a/src/detect-engine-uri.h +++ b/src/detect-engine-uri.h @@ -24,9 +24,9 @@ #ifndef __DETECT_ENGINE_URICONTENT_H__ #define __DETECT_ENGINE_URICONTENT_H__ -int DetectEngineInspectPacketUris(DetectEngineCtx *, - DetectEngineThreadCtx *, Signature *, Flow *, uint8_t, - void *); +int DetectEngineInspectPacketUris(DetectEngineCtx *, DetectEngineThreadCtx *, + Signature *, Flow *, uint8_t, void *); +void UriRegisterTests(void); #endif /* __DETECT_ENGINE_URICONTENT_H__ */ diff --git a/src/detect-pcre.c b/src/detect-pcre.c index a7863ee..44c5850 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -840,6 +840,18 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst AppLayerHtpEnableRequestBodyCallback(); SigMatchAppendAppLayer(s, sm); + } else if (pd->flags & DETECT_PCRE_URI) { + s->flags |= SIG_FLAG_APPLAYER; + + if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { + SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting" + " keywords."); + goto error; + } + + s->alproto = ALPROTO_HTTP; + + SigMatchAppendUricontent(s, sm); } else { switch (s->alproto) { case ALPROTO_DCERPC: @@ -1180,6 +1192,7 @@ static int DetectPcreTestSig01Real(int mpm_type) { "Host: two.example.org\r\n" "\r\n\r\n"; uint16_t buflen = strlen((char *)buf); + TcpSession ssn; Packet p; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; @@ -1190,13 +1203,25 @@ static int DetectPcreTestSig01Real(int mpm_type) { memset(&th_v, 0, sizeof(th_v)); memset(&p, 0, sizeof(p)); + memset(&ssn, 0, sizeof(TcpSession)); + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.src.family = AF_INET; + f.dst.family = AF_INET; + f.alproto = ALPROTO_HTTP; + p.src.family = AF_INET; p.dst.family = AF_INET; p.payload = buf; p.payload_len = buflen; p.proto = IPPROTO_TCP; p.flow = &f; + p.flowflags |= FLOW_PKT_TOSERVER; + p.flowflags |= FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(TRUE); + FlowL7DataPtrInit(&f); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { @@ -1215,18 +1240,28 @@ static int DetectPcreTestSig01Real(int mpm_type) { SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, buf, buflen); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } SigMatchSignatures(&th_v, de_ctx, det_ctx, &p); if (PacketAlertCheck(&p, 1) == 1) { result = 1; } +end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); + + FlowL7DataPtrFree(&f); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); -end: return result; } diff --git a/src/suricata.c b/src/suricata.c index 6950703..d76833f 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -51,6 +51,7 @@ #include "detect-engine-sigorder.h" #include "detect-engine-payload.h" #include "detect-engine-dcepayload.h" +#include "detect-engine-uri.h" #include "detect-engine-state.h" #include "tm-queuehandlers.h" @@ -877,6 +878,7 @@ int main(int argc, char **argv) #endif PayloadRegisterTests(); DcePayloadRegisterTests(); + UriRegisterTests(); #ifdef PROFILING SCProfilingRegisterTests(); #endif -- 1.7.0.2