|
|
|
@ -28,12 +28,16 @@
|
|
|
|
|
#include "decode.h"
|
|
|
|
|
|
|
|
|
|
#include "detect.h"
|
|
|
|
|
#include "detect-engine.h"
|
|
|
|
|
#include "detect-parse.h"
|
|
|
|
|
#include "detect-engine-state.h"
|
|
|
|
|
#include "detect-uricontent.h"
|
|
|
|
|
#include "detect-pcre.h"
|
|
|
|
|
#include "detect-isdataat.h"
|
|
|
|
|
#include "detect-bytetest.h"
|
|
|
|
|
#include "detect-bytejump.h"
|
|
|
|
|
|
|
|
|
|
#include "flow-util.h"
|
|
|
|
|
#include "util-spm.h"
|
|
|
|
|
#include "util-debug.h"
|
|
|
|
|
#include "util-print.h"
|
|
|
|
@ -53,24 +57,26 @@
|
|
|
|
|
#include "app-layer-htp.h"
|
|
|
|
|
#include "app-layer-protos.h"
|
|
|
|
|
|
|
|
|
|
/** \brief Run the actual payload match function for uricontent
|
|
|
|
|
/**
|
|
|
|
|
* \brief Run the actual payload match function for uricontent.
|
|
|
|
|
*
|
|
|
|
|
* For accounting the last match in relative matching the
|
|
|
|
|
* det_ctx->uricontent_payload_offset int is used.
|
|
|
|
|
* For accounting the last match in relative matching the
|
|
|
|
|
* det_ctx->payload_offset int is used.
|
|
|
|
|
*
|
|
|
|
|
* \param de_ctx Detection engine context
|
|
|
|
|
* \param det_ctx Detection engine thread context
|
|
|
|
|
* \param s Signature to inspect
|
|
|
|
|
* \param sm SigMatch to inspect
|
|
|
|
|
* \param payload ptr to the uricontent payload to inspect
|
|
|
|
|
* \param payload_len length of the uricontent payload
|
|
|
|
|
* \param de_ctx Detection engine context.
|
|
|
|
|
* \param det_ctx Detection engine thread context.
|
|
|
|
|
* \param s Signature to inspect.
|
|
|
|
|
* \param sm SigMatch to inspect.
|
|
|
|
|
* \param payload Ptr to the uricontent payload to inspect.
|
|
|
|
|
* \param payload_len Length of the uricontent payload.
|
|
|
|
|
*
|
|
|
|
|
* \retval 0 no match
|
|
|
|
|
* \retval 1 match
|
|
|
|
|
* \retval 0 no match.
|
|
|
|
|
* \retval 1 match.
|
|
|
|
|
*/
|
|
|
|
|
static int DoInspectPacketUri(DetectEngineCtx *de_ctx,
|
|
|
|
|
DetectEngineThreadCtx *det_ctx, Signature *s, SigMatch *sm,
|
|
|
|
|
uint8_t *payload, uint32_t payload_len)
|
|
|
|
|
DetectEngineThreadCtx *det_ctx,
|
|
|
|
|
Signature *s, SigMatch *sm,
|
|
|
|
|
uint8_t *payload, uint32_t payload_len)
|
|
|
|
|
{
|
|
|
|
|
SCEnter();
|
|
|
|
|
|
|
|
|
@ -102,7 +108,7 @@ static int DoInspectPacketUri(DetectEngineCtx *de_ctx,
|
|
|
|
|
ud->flags & DETECT_URICONTENT_WITHIN) {
|
|
|
|
|
SCLogDebug("det_ctx->uricontent_payload_offset %"PRIu32, det_ctx->uricontent_payload_offset);
|
|
|
|
|
|
|
|
|
|
offset = det_ctx->uricontent_payload_offset;
|
|
|
|
|
offset = det_ctx->payload_offset;
|
|
|
|
|
depth = payload_len;
|
|
|
|
|
|
|
|
|
|
if (ud->flags & DETECT_URICONTENT_DISTANCE) {
|
|
|
|
@ -116,17 +122,17 @@ static int DoInspectPacketUri(DetectEngineCtx *de_ctx,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ud->flags & DETECT_URICONTENT_WITHIN) {
|
|
|
|
|
if ((int32_t)depth > (int32_t)(det_ctx->uricontent_payload_offset + ud->within)) {
|
|
|
|
|
depth = det_ctx->uricontent_payload_offset + ud->within;
|
|
|
|
|
if ((int32_t)depth > (int32_t)(det_ctx->payload_offset + ud->within)) {
|
|
|
|
|
depth = det_ctx->payload_offset + ud->within;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SCLogDebug("ud->within %"PRIi32", det_ctx->uricontent_payload_offset %"PRIu32", depth %"PRIu32,
|
|
|
|
|
ud->within, det_ctx->uricontent_payload_offset, depth);
|
|
|
|
|
SCLogDebug("ud->within %"PRIi32", det_ctx->payload_offset %"PRIu32", depth %"PRIu32,
|
|
|
|
|
ud->within, det_ctx->payload_offset, depth);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ud->depth != 0) {
|
|
|
|
|
if ((ud->depth + det_ctx->uricontent_payload_offset) < depth) {
|
|
|
|
|
depth = det_ctx->uricontent_payload_offset + ud->depth;
|
|
|
|
|
if ((ud->depth + det_ctx->payload_offset) < depth) {
|
|
|
|
|
depth = det_ctx->payload_offset + ud->depth;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SCLogDebug("ud->depth %"PRIu32", depth %"PRIu32, ud->depth, depth);
|
|
|
|
@ -196,7 +202,7 @@ static int DoInspectPacketUri(DetectEngineCtx *de_ctx,
|
|
|
|
|
} else {
|
|
|
|
|
match_offset = (uint32_t)((found - payload) + ud->uricontent_len);
|
|
|
|
|
SCLogDebug("uricontent %"PRIu32" matched at offset %"PRIu32"", ud->id, match_offset);
|
|
|
|
|
det_ctx->uricontent_payload_offset = match_offset;
|
|
|
|
|
det_ctx->payload_offset = match_offset;
|
|
|
|
|
|
|
|
|
|
if (!(ud->flags & DETECT_URICONTENT_RELATIVE_NEXT)) {
|
|
|
|
|
SCLogDebug("no relative match coming up, so this is a match");
|
|
|
|
@ -220,6 +226,16 @@ static int DoInspectPacketUri(DetectEngineCtx *de_ctx,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} while(1);
|
|
|
|
|
} else if (sm->type == DETECT_PCRE) {
|
|
|
|
|
SCLogDebug("inspecting pcre");
|
|
|
|
|
|
|
|
|
|
int r = DetectPcrePayloadMatch(det_ctx, s, sm, /* no packet */NULL,
|
|
|
|
|
NULL, payload, payload_len);
|
|
|
|
|
if (r == 1) {
|
|
|
|
|
goto match;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SCReturnInt(0);
|
|
|
|
|
} else {
|
|
|
|
|
/* we should never get here, but bail out just in case */
|
|
|
|
|
BUG_ON(1);
|
|
|
|
@ -230,7 +246,8 @@ match:
|
|
|
|
|
/* this sigmatch matched, inspect the next one. If it was the last,
|
|
|
|
|
* the payload portion of the signature matched. */
|
|
|
|
|
if (sm->next != NULL) {
|
|
|
|
|
int r = DoInspectPacketUri(de_ctx,det_ctx,s,sm->next, payload, payload_len);
|
|
|
|
|
int r = DoInspectPacketUri(de_ctx, det_ctx, s, sm->next, payload,
|
|
|
|
|
payload_len);
|
|
|
|
|
SCReturnInt(r);
|
|
|
|
|
} else {
|
|
|
|
|
SCReturnInt(1);
|
|
|
|
@ -259,11 +276,6 @@ int DetectEngineInspectPacketUris(DetectEngineCtx *de_ctx,
|
|
|
|
|
int r = 0;
|
|
|
|
|
HtpState *htp_state = NULL;
|
|
|
|
|
|
|
|
|
|
if (!(det_ctx->sgh->flags & SIG_GROUP_HAVEURICONTENT)) {
|
|
|
|
|
SCLogDebug("no uricontent in sgh");
|
|
|
|
|
SCReturnInt(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
htp_state = (HtpState *)alstate;
|
|
|
|
|
if (htp_state == NULL) {
|
|
|
|
|
SCLogDebug("no HTTP state");
|
|
|
|
@ -278,6 +290,7 @@ int DetectEngineInspectPacketUris(DetectEngineCtx *de_ctx,
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
det_ctx->de_have_httpuri = TRUE;
|
|
|
|
|
/* If we have the uricontent multi pattern matcher signatures in
|
|
|
|
|
signature list, then search the received HTTP uri(s) in the htp
|
|
|
|
|
state against those patterns */
|
|
|
|
@ -288,8 +301,8 @@ int DetectEngineInspectPacketUris(DetectEngineCtx *de_ctx,
|
|
|
|
|
/* only consider uri sigs if we've seen at least one match */
|
|
|
|
|
/** \warning when we start supporting negated uri content matches
|
|
|
|
|
* we need to update this check as well */
|
|
|
|
|
if (cnt > 0) {
|
|
|
|
|
det_ctx->de_have_httpuri = TRUE;
|
|
|
|
|
if (cnt <= 0) {
|
|
|
|
|
det_ctx->de_have_httpuri = FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SCLogDebug("uricontent cnt %"PRIu32"", cnt);
|
|
|
|
@ -306,7 +319,7 @@ int DetectEngineInspectPacketUris(DetectEngineCtx *de_ctx,
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (det_ctx->de_mpm_scanned_uri == TRUE) {
|
|
|
|
|
if ((s->flags & SIG_FLAG_MPM_URI) && (det_ctx->de_mpm_scanned_uri == TRUE)) {
|
|
|
|
|
if (det_ctx->pmq.pattern_id_bitarray != NULL) {
|
|
|
|
|
/* filter out sigs that want pattern matches, but
|
|
|
|
|
* have no matches */
|
|
|
|
@ -321,7 +334,7 @@ int DetectEngineInspectPacketUris(DetectEngineCtx *de_ctx,
|
|
|
|
|
|
|
|
|
|
sm = s->umatch;
|
|
|
|
|
|
|
|
|
|
det_ctx->uricontent_payload_offset = 0;
|
|
|
|
|
det_ctx->payload_offset = 0;
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
DetectUricontentData *co = (DetectUricontentData *)sm->ctx;
|
|
|
|
@ -356,3 +369,133 @@ end:
|
|
|
|
|
SCReturnInt(r);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************Unittests**********************************/
|
|
|
|
|
|
|
|
|
|
#ifdef UNITTESTS
|
|
|
|
|
|
|
|
|
|
static int UriTestSig01(void)
|
|
|
|
|
{
|
|
|
|
|
int result = 1;
|
|
|
|
|
Flow f;
|
|
|
|
|
HtpState *http_state = NULL;
|
|
|
|
|
uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n"
|
|
|
|
|
"User-Agent: Mozilla/1.0\r\n"
|
|
|
|
|
"Cookie: hellocatch\r\n\r\n";
|
|
|
|
|
uint32_t http_buf1_len = sizeof(http_buf1) - 1;
|
|
|
|
|
uint8_t http_buf2[] = "POST /oneself HTTP/1.0\r\n"
|
|
|
|
|
"User-Agent: Mozilla/1.0\r\n"
|
|
|
|
|
"Cookie: hellocatch\r\n\r\n";
|
|
|
|
|
uint32_t http_buf2_len = sizeof(http_buf2) - 1;
|
|
|
|
|
TcpSession ssn;
|
|
|
|
|
Packet p;
|
|
|
|
|
Signature *s = NULL;
|
|
|
|
|
ThreadVars tv;
|
|
|
|
|
DetectEngineThreadCtx *det_ctx = NULL;
|
|
|
|
|
|
|
|
|
|
memset(&tv, 0, sizeof(ThreadVars));
|
|
|
|
|
memset(&p, 0, sizeof(Packet));
|
|
|
|
|
memset(&f, 0, sizeof(Flow));
|
|
|
|
|
memset(&ssn, 0, sizeof(TcpSession));
|
|
|
|
|
|
|
|
|
|
p.src.family = AF_INET;
|
|
|
|
|
p.dst.family = AF_INET;
|
|
|
|
|
p.payload = http_buf1;
|
|
|
|
|
p.payload_len = http_buf1_len;
|
|
|
|
|
p.proto = IPPROTO_TCP;
|
|
|
|
|
|
|
|
|
|
FLOW_INITIALIZE(&f);
|
|
|
|
|
f.protoctx = (void *)&ssn;
|
|
|
|
|
f.src.family = AF_INET;
|
|
|
|
|
f.dst.family = AF_INET;
|
|
|
|
|
|
|
|
|
|
p.flow = &f;
|
|
|
|
|
p.flowflags |= FLOW_PKT_TOSERVER;
|
|
|
|
|
p.flowflags |= FLOW_PKT_ESTABLISHED;
|
|
|
|
|
f.alproto = ALPROTO_HTTP;
|
|
|
|
|
|
|
|
|
|
StreamTcpInitConfig(TRUE);
|
|
|
|
|
FlowL7DataPtrInit(&f);
|
|
|
|
|
|
|
|
|
|
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
|
|
|
|
|
if (de_ctx == NULL) {
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
|
|
|
|
de_ctx->mpm_matcher = MPM_B2G;
|
|
|
|
|
de_ctx->flags |= DE_QUIET;
|
|
|
|
|
|
|
|
|
|
s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any "
|
|
|
|
|
"(msg:\"Test pcre U option\"; "
|
|
|
|
|
"uricontent:one; sid:1;)");
|
|
|
|
|
if (s == NULL) {
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SigGroupBuild(de_ctx);
|
|
|
|
|
DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
|
|
|
|
|
|
|
|
|
|
int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len);
|
|
|
|
|
if (r != 0) {
|
|
|
|
|
printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
|
|
|
|
|
if (http_state == NULL) {
|
|
|
|
|
printf("no http state: ");
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* do detect */
|
|
|
|
|
SigMatchSignatures(&tv, de_ctx, det_ctx, &p);
|
|
|
|
|
|
|
|
|
|
if (!PacketAlertCheck(&p, 1)) {
|
|
|
|
|
printf("sig 1 alerted, but it should not: ");
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len);
|
|
|
|
|
if (r != 0) {
|
|
|
|
|
printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
|
|
|
|
|
if (http_state == NULL) {
|
|
|
|
|
printf("no http state: ");
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!PacketAlertCheck(&p, 1)) {
|
|
|
|
|
printf("sig 1 alerted, but it should not: ");
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* do detect */
|
|
|
|
|
SigMatchSignatures(&tv, de_ctx, det_ctx, &p);
|
|
|
|
|
|
|
|
|
|
result = 1;
|
|
|
|
|
|
|
|
|
|
end:
|
|
|
|
|
if (det_ctx != NULL)
|
|
|
|
|
DetectEngineThreadCtxDeinit(&tv, det_ctx);
|
|
|
|
|
if (de_ctx != NULL)
|
|
|
|
|
SigGroupCleanup(de_ctx);
|
|
|
|
|
if (de_ctx != NULL)
|
|
|
|
|
DetectEngineCtxFree(de_ctx);
|
|
|
|
|
|
|
|
|
|
StreamTcpFreeConfig(TRUE);
|
|
|
|
|
FLOW_DESTROY(&f);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif /* UNITTESTS */
|
|
|
|
|
|
|
|
|
|
void UriRegisterTests(void)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
#ifdef UNITTESTS
|
|
|
|
|
UtRegisterTest("UriTestSig01", UriTestSig01, 1);
|
|
|
|
|
#endif /* UNITTESTS */
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|