diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index 19511d9ca8..5ee6cc6e69 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -2300,7 +2300,7 @@ static void HTPConfigParseParameters(HTPCfgRec *cfg_prec, ConfNode *s, return; } -static void HTPConfigure(void) +void HTPConfigure(void) { SCEnter(); @@ -2464,7 +2464,7 @@ void RegisterHTPParsers(void) #ifdef UNITTESTS static HTPCfgRec cfglist_backup; -static void HtpConfigCreateBackup(void) +void HtpConfigCreateBackup(void) { cfglist_backup.cfg = cfglist.cfg; cfglist_backup.next = cfglist.next; @@ -2473,7 +2473,7 @@ static void HtpConfigCreateBackup(void) return; } -static void HtpConfigRestoreBackup(void) +void HtpConfigRestoreBackup(void) { cfglist.cfg = cfglist_backup.cfg; cfglist.next = cfglist_backup.next; diff --git a/src/app-layer-htp.h b/src/app-layer-htp.h index 4a0f885a56..f12a1e55c7 100644 --- a/src/app-layer-htp.h +++ b/src/app-layer-htp.h @@ -253,6 +253,11 @@ void AppLayerHtpEnableResponseBodyCallback(void); void AppLayerHtpNeedFileInspection(void); void AppLayerHtpPrintStats(void); +void HTPConfigure(void); + +void HtpConfigCreateBackup(void); +void HtpConfigRestoreBackup(void); + #endif /* __APP_LAYER_HTP_H__ */ /** diff --git a/src/detect-engine-content-inspection.c b/src/detect-engine-content-inspection.c index ab44f2ee3a..525be21508 100644 --- a/src/detect-engine-content-inspection.c +++ b/src/detect-engine-content-inspection.c @@ -78,6 +78,10 @@ * \param f Flow (for pcre flowvar storage) * \param buffer Ptr to the buffer to inspect * \param buffer_len Length of the payload + * \param stream_start_offset Indicates the start of the current buffer in + * the whole buffer stream inspected. This + * applies if the current buffer is inspected + * in chunks. * \param inspection_mode Refers to the engine inspection mode we are currently * inspecting. Can be payload, stream, one of the http * buffer inspection modes or dce inspection mode. @@ -92,6 +96,7 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx Signature *s, SigMatch *sm, Flow *f, uint8_t *buffer, uint32_t buffer_len, + uint32_t stream_start_offset, uint8_t inspection_mode, void *data) { SCEnter(); @@ -168,6 +173,16 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx SCLogDebug("cd->within %"PRIi32", det_ctx->buffer_offset %"PRIu32", depth %"PRIu32, cd->within, prev_buffer_offset, depth); } + + if (stream_start_offset != 0 && prev_buffer_offset == 0) { + if (depth <= stream_start_offset) { + SCReturnInt(0); + } else if (depth >= (stream_start_offset + buffer_len)) { + ; + } else { + depth = depth - stream_start_offset; + } + } } if (cd->flags & DETECT_CONTENT_DEPTH_BE) { @@ -203,6 +218,16 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx } } + if (stream_start_offset != 0 && cd->flags & DETECT_CONTENT_DEPTH) { + if (depth <= stream_start_offset) { + SCReturnInt(0); + } else if (depth >= (stream_start_offset + buffer_len)) { + ; + } else { + depth = depth - stream_start_offset; + } + } + /* set offset */ if (cd->flags & DETECT_CONTENT_OFFSET_BE) offset = det_ctx->bj_values[cd->offset]; @@ -294,7 +319,7 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx /* see if the next buffer keywords match. If not, we will * search for another occurence of this content and see * if the others match then until we run out of matches */ - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm->next, f, buffer, buffer_len, inspection_mode, data); + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm->next, f, buffer, buffer_len, stream_start_offset, inspection_mode, data); if (r == 1) { SCReturnInt(1); } @@ -369,7 +394,7 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx * search for another occurence of this pcre and see * if the others match, until we run out of matches */ r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm->next, - f, buffer, buffer_len, inspection_mode, data); + f, buffer, buffer_len, stream_start_offset, inspection_mode, data); if (r == 1) { SCReturnInt(1); } @@ -523,7 +548,7 @@ match: /* this sigmatch matched, inspect the next one. If it was the last, * the buffer portion of the signature matched. */ if (sm->next != NULL) { - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm->next, f, buffer, buffer_len, inspection_mode, data); + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm->next, f, buffer, buffer_len, stream_start_offset, inspection_mode, data); SCReturnInt(r); } else { SCReturnInt(1); diff --git a/src/detect-engine-content-inspection.h b/src/detect-engine-content-inspection.h index a627a8d2f6..3fff4a869b 100644 --- a/src/detect-engine-content-inspection.h +++ b/src/detect-engine-content-inspection.h @@ -49,12 +49,11 @@ enum { DETECT_ENGINE_CONTENT_INSPECTION_MODE_HRHHD, }; -int DetectEngineContentInspection(DetectEngineCtx *, - DetectEngineThreadCtx *, - Signature *, SigMatch *, - Flow *, - uint8_t *, uint32_t, - uint8_t, - void *data); +int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + Signature *s, SigMatch *sm, + Flow *f, + uint8_t *buffer, uint32_t buffer_len, + uint32_t stream_start_offset, + uint8_t inspection_mode, void *data); #endif /* __DETECT_ENGINE_CONTENT_INSPECTION_H__ */ diff --git a/src/detect-engine-dcepayload.c b/src/detect-engine-dcepayload.c index 99677245be..83767e6e24 100644 --- a/src/detect-engine-dcepayload.c +++ b/src/detect-engine-dcepayload.c @@ -86,6 +86,7 @@ int DetectEngineInspectDcePayload(DetectEngineCtx *de_ctx, f, dce_stub_data, dce_stub_data_len, + 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_DCE, dcerpc_state); //r = DoInspectDcePayload(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_DMATCH], f, //dce_stub_data, dce_stub_data_len, dcerpc_state); @@ -108,6 +109,7 @@ int DetectEngineInspectDcePayload(DetectEngineCtx *de_ctx, f, dce_stub_data, dce_stub_data_len, + 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_DCE, dcerpc_state); //r = DoInspectDcePayload(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_DMATCH], f, //dce_stub_data, dce_stub_data_len, dcerpc_state); diff --git a/src/detect-engine-hcbd.c b/src/detect-engine-hcbd.c index 4d9bbaa1f5..459e771b97 100644 --- a/src/detect-engine-hcbd.c +++ b/src/detect-engine-hcbd.c @@ -55,6 +55,9 @@ #include "app-layer-htp.h" #include "app-layer-protos.h" +#include "conf.h" +#include "conf-yaml-loader.h" + #define BUFFER_STEP 50 static inline int HCBDCreateSpace(DetectEngineThreadCtx *det_ctx, uint16_t size) @@ -85,11 +88,13 @@ static uint8_t *DetectEngineHCBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, DetectEngineThreadCtx *det_ctx, Flow *f, HtpState *htp_state, uint8_t flags, - uint32_t *buffer_len) + uint32_t *buffer_len, + uint32_t *stream_start_offset) { int index = 0; uint8_t *buffer = NULL; *buffer_len = 0; + *stream_start_offset = 0; if (det_ctx->hcbd_buffers_list_len == 0) { if (HCBDCreateSpace(det_ctx, 1) < 0) @@ -104,6 +109,7 @@ static uint8_t *DetectEngineHCBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, if ((tx_id - det_ctx->hcbd_start_tx_id) < det_ctx->hcbd_buffers_list_len) { if (det_ctx->hcbd[(tx_id - det_ctx->hcbd_start_tx_id)].buffer_len != 0) { *buffer_len = det_ctx->hcbd[(tx_id - det_ctx->hcbd_start_tx_id)].buffer_len; + *stream_start_offset = det_ctx->hcbd[(tx_id - det_ctx->hcbd_start_tx_id)].offset; return det_ctx->hcbd[(tx_id - det_ctx->hcbd_start_tx_id)].buffer; } } else { @@ -218,6 +224,7 @@ static uint8_t *DetectEngineHCBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, buffer = det_ctx->hcbd[index].buffer; *buffer_len = det_ctx->hcbd[index].buffer_len; + *stream_start_offset = det_ctx->hcbd[index].offset; end: return buffer; } @@ -229,11 +236,13 @@ int DetectEngineRunHttpClientBodyMpm(DetectEngineCtx *de_ctx, { uint32_t cnt = 0; uint32_t buffer_len = 0; + uint32_t stream_start_offset = 0; uint8_t *buffer = DetectEngineHCBDGetBufferForTX(tx, idx, de_ctx, det_ctx, f, htp_state, flags, - &buffer_len); + &buffer_len, + &stream_start_offset); if (buffer_len == 0) goto end; @@ -251,11 +260,13 @@ int DetectEngineInspectHttpClientBody(ThreadVars *tv, { HtpState *htp_state = (HtpState *)alstate; uint32_t buffer_len = 0; + uint32_t stream_start_offset = 0; uint8_t *buffer = DetectEngineHCBDGetBufferForTX(tx, tx_id, de_ctx, det_ctx, f, htp_state, flags, - &buffer_len); + &buffer_len, + &stream_start_offset); if (buffer_len == 0) goto end; @@ -266,6 +277,7 @@ int DetectEngineInspectHttpClientBody(ThreadVars *tv, f, buffer, buffer_len, + stream_start_offset, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HCBD, NULL); if (r == 1) return DETECT_ENGINE_INSPECT_SIG_MATCH; @@ -3457,6 +3469,290 @@ end: return result; } +static int DetectEngineHttpClientBodyTest30(void) +{ + char input[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ + personality: IDS\n\ + request-body-limit: 0\n\ + response-body-limit: 0\n\ +\n\ + request-body-inspect-window: 0\n\ + response-body-inspect-window: 0\n\ + request-body-minimal-inspect-size: 0\n\ + response-body-minimal-inspect-size: 0\n\ +"; + + ConfCreateContextBackup(); + ConfInit(); + HtpConfigCreateBackup(); + + ConfYamlLoadString(input, strlen(input)); + HTPConfigure(); + + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http1_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1"; + uint8_t http2_buf[] = + "bags is dummy message body2"; + uint32_t http1_len = sizeof(http1_buf) - 1; + uint32_t http2_len = sizeof(http2_buf) - 1; + int result = 0; + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOSERVER; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http client body test\"; " + "content:\"bags\"; within:4; http_client_body; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: \n"); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if (PacketAlertCheck(p1, 1)) { + printf("sid 1 matched but shouldn't have\n"); + goto end; + } + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (PacketAlertCheck(p2, 1)) { + printf("sid 1 matched but shouldn't have\n"); + goto end; + } + + result = 1; + +end: + HtpConfigRestoreBackup(); + ConfRestoreContextBackup(); + + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +static int DetectEngineHttpClientBodyTest31(void) +{ + char input[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ + personality: IDS\n\ + request-body-limit: 0\n\ + response-body-limit: 0\n\ +\n\ + request-body-inspect-window: 0\n\ + response-body-inspect-window: 0\n\ + request-body-minimal-inspect-size: 0\n\ + response-body-minimal-inspect-size: 0\n\ +"; + + ConfCreateContextBackup(); + ConfInit(); + HtpConfigCreateBackup(); + + ConfYamlLoadString(input, strlen(input)); + HTPConfigure(); + + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http1_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1"; + uint8_t http2_buf[] = + "bags is dummy message body2"; + uint32_t http1_len = sizeof(http1_buf) - 1; + uint32_t http2_len = sizeof(http2_buf) - 1; + int result = 0; + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOSERVER; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http client body test\"; " + "content:\"bags\"; depth:4; http_client_body; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: \n"); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if (PacketAlertCheck(p1, 1)) { + printf("sid 1 matched but shouldn't have\n"); + goto end; + } + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (PacketAlertCheck(p2, 1)) { + printf("sid 1 matched but shouldn't have\n"); + goto end; + } + + result = 1; + +end: + HtpConfigRestoreBackup(); + ConfRestoreContextBackup(); + + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + #endif /* UNITTESTS */ void DetectEngineHttpClientBodyRegisterTests(void) @@ -3521,6 +3817,11 @@ void DetectEngineHttpClientBodyRegisterTests(void) DetectEngineHttpClientBodyTest28, 1); UtRegisterTest("DetectEngineHttpClientBodyTest29", DetectEngineHttpClientBodyTest29, 1); + + UtRegisterTest("DetectEngineHttpClientBodyTest30", + DetectEngineHttpClientBodyTest30, 1); + UtRegisterTest("DetectEngineHttpClientBodyTest31", + DetectEngineHttpClientBodyTest31, 1); #endif /* UNITTESTS */ return; diff --git a/src/detect-engine-hcd.c b/src/detect-engine-hcd.c index da6f35c8da..2dc8906709 100644 --- a/src/detect-engine-hcd.c +++ b/src/detect-engine-hcd.c @@ -133,6 +133,7 @@ int DetectEngineInspectHttpCookie(ThreadVars *tv, f, (uint8_t *)bstr_ptr(h->value), bstr_len(h->value), + 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HCD, NULL); if (r == 1) return DETECT_ENGINE_INSPECT_SIG_MATCH; diff --git a/src/detect-engine-hhd.c b/src/detect-engine-hhd.c index 7521910943..2838db8d8b 100644 --- a/src/detect-engine-hhd.c +++ b/src/detect-engine-hhd.c @@ -224,6 +224,7 @@ int DetectEngineInspectHttpHeader(ThreadVars *tv, f, buffer, buffer_len, + 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HHD, NULL); if (r == 1) return DETECT_ENGINE_INSPECT_SIG_MATCH; diff --git a/src/detect-engine-hhhd.c b/src/detect-engine-hhhd.c index 8c2cb77f12..9ae7962d8e 100644 --- a/src/detect-engine-hhhd.c +++ b/src/detect-engine-hhhd.c @@ -110,6 +110,7 @@ int DetectEngineInspectHttpHH(ThreadVars *tv, int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HHHDMATCH], f, hname, hname_len, + 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HHHD, NULL); if (r == 1) return DETECT_ENGINE_INSPECT_SIG_MATCH; diff --git a/src/detect-engine-hmd.c b/src/detect-engine-hmd.c index 3f5411dd11..09c76a42a2 100644 --- a/src/detect-engine-hmd.c +++ b/src/detect-engine-hmd.c @@ -107,6 +107,7 @@ int DetectEngineInspectHttpMethod(ThreadVars *tv, f, (uint8_t *)bstr_ptr(tx->request_method), bstr_len(tx->request_method), + 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HMD, NULL); if (r == 1) return DETECT_ENGINE_INSPECT_SIG_MATCH; diff --git a/src/detect-engine-hrhd.c b/src/detect-engine-hrhd.c index 82e69ed47a..299f6a701c 100644 --- a/src/detect-engine-hrhd.c +++ b/src/detect-engine-hrhd.c @@ -130,6 +130,7 @@ int DetectEngineInspectHttpRawHeader(ThreadVars *tv, f, (uint8_t *)bstr_ptr(raw_headers), bstr_len(raw_headers), + 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HRHD, NULL); if (r == 1) return DETECT_ENGINE_INSPECT_SIG_MATCH; diff --git a/src/detect-engine-hrhhd.c b/src/detect-engine-hrhhd.c index 13e76ba1e0..af5481a256 100644 --- a/src/detect-engine-hrhhd.c +++ b/src/detect-engine-hrhhd.c @@ -137,6 +137,7 @@ int DetectEngineInspectHttpHRH(ThreadVars *tv, int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HRHHDMATCH], f, hname, hname_len, + 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HRHHD, NULL); if (r == 1) return DETECT_ENGINE_INSPECT_SIG_MATCH; diff --git a/src/detect-engine-hrud.c b/src/detect-engine-hrud.c index 92ac54eeb1..1a39ca7278 100644 --- a/src/detect-engine-hrud.c +++ b/src/detect-engine-hrud.c @@ -115,6 +115,7 @@ int DetectEngineInspectHttpRawUri(ThreadVars *tv, f, (uint8_t *)bstr_ptr(tx->request_uri), bstr_len(tx->request_uri), + 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HRUD, NULL); if (r == 1) return DETECT_ENGINE_INSPECT_SIG_MATCH; diff --git a/src/detect-engine-hsbd.c b/src/detect-engine-hsbd.c index 6a8ff25011..d20e710e29 100644 --- a/src/detect-engine-hsbd.c +++ b/src/detect-engine-hsbd.c @@ -56,6 +56,9 @@ #include "app-layer-htp.h" #include "app-layer-protos.h" +#include "conf.h" +#include "conf-yaml-loader.h" + #define BUFFER_STEP 50 static inline int HSBDCreateSpace(DetectEngineThreadCtx *det_ctx, uint16_t size) @@ -84,11 +87,13 @@ static uint8_t *DetectEngineHSBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, DetectEngineThreadCtx *det_ctx, Flow *f, HtpState *htp_state, uint8_t flags, - uint32_t *buffer_len) + uint32_t *buffer_len, + uint32_t *stream_start_offset) { int index = 0; uint8_t *buffer = NULL; *buffer_len = 0; + *stream_start_offset = 0; if (det_ctx->hsbd_buffers_list_len == 0) { if (HSBDCreateSpace(det_ctx, 1) < 0) @@ -103,6 +108,7 @@ static uint8_t *DetectEngineHSBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, if ((tx_id - det_ctx->hsbd_start_tx_id) < det_ctx->hsbd_buffers_list_len) { if (det_ctx->hsbd[(tx_id - det_ctx->hsbd_start_tx_id)].buffer_len != 0) { *buffer_len = det_ctx->hsbd[(tx_id - det_ctx->hsbd_start_tx_id)].buffer_len; + *stream_start_offset = det_ctx->hsbd[(tx_id - det_ctx->hsbd_start_tx_id)].offset; return det_ctx->hsbd[(tx_id - det_ctx->hsbd_start_tx_id)].buffer; } } else { @@ -217,6 +223,7 @@ static uint8_t *DetectEngineHSBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, buffer = det_ctx->hsbd[index].buffer; *buffer_len = det_ctx->hsbd[index].buffer_len; + *stream_start_offset = det_ctx->hsbd[index].offset; end: return buffer; } @@ -228,11 +235,13 @@ int DetectEngineRunHttpServerBodyMpm(DetectEngineCtx *de_ctx, { uint32_t cnt = 0; uint32_t buffer_len = 0; + uint32_t stream_start_offset = 0; uint8_t *buffer = DetectEngineHSBDGetBufferForTX(tx, idx, de_ctx, det_ctx, f, htp_state, flags, - &buffer_len); + &buffer_len, + &stream_start_offset); if (buffer_len == 0) goto end; @@ -251,11 +260,13 @@ int DetectEngineInspectHttpServerBody(ThreadVars *tv, { HtpState *htp_state = (HtpState *)alstate; uint32_t buffer_len = 0; + uint32_t stream_start_offset = 0; uint8_t *buffer = DetectEngineHSBDGetBufferForTX(tx, tx_id, de_ctx, det_ctx, f, htp_state, flags, - &buffer_len); + &buffer_len, + &stream_start_offset); if (buffer_len == 0) goto end; @@ -266,6 +277,7 @@ int DetectEngineInspectHttpServerBody(ThreadVars *tv, f, buffer, buffer_len, + stream_start_offset, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HSBD, NULL); if (r == 1) return DETECT_ENGINE_INSPECT_SIG_MATCH; @@ -2067,6 +2079,330 @@ end: return result; } +static int DetectEngineHttpServerBodyTest16(void) +{ + char input[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ + personality: IDS\n\ + request-body-limit: 0\n\ + response-body-limit: 0\n\ +\n\ + request-body-inspect-window: 0\n\ + response-body-inspect-window: 0\n\ + request-body-minimal-inspect-size: 0\n\ + response-body-minimal-inspect-size: 0\n\ +"; + + ConfCreateContextBackup(); + ConfInit(); + HtpConfigCreateBackup(); + + ConfYamlLoadString(input, strlen(input)); + HTPConfigure(); + + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + int result = 0; + uint8_t http_buf1[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; + uint32_t http_len1 = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = + "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 17\r\n" + "\r\n" + "1234567"; + uint32_t http_len2 = sizeof(http_buf2) - 1; + uint8_t http_buf3[] = + "8901234ABC"; + uint32_t http_len3 = sizeof(http_buf3) - 1; + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOCLIENT; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http server body test\"; " + "content:\"890\"; within:3; http_server_body; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: \n"); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if (PacketAlertCheck(p1, 1)) { + printf("sid 1 matched but shouldn't have\n"); + goto end; + } + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (PacketAlertCheck(p2, 1)) { + printf("sid 1 matched but shouldn't have\n"); + goto end; + } + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf3, http_len3); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (PacketAlertCheck(p2, 1)) { + printf("sid 1 matched but shouldn't have\n"); + goto end; + } + + result = 1; + +end: + HtpConfigRestoreBackup(); + ConfRestoreContextBackup(); + + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +static int DetectEngineHttpServerBodyTest17(void) +{ + char input[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ + personality: IDS\n\ + request-body-limit: 0\n\ + response-body-limit: 0\n\ +\n\ + request-body-inspect-window: 0\n\ + response-body-inspect-window: 0\n\ + request-body-minimal-inspect-size: 0\n\ + response-body-minimal-inspect-size: 0\n\ +"; + + ConfCreateContextBackup(); + ConfInit(); + HtpConfigCreateBackup(); + + ConfYamlLoadString(input, strlen(input)); + HTPConfigure(); + + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + int result = 0; + uint8_t http_buf1[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; + uint32_t http_len1 = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = + "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 17\r\n" + "\r\n" + "1234567"; + uint32_t http_len2 = sizeof(http_buf2) - 1; + uint8_t http_buf3[] = + "8901234ABC"; + uint32_t http_len3 = sizeof(http_buf3) - 1; + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOCLIENT; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http server body test\"; " + "content:\"890\"; depth:3; http_server_body; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: \n"); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if (PacketAlertCheck(p1, 1)) { + printf("sid 1 matched but shouldn't have\n"); + goto end; + } + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (PacketAlertCheck(p2, 1)) { + printf("sid 1 matched but shouldn't have\n"); + goto end; + } + + r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf3, http_len3); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (PacketAlertCheck(p2, 1)) { + printf("sid 1 matched but shouldn't have\n"); + goto end; + } + + result = 1; + +end: + HtpConfigRestoreBackup(); + ConfRestoreContextBackup(); + + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + static int DetectEngineHttpServerBodyFileDataTest01(void) { TcpSession ssn; @@ -2341,6 +2677,10 @@ void DetectEngineHttpServerBodyRegisterTests(void) DetectEngineHttpServerBodyTest14, 1); UtRegisterTest("DetectEngineHttpServerBodyTest15", DetectEngineHttpServerBodyTest15, 1); + UtRegisterTest("DetectEngineHttpServerBodyTest16", + DetectEngineHttpServerBodyTest16, 1); + UtRegisterTest("DetectEngineHttpServerBodyTest17", + DetectEngineHttpServerBodyTest17, 1); UtRegisterTest("DetectEngineHttpServerBodyFileDataTest01", DetectEngineHttpServerBodyFileDataTest01, 1); diff --git a/src/detect-engine-hscd.c b/src/detect-engine-hscd.c index 144657d580..8257ff8ced 100644 --- a/src/detect-engine-hscd.c +++ b/src/detect-engine-hscd.c @@ -112,6 +112,7 @@ int DetectEngineInspectHttpStatCode(ThreadVars *tv, f, (uint8_t *)bstr_ptr(tx->response_status), bstr_len(tx->response_status), + 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HSCD, NULL); if (r == 1) return DETECT_ENGINE_INSPECT_SIG_MATCH; diff --git a/src/detect-engine-hsmd.c b/src/detect-engine-hsmd.c index 92ebf47c44..1540cbb202 100644 --- a/src/detect-engine-hsmd.c +++ b/src/detect-engine-hsmd.c @@ -112,6 +112,7 @@ int DetectEngineInspectHttpStatMsg(ThreadVars *tv, f, (uint8_t *)bstr_ptr(tx->response_message), bstr_len(tx->response_message), + 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HSMD, NULL); if (r == 1) return DETECT_ENGINE_INSPECT_SIG_MATCH; diff --git a/src/detect-engine-hua.c b/src/detect-engine-hua.c index 1ffbf79fea..ef5baf164f 100644 --- a/src/detect-engine-hua.c +++ b/src/detect-engine-hua.c @@ -114,6 +114,7 @@ int DetectEngineInspectHttpUA(ThreadVars *tv, f, (uint8_t *)bstr_ptr(h->value), bstr_len(h->value), + 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HUAD, NULL); if (r == 1) return DETECT_ENGINE_INSPECT_SIG_MATCH; diff --git a/src/detect-engine-payload.c b/src/detect-engine-payload.c index 40a1c178e9..25a84d2266 100644 --- a/src/detect-engine-payload.c +++ b/src/detect-engine-payload.c @@ -71,7 +71,7 @@ int DetectEngineInspectPacketPayload(DetectEngineCtx *de_ctx, //det_ctx->flags |= DETECT_ENGINE_THREAD_CTX_INSPECTING_PACKET; r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_PMATCH], - f, p->payload, p->payload_len, + f, p->payload, p->payload_len, 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_PAYLOAD, p); //r = DoInspectPacketPayload(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_PMATCH], p, f, p->payload, p->payload_len); //det_ctx->flags &= ~DETECT_ENGINE_THREAD_CTX_INSPECTING_PACKET; @@ -115,7 +115,7 @@ int DetectEngineInspectStreamPayload(DetectEngineCtx *de_ctx, //det_ctx->flags |= DETECT_ENGINE_THREAD_CTX_INSPECTING_STREAM; r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_PMATCH], - f, payload, payload_len, + f, payload, payload_len, 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STREAM, NULL); //r = DoInspectPacketPayload(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_PMATCH], NULL, f, payload, payload_len); diff --git a/src/detect-engine-uri.c b/src/detect-engine-uri.c index a3f6c1558f..d9cb33aecb 100644 --- a/src/detect-engine-uri.c +++ b/src/detect-engine-uri.c @@ -92,6 +92,7 @@ int DetectEngineInspectPacketUris(ThreadVars *tv, f, (uint8_t *)bstr_ptr(tx->request_uri_normalized), bstr_len(tx->request_uri_normalized), + 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_URI, NULL); if (r == 1) { return DETECT_ENGINE_INSPECT_SIG_MATCH; diff --git a/src/util-misc.c b/src/util-misc.c index 9a993274cc..cc716f24a1 100644 --- a/src/util-misc.c +++ b/src/util-misc.c @@ -70,7 +70,7 @@ static int ParseSizeString(const char *size, double *res) "xxx <- indicates it is just bytes\n" "xxxkb or xxxKb or xxxKB or xxxkB <- indicates kilobytes\n" "xxxmb or xxxMb or xxxMB or xxxmB <- indicates megabytes\n" - "xxxgb or xxxGb or xxxGB or xxxgB <- indicates gigabytes.", + "xxxgb or xxxGb or xxxGB or xxxgB <- indicates gigabytes.\n", size); retval = -2; goto end;