Adding Uricontent inspection with spm. Modifiers for uricontent are now supported

remotes/origin/master-1.0.x
Pablo Rincon 16 years ago committed by Victor Julien
parent e3552a8e3f
commit b708d7f65d

@ -56,6 +56,7 @@ detect-engine-siggroup.c detect-engine-siggroup.h \
detect-engine-mpm.c detect-engine-mpm.h \
detect-engine-iponly.c detect-engine-iponly.h \
detect-engine-payload.c detect-engine-payload.h \
detect-engine-uricontent.c detect-engine-uricontent.h \
detect-parse.c detect-parse.h \
detect-ack.c detect-ack.h \
detect-seq.c detect-seq.h \

@ -339,7 +339,7 @@ SigMatch *SigMatchGetLastPattern(Signature *s) {
BUG_ON(s == NULL);
SigMatch *co_sm = DetectContentFindPrevApplicableSM(s->pmatch_tail);
SigMatch *ur_sm = SigMatchGetLastSM(s->match_tail, DETECT_URICONTENT);
SigMatch *ur_sm = SigMatchGetLastSM(s->umatch_tail, DETECT_URICONTENT);
SigMatch *sm = NULL;
if (co_sm != NULL && ur_sm != NULL) {

@ -57,6 +57,7 @@ SigMatch *DetectContentFindNextApplicableSM(SigMatch *);
SigMatch *DetectContentHasPrevSMPattern(SigMatch *);
SigMatch *SigMatchGetLastPattern(Signature *s);
void SigMatchAppendUricontent(Signature *, SigMatch *);
void DetectContentFree(void *);

@ -5,6 +5,7 @@
#include "decode.h"
#include "detect.h"
#include "detect-parse.h"
#include "detect-content.h"
#include "detect-uricontent.h"
@ -36,26 +37,51 @@ static int DetectDepthSetup (DetectEngineCtx *de_ctx, Signature *s, char *depths
dubbed = 1;
}
/** Search for the first previous DetectContent
/** Search for the first previous DetectContent or uricontent
* SigMatch (it can be the same as this one) */
SigMatch *pm = DetectContentFindPrevApplicableSM(s->pmatch_tail);
SigMatch *pm = SignatureGetLastModifiableSM(s);
if (pm == NULL) {
SCLogError(SC_ERR_DEPTH_MISSING_CONTENT, "depth needs a preceeding content option");
if (dubbed) SCFree(str);
return -1;
}
DetectContentData *cd = (DetectContentData *)pm->ctx;
if (cd == NULL) {
SCLogError(SC_ERR_INVALID_ARGUMENT, "invalid argument");
if (dubbed) SCFree(str);
return -1;
}
DetectUricontentData *ud = NULL;
DetectContentData *cd = NULL;
switch (pm->type) {
case DETECT_URICONTENT:
ud = (DetectUricontentData *)pm->ctx;
if (ud == NULL) {
SCLogError(SC_ERR_INVALID_ARGUMENT, "invalid argpment");
if (dubbed) SCFree(str);
return -1;
}
ud->depth = (uint32_t)atoi(str);
if (ud->uricontent_len + ud->offset > ud->depth) {
SCLogDebug("depth increased to %"PRIu32" to match pattern len and offset", ud->uricontent_len + ud->offset);
ud->depth = ud->uricontent_len + ud->offset;
}
break;
case DETECT_CONTENT:
cd = (DetectContentData *)pm->ctx;
if (cd == NULL) {
SCLogError(SC_ERR_INVALID_ARGUMENT, "invalid argument");
if (dubbed) SCFree(str);
return -1;
}
cd->depth = (uint32_t)atoi(str);
if (cd->content_len + cd->offset > cd->depth) {
SCLogDebug("depth increased to %"PRIu32" to match pattern len and offset", cd->content_len + cd->offset);
cd->depth = cd->content_len + cd->offset;
}
break;
cd->depth = (uint32_t)atoi(str);
if (cd->content_len + cd->offset > cd->depth) {
SCLogDebug("depth increased to %"PRIu32" to match pattern len and offset", cd->content_len + cd->offset);
cd->depth = cd->content_len + cd->offset;
default:
SCLogError(SC_ERR_DEPTH_MISSING_CONTENT, "depth needs a preceeding content (or uricontent) option");
if (dubbed) SCFree(str);
return -1;
break;
}
if (dubbed) SCFree(str);

@ -5,6 +5,7 @@
#include "decode.h"
#include "detect.h"
#include "detect-parse.h"
#include "detect-content.h"
#include "detect-uricontent.h"
@ -36,53 +37,84 @@ static int DetectDistanceSetup (DetectEngineCtx *de_ctx, Signature *s, char *dis
dubbed = 1;
}
if (s->pmatch == NULL) {
SCLogError(SC_ERR_DISTANCE_MISSING_CONTENT, "distance needs two preceeding content options");
goto error;
}
/** Search for the first previous DetectContent
* SigMatch (it can be the same as this one) */
SigMatch *pm = DetectContentFindPrevApplicableSM(s->pmatch_tail);
SigMatch *pm = SignatureGetLastModifiableSM(s);
if (pm == NULL) {
SCLogError(SC_ERR_DISTANCE_MISSING_CONTENT, "distance needs two preceeding content options");
if (dubbed) SCFree(str);
return -1;
}
if (DetectContentHasPrevSMPattern(pm) == NULL) {
SCLogError(SC_ERR_DISTANCE_MISSING_CONTENT, "distance needs two preceeding content options");
SCLogError(SC_ERR_WITHIN_MISSING_CONTENT, "depth needs two preceeding content (or uricontent) options");
if (dubbed) SCFree(str);
return -1;
}
DetectContentData *cd = (DetectContentData *)pm->ctx;
if (cd == NULL) {
SCLogError(SC_ERR_RULE_KEYWORD_UNKNOWN, "Unknown previous keyword!");
if (dubbed) SCFree(str);
return -1;
}
cd->distance = strtol(str, NULL, 10);
cd->flags |= DETECT_CONTENT_DISTANCE;
if (cd->flags & DETECT_CONTENT_WITHIN) {
if (cd->distance + cd->content_len > cd->within) {
cd->within = cd->distance + cd->content_len;
}
}
pm = DetectContentFindPrevApplicableSM(s->pmatch_tail->prev);
if (pm == NULL) {
SCLogError(SC_ERR_DISTANCE_MISSING_CONTENT, "distance needs two preceeding content options");
goto error;
}
if (pm->type == DETECT_CONTENT) {
DetectContentData *cd = (DetectContentData *)pm->ctx;
cd->flags |= DETECT_CONTENT_RELATIVE_NEXT;
} else {
SCLogError(SC_ERR_RULE_KEYWORD_UNKNOWN, "Unknown previous-previous keyword!");
goto error;
DetectUricontentData *ud = NULL;
DetectContentData *cd = NULL;
switch (pm->type) {
case DETECT_URICONTENT:
ud = (DetectUricontentData *)pm->ctx;
if (ud == NULL) {
printf("DetectWithinSetup: Unknown previous keyword!\n");
goto error;
}
ud->distance = strtol(str, NULL, 10);
ud->flags |= DETECT_URICONTENT_DISTANCE;
if (ud->flags & DETECT_URICONTENT_WITHIN) {
if (ud->distance + ud->uricontent_len > ud->within) {
ud->within = ud->distance + ud->uricontent_len;
}
}
pm = DetectUricontentFindPrevApplicableSM(s->umatch_tail->prev);
if (pm == NULL) {
SCLogError(SC_ERR_DISTANCE_MISSING_CONTENT, "distance needs two preceeding content options");
goto error;
}
if (pm->type == DETECT_URICONTENT) {
ud = (DetectUricontentData *)pm->ctx;
ud->flags |= DETECT_URICONTENT_RELATIVE_NEXT;
} else {
SCLogError(SC_ERR_RULE_KEYWORD_UNKNOWN, "Unknown previous-previous keyword!");
goto error;
}
break;
case DETECT_CONTENT:
cd = (DetectContentData *)pm->ctx;
if (cd == NULL) {
printf("DetectWithinSetup: Unknown previous keyword!\n");
goto error;
}
cd->distance = strtol(str, NULL, 10);
cd->flags |= DETECT_CONTENT_DISTANCE;
if (cd->flags & DETECT_CONTENT_WITHIN) {
if (cd->distance + cd->content_len > cd->within) {
cd->within = cd->distance + cd->content_len;
}
}
pm = DetectContentFindPrevApplicableSM(s->pmatch_tail->prev);
if (pm == NULL) {
SCLogError(SC_ERR_DISTANCE_MISSING_CONTENT, "distance needs two preceeding content options");
goto error;
}
if (pm->type == DETECT_CONTENT) {
cd = (DetectContentData *)pm->ctx;
cd->flags |= DETECT_CONTENT_RELATIVE_NEXT;
} else {
SCLogError(SC_ERR_RULE_KEYWORD_UNKNOWN, "Unknown previous-previous keyword!");
goto error;
}
break;
default:
SCLogError(SC_ERR_WITHIN_MISSING_CONTENT, "within needs two preceeding content (or uricontent) options");
if (dubbed) SCFree(str);
return -1;
break;
}
if (dubbed) SCFree(str);

@ -145,6 +145,7 @@ uint32_t UriPatternSearch(ThreadVars *tv, DetectEngineThreadCtx *det_ctx,
SCReturnUInt(ret);
}
/** \brief cleans up the mpm instance after a match */
void PacketPatternCleanup(ThreadVars *t, DetectEngineThreadCtx *det_ctx) {
PmqReset(&det_ctx->pmq);
@ -586,7 +587,7 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh)
}
}
for (sm = s->match; sm != NULL; sm = sm->next) {
for (sm = s->umatch; sm != NULL; sm = sm->next) {
if (sm->type == DETECT_URICONTENT) {
ur_cnt++;
s->flags |= SIG_FLAG_MPM;
@ -674,7 +675,7 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh)
}
}
}
for (sm = s->match; sm != NULL; sm = sm->next) {
for (sm = s->umatch; sm != NULL; sm = sm->next) {
if (sm->type == DETECT_URICONTENT && !(sh->flags & SIG_GROUP_HEAD_MPM_URI_COPY)) {
DetectUricontentData *ud = (DetectUricontentData *)sm->ctx;
if (ud->uricontent_len > uricontent_maxlen)
@ -809,7 +810,7 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh)
content_minlen = cd->content_len;
}
}
for (sm = s->match; sm != NULL; sm = sm->next) {
for (sm = s->umatch; sm != NULL; sm = sm->next) {
if (sm->type == DETECT_URICONTENT && !(sh->flags & SIG_GROUP_HEAD_MPM_URI_COPY)) {
DetectUricontentData *ud = (DetectUricontentData *)sm->ctx;
if (ud->uricontent_len > uricontent_maxlen)
@ -821,7 +822,7 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh)
}
}
char uricontent_mpmadded = 0;
for (sm = s->match; sm != NULL; sm = sm->next) {
for (sm = s->umatch; sm != NULL; sm = sm->next) {
if (sm->type == DETECT_URICONTENT && !(sh->flags & SIG_GROUP_HEAD_MPM_URI_COPY)) {
DetectUricontentData *ud = (DetectUricontentData *)sm->ctx;

@ -49,7 +49,7 @@
* \retval 1 match
*/
static inline int DoInspectPacketPayload(DetectEngineCtx *de_ctx,
DetectEngineThreadCtx *det_ctx, Signature *s, SigMatch *sm,
DetectEngineThreadCtx *det_ctx, Signature *s, SigMatch *sm,
Packet *p, uint8_t *payload, uint32_t payload_len)
{
SCEnter();

@ -1223,7 +1223,7 @@ int SigGroupHeadLoadUricontent(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
if (!(s->flags & SIG_FLAG_MPM))
continue;
sm = s->match;
sm = s->umatch;
if (sm == NULL)
continue;
@ -1246,7 +1246,7 @@ int SigGroupHeadLoadUricontent(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
* \param Pointer to the SigGroupHead whose uri_content_array would to be
* cleared.
*
* \ret 0 Always.
* \retval 0 Always.
*/
int SigGroupHeadClearUricontent(SigGroupHead *sh)
{

@ -0,0 +1,294 @@
/**
* Copyright (c) 2009 Open Information Security Foundation
*
* \author Pablo Rincon Crespo <pablo.rincon.crespo@gmail.com>
*/
#include "suricata-common.h"
#include "suricata.h"
#include "decode.h"
#include "detect.h"
#include "detect-uricontent.h"
#include "detect-pcre.h"
#include "detect-isdataat.h"
#include "detect-bytetest.h"
#include "detect-bytejump.h"
#include "util-spm.h"
#include "util-debug.h"
#include "util-print.h"
#include "flow.h"
#include "detect-flow.h"
#include "flow-var.h"
#include "threads.h"
#include "flow-alert-sid.h"
#include "stream-tcp.h"
#include "stream.h"
#include "app-layer-parser.h"
#include "util-unittest.h"
#include "util-unittest-helper.h"
#include "app-layer.h"
#include "app-layer-htp.h"
#include "app-layer-protos.h"
/** \brief Run the actual payload match function for uricontent
*
* For accounting the last match in relative matching the
* det_ctx->uricontent_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 p Packet
* \param payload ptr to the uricontent payload to inspect
* \param payload_len length of the uricontent payload
*
* \retval 0 no match
* \retval 1 match
*/
static inline int DoInspectPacketUricontentPayload(DetectEngineCtx *de_ctx,
DetectEngineThreadCtx *det_ctx, Signature *s, SigMatch *sm,
Packet *p, uint8_t *payload, uint32_t payload_len)
{
SCEnter();
if (sm == NULL) {
SCReturnInt(0);
}
if (sm->type == DETECT_URICONTENT) {
if (payload_len == 0) {
SCReturnInt(0);
}
DetectUricontentData *ud = NULL;
ud = (DetectUricontentData *)sm->ctx;
SCLogDebug("inspecting content %"PRIu32" payload_len %"PRIu32, ud->id, payload_len);
/* rule parsers should take care of this */
BUG_ON(ud->depth != 0 && ud->depth <= ud->offset);
/* search for our pattern, checking the matches recursively.
* if we match we look for the next SigMatch as well */
uint8_t *found = NULL;
uint32_t offset = 0;
uint32_t depth = payload_len;
uint32_t prev_offset = 0; /**< used in recursive searching */
do {
if (ud->flags & DETECT_URICONTENT_DISTANCE ||
ud->flags & DETECT_URICONTENT_WITHIN) {
SCLogDebug("det_ctx->uricontent_payload_offset %"PRIu32, det_ctx->uricontent_payload_offset);
offset = det_ctx->uricontent_payload_offset;
depth = payload_len;
if (ud->flags & DETECT_URICONTENT_DISTANCE) {
if (ud->distance < 0 && (uint32_t)(abs(ud->distance)) > offset)
offset = 0;
else
offset += ud->distance;
SCLogDebug("ud->distance %"PRIi32", offset %"PRIu32", depth %"PRIu32,
ud->distance, offset, depth);
}
if (ud->flags & DETECT_URICONTENT_WITHIN) {
if ((int32_t)depth > (int32_t)(det_ctx->uricontent_payload_offset + ud->within)) {
depth = det_ctx->uricontent_payload_offset + ud->within;
}
SCLogDebug("ud->within %"PRIi32", det_ctx->uricontent_payload_offset %"PRIu32", depth %"PRIu32,
ud->within, det_ctx->uricontent_payload_offset, depth);
}
if (ud->depth != 0) {
if ((ud->depth + det_ctx->uricontent_payload_offset) < depth) {
depth = det_ctx->uricontent_payload_offset + ud->depth;
}
SCLogDebug("ud->depth %"PRIu32", depth %"PRIu32, ud->depth, depth);
}
if (ud->offset > offset) {
offset = ud->offset;
SCLogDebug("setting offset %"PRIu32, offset);
}
} else { /* implied no relative matches */
/* set depth */
if (ud->depth != 0) {
depth = ud->depth;
}
/* set offset */
offset = ud->offset;
}
/* update offset with prev_offset if we're searching for
* matches after the first occurence. */
SCLogDebug("offset %"PRIu32", prev_offset %"PRIu32, prev_offset, depth);
offset += prev_offset;
SCLogDebug("offset %"PRIu32", depth %"PRIu32, offset, depth);
if (depth > payload_len)
depth = payload_len;
/* if offset is bigger than depth we can never match on a pattern.
* We can however, "match" on a negated pattern. */
if (offset > depth || depth == 0) {
if (ud->flags & DETECT_URICONTENT_NEGATED) {
goto match;
} else {
SCReturnInt(0);
}
}
uint8_t *spayload = payload + offset;
uint32_t spayload_len = depth - offset;
uint32_t match_offset = 0;
SCLogDebug("spayload_len %"PRIu32, spayload_len);
BUG_ON(spayload_len > payload_len);
//PrintRawDataFp(stdout,ud->uricontent,ud->uricontent_len);
//PrintRawDataFp(stdout,spayload,spayload_len);
/* do the actual search */
if (ud->flags & DETECT_URICONTENT_NOCASE)
found = SpmNocaseSearch(spayload, spayload_len, ud->uricontent, ud->uricontent_len);
else
found = SpmSearch(spayload, spayload_len, ud->uricontent, ud->uricontent_len);
/* next we evaluate the result in combination with the
* negation flag. */
SCLogDebug("found %p ud negated %s", found, ud->flags & DETECT_URICONTENT_NEGATED ? "true" : "false");
if (found == NULL && !(ud->flags & DETECT_URICONTENT_NEGATED)) {
SCReturnInt(0);
} else if (found == NULL && ud->flags & DETECT_URICONTENT_NEGATED) {
goto match;
} else if (found != NULL && ud->flags & DETECT_URICONTENT_NEGATED) {
match_offset = (uint32_t)((found - payload) + ud->uricontent_len);
SCLogDebug("uricontent %"PRIu32" matched at offset %"PRIu32", but negated so no match", ud->id, match_offset);
SCReturnInt(0);
} else {
match_offset = (uint32_t)((found - payload) + ud->uricontent_len);
SCLogDebug("uricontent %"PRIu32" matched at offset %"PRIu32"", ud->id, match_offset);
det_ctx->uricontent_payload_offset = match_offset;
if (!(ud->flags & DETECT_URICONTENT_RELATIVE_NEXT)) {
SCLogDebug("no relative match coming up, so this is a match");
goto match;
}
BUG_ON(sm->next == NULL);
SCLogDebug("uricontent %"PRIu32, ud->id);
/* see if the next payload keywords match. If not, we will
* search for another occurence of this uricontent and see
* if the others match then until we run out of matches */
int r = DoInspectPacketUricontentPayload(de_ctx,det_ctx,s,sm->next, p, payload, payload_len);
if (r == 1) {
SCReturnInt(1);
}
/* set the previous match offset to the start of this match + 1 */
prev_offset += (match_offset - (ud->uricontent_len - 1));
SCLogDebug("trying to see if there is another match after prev_offset %"PRIu32, prev_offset);
}
} while(1);
} else {
/* we should never get here, but bail out just in case */
BUG_ON(1);
}
SCReturnInt(0);
match:
/* this sigmatch matched, inspect the next one. If it was the last,
* the payload portion of the signature matched. */
if (sm->next != NULL) {
int r = DoInspectPacketUricontentPayload(de_ctx,det_ctx,s,sm->next, p, payload, payload_len);
SCReturnInt(r);
} else {
SCReturnInt(1);
}
}
/** \brief Do the content inspection & validation for a signature
*
* \param de_ctx Detection engine context
* \param det_ctx Detection engine thread context
* \param s Signature to inspect
* \param sm SigMatch to inspect
* \param f Flow
* \param flags app layer flags
* \param state App layer state
* \param p Packet
*
* \retval 0 no match
* \retval 1 match
*/
int DetectEngineInspectPacketUricontentPayload(DetectEngineCtx *de_ctx,
DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags,
void *alstate, Packet *p)
{
SCEnter();
SigMatch *sm = NULL;
int r = 1;
HtpState *htp_state = NULL;
htp_state = (HtpState *)alstate;
if (htp_state == NULL) {
SCLogDebug("no HTTP state");
r = 0;
goto end;
}
/* locking the flow, we will inspect the htp state */
SCMutexLock(&f->m);
/* if we don't have a uri, don't bother inspecting */
if (det_ctx->de_have_httpuri == FALSE) {
SCLogDebug("We don't have uri");
r = 0;
goto end;
}
sm = s->umatch;
det_ctx->uricontent_payload_offset = 0;
DetectUricontentData *co = (DetectUricontentData *)sm->ctx;
SCLogDebug("co->id %"PRIu32, co->id);
size_t idx = 0;
htp_tx_t *tx = NULL;
for (idx = htp_state->new_in_tx_index;
idx < list_size(htp_state->connp->conn->transactions); idx++)
{
tx = list_get(htp_state->connp->conn->transactions, idx);
if (tx == NULL || tx->request_uri_normalized == NULL)
continue;
/* Inspect all the uricontents fetched on each transaction at the app layer */
r = DoInspectPacketUricontentPayload(de_ctx, det_ctx, s, s->umatch, p, (uint8_t *) bstr_ptr(tx->request_uri_normalized), bstr_len(tx->request_uri_normalized));
if (r == 1) {
break;
}
}
if (r < 1)
r = 0;
end:
SCMutexUnlock(&f->m);
SCReturnInt(r);
}

@ -0,0 +1,9 @@
#ifndef __DETECT_ENGINE_URICONTENT_H__
#define __DETECT_ENGINE_URICONTENT_H__
int DetectEngineInspectPacketUricontentPayload(DetectEngineCtx *,
DetectEngineThreadCtx *, Signature *, Flow *, uint8_t,
void *, Packet *);
#endif /* __DETECT_ENGINE_URICONTENT_H__ */

@ -413,12 +413,12 @@ int DetectHttpCookieTest06(void)
if (s->match->type != DETECT_AL_HTTP_COOKIE)
goto end;
if (s->match->next == NULL) {
if (s->umatch == NULL) {
printf("expected another SigMatch, got NULL: ");
goto end;
}
if (s->match->next->type != DETECT_URICONTENT) {
if (s->umatch->type != DETECT_URICONTENT) {
goto end;
}

@ -43,30 +43,39 @@ static int DetectNocaseSetup (DetectEngineCtx *de_ctx, Signature *s, char *nulls
SCLogError(SC_ERR_INVALID_VALUE, "nocase has no value");
SCReturnInt(-1);
}
SigMatch *pm = SigMatchGetLastPattern(s);
/** Search for the first previous DetectContent or uricontent
* SigMatch (it can be the same as this one) */
SigMatch *pm = SignatureGetLastModifiableSM(s);
if (pm == NULL) {
SCLogError(SC_ERR_NOCASE_MISSING_PATTERN, "\"nocase\" needs a preceeding content or uricontent option.");
SCLogError(SC_ERR_DEPTH_MISSING_CONTENT, "depth needs a preceeding content option");
SCReturnInt(-1);
}
DetectUricontentData *ud = NULL;
DetectContentData *cd = NULL;
switch (pm->type) {
case DETECT_URICONTENT:
ud = (DetectUricontentData *)pm->ctx;
if (ud == NULL) {
SCLogError(SC_ERR_INVALID_ARGUMENT, "invalid argpment");
SCReturnInt(-1);
}
ud->flags |= DETECT_URICONTENT_NOCASE;
break;
case DETECT_CONTENT:
{
DetectContentData *cd = (DetectContentData *)pm->ctx;
cd = (DetectContentData *)pm->ctx;
if (cd == NULL) {
SCLogError(SC_ERR_INVALID_ARGUMENT, "invalid argument");
SCReturnInt(-1);
}
cd->flags |= DETECT_CONTENT_NOCASE;
break;
}
case DETECT_URICONTENT:
{
DetectUricontentData *cd = (DetectUricontentData *)pm->ctx;
cd->flags |= DETECT_URICONTENT_NOCASE;
break;
}
/* should never happen */
break;
default:
BUG_ON(1);
break;
SCLogError(SC_ERR_DEPTH_MISSING_CONTENT, "depth needs a preceeding content (or uricontent) option");
SCReturnInt(-1);
break;
}
SCReturnInt(0);

@ -5,6 +5,7 @@
#include "decode.h"
#include "detect.h"
#include "detect-parse.h"
#include "detect-content.h"
#include "detect-uricontent.h"
@ -36,30 +37,51 @@ int DetectOffsetSetup (DetectEngineCtx *de_ctx, Signature *s, char *offsetstr)
dubbed = 1;
}
/* Search for the first previous DetectContent
/** Search for the first previous DetectContent or uricontent
* SigMatch (it can be the same as this one) */
SigMatch *pm = DetectContentFindPrevApplicableSM(s->pmatch_tail);
SigMatch *pm = SignatureGetLastModifiableSM(s);
if (pm == NULL) {
SCLogError(SC_ERR_OFFSET_MISSING_CONTENT, "offset needs a preceeding content option");
SCLogError(SC_ERR_DEPTH_MISSING_CONTENT, "depth needs a preceeding content option");
if (dubbed) SCFree(str);
return -1;
}
DetectContentData *cd = (DetectContentData *)pm->ctx;
if (cd == NULL) {
SCLogError(SC_ERR_INVALID_ARGUMENT, "invalid argument");
if (dubbed) SCFree(str);
return -1;
}
cd->offset = (uint32_t)atoi(str);
/* check if offset and depth make sense with the pattern len */
if (cd->depth != 0) {
if (cd->content_len + cd->offset > cd->depth) {
SCLogDebug("depth increased to %"PRIu32" to match pattern len and offset", cd->content_len + cd->offset);
cd->depth = cd->content_len + cd->offset;
}
DetectUricontentData *ud = NULL;
DetectContentData *cd = NULL;
switch (pm->type) {
case DETECT_URICONTENT:
ud = (DetectUricontentData *)pm->ctx;
if (ud == NULL) {
SCLogError(SC_ERR_INVALID_ARGUMENT, "invalid argpment");
if (dubbed) SCFree(str);
return -1;
}
ud->offset = (uint32_t)atoi(str);
if (ud->depth != 0) {
SCLogDebug("depth increased to %"PRIu32" to match pattern len and offset", ud->uricontent_len + ud->offset);
ud->depth = ud->uricontent_len + ud->offset;
}
break;
case DETECT_CONTENT:
cd = (DetectContentData *)pm->ctx;
if (cd == NULL) {
SCLogError(SC_ERR_INVALID_ARGUMENT, "invalid argument");
if (dubbed) SCFree(str);
return -1;
}
cd->offset = (uint32_t)atoi(str);
if (cd->depth != 0) {
SCLogDebug("depth increased to %"PRIu32" to match pattern len and offset", cd->content_len + cd->offset);
cd->depth = cd->content_len + cd->offset;
}
break;
default:
SCLogError(SC_ERR_DEPTH_MISSING_CONTENT, "depth needs a preceeding content (or uricontent) option");
if (dubbed) SCFree(str);
return -1;
break;
}
if (dubbed) SCFree(str);

@ -104,6 +104,30 @@ SigTableElmt *SigTableGet(char *name) {
return NULL;
}
/**
* \brief SigMatchAppendUricontent, append a SigMatch of type uricontent
* to the Signature structure
* \param s pointer to the Signature
* \param new pointer to the SigMatch of type uricontent to be appended
*/
void SigMatchAppendUricontent(Signature *s, SigMatch *new) {
if (s->umatch == NULL) {
s->umatch = new;
s->umatch_tail = new;
new->next = NULL;
new->prev = NULL;
} else {
SigMatch *cur = s->umatch_tail;
cur->next = new;
new->prev = cur;
new->next = NULL;
s->umatch_tail = new;
}
new->idx = s->sm_cnt;
s->sm_cnt++;
}
void SigMatchAppendPayload(Signature *s, SigMatch *new) {
if (s->pmatch == NULL) {
s->pmatch = new;
@ -111,13 +135,10 @@ void SigMatchAppendPayload(Signature *s, SigMatch *new) {
new->next = NULL;
new->prev = NULL;
} else {
SigMatch *cur = s->pmatch;
for ( ; cur->next != NULL; cur = cur->next);
SigMatch *cur = s->pmatch_tail;
cur->next = new;
new->next = NULL;
new->prev = cur;
new->next = NULL;
s->pmatch_tail = new;
}
@ -264,6 +285,48 @@ SigMatch *SigMatchGetLastSM(SigMatch *sm, uint8_t type)
return NULL;
}
/**
* \brief Returns a pointer to the last SigMatch instance that apply to Modifiers
* (atm: DETECT_CONTENT and DETECT_URICONTENT)
*
* \param s Pointer to the signature (it will search at pmatch and umatch)
*
* \retval match Pointer to the last SigMatch instance.
*/
SigMatch *SignatureGetLastModifiableSM(Signature *s)
{
SigMatch *pm = s->pmatch_tail;
SigMatch *um = s->umatch_tail;
while (pm != NULL) {
if (pm->type == DETECT_CONTENT) {
break;
}
pm = pm->prev;
}
while (um != NULL) {
if (um->type == DETECT_URICONTENT) {
break;
}
um = um->prev;
}
if (um == NULL)
return pm;
if (pm == NULL)
return um;
/* Now we should have the latest content and uricontent.
* Let's see which one is more recent */
if (um->idx > pm->idx)
return um;
else
return pm;
return NULL;
}
void SigParsePrepare(void) {
char *regexstr = CONFIG_PCRE;
const char *eb;
@ -714,7 +777,7 @@ Signature *SigInit(DetectEngineCtx *de_ctx, char *sigstr) {
}
}
}
for (sm = sig->match; sm != NULL; sm = sm->next) {
for (sm = sig->umatch; sm != NULL; sm = sm->next) {
if (sm->type == DETECT_URICONTENT) {
DetectUricontentData *ud = (DetectUricontentData *)sm->ctx;
if (ud == NULL)
@ -742,7 +805,7 @@ Signature *SigInit(DetectEngineCtx *de_ctx, char *sigstr) {
}
}
for (sm = sig->match; sm != NULL; sm = sm->next) {
for (sm = sig->umatch; sm != NULL; sm = sm->next) {
if (sm->type == DETECT_URICONTENT) {
DetectUricontentData *ud = (DetectUricontentData *)sm->ctx;
if (sig->mpm_uricontent_maxlen == 0)
@ -831,7 +894,7 @@ Signature *SigInitReal(DetectEngineCtx *de_ctx, char *sigstr) {
}
}
for (sm = sig->match; sm != NULL; sm = sm->next) {
for (sm = sig->umatch; sm != NULL; sm = sm->next) {
if (sm->type == DETECT_URICONTENT) {
DetectUricontentData *ud = (DetectUricontentData *)sm->ctx;
if (ud == NULL)
@ -859,7 +922,7 @@ Signature *SigInitReal(DetectEngineCtx *de_ctx, char *sigstr) {
}
}
for (sm = sig->match; sm != NULL; sm = sm->next) {
for (sm = sig->umatch; sm != NULL; sm = sm->next) {
if (sm->type == DETECT_URICONTENT) {
DetectUricontentData *ud = (DetectUricontentData *)sm->ctx;
if (sig->mpm_uricontent_maxlen == 0)
@ -901,7 +964,7 @@ Signature *SigInitReal(DetectEngineCtx *de_ctx, char *sigstr) {
sig->next->mpm_content_maxlen = cd->content_len;
}
}
for (sm = sig->next->match; sm != NULL; sm = sm->next) {
for (sm = sig->next->umatch; sm != NULL; sm = sm->next) {
if (sm->type == DETECT_URICONTENT) {
DetectUricontentData *ud = (DetectUricontentData *)sm->ctx;
if (sig->next->mpm_uricontent_maxlen == 0)

@ -22,9 +22,12 @@ Signature *SigAlloc(void);
void SigFree(Signature *s);
Signature *SigInit(DetectEngineCtx *,char *sigstr);
SigMatch *SigMatchGetLastSM(SigMatch *, uint8_t);
SigMatch *SignatureGetLastModifiableSM(Signature *);
void SigParsePrepare(void);
void SigParseRegisterTests(void);
Signature *DetectEngineAppendSig(DetectEngineCtx *, char *);
void SigMatchAppendUricontent(Signature *, SigMatch *);
void SigMatchReplace(Signature *, SigMatch *, SigMatch *);
void SigMatchReplaceContent(Signature *, SigMatch *, SigMatch *);

@ -12,6 +12,7 @@
#include "suricata-common.h"
#include "decode.h"
#include "detect.h"
#include "detect-content.h"
#include "detect-uricontent.h"
#include "detect-engine-mpm.h"
#include "detect-parse.h"
@ -36,8 +37,6 @@
#include "util-spm.h"
/* prototypes */
int DetectUricontentMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *,
Signature *, SigMatch *);
static int DetectUricontentSetup (DetectEngineCtx *, Signature *, char *);
void HttpUriRegisterTests(void);
@ -51,7 +50,7 @@ int DetectAppLayerUricontentMatch (ThreadVars *, DetectEngineThreadCtx *,
void DetectUricontentRegister (void)
{
sigmatch_table[DETECT_URICONTENT].name = "uricontent";
sigmatch_table[DETECT_URICONTENT].AppLayerMatch = DetectAppLayerUricontentMatch;
sigmatch_table[DETECT_URICONTENT].AppLayerMatch = NULL;
sigmatch_table[DETECT_URICONTENT].Match = NULL;
sigmatch_table[DETECT_URICONTENT].Setup = DetectUricontentSetup;
sigmatch_table[DETECT_URICONTENT].Free = NULL;
@ -70,6 +69,72 @@ uint32_t DetectUricontentMaxId(DetectEngineCtx *de_ctx)
return de_ctx->uricontent_max_id;
}
/**
* \brief Helper function to print a DetectContentData
*/
void DetectUricontentPrint(DetectUricontentData *cd)
{
int i = 0;
if (cd == NULL) {
SCLogDebug("Detect UricontentData \"cd\" is NULL");
return;
}
char *tmpstr = SCMalloc(sizeof(char) * cd->uricontent_len + 1);
if (tmpstr != NULL) {
for (i = 0; i < cd->uricontent_len; i++) {
if (isprint(cd->uricontent[i]))
tmpstr[i] = cd->uricontent[i];
else
tmpstr[i] = '.';
}
tmpstr[i] = '\0';
SCLogDebug("Uricontent: \"%s\"", tmpstr);
SCFree(tmpstr);
} else {
SCLogDebug("Uricontent: ");
for (i = 0; i < cd->uricontent_len; i++)
SCLogDebug("%c", cd->uricontent[i]);
}
SCLogDebug("Uricontent_id: %"PRIu32, cd->id);
SCLogDebug("Uricontent_len: %"PRIu16, cd->uricontent_len);
SCLogDebug("Depth: %"PRIu16, cd->depth);
SCLogDebug("Offset: %"PRIu16, cd->offset);
SCLogDebug("Within: %"PRIi32, cd->within);
SCLogDebug("Distance: %"PRIi32, cd->distance);
SCLogDebug("flags: %u ", cd->flags);
SCLogDebug("negated: %s ", cd->flags & DETECT_URICONTENT_NEGATED ? "true" : "false");
SCLogDebug("relative match next: %s ", cd->flags & DETECT_URICONTENT_RELATIVE_NEXT ? "true" : "false");
SCLogDebug("-----------");
}
/**
* \brief Search the first DETECT_URICONTENT
* \retval pointer to the SigMatch holding the DetectUricontent
* \param sm pointer to the current SigMatch of a parsing process
* \retval null if no applicable DetectUricontent was found
* \retval pointer to the SigMatch that has the previous SigMatch
* of type DetectUricontent
*/
SigMatch *DetectUricontentFindPrevApplicableSM(SigMatch *sm)
{
if (sm == NULL)
return NULL;
while (sm != NULL && sm->type != DETECT_URICONTENT)
sm = sm->prev;
if (sm == NULL)
return NULL;
DetectUricontentData *cd = (DetectUricontentData*) sm->ctx;
if (cd == NULL)
return NULL;
return sm;
}
/**
* \brief Setup the detecturicontent keyword data from the string defined in
* the rule set.
@ -106,9 +171,8 @@ DetectUricontentData *DoDetectUricontentSetup (char * contentstr)
};
if (temp[pos] == '!') {
SCLogError(SC_ERR_NO_URICONTENT_NEGATION, "uricontent negation is not "
"supported at this time. See bug #31.");
goto error;
cd->flags |= DETECT_URICONTENT_NEGATED;
pos++;
}
if (temp[pos] == '\"' && temp[strlen(temp)-1] == '\"') {
@ -238,7 +302,7 @@ int DetectUricontentSetup (DetectEngineCtx *de_ctx, Signature *s, char *contents
sm->type = DETECT_URICONTENT;
sm->ctx = (void *)cd;
SigMatchAppendAppLayer(s, sm);
//SigMatchAppendAppLayer(s, sm);
/** \todo use unique id here as well */
cd->id = de_ctx->uricontent_max_id;
@ -253,6 +317,9 @@ int DetectUricontentSetup (DetectEngineCtx *de_ctx, Signature *s, char *contents
}
s->alproto = ALPROTO_HTTP;
SigMatchAppendUricontent(s,sm);
SCReturnInt(0);
error:
@ -303,79 +370,6 @@ int DoDetectAppLayerUricontentMatch (ThreadVars *tv, DetectEngineThreadCtx *det_
return ret;
}
/**
* \brief Checks if the received http request has a uricontent, which matches
* with the defined signature
*
* \param t Pointer to the tv for this detection module instance
* \param det_ctx Pointer to the detection engine thread context
* \param f pointer to the current flow
* \param flags flags to indicate the direction of the received packet
* \param state pointer the app layer state, which will cast into HtpState
* \param s pointer to the current signature
* \param m pointer to the sigmatch that we will cast into
* DetectUricontentData
*
* \retval 1 if the contents matches; 0 no match
*/
int DetectAppLayerUricontentMatch (ThreadVars *tv, DetectEngineThreadCtx *det_ctx,
Flow *f, uint8_t flags, void *state,
Signature *s, SigMatch *sm)
{
SCEnter();
int res = 0;
size_t idx = 0;
htp_tx_t *tx = NULL;
/* if we don't have a uri, don't bother inspecting */
if (det_ctx->de_have_httpuri == FALSE) {
SCLogDebug("We don't have uri");
SCReturnInt(0);
}
/* we're locking the flow as we'll be accessing the HTP state */
SCMutexLock(&f->m);
DetectUricontentData *co = (DetectUricontentData *)sm->ctx;
if (co == NULL)
goto end;
SCLogDebug("co->id %"PRIu32, co->id);
HtpState *htp_state = (HtpState *)state;
if (htp_state == NULL) {
SCLogDebug("no HTTP state");
goto end;
}
for (idx = htp_state->new_in_tx_index;
idx < list_size(htp_state->connp->conn->transactions); idx++)
{
tx = list_get(htp_state->connp->conn->transactions, idx);
if (tx == NULL || tx->request_uri_normalized == NULL)
continue;
/* Search for the pattern in each uri. Bail out on the first match */
if ((BasicSearch((uint8_t *) bstr_ptr(tx->request_uri_normalized),
bstr_len(tx->request_uri_normalized),
co->uricontent, co->uricontent_len)) != NULL) {
SCLogDebug("Match has been found in the received request and "
"signature s->id %"PRIu32"", s->id);
res = 1;
break;
}
}
if (res == 0) {
SCLogDebug("We don't have app layer URI match");
}
end:
SCMutexUnlock(&f->m);
SCReturnInt(res);
}
/** \brief Run the pattern matcher against the uri(s)
*
* We run against _all_ uri(s) we have as the pattern matcher will
@ -713,7 +707,7 @@ int DetectUriSigTest01(void)
BUG_ON(de_ctx->sig_list == NULL);
sm = de_ctx->sig_list->match;
sm = de_ctx->sig_list->umatch;
if (sm->type == DETECT_URICONTENT) {
result = 1;
} else {
@ -948,6 +942,515 @@ end:
return result;
}
/**
* \test Check that modifiers of content apply only to content keywords
* and the same for uricontent modifiers
*/
static int DetectUriSigTest04(void) {
int result = 0;
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
Signature *s = NULL;
s = SigInit(de_ctx,"alert tcp any any -> any any (msg:"
"\" Test uricontent\"; "
"uricontent:\"foo\"; sid:1;)");
if (s == NULL ||
s->umatch == NULL ||
s->pmatch != NULL ||
s->match != NULL)
{
goto end;
}
s = SigInit(de_ctx,"alert tcp any any -> any any (msg:"
"\" Test uricontent and content\"; "
"uricontent:\"foo\"; content:\"bar\";sid:1;)");
if (s == NULL ||
s->umatch == NULL ||
s->pmatch == NULL ||
s->match != NULL)
{
goto end;
}
s = SigInit(de_ctx,"alert tcp any any -> any any (msg:"
"\" Test uricontent and content\"; "
"uricontent:\"foo\"; content:\"bar\";"
" depth:10; offset: 5; sid:1;)");
if (s == NULL ||
s->umatch == NULL ||
s->pmatch == NULL ||
((DetectContentData*)s->pmatch->ctx)->depth != 8||
((DetectContentData*)s->pmatch->ctx)->offset != 5 ||
s->match != NULL)
{
goto end;
}
s = SigInit(de_ctx,"alert tcp any any -> any any (msg:"
"\" Test uricontent and content\"; "
"content:\"foo\"; uricontent:\"bar\";"
" depth:10; offset: 5; sid:1;)");
if (s == NULL ||
s->umatch == NULL ||
s->pmatch == NULL ||
((DetectUricontentData*)s->umatch->ctx)->depth != 8||
((DetectUricontentData*)s->umatch->ctx)->offset != 5 ||
s->match != NULL)
{
goto end;
}
s = SigInit(de_ctx,"alert tcp any any -> any any (msg:"
"\" Test uricontent and content\"; "
"uricontent:\"foo\"; content:\"bar\";"
" depth:10; offset: 5; within:3; sid:1;)");
if (s != NULL) {
goto end;
}
s = SigInit(de_ctx,"alert tcp any any -> any any (msg:"
"\" Test uricontent and content\"; "
"uricontent:\"foo\"; content:\"bar\";"
" depth:10; offset: 5; distance:3; sid:1;)");
if (s != NULL) {
goto end;
}
s = SigInit(de_ctx,"alert tcp any any -> any any (msg:"
"\" Test uricontent and content\"; "
"uricontent:\"foo\"; content:\"bar\";"
" depth:10; offset: 5; content:"
"\"two_contents\"; within:30; sid:1;)");
if (s == NULL ||
s->umatch == NULL ||
s->pmatch == NULL ||
((DetectContentData*)s->pmatch->ctx)->depth != 8||
((DetectContentData*)s->pmatch->ctx)->offset != 5 ||
((DetectContentData*)s->pmatch_tail->ctx)->within != 30 ||
s->match != NULL)
{
DetectContentPrint((DetectContentData*)s->pmatch_tail->ctx);
goto end;
}
s = SigInit(de_ctx,"alert tcp any any -> any any (msg:"
"\" Test uricontent and content\"; "
"uricontent:\"foo\"; content:\"bar\";"
" depth:10; offset: 5; uricontent:"
"\"two_uricontents\"; within:30; sid:1;)");
if (s == NULL ||
s->umatch == NULL ||
s->pmatch == NULL ||
((DetectContentData*)s->pmatch->ctx)->depth != 8||
((DetectContentData*)s->pmatch->ctx)->offset != 5 ||
((DetectContentData*)s->umatch_tail->ctx)->within != 30 ||
s->match != NULL)
{
DetectUricontentPrint((DetectUricontentData*)s->umatch_tail->ctx);
goto end;
}
s = SigInit(de_ctx,"alert tcp any any -> any any (msg:"
"\" Test uricontent and content\"; "
"uricontent:\"foo\"; content:\"bar\";"
" depth:10; offset: 5; content:"
"\"two_contents\"; distance:30; sid:1;)");
if (s == NULL ||
s->umatch == NULL ||
s->pmatch == NULL ||
((DetectContentData*)s->pmatch->ctx)->depth != 8||
((DetectContentData*)s->pmatch->ctx)->offset != 5 ||
((DetectContentData*)s->pmatch_tail->ctx)->distance != 30 ||
s->match != NULL)
{
DetectContentPrint((DetectContentData*)s->pmatch_tail->ctx);
goto end;
}
s = SigInit(de_ctx,"alert tcp any any -> any any (msg:"
"\" Test uricontent and content\"; "
"uricontent:\"foo\"; content:\"bar\";"
" depth:10; offset: 5; uricontent:"
"\"two_uricontents\"; distance:30; sid:1;)");
if (s == NULL ||
s->umatch == NULL ||
s->pmatch == NULL ||
((DetectContentData*)s->pmatch->ctx)->depth != 8||
((DetectContentData*)s->pmatch->ctx)->offset != 5 ||
((DetectContentData*)s->umatch_tail->ctx)->distance != 30 ||
s->match != NULL)
{
DetectUricontentPrint((DetectUricontentData*)s->umatch_tail->ctx);
goto end;
}
s = SigInit(de_ctx,"alert tcp any any -> any any (msg:"
"\" Test uricontent and content\"; "
"uricontent:\"foo\"; content:\"bar\";"
" depth:10; offset: 5; uricontent:"
"\"two_uricontents\"; distance:30; "
"within:60; content:\"two_contents\";"
" within:70; distance:45; sid:1;)");
if (s == NULL ||
s->umatch == NULL ||
s->pmatch == NULL ||
((DetectContentData*)s->pmatch->ctx)->depth != 8 ||
((DetectContentData*)s->pmatch->ctx)->offset != 5 ||
((DetectContentData*)s->umatch_tail->ctx)->distance != 30 ||
((DetectContentData*)s->umatch_tail->ctx)->within != 60 ||
((DetectContentData*)s->pmatch_tail->ctx)->distance != 45 ||
((DetectContentData*)s->pmatch_tail->ctx)->within != 70 ||
s->match != NULL)
{
DetectUricontentPrint((DetectUricontentData*)s->umatch_tail->ctx);
goto end;
}
result = 1;
end:
if (de_ctx != NULL) SigCleanSignatures(de_ctx);
if (de_ctx != NULL) SigGroupCleanup(de_ctx);
return result;
}
/** \test Check the modifiers for uricontent and content
* match
*/
static int DetectUriSigTest05(void) {
int result = 0;
Flow f;
HtpState *http_state = NULL;
uint8_t httpbuf1[] = "POST /one/two/three HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\nCookie:"
" hellocatch\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;
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 = httpbuf1;
p.payload_len = httplen1;
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->mpm_matcher = MPM_B2G;
de_ctx->flags |= DE_QUIET;
s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:"
"\" Test uricontent\"; "
"uricontent:\"foo\"; sid:1;)");
if (s == NULL) {
goto end;
}
s = s->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:"
"\" Test uricontent\"; "
"uricontent:\"one\"; content:\"two\"; sid:2;)");
if (s == NULL) {
goto end;
}
s = s->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:"
"\" Test uricontent\"; "
"uricontent:\"one\"; offset:1; depth:10; "
"uricontent:\"two\"; distance:1; within: 4; "
"uricontent:\"three\"; distance:1; within: 6; "
"sid:3;)");
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);
goto end;
}
/* do detect */
SigMatchSignatures(&th_v, de_ctx, det_ctx, &p);
http_state = ssn.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\n");
goto end;
} else if (! PacketAlertCheck(&p, 2)) {
printf("sig: 2 did not alerted, but it should\n");
goto end;
} else if (! (PacketAlertCheck(&p, 3))) {
printf("sig: 3 did not alerted, but it should\n");
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 (det_ctx != NULL) DetectEngineThreadCtxDeinit(&th_v, det_ctx);
if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
StreamL7DataPtrFree(&ssn);
StreamTcpFreeConfig(TRUE);
return result;
}
/** \test Check the modifiers for uricontent and content
* match
*/
static int DetectUriSigTest06(void) {
int result = 0;
Flow f;
HtpState *http_state = NULL;
uint8_t httpbuf1[] = "POST /one/two/three HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\nCookie:"
" hellocatch\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;
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 = httpbuf1;
p.payload_len = httplen1;
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->mpm_matcher = MPM_B2G;
de_ctx->flags |= DE_QUIET;
s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:"
"\" Test uricontent\"; "
"uricontent:\"foo\"; content:\"bar\"; sid:1;)");
if (s == NULL) {
goto end;
}
s = s->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:"
"\" Test uricontent\"; "
"uricontent:\"one\"; offset:1; depth:10; "
"content:\"one\"; offset:1; depth:10; "
"uricontent:\"two\"; distance:1; within: 4; "
"content:\"two\"; distance:1; within: 4; "
"uricontent:\"three\"; distance:1; within: 6; "
"content:\"/three\"; distance:0; within: 7; "
"sid:2;)");
if (s == NULL) {
goto end;
}
s = s->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:"
"\" Test uricontent\"; "
"uricontent:\"one\"; offset:1; depth:10; "
"uricontent:\"two\"; distance:1; within: 4; "
"uricontent:\"three\"; distance:1; within: 6; "
"sid:3;)");
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);
goto end;
}
/* do detect */
SigMatchSignatures(&th_v, de_ctx, det_ctx, &p);
http_state = ssn.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\n");
goto end;
} else if (! PacketAlertCheck(&p, 2)) {
printf("sig: 2 did not alerted, but it should\n");
goto end;
} else if (! (PacketAlertCheck(&p, 3))) {
printf("sig: 3 did not alerted, but it should\n");
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 (det_ctx != NULL) DetectEngineThreadCtxDeinit(&th_v, det_ctx);
if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
StreamL7DataPtrFree(&ssn);
StreamTcpFreeConfig(TRUE);
return result;
}
/** \test Check the modifiers for uricontent and content
* match
*/
static int DetectUriSigTest07(void) {
int result = 0;
Flow f;
HtpState *http_state = NULL;
uint8_t httpbuf1[] = "POST /one/two/three HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\nCookie:"
" hellocatch\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;
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 = httpbuf1;
p.payload_len = httplen1;
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->mpm_matcher = MPM_B2G;
de_ctx->flags |= DE_QUIET;
s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:"
"\" Test uricontent\"; "
"uricontent:\"foo\"; content:\"bar\"; sid:1;)");
if (s == NULL) {
goto end;
}
s = s->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:"
"\" Test uricontent\"; "
"uricontent:\"one\"; offset:1; depth:10; "
"content:\"one\"; offset:1; depth:10; "
"uricontent:\"two\"; distance:3; within: 4; "
"content:\"two\"; distance:1; within: 4; "
"uricontent:\"three\"; distance:1; within: 6; "
"content:\"/three\"; distance:0; within: 7; "
"sid:2;)");
if (s == NULL) {
goto end;
}
s = s->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:"
"\" Test uricontent\"; "
"uricontent:\"one\"; offset:1; depth:10; "
"uricontent:\"two\"; distance:1; within: 4; "
"uricontent:\"six\"; distance:1; within: 6; "
"sid:3;)");
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);
goto end;
}
/* do detect */
SigMatchSignatures(&th_v, de_ctx, det_ctx, &p);
http_state = ssn.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\n");
goto end;
} else if (PacketAlertCheck(&p, 2)) {
printf("sig: 2 did not alerted, but it should\n");
goto end;
} else if (PacketAlertCheck(&p, 3)) {
printf("sig: 3 did not alerted, but it should\n");
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 (det_ctx != NULL) DetectEngineThreadCtxDeinit(&th_v, det_ctx);
if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
StreamL7DataPtrFree(&ssn);
StreamTcpFreeConfig(TRUE);
return result;
}
#endif /* UNITTESTS */
void HttpUriRegisterTests(void) {
@ -959,5 +1462,9 @@ void HttpUriRegisterTests(void) {
UtRegisterTest("DetectUriSigTest01", DetectUriSigTest01, 1);
UtRegisterTest("DetectUriSigTest02", DetectUriSigTest02, 1);
UtRegisterTest("DetectUriSigTest03", DetectUriSigTest03, 1);
UtRegisterTest("DetectUriSigTest04 - Modifiers", DetectUriSigTest04, 1);
UtRegisterTest("DetectUriSigTest05 - Inspection", DetectUriSigTest05, 1);
UtRegisterTest("DetectUriSigTest06 - Inspection", DetectUriSigTest06, 1);
UtRegisterTest("DetectUriSigTest07 - Inspection", DetectUriSigTest07, 1);
#endif /* UNITTESTS */
}

@ -9,6 +9,14 @@
#define DETECT_URICONTENT_WITHIN_NEXT 0x10
#define DETECT_URICONTENT_RAWBYTES 0x20
#define DETECT_URICONTENT_NEGATED 0x40
#define DETECT_URICONTENT_RELATIVE_NEXT 0x80
#define DETECT_URICONTENT_IS_SINGLE(c) (!((c)->flags & DETECT_URICONTENT_DISTANCE || \
(c)->flags & DETECT_URICONTENT_WITHIN || \
(c)->flags & DETECT_URICONTENT_RELATIVE || \
(c)->depth > 0 || \
(c)->within > 0))
typedef struct DetectUricontentData_ {
uint8_t *uricontent;
@ -26,6 +34,8 @@ typedef struct DetectUricontentData_ {
void DetectUricontentRegister (void);
uint32_t DetectUricontentMaxId(DetectEngineCtx *);
uint32_t DetectUricontentInspectMpm(ThreadVars *th_v, DetectEngineThreadCtx *det_ctx, void *alstate);
SigMatch *DetectUricontentFindPrevApplicableSM(SigMatch *);
void DetectUricontentPrint(DetectUricontentData *);
#endif /* __DETECT_URICONTENT_H__ */

@ -9,6 +9,7 @@
#include "decode.h"
#include "detect.h"
#include "detect-parse.h"
#include "detect-content.h"
#include "detect-uricontent.h"
@ -47,55 +48,106 @@ static int DetectWithinSetup (DetectEngineCtx *de_ctx, Signature *s, char *withi
dubbed = 1;
}
if (s->pmatch == NULL) {
SCLogError(SC_ERR_WITHIN_MISSING_CONTENT, "within needs two preceeding content options");
goto error;
}
/* Search for the first previous DetectContent
/** Search for the first previous DetectContent
* SigMatch (it can be the same as this one) */
SigMatch *pm = DetectContentFindPrevApplicableSM(s->pmatch_tail);
if (pm == NULL || DetectContentHasPrevSMPattern(pm) == NULL) {
SCLogError(SC_ERR_WITHIN_MISSING_CONTENT, "within needs two preceeding content options");
goto error;
}
DetectContentData *cd = (DetectContentData *)pm->ctx;
if (cd == NULL) {
printf("DetectWithinSetup: Unknown previous keyword!\n");
goto error;
}
cd->within = strtol(str, NULL, 10);
if (cd->within < (int32_t)cd->content_len) {
SCLogError(SC_ERR_WITHIN_INVALID, "within argument \"%"PRIi32"\" is "
"less than the content length \"%"PRIu32"\" which is invalid, since "
"this will never match. Invalidating signature", cd->within,
cd->content_len);
goto error;
}
cd->flags |= DETECT_CONTENT_WITHIN;
if (cd->flags & DETECT_CONTENT_DISTANCE) {
if (cd->distance > (cd->content_len + cd->within)) {
cd->within = cd->distance + cd->content_len;
}
}
pm = DetectContentFindPrevApplicableSM(s->pmatch_tail->prev);
SigMatch *pm = SignatureGetLastModifiableSM(s);
if (pm == NULL) {
SCLogError(SC_ERR_WITHIN_MISSING_CONTENT, "within needs two preceeding content options");
goto error;
SCLogError(SC_ERR_WITHIN_MISSING_CONTENT, "depth needs two preceeding content (or uricontent) options");
if (dubbed) SCFree(str);
return -1;
}
/* Set the relative next flag on the prev sigmatch */
if (pm->type == DETECT_CONTENT) {
DetectContentData *cd = (DetectContentData *)pm->ctx;
cd->flags |= DETECT_CONTENT_RELATIVE_NEXT;
} else {
printf("DetectWithinSetup: Unknown previous-previous keyword!\n");
goto error;
DetectUricontentData *ud = NULL;
DetectContentData *cd = NULL;
switch (pm->type) {
case DETECT_URICONTENT:
ud = (DetectUricontentData *)pm->ctx;
if (ud == NULL) {
printf("DetectWithinSetup: Unknown previous keyword!\n");
goto error;
}
ud->within = strtol(str, NULL, 10);
if (ud->within < (int32_t)ud->uricontent_len) {
SCLogError(SC_ERR_WITHIN_INVALID, "within argument \"%"PRIi32"\" is "
"less than the content length \"%"PRIu32"\" which is invalid, since "
"this will never match. Invalidating signature", ud->within,
ud->uricontent_len);
goto error;
}
ud->flags |= DETECT_URICONTENT_WITHIN;
if (ud->flags & DETECT_URICONTENT_DISTANCE) {
if (ud->distance > (ud->uricontent_len + ud->within)) {
ud->within = ud->distance + ud->uricontent_len;
}
}
pm = DetectUricontentFindPrevApplicableSM(s->umatch_tail->prev);
if (pm == NULL) {
SCLogError(SC_ERR_WITHIN_MISSING_CONTENT, "within needs two preceeding content options");
goto error;
}
/* Set the relative next flag on the prev sigmatch */
if (pm->type == DETECT_URICONTENT) {
ud = (DetectUricontentData *)pm->ctx;
ud->flags |= DETECT_URICONTENT_RELATIVE_NEXT;
} else {
printf("DetectWithinSetup: Unknown previous-previous keyword!\n");
goto error;
}
DetectUricontentPrint(ud);
break;
case DETECT_CONTENT:
cd = (DetectContentData *)pm->ctx;
if (cd == NULL) {
printf("DetectWithinSetup: Unknown previous keyword!\n");
goto error;
}
cd->within = strtol(str, NULL, 10);
if (cd->within < (int32_t)cd->content_len) {
SCLogError(SC_ERR_WITHIN_INVALID, "within argument \"%"PRIi32"\" is "
"less than the content length \"%"PRIu32"\" which is invalid, since "
"this will never match. Invalidating signature", cd->within,
cd->content_len);
goto error;
}
cd->flags |= DETECT_CONTENT_WITHIN;
if (cd->flags & DETECT_CONTENT_DISTANCE) {
if (cd->distance > (cd->content_len + cd->within)) {
cd->within = cd->distance + cd->content_len;
}
}
pm = DetectContentFindPrevApplicableSM(s->pmatch_tail->prev);
if (pm == NULL) {
SCLogError(SC_ERR_WITHIN_MISSING_CONTENT, "within needs two preceeding content options");
goto error;
}
/* Set the relative next flag on the prev sigmatch */
if (pm->type == DETECT_CONTENT) {
cd = (DetectContentData *)pm->ctx;
cd->flags |= DETECT_CONTENT_RELATIVE_NEXT;
} else {
printf("DetectWithinSetup: Unknown previous-previous keyword!\n");
goto error;
}
break;
default:
SCLogError(SC_ERR_WITHIN_MISSING_CONTENT, "within needs two preceeding content (or uricontent) options");
if (dubbed) SCFree(str);
return -1;
break;
}
if (dubbed) SCFree(str);

@ -18,6 +18,7 @@
#include "detect-engine-iponly.h"
#include "detect-engine-threshold.h"
#include "detect-engine-payload.h"
#include "detect-engine-uricontent.h"
#include "detect-http-cookie.h"
#include "detect-http-method.h"
@ -661,6 +662,12 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh
continue;
}
/* Check the uricontent keywords here. */
if (s->umatch != NULL) {
if (DetectEngineInspectPacketUricontentPayload(de_ctx, det_ctx, s, p->flow, flags, alstate, p) != 1)
continue;
}
/* if we get here but have no sigmatches to match against,
* we consider the sig matched. */
if (s->match == NULL) {
@ -882,6 +889,9 @@ int SignatureIsIPOnly(DetectEngineCtx *de_ctx, Signature *s) {
if (s->pmatch != NULL)
return 0;
if (s->umatch != NULL)
return 0;
SigMatch *sm = s->match;
if (sm == NULL)
goto iponly;
@ -3328,6 +3338,7 @@ static int SigTest06Real (int mpm_type) {
result = 0;
goto end;
}
de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP URI test\"; uricontent:\"two\"; sid:2;)");
if (de_ctx->sig_list->next == NULL) {
result = 0;

@ -202,11 +202,13 @@ typedef struct Signature_ {
DetectProto proto;
DetectPort *sp, *dp;
/** ptr to the SigMatch list */
/** ptr to the SigMatch lists */
struct SigMatch_ *match; /* non-payload matches */
struct SigMatch_ *match_tail; /* non-payload matches, tail of the list */
struct SigMatch_ *pmatch; /* payload matches */
struct SigMatch_ *pmatch_tail; /* payload matches, tail of the list */
struct SigMatch_ *umatch; /* uricontent payload matches */
struct SigMatch_ *umatch_tail; /* uricontent payload matches, tail of the list */
/** ptr to the next sig in the list */
struct Signature_ *next;
@ -389,10 +391,15 @@ typedef struct DetectionEngineThreadCtx_ {
* content, pcre, etc */
uint32_t payload_offset;
/** offset into the uri payload of the last match by
* uricontent */
uint32_t uricontent_payload_offset;
/** recursive counter */
uint8_t pkt_cnt;
char de_checking_distancewithin;
char de_checking_uricontent_distancewithin;
/* http_uri stuff for uricontent */
char de_have_httpuri;

@ -33,7 +33,6 @@
#include "stream.h"
#include "util-debug.h"
#include "app-layer-protos.h"
//#define DEBUG

Loading…
Cancel
Save