/* Copyright (C) 2007-2010 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 Victor Julien * \author Pablo Rincon Crespo * * Based on detect-engine-uri.c */ #include "suricata-common.h" #include "suricata.h" #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-urilen.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" #include "flow.h" #include "detect-flow.h" #include "flow-var.h" #include "threads.h" #include "flow-alert-sid.h" #include "stream-tcp.h" #include "stream.h" #include "app-layer-parser.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "app-layer.h" #include "app-layer-htp.h" #include "app-layer-protos.h" /** * \brief Run the actual payload match function for uricontent. * * 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. * * \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) { SCEnter(); if (sm == NULL) { SCReturnInt(0); } if (sm->type == DETECT_URICONTENT) { if (payload_len == 0) { SCReturnInt(0); } DetectUricontentData *ud = NULL; ud = (DetectUricontentData *)sm->ctx; SCLogDebug("inspecting content %"PRIu32" payload_len %"PRIu32, ud->id, payload_len); /* rule parsers should take care of this */ BUG_ON(ud->depth != 0 && ud->depth <= ud->offset); /* 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 = payload_len; uint32_t prev_offset = 0; /**< used in recursive searching */ uint32_t prev_payload_offset = det_ctx->payload_offset; do { if (ud->flags & DETECT_URICONTENT_DISTANCE || ud->flags & DETECT_URICONTENT_WITHIN) { SCLogDebug("prev_payload_offset %"PRIu32, prev_payload_offset); offset = prev_payload_offset; depth = payload_len; if (ud->flags & DETECT_URICONTENT_DISTANCE) { if (ud->distance < 0 && (uint32_t)(abs(ud->distance)) > offset) offset = 0; else offset += ud->distance; SCLogDebug("ud->distance %"PRIi32", offset %"PRIu32", depth %"PRIu32, ud->distance, offset, depth); } if (ud->flags & DETECT_URICONTENT_WITHIN) { if ((int32_t)depth > (int32_t)(prev_payload_offset + ud->within)) { depth = prev_payload_offset + ud->within; } SCLogDebug("ud->within %"PRIi32", prev_payload_offset %"PRIu32", depth %"PRIu32, ud->within, prev_payload_offset, depth); } if (ud->depth != 0) { if ((ud->depth + prev_payload_offset) < depth) { depth = prev_payload_offset + ud->depth; } SCLogDebug("ud->depth %"PRIu32", depth %"PRIu32, ud->depth, depth); } if (ud->offset > offset) { offset = ud->offset; SCLogDebug("setting offset %"PRIu32, offset); } } else { /* implied no relative matches */ /* set depth */ if (ud->depth != 0) { depth = ud->depth; } /* set offset */ offset = ud->offset; prev_payload_offset = 0; } /* update offset with prev_offset if we're searching for * matches after the first occurence. */ SCLogDebug("offset %"PRIu32", prev_offset %"PRIu32, prev_offset, depth); if (prev_offset != 0) offset = prev_offset; SCLogDebug("offset %"PRIu32", depth %"PRIu32, offset, depth); if (depth > payload_len) depth = payload_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 (ud->flags & DETECT_URICONTENT_NEGATED) { goto match; } else { SCReturnInt(0); } } uint8_t *spayload = payload + offset; uint32_t spayload_len = depth - offset; uint32_t match_offset = 0; SCLogDebug("spayload_len %"PRIu32, spayload_len); BUG_ON(spayload_len > payload_len); //PrintawDataFp(stdout,ud->uricontent,ud->uricontent_len); /* do the actual search with boyer moore precooked ctx */ if (ud->flags & DETECT_URICONTENT_NOCASE) found = BoyerMooreNocase(ud->uricontent, ud->uricontent_len, spayload, spayload_len, ud->bm_ctx->bmGs, ud->bm_ctx->bmBc); else found = BoyerMoore(ud->uricontent, ud->uricontent_len, spayload, spayload_len, ud->bm_ctx->bmGs, ud->bm_ctx->bmBc); /* next we evaluate the result in combination with the * negation flag. */ SCLogDebug("found %p ud negated %s", found, ud->flags & DETECT_URICONTENT_NEGATED ? "true" : "false"); if (found == NULL && !(ud->flags & DETECT_URICONTENT_NEGATED)) { SCReturnInt(0); } else if (found == NULL && ud->flags & DETECT_URICONTENT_NEGATED) { goto match; } else if (found != NULL && ud->flags & DETECT_URICONTENT_NEGATED) { /* why are we saving match offset here? */ match_offset = (uint32_t)((found - payload) + ud->uricontent_len); SCLogDebug("uricontent %"PRIu32" matched at offset %"PRIu32", but negated so no match", ud->id, match_offset); SCReturnInt(0); } else { match_offset = (uint32_t)((found - payload) + ud->uricontent_len); SCLogDebug("uricontent %"PRIu32" matched at offset %"PRIu32"", ud->id, 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"); goto match; } BUG_ON(sm->next == NULL); SCLogDebug("uricontent %"PRIu32, ud->id); /* see if the next payload keywords match. If not, we will * search for another occurence of this uricontent and see * if the others match then until we run out of matches */ int r = DoInspectPacketUri(de_ctx,det_ctx,s,sm->next, payload, payload_len); if (r == 1) { SCReturnInt(1); } /* set the previous match offset to the start of this match + 1 */ prev_offset = (match_offset - (ud->uricontent_len - 1)); SCLogDebug("trying to see if there is another match after prev_offset %"PRIu32, prev_offset); } } 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); /* PrintRawDataFp(stdout, payload, payload_len); */ if (r == 1) { goto match; } SCReturnInt(0); } 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 (payload_len == urilend->urilen1) r = 1; break; case DETECT_URILEN_LT: if (payload_len < urilend->urilen1) r = 1; break; case DETECT_URILEN_GT: if (payload_len > urilend->urilen1) r = 1; break; case DETECT_URILEN_RA: if (payload_len > urilend->urilen1 && payload_len < urilend->urilen2) r = 1; break; } if (r == 1) { goto match; } SCReturnInt(0); } else { /* we should never get here, but bail out just in case */ BUG_ON(1); } SCReturnInt(0); 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); SCReturnInt(r); } else { SCReturnInt(1); } } /** \brief Do the content inspection & validation for a signature * * \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 * \param flags app layer flags * \param state App layer state * * \retval 0 no match * \retval 1 match */ int DetectEngineInspectPacketUris(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, void *alstate) { SCEnter(); SigMatch *sm = NULL; int r = 0; HtpState *htp_state = NULL; htp_state = (HtpState *)alstate; if (htp_state == NULL) { SCLogDebug("no HTTP state"); SCReturnInt(0); } /* locking the flow, we will inspect the htp state */ SCMutexLock(&f->m); if (htp_state->connp == NULL) { SCLogDebug("HTP state has no connp"); 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 */ if (s->flags & SIG_FLAG_MPM_URI) { if (det_ctx->de_mpm_scanned_uri == FALSE) { uint32_t cnt = DetectUricontentInspectMpm(det_ctx, f, htp_state); /* 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 = FALSE; } SCLogDebug("uricontent cnt %"PRIu32"", cnt); /* make sure we don't inspect this mpm again */ det_ctx->de_mpm_scanned_uri = TRUE; } } /* if we don't have a uri, don't bother inspecting */ if (det_ctx->de_have_httpuri == FALSE) { SCLogDebug("We don't have uri"); goto end; } 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 */ if (!(det_ctx->pmq.pattern_id_bitarray[(s->mpm_uripattern_id / 8)] & (1<<(s->mpm_uripattern_id % 8))) && (s->flags & SIG_FLAG_MPM_URI) && !(s->flags & SIG_FLAG_MPM_URI_NEG)) { SCLogDebug("mpm sig without matches (pat id %"PRIu32 " check in uri).", s->mpm_uripattern_id); goto end; } } } sm = s->umatch; det_ctx->payload_offset = 0; #ifdef DEBUG DetectUricontentData *co = (DetectUricontentData *)sm->ctx; SCLogDebug("co->id %"PRIu32, co->id); #endif size_t idx = AppLayerTransactionGetInspectId(f); htp_tx_t *tx = NULL; for ( ; idx < list_size(htp_state->connp->conn->transactions); idx++) { tx = list_get(htp_state->connp->conn->transactions, idx); if (tx == NULL || tx->request_uri_normalized == NULL) continue; /* Inspect all the uricontents fetched on each * transaction at the app layer */ r = DoInspectPacketUri(de_ctx, det_ctx, s, s->umatch, (uint8_t *) bstr_ptr(tx->request_uri_normalized), bstr_len(tx->request_uri_normalized)); if (r == 1) { break; } } if (r < 1) r = 0; end: SCMutexUnlock(&f->m); SCReturnInt(r); } /***********************************Unittests**********************************/ #ifdef UNITTESTS /** \test Test a simple uricontent option */ static int UriTestSig01(void) { int result = 0; 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 uricontent 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; } DetectEngineStateReset(f.de_state); 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; } /** \test Test the pcre /U option */ static int UriTestSig02(void) { int result = 0; Flow f; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /on 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 /one 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\"; " "pcre:/one/U; 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 with payload2, but it should not: "); goto end; } DetectEngineStateReset(f.de_state); 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; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, &p); if (!PacketAlertCheck(&p, 1)) { printf("sig 1 didnt alert, but it should: "); goto end; } 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; } /** \test Test the pcre /U option */ static int UriTestSig03(void) { int result = 0; 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\"; " "pcre:/blah/U; 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; } DetectEngineStateReset(f.de_state); 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; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, &p); if (PacketAlertCheck(&p, 1)) { printf("sig 1 alerted, but it should not: "); goto end; } 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; } /** \test Test the urilen option */ static int UriTestSig04(void) { int result = 0; 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 urilen option\"; " "urilen:>20; 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; } DetectEngineStateReset(f.de_state); 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; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, &p); if (PacketAlertCheck(&p, 1)) { printf("sig 1 alerted, but it should not: "); goto end; } 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; } /** \test Test the urilen option */ static int UriTestSig05(void) { int result = 0; 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 urilen option\"; " "urilen:>4; 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; } DetectEngineStateReset(f.de_state); 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; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, &p); if (!PacketAlertCheck(&p, 1)) { printf("sig 1 didnt alert with payload2, but it should: "); goto end; } 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; } /** \test Test the pcre /U option */ static int UriTestSig06(void) { int result = 0; Flow f; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /oneoneoneone 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\"; " "pcre:/(oneself)+/U; 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; } DetectEngineStateReset(f.de_state); 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; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, &p); if (!PacketAlertCheck(&p, 1)) { printf("sig 1 didnt alert on payload2, but it should: "); goto end; } 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; } /** \test Test the pcre /U option in combination with urilen */ static int UriTestSig07(void) { int result = 0; Flow f; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /oneoneoneone 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 /oneoneself 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 with urilen \"; " "pcre:/(one){2,}(self)?/U; urilen:3<>20; 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 didnt alert, but it should: "); goto end; } DetectEngineStateReset(f.de_state); 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; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, &p); if (!PacketAlertCheck(&p, 1)) { printf("sig 1 didnt alert with payload2, but it should: "); goto end; } 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; } /** \test Test the pcre /U option in combination with urilen */ static int UriTestSig08(void) { int result = 0; Flow f; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /oneoneoneone 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 /oneoneself 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 with urilen\"; " "pcre:/(blabla){2,}(self)?/U; urilen:3<>20; 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; } DetectEngineStateReset(f.de_state); 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; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, &p); if (PacketAlertCheck(&p, 1)) { printf("sig 1 alerted, but it should not: "); goto end; } 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; } /** \test Test the pcre /U option in combination with urilen */ static int UriTestSig09(void) { int result = 0; Flow f; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /oneoneoneone 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 /oneoneself 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 with urilen \"; " "pcre:/(one){2,}(self)?/U; urilen:<2; 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; } DetectEngineStateReset(f.de_state); 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; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, &p); if (PacketAlertCheck(&p, 1)) { printf("sig 1 alerted, but it should not: "); goto end; } 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; } /** \test Test the uricontent option in combination with urilen */ static int UriTestSig10(void) { int result = 0; Flow f; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /oneoneoneone 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 /oneoneself 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 uricontent with urilen option\"; " "uricontent:one; urilen:<2; 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; } DetectEngineStateReset(f.de_state); 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; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, &p); if (PacketAlertCheck(&p, 1)) { printf("sig 1 alerted, but it should not: "); goto end; } 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; } /** \test Test content, uricontent, urilen, pcre /U options */ static int UriTestSig11(void) { int result = 0; Flow f; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /oneoneoneone 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 /oneoneself 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 content, uricontent, pcre /U and urilen options\"; " "content:one; uricontent:one; pcre:/(one){2,}(self)?/U;" "urilen:<2; 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; } DetectEngineStateReset(f.de_state); 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; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, &p); if (PacketAlertCheck(&p, 1)) { printf("sig 1 alerted, but it should not: "); goto end; } 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; } /** \test Test uricontent, urilen, pcre /U options */ static int UriTestSig12(void) { int result = 0; Flow f; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /oneoneoneone 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 /oneoneself 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, uricontent and urilen option\"; " "uricontent:one; " "pcre:/(one)+self/U; urilen:>2; 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; } DetectEngineStateReset(f.de_state); 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; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, &p); if (!PacketAlertCheck(&p, 1)) { printf("sig 1 didnt alert with payload2, but it should: "); goto end; } 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; } /** \test Test uricontent, urilen */ static int UriTestSig13(void) { int result = 0; 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 urilen option\"; " "urilen:>2; 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 didnt alert with pkt, but it should: "); goto end; } DetectEngineStateReset(f.de_state); 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; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, &p); if (!PacketAlertCheck(&p, 1)) { printf("sig 1 didnt alert with payload2, but it should: "); goto end; } 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; } /** \test Test uricontent, pcre /U */ static int UriTestSig14(void) { int result = 0; 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 uricontent option\"; " "uricontent:one; pcre:/one(self)?/U;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 didnt alert with pkt, but it should: "); goto end; } DetectEngineStateReset(f.de_state); 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; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, &p); if (!PacketAlertCheck(&p, 1)) { printf("sig 1 didnt alert with payload2, but it should: "); goto end; } 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; } /** \test Test pcre /U with anchored regex (bug 155) */ static int UriTestSig15(void) { int result = 0; 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 uricontent option\"; " "uricontent:one; pcre:/^\\/one(self)?$/U;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 didnt alert with pkt, but it should: "); goto end; } DetectEngineStateReset(f.de_state); 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; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, &p); if (!PacketAlertCheck(&p, 1)) { printf("sig 1 didnt alert with payload2, but it should: "); goto end; } 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; } /** \test Test pcre /U with anchored regex (bug 155) */ static int UriTestSig16(void) { int result = 0; Flow f; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /search?q=123&aq=7123abcee HTTP/1.0\r\n" "User-Agent: Mozilla/1.0/\r\n" "Host: 1.2.3.4\r\n\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "POST /search?q=123&aq=7123abcee 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, "drop tcp any any -> any any (msg:\"ET TROJAN Downadup/Conficker A or B Worm reporting\"; flow:to_server,established; uricontent:\"/search?q=\"; pcre:\"/^\\/search\\?q=[0-9]{1,3}(&aq=7(\\?[0-9a-f]{8})?)?/U\"; pcre:\"/\\x0d\\x0aHost\\: \\d+\\.\\d+\\.\\d+\\.\\d+\\x0d\\x0a/\"; reference:url,www.f-secure.com/weblog/archives/00001584.html; reference:url,doc.emergingthreats.net/bin/view/Main/2009024; reference:url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/VIRUS/TROJAN_Conficker; sid:2009024; rev:9;)"); 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, 2009024)) { printf("sig 1 didnt alert with pkt, but it should: "); goto end; } p.alerts.cnt = 0; DetectEngineStateReset(f.de_state); p.payload = http_buf2; p.payload_len = http_buf2_len; 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; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, &p); if (PacketAlertCheck(&p, 2009024)) { printf("sig 1 alerted, but it should not (host should not match): "); goto end; } 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; } /** * \test Test multiple relative contents */ static int UriTestSig17(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /now_this_is_is_big_big_string_now HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; HtpState *http_state = NULL; Packet p; 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_buf; p.payload_len = http_buf_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; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"test multiple relative uricontents\"; " "uricontent:this; uricontent:is; within:6; " "uricontent:big; within:8; " "uricontent:string; within:8; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_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; } 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; } /** * \test Test multiple relative contents */ static int UriTestSig18(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /now_this_is_is_is_big_big_big_string_now HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; HtpState *http_state = NULL; Packet p; 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_buf; p.payload_len = http_buf_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; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"test multiple relative uricontents\"; " "uricontent:this; uricontent:is; within:9; " "uricontent:big; within:12; " "uricontent:string; within:8; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_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; } 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; } /** * \test Test multiple relative contents */ static int UriTestSig19(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /this_this_now_is_is_____big_string_now HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; HtpState *http_state = NULL; Packet p; 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_buf; p.payload_len = http_buf_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; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"test multiple relative uricontents\"; " "uricontent:now; uricontent:this; " "uricontent:is; within:12; " "uricontent:big; within:8; " "uricontent:string; within:8; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_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; } 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; } /** * \test Test multiple relative contents with offset */ static int UriTestSig20(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /_________thus_thus_is_a_big HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; HtpState *http_state = NULL; Packet p; 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_buf; p.payload_len = http_buf_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; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"test multiple relative uricontents\"; " "uricontent:thus; offset:8; " "uricontent:is; within:6; " "uricontent:big; within:8; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_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; } 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); UtRegisterTest("UriTestSig02", UriTestSig02, 1); UtRegisterTest("UriTestSig03", UriTestSig03, 1); UtRegisterTest("UriTestSig04", UriTestSig04, 1); UtRegisterTest("UriTestSig05", UriTestSig05, 1); UtRegisterTest("UriTestSig06", UriTestSig06, 1); UtRegisterTest("UriTestSig07", UriTestSig07, 1); UtRegisterTest("UriTestSig08", UriTestSig08, 1); UtRegisterTest("UriTestSig09", UriTestSig09, 1); UtRegisterTest("UriTestSig10", UriTestSig10, 1); UtRegisterTest("UriTestSig11", UriTestSig11, 1); UtRegisterTest("UriTestSig12", UriTestSig12, 1); UtRegisterTest("UriTestSig13", UriTestSig13, 1); UtRegisterTest("UriTestSig14", UriTestSig14, 1); UtRegisterTest("UriTestSig15", UriTestSig15, 1); UtRegisterTest("UriTestSig16", UriTestSig16, 1); UtRegisterTest("UriTestSig17", UriTestSig17, 1); UtRegisterTest("UriTestSig18", UriTestSig18, 1); UtRegisterTest("UriTestSig19", UriTestSig19, 1); UtRegisterTest("UriTestSig20", UriTestSig20, 1); #endif /* UNITTESTS */ return; }