/* 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 Gurvinder Singh * * Implements the http_cookie keyword */ #include "suricata-common.h" #include "threads.h" #include "debug.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-content.h" #include "detect-pcre.h" #include "flow.h" #include "flow-var.h" #include "flow-util.h" #include "util-debug.h" #include "util-error.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-spm.h" #include "util-print.h" #include "app-layer.h" #include #include "app-layer-htp.h" #include "detect-http-cookie.h" #include "stream-tcp.h" static int DetectHttpCookieSetup (DetectEngineCtx *, Signature *, char *); void DetectHttpCookieRegisterTests(void); void DetectHttpCookieFree(void *); /** * \brief Registration function for keyword: http_cookie */ void DetectHttpCookieRegister (void) { sigmatch_table[DETECT_AL_HTTP_COOKIE].name = "http_cookie"; sigmatch_table[DETECT_AL_HTTP_COOKIE].Match = NULL; sigmatch_table[DETECT_AL_HTTP_COOKIE].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_COOKIE].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_AL_HTTP_COOKIE].Setup = DetectHttpCookieSetup; sigmatch_table[DETECT_AL_HTTP_COOKIE].Free = DetectHttpCookieFree; sigmatch_table[DETECT_AL_HTTP_COOKIE].RegisterTests = DetectHttpCookieRegisterTests; sigmatch_table[DETECT_AL_HTTP_COOKIE].flags |= SIGMATCH_PAYLOAD; } /** * \brief this function clears the memory of http_cookie modifier keyword * * \param ptr Pointer to the Detection Cookie data */ void DetectHttpCookieFree(void *ptr) { DetectContentData *hcd = (DetectContentData *)ptr; if (hcd == NULL) return; if (hcd->content != NULL) SCFree(hcd->content); SCFree(hcd); } /** * \brief this function setups the http_cookie modifier keyword used in the rule * * \param de_ctx Pointer to the Detection Engine Context * \param s Pointer to the Signature to which the current keyword belongs * \param str Should hold an empty string always * * \retval 0 On success * \retval -1 On failure */ static int DetectHttpCookieSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) { DetectContentData *cd = NULL; SigMatch *sm = NULL; if (str != NULL && strcmp(str, "") != 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "http_cookie shouldn't be supplied " "with an argument"); return -1; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { SCLogError(SC_ERR_HTTP_COOKIE_NEEDS_PRECEEDING_CONTENT, "http_cookie " "found inside the rule, without any preceding content keywords"); return -1; } sm = DetectContentGetLastPattern(s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); if (sm == NULL) { SCLogWarning(SC_ERR_HTTP_COOKIE_NEEDS_PRECEEDING_CONTENT, "http_cookie " "found inside the rule, without a content context. Please use a " "content keyword before using http_cookie"); return -1; } cd = (DetectContentData *)sm->ctx; /* http_cookie should not be used with the rawbytes rule */ if (cd->flags & DETECT_CONTENT_RAWBYTES) { SCLogError(SC_ERR_HTTP_COOKIE_INCOMPATIBLE_WITH_RAWBYTES, "http_cookie " "rule can not be used with the rawbytes rule keyword"); return -1; } if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains keywords" "that conflict with http_cookie"); goto error; } if (cd->flags & DETECT_CONTENT_WITHIN || cd->flags & DETECT_CONTENT_DISTANCE) { SigMatch *pm = SigMatchGetLastSMFromLists(s, 4, DETECT_CONTENT, sm->prev, DETECT_PCRE, sm->prev); if (pm != NULL) { /* pm is never NULL. So no NULL check */ if (pm->type == DETECT_CONTENT) { DetectContentData *tmp_cd = (DetectContentData *)pm->ctx; tmp_cd->flags &= ~DETECT_CONTENT_RELATIVE_NEXT; } else { DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx; tmp_pd->flags &= ~DETECT_PCRE_RELATIVE_NEXT; } } /* if (pm != NULL) */ /* please note. reassigning pm */ pm = SigMatchGetLastSMFromLists(s, 4, DETECT_AL_HTTP_COOKIE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]); if (pm == NULL) { SCLogError(SC_ERR_HTTP_COOKIE_RELATIVE_MISSING, "http_cookie with " "a distance or within requires preceeding http_cookie " "content, but none was found"); goto error; } if (pm->type == DETECT_PCRE) { DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx; tmp_pd->flags |= DETECT_PCRE_RELATIVE_NEXT; } else { DetectContentData *tmp_cd = (DetectContentData *)pm->ctx; tmp_cd->flags |= DETECT_CONTENT_RELATIVE_NEXT; } } cd->id = DetectPatternGetId(de_ctx->mpm_pattern_id_store, cd, DETECT_AL_HTTP_COOKIE); sm->type = DETECT_AL_HTTP_COOKIE; /* transfer the sm from the pmatch list to hmdmatch list */ SigMatchTransferSigMatchAcrossLists(sm, &s->sm_lists[DETECT_SM_LIST_PMATCH], &s->sm_lists_tail[DETECT_SM_LIST_PMATCH], &s->sm_lists[DETECT_SM_LIST_HCDMATCH], &s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]); /* flag the signature to indicate that we scan the app layer data */ s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_HTTP; return 0; error: return -1; } /******************************** UNITESTS **********************************/ #ifdef UNITTESTS #include "stream-tcp-reassemble.h" /** * \test Checks if a http_cookie is registered in a Signature, if content is not * specified in the signature */ int DetectHttpCookieTest01(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(msg:\"Testing http_cookie\"; http_cookie;sid:1;)"); if (de_ctx->sig_list == NULL) result = 1; end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a http_cookie is registered in a Signature, if some parameter * is specified with http_cookie in the signature */ int DetectHttpCookieTest02(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(msg:\"Testing http_cookie\"; content:\"me\"; " "http_cookie:woo; sid:1;)"); if (de_ctx->sig_list == NULL) result = 1; end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a http_cookie is registered in a Signature */ int DetectHttpCookieTest03(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(msg:\"Testing http_cookie\"; content:\"one\"; " "http_cookie; content:\"two\"; http_cookie; " "content:\"two\"; http_cookie; " "sid:1;)"); if (de_ctx->sig_list == NULL) { printf("sig parse failed: "); goto end; } result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCDMATCH]; if (sm == NULL) { printf("no sigmatch(es): "); goto end; } while (sm != NULL) { if (sm->type == DETECT_AL_HTTP_COOKIE) { result = 1; } else { printf("expected DETECT_AL_HTTP_COOKIE, got %d: ", sm->type); goto end; } sm = sm->next; } end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a http_cookie is registered in a Signature, when fast_pattern * is also specified in the signature (now it should) */ int DetectHttpCookieTest04(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(msg:\"Testing http_cookie\"; content:\"one\"; " "fast_pattern; http_cookie; sid:1;)"); if (de_ctx->sig_list != NULL) result = 1; end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a http_cookie is registered in a Signature, when rawbytes is * also specified in the signature */ int DetectHttpCookieTest05(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(msg:\"Testing http_cookie\"; content:\"one\"; " "rawbytes; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) result = 1; end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a http_cookie is registered in a Signature, when rawbytes is * also specified in the signature */ int DetectHttpCookieTest06(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_cookie\"; content:\"one\"; " "http_cookie; uricontent:\"abc\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; Signature *s = de_ctx->sig_list; BUG_ON(s->sm_lists[DETECT_SM_LIST_HCDMATCH] == NULL); if (s->sm_lists[DETECT_SM_LIST_HCDMATCH]->type != DETECT_AL_HTTP_COOKIE) goto end; if (s->sm_lists[DETECT_SM_LIST_UMATCH] == NULL) { printf("expected another SigMatch, got NULL: "); goto end; } if (s->sm_lists[DETECT_SM_LIST_UMATCH]->type != DETECT_URICONTENT) { goto end; } result = 1; end: if (de_ctx != NULL) { DetectEngineCtxFree(de_ctx); } return result; } int DetectHttpCookieTest07(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:one; content:one; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hcd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; if (cd->id == hcd->id) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpCookieTest08(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:one; http_cookie; content:one; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hcd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; if (cd->id == hcd->id) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpCookieTest09(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:one; content:one; content:one; http_cookie; content:one; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hcd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; if (cd->id != 0 || hcd->id != 1) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpCookieTest10(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:one; http_cookie; content:one; content:one; content:one; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hcd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; if (cd->id != 1 || hcd->id != 0) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpCookieTest11(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:one; http_cookie; " "content:one; content:one; http_cookie; content:one; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hcd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; DetectContentData *hcd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; if (cd->id != 1 || hcd1->id != 0 || hcd2->id != 0) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpCookieTest12(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:one; http_cookie; " "content:one; content:one; http_cookie; content:two; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hcd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; DetectContentData *hcd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; if (cd->id != 2 || hcd1->id != 0 || hcd2->id != 0) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** \test Check the signature working to alert when http_cookie is matched . */ static int DetectHttpCookieSigTest01(void) { int result = 0; Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\nCookie:" " hellocatchme\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, 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; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); FlowL7DataPtrInit(&f); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP cookie\"; content:\"me\"; " "http_cookie; sid:1;)"); if (s == NULL) { goto end; } s->next = SigInit(de_ctx,"alert http any any -> any any (msg:\"HTTP " "cookie\"; content:\"go\"; http_cookie; sid:2;)"); if (s->next == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)]; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } if (PacketAlertCheck(p, 2)) { printf("sid 2 matched but shouldn't: "); goto end; } result = 1; end: if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } FlowL7DataPtrFree(&f); StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); return result; } /** \test Check the signature working to alert when http_cookie is not present */ static int DetectHttpCookieSigTest02(void) { int result = 0; Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&p, 0, sizeof(p)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, 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; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); FlowL7DataPtrInit(&f); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP cookie\"; content:\"me\"; " "http_cookie; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)]; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if ((PacketAlertCheck(p, 1))) { goto end; } result = 1; end: if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } FlowL7DataPtrFree(&f); StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); return result; } /** \test Check the signature working to alert when http_cookie is not present */ static int DetectHttpCookieSigTest03(void) { int result = 0; Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n" "Cookie: dummy\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, 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; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); FlowL7DataPtrInit(&f); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP cookie\"; content:boo; " "http_cookie; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)]; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if ((PacketAlertCheck(p, 1))) { goto end; } result = 1; end: if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } FlowL7DataPtrFree(&f); StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); return result; } /** \test Check the signature working to alert when http_cookie is not present */ static int DetectHttpCookieSigTest04(void) { int result = 0; Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n" "Cookie: dummy\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&p, 0, sizeof(p)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, 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; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); FlowL7DataPtrInit(&f); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP cookie\"; content:!boo; " "http_cookie; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)]; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { goto end; } result = 1; end: if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } FlowL7DataPtrFree(&f); StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); return result; } /** \test Check the signature working to alert when http_cookie is not present */ static int DetectHttpCookieSigTest05(void) { int result = 0; Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n" "Cookie: DuMmY\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&p, 0, sizeof(p)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, 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; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); FlowL7DataPtrInit(&f); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP cookie\"; content:dummy; nocase; " "http_cookie; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)]; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { goto end; } result = 1; end: if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } FlowL7DataPtrFree(&f); StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); return result; } /** \test Check the signature working to alert when http_cookie is not present */ static int DetectHttpCookieSigTest06(void) { int result = 0; Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n" "Cookie: DuMmY\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&p, 0, sizeof(p)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, 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; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); FlowL7DataPtrInit(&f); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP cookie\"; content:\"dummy\"; " "http_cookie; nocase; sid:1;)"); if (s == NULL) { printf("sig parse failed: "); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); 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(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 failed to match: "); goto end; } result = 1; end: if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } FlowL7DataPtrFree(&f); StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); return result; } /** \test Check the signature working to alert when http_cookie is not present */ static int DetectHttpCookieSigTest07(void) { int result = 0; Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n" "Cookie: dummy\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, 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; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); FlowL7DataPtrInit(&f); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP cookie\"; content:!dummy; " "http_cookie; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)]; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { goto end; } result = 1; end: if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } FlowL7DataPtrFree(&f); StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); return result; } #endif /* UNITTESTS */ /** * \brief Register the UNITTESTS for the http_cookie keyword */ void DetectHttpCookieRegisterTests (void) { #ifdef UNITTESTS /* UNITTESTS */ UtRegisterTest("DetectHttpCookieTest01", DetectHttpCookieTest01, 1); UtRegisterTest("DetectHttpCookieTest02", DetectHttpCookieTest02, 1); UtRegisterTest("DetectHttpCookieTest03", DetectHttpCookieTest03, 1); UtRegisterTest("DetectHttpCookieTest04", DetectHttpCookieTest04, 1); UtRegisterTest("DetectHttpCookieTest05", DetectHttpCookieTest05, 1); UtRegisterTest("DetectHttpCookieTest06", DetectHttpCookieTest06, 1); UtRegisterTest("DetectHttpCookieTest07", DetectHttpCookieTest07, 1); UtRegisterTest("DetectHttpCookieTest08", DetectHttpCookieTest08, 1); UtRegisterTest("DetectHttpCookieTest09", DetectHttpCookieTest09, 1); UtRegisterTest("DetectHttpCookieTest10", DetectHttpCookieTest10, 1); UtRegisterTest("DetectHttpCookieTest11", DetectHttpCookieTest11, 1); UtRegisterTest("DetectHttpCookieTest12", DetectHttpCookieTest12, 1); UtRegisterTest("DetectHttpCookieSigTest01", DetectHttpCookieSigTest01, 1); UtRegisterTest("DetectHttpCookieSigTest02", DetectHttpCookieSigTest02, 1); UtRegisterTest("DetectHttpCookieSigTest03", DetectHttpCookieSigTest03, 1); UtRegisterTest("DetectHttpCookieSigTest04", DetectHttpCookieSigTest04, 1); UtRegisterTest("DetectHttpCookieSigTest05", DetectHttpCookieSigTest05, 1); UtRegisterTest("DetectHttpCookieSigTest06", DetectHttpCookieSigTest06, 1); UtRegisterTest("DetectHttpCookieSigTest07", DetectHttpCookieSigTest07, 1); #endif /* UNITTESTS */ }