From d88218864a4b262f0e4dc27e441821f6e1c29b0f Mon Sep 17 00:00:00 2001 From: Anoop Saldanha Date: Fri, 16 Apr 2010 17:54:19 +0530 Subject: [PATCH] support nocase and negation for http_cookie --- src/detect-http-cookie.c | 457 +++++++++++++++++++++++++++++++++++++++++++++- src/detect-http-cookie.h | 4 + src/detect-nocase.c | 108 +++++++---- 3 files changed, 521 insertions(+), 48 deletions(-) diff --git a/src/detect-http-cookie.c b/src/detect-http-cookie.c index dd18ff6..b685e65 100644 --- a/src/detect-http-cookie.c +++ b/src/detect-http-cookie.c @@ -119,15 +119,27 @@ int DetectHttpCookieMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, SCLogDebug("we have a cookie header"); - if (SpmSearch((uint8_t *) bstr_ptr(h->value), bstr_size(h->value), - co->data, co->data_len) != NULL) { - SCLogDebug("match has been found in received request and given http_" - "cookie rule"); - ret = 1; - goto end; + /* call the case insensitive version if nocase has been specified in the sig */ + if (co->flags & DETECT_AL_HTTP_COOKIE_NOCASE) { + if (SpmNocaseSearch((uint8_t *) bstr_ptr(h->value), bstr_size(h->value), + co->data, co->data_len) != NULL) { + SCLogDebug("match has been found in received request and given http_" + "cookie rule"); + ret = 1; + } + } else { + if (SpmSearch((uint8_t *) bstr_ptr(h->value), bstr_size(h->value), + co->data, co->data_len) != NULL) { + SCLogDebug("match has been found in received request and given http_" + "cookie rule"); + ret = 1; + } } } + SCMutexUnlock(&f->m); + return ret ^ ((co->flags & DETECT_AL_HTTP_COOKIE_NEGATED) ? 1 : 0); + end: SCMutexUnlock(&f->m); SCLogDebug("released lock %p", &f->m); @@ -203,7 +215,10 @@ static int DetectHttpCookieSetup (DetectEngineCtx *de_ctx, Signature *s, char *s hd->data_len = ((DetectContentData *)pm->ctx)->content_len; hd->data = ((DetectContentData *)pm->ctx)->content; - + hd->flags |= (((DetectContentData *)pm->ctx)->flags & DETECT_CONTENT_NOCASE) ? + DETECT_AL_HTTP_COOKIE_NOCASE : 0; + hd->flags |= (((DetectContentData *)pm->ctx)->flags & DETECT_CONTENT_NEGATED) ? + DETECT_AL_HTTP_COOKIE_NEGATED : 0; nm->type = DETECT_AL_HTTP_COOKIE; nm->ctx = (void *)hd; @@ -477,7 +492,7 @@ static int DetectHttpCookieSigTest01(void) { } s->next = SigInit(de_ctx,"alert http any any -> any any (msg:\"HTTP " - "cookie\"; content:\"go\"; http_cookie; sid:2;)"); + "cookie\"; content:\"go\"; http_cookie; sid:2;)"); if (s->next == NULL) { goto end; } @@ -608,6 +623,427 @@ end: StreamTcpFreeConfig(TRUE); 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; + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx; + 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.src.family = AF_INET; + p.dst.family = AF_INET; + p.payload = NULL; + p.payload_len = 0; + p.proto = IPPROTO_TCP; + + f.protoctx = (void *)&ssn; + p.flow = &f; + p.flowflags |= FLOW_PKT_TOSERVER; + ssn.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + StreamL7DataPtrInit(&ssn); + + 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 = ssn.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 (http_state != NULL) + HTPStateFree(http_state); + if (de_ctx != NULL) SigGroupCleanup(de_ctx); + if (de_ctx != NULL) SigCleanSignatures(de_ctx); + if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); + + StreamL7DataPtrFree(&ssn); + StreamTcpFreeConfig(TRUE); + 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; + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx; + 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.src.family = AF_INET; + p.dst.family = AF_INET; + p.payload = NULL; + p.payload_len = 0; + p.proto = IPPROTO_TCP; + + f.protoctx = (void *)&ssn; + p.flow = &f; + p.flowflags |= FLOW_PKT_TOSERVER; + ssn.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + StreamL7DataPtrInit(&ssn); + + 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 = ssn.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 (http_state != NULL) + HTPStateFree(http_state); + if (de_ctx != NULL) SigGroupCleanup(de_ctx); + if (de_ctx != NULL) SigCleanSignatures(de_ctx); + if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); + + StreamL7DataPtrFree(&ssn); + StreamTcpFreeConfig(TRUE); + 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; + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx; + 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.src.family = AF_INET; + p.dst.family = AF_INET; + p.payload = NULL; + p.payload_len = 0; + p.proto = IPPROTO_TCP; + + f.protoctx = (void *)&ssn; + p.flow = &f; + p.flowflags |= FLOW_PKT_TOSERVER; + ssn.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + StreamL7DataPtrInit(&ssn); + + 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 = ssn.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 (http_state != NULL) + HTPStateFree(http_state); + if (de_ctx != NULL) SigGroupCleanup(de_ctx); + if (de_ctx != NULL) SigCleanSignatures(de_ctx); + if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); + + StreamL7DataPtrFree(&ssn); + StreamTcpFreeConfig(TRUE); + 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; + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx; + 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.src.family = AF_INET; + p.dst.family = AF_INET; + p.payload = NULL; + p.payload_len = 0; + p.proto = IPPROTO_TCP; + + f.protoctx = (void *)&ssn; + p.flow = &f; + p.flowflags |= FLOW_PKT_TOSERVER; + ssn.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + StreamL7DataPtrInit(&ssn); + + 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) { + 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 = ssn.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 (http_state != NULL) + HTPStateFree(http_state); + if (de_ctx != NULL) SigGroupCleanup(de_ctx); + if (de_ctx != NULL) SigCleanSignatures(de_ctx); + if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); + + StreamL7DataPtrFree(&ssn); + StreamTcpFreeConfig(TRUE); + 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; + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx; + 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.src.family = AF_INET; + p.dst.family = AF_INET; + p.payload = NULL; + p.payload_len = 0; + p.proto = IPPROTO_TCP; + + f.protoctx = (void *)&ssn; + p.flow = &f; + p.flowflags |= FLOW_PKT_TOSERVER; + ssn.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + StreamL7DataPtrInit(&ssn); + + 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 = ssn.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 (http_state != NULL) + HTPStateFree(http_state); + if (de_ctx != NULL) SigGroupCleanup(de_ctx); + if (de_ctx != NULL) SigCleanSignatures(de_ctx); + if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); + + StreamL7DataPtrFree(&ssn); + StreamTcpFreeConfig(TRUE); + return result; +} + #endif /* UNITTESTS */ /** @@ -624,6 +1060,11 @@ void DetectHttpCookieRegisterTests (void) UtRegisterTest("DetectHttpCookieTest06", DetectHttpCookieTest06, 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 */ } diff --git a/src/detect-http-cookie.h b/src/detect-http-cookie.h index cac25a7..e10c0ca 100644 --- a/src/detect-http-cookie.h +++ b/src/detect-http-cookie.h @@ -7,9 +7,13 @@ #ifndef _DETECT_HTTP_COOKIE_H #define _DETECT_HTTP_COOKIE_H +#define DETECT_AL_HTTP_COOKIE_NOCASE 0x01 +#define DETECT_AL_HTTP_COOKIE_NEGATED 0x02 + typedef struct DetectHttpCookieData_ { uint8_t *data; uint8_t data_len; + uint8_t flags; } DetectHttpCookieData; /* prototypes */ diff --git a/src/detect-nocase.c b/src/detect-nocase.c index b80f628..a4194d0 100644 --- a/src/detect-nocase.c +++ b/src/detect-nocase.c @@ -12,6 +12,7 @@ #include "detect-uricontent.h" #include "detect-pcre.h" #include "detect-http-client-body.h" +#include "detect-http-cookie.h" #include "util-debug.h" @@ -46,41 +47,68 @@ static SigMatch *SigMatchGetLastNocasePattern(Signature *s) { SigMatch *ur_sm = SigMatchGetLastSM(s->umatch_tail, DETECT_URICONTENT); /* http client body SigMatch */ SigMatch *hcbd_sm = SigMatchGetLastSM(s->match_tail, DETECT_AL_HTTP_CLIENT_BODY); - SigMatch *sm = NULL; - - if (co_sm != NULL && ur_sm != NULL && hcbd_sm != NULL) { - BUG_ON(co_sm->idx == ur_sm->idx); - - if (co_sm->idx > ur_sm->idx && ur_sm > hcbd_sm) - sm = co_sm; - else if (ur_sm->idx > co_sm->idx && co_sm > hcbd_sm) - sm = ur_sm; - else - sm = hcbd_sm; - } else if (co_sm != NULL && ur_sm != NULL) { - if (co_sm->idx > ur_sm->idx) - sm = co_sm; - else - sm = ur_sm; - } else if (co_sm != NULL && hcbd_sm != NULL) { - if (co_sm->idx > hcbd_sm->idx) - sm = co_sm; - else - sm = hcbd_sm; - } else if (ur_sm != NULL && hcbd_sm != NULL) { - if (ur_sm->idx > hcbd_sm->idx) - sm = ur_sm; - else - sm = hcbd_sm; - } else if (co_sm != NULL) { - sm = co_sm; - } else if (ur_sm != NULL) { - sm = ur_sm; - } else if (hcbd_sm != NULL) { - sm = hcbd_sm; + /* http cookie SigMatch */ + SigMatch *hcd_sm = SigMatchGetLastSM(s->match_tail, DETECT_AL_HTTP_COOKIE); + SigMatch *temp_sm = NULL; + + SigMatch **sm_list = NULL; + uint8_t sm_list_count = 0; + + if (co_sm != NULL) { + sm_list_count++; + if ( (sm_list = SCRealloc(sm_list, sizeof(SigMatch *) * sm_list_count)) == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); + exit(EXIT_FAILURE); + } + sm_list[sm_list_count - 1] = co_sm; + } + if (ur_sm != NULL) { + sm_list_count++; + if ( (sm_list = SCRealloc(sm_list, sizeof(SigMatch *) * sm_list_count)) == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); + exit(EXIT_FAILURE); + } + sm_list[sm_list_count - 1] = ur_sm; + } + if (hcbd_sm != NULL) { + sm_list_count++; + if ( (sm_list = SCRealloc(sm_list, sizeof(SigMatch *) * sm_list_count)) == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); + exit(EXIT_FAILURE); + } + sm_list[sm_list_count - 1] = hcbd_sm; + } + if (hcd_sm != NULL) { + sm_list_count++; + if ( (sm_list = SCRealloc(sm_list, sizeof(SigMatch *) * sm_list_count)) == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); + exit(EXIT_FAILURE); + } + sm_list[sm_list_count - 1] = hcd_sm; + } + + if (sm_list_count == 0) + SCReturnPtr(NULL, "SigMatch"); + + int i = 0, j = 0; + int swapped = 1; + while (swapped) { + swapped = 0; + for (j = i; j < sm_list_count - 1; j++) { + if (sm_list[j]->idx < sm_list[j + 1]->idx) { + temp_sm = sm_list[j]; + sm_list[j] = sm_list[j + 1]; + sm_list[j + 1] = temp_sm; + swapped = 1; + i++; + } + } } - SCReturnPtr(sm, "SigMatch"); + temp_sm = sm_list[0]; + SCFree(sm_list); + + SCReturnPtr(temp_sm, "SigMatch"); } /** \internal @@ -113,7 +141,7 @@ static int DetectNocaseSetup (DetectEngineCtx *de_ctx, Signature *s, char *nulls case DETECT_URICONTENT: ud = (DetectUricontentData *)pm->ctx; if (ud == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, "invalid argpment"); + SCLogError(SC_ERR_INVALID_ARGUMENT, "invalid argument"); SCReturnInt(-1); } ud->flags |= DETECT_URICONTENT_NOCASE; @@ -128,12 +156,12 @@ static int DetectNocaseSetup (DetectEngineCtx *de_ctx, Signature *s, char *nulls cd->flags |= DETECT_CONTENT_NOCASE; break; case DETECT_AL_HTTP_CLIENT_BODY: - { - ((DetectHttpClientBodyData *)(pm->ctx))->flags |= DETECT_AL_HTTP_CLIENT_BODY_NOCASE; - break; - } - - /* should never happen */ + ((DetectHttpClientBodyData *)(pm->ctx))->flags |= DETECT_AL_HTTP_CLIENT_BODY_NOCASE; + break; + case DETECT_AL_HTTP_COOKIE: + ((DetectHttpCookieData *)(pm->ctx))->flags |= DETECT_AL_HTTP_COOKIE_NOCASE; + break; + /* should never happen */ default: SCLogError(SC_ERR_NOCASE_MISSING_PATTERN, "nocase needs a preceeding content (or uricontent) option"); SCReturnInt(-1); -- 1.7.0.2