You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
suricata/src/detect-uricontent.c

964 lines
29 KiB
C

/* Copyright (C) 2008 by Victor Julien <victor@inliniac.net>
* Copyright (c) 2009 Open Information Security Foundation */
/**
* \file Simple uricontent match part of the detection engine.
*
* \author Victor Julien <victor@inliniac.net>
* \author Gurvinder Singh <gurvindersinghdahiya@gmail.com>
*
*/
#include "suricata-common.h"
#include "decode.h"
#include "detect.h"
#include "detect-uricontent.h"
#include "detect-engine-mpm.h"
#include "detect-parse.h"
#include "detect-engine.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 "app-layer-protos.h"
#include "app-layer-htp.h"
#include "util-mpm.h"
#include "util-print.h"
#include "util-debug.h"
#include "util-unittest.h"
#include "util-binsearch.h"
#include "util-spm.h"
/* prototypes */
int DetectUricontentMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *,
Signature *, SigMatch *);
static int DetectUricontentSetup (DetectEngineCtx *, Signature *, char *);
void HttpUriRegisterTests(void);
int DetectAppLayerUricontentMatch (ThreadVars *, DetectEngineThreadCtx *,
Flow *, uint8_t , void *,
Signature *, SigMatch *);
/**
* \brief Registration function for uricontent: keyword
*/
void DetectUricontentRegister (void)
{
sigmatch_table[DETECT_URICONTENT].name = "uricontent";
sigmatch_table[DETECT_URICONTENT].AppLayerMatch = DetectAppLayerUricontentMatch;
sigmatch_table[DETECT_URICONTENT].Match = NULL;
sigmatch_table[DETECT_URICONTENT].Setup = DetectUricontentSetup;
sigmatch_table[DETECT_URICONTENT].Free = NULL;
sigmatch_table[DETECT_URICONTENT].RegisterTests = HttpUriRegisterTests;
sigmatch_table[DETECT_URICONTENT].alproto = ALPROTO_HTTP;
sigmatch_table[DETECT_URICONTENT].flags |= SIGMATCH_PAYLOAD;
}
/**
* \brief pass on the uricontent_max_id
* \param de_ctx pointer to the detect egine context whose max id is asked
*/
uint32_t DetectUricontentMaxId(DetectEngineCtx *de_ctx)
{
return de_ctx->uricontent_max_id;
}
/**
* \brief Setup the detecturicontent keyword data from the string defined in
* the rule set.
* \param contentstr Pointer to the string which has been defined in the rule
*/
DetectUricontentData *DoDetectUricontentSetup (char * contentstr)
{
DetectUricontentData *cd = NULL;
char *temp = NULL;
char *str = NULL;
uint16_t len = 0;
uint16_t pos = 0;
uint16_t slen = 0;
if ((temp = SCStrdup(contentstr)) == NULL)
goto error;
if (strlen(temp) == 0) {
SCFree(temp);
return NULL;
}
cd = SCMalloc(sizeof(DetectUricontentData));
if (cd == NULL) {
SCLogError(SC_ERR_MEM_ALLOC, "SCMalloc failed");
goto error;
}
memset(cd,0,sizeof(DetectUricontentData));
/* skip the first spaces */
slen = strlen(temp);
while (pos < slen && isspace(temp[pos])) {
pos++;
};
if (temp[pos] == '!') {
SCLogError(SC_ERR_NO_URICONTENT_NEGATION, "uricontent negation is not "
"supported at this time. See bug #31.");
goto error;
}
if (temp[pos] == '\"' && temp[strlen(temp)-1] == '\"') {
if ((str = SCStrdup(temp + pos + 1)) == NULL)
goto error;
str[strlen(temp) - pos - 2] = '\0';
} else {
if ((str = SCStrdup(temp + pos)) == NULL)
goto error;
}
SCFree(temp);
temp = NULL;
len = strlen(str);
SCLogDebug("\"%s\", len %" PRIu32 "", str, len);
char converted = 0;
{
uint16_t i, x;
uint8_t bin = 0, binstr[3] = "", binpos = 0;
for (i = 0, x = 0; i < len; i++) {
SCLogDebug("str[%02u]: %c", i, str[i]);
if (str[i] == '|') {
if (bin) {
bin = 0;
} else {
bin = 1;
}
} else {
if (bin) {
if (isdigit(str[i]) ||
str[i] == 'A' || str[i] == 'a' ||
str[i] == 'B' || str[i] == 'b' ||
str[i] == 'C' || str[i] == 'c' ||
str[i] == 'D' || str[i] == 'd' ||
str[i] == 'E' || str[i] == 'e' ||
str[i] == 'F' || str[i] == 'f') {
SCLogDebug("part of binary: %c", str[i]);
binstr[binpos] = (char)str[i];
binpos++;
if (binpos == 2) {
uint8_t c = strtol((char *)binstr, (char **) NULL,
16) & 0xFF;
binpos = 0;
str[x] = c;
x++;
converted = 1;
}
} else if (str[i] == ' ') {
SCLogDebug("space as part of binary string");
}
} else {
str[x] = str[i];
x++;
}
}
}
#ifdef DEBUG
if (SCLogDebugEnabled()) {
for (i = 0; i < x; i++) {
if (isprint(str[i])) printf("%c", str[i]);
else printf("\\x%02u", str[i]);
}
printf("\n");
}
#endif
if (converted)
len = x;
}
SCLogDebug("len %" PRIu32 "", len);
cd->uricontent = SCMalloc(len);
if (cd->uricontent == NULL) {
SCFree(cd);
SCFree(str);
return NULL;;
}
memcpy(cd->uricontent, str, len);
cd->uricontent_len = len;
cd->depth = 0;
cd->offset = 0;
cd->within = 0;
cd->distance = 0;
cd->flags = 0;
SCFree(str);
return cd;
error:
SCFree(str);
if (cd) SCFree(cd);
return NULL;
}
/**
* \brief Creates a SigMatch for the uricontent keyword being sent as argument,
* and appends it to the Signature(s).
*
* \param de_ctx Pointer to the detection engine context
* \param s Pointer to signature for the current Signature being parsed
* from the rules
* \param contentstr Pointer to the string holding the keyword value
*
* \retval 0 on success, -1 on failure
*/
int DetectUricontentSetup (DetectEngineCtx *de_ctx, Signature *s, char *contentstr)
{
SCEnter();
SigMatch *sm = NULL;
DetectUricontentData *cd = DoDetectUricontentSetup(contentstr);
if (cd == NULL)
goto error;
/* Okay so far so good, lets get this into a SigMatch
* and put it in the Signature. */
sm = SigMatchAlloc();
if (sm == NULL)
goto error;
sm->type = DETECT_URICONTENT;
sm->ctx = (void *)cd;
SigMatchAppendAppLayer(s, sm);
/** \todo use unique id here as well */
cd->id = de_ctx->uricontent_max_id;
de_ctx->uricontent_max_id++;
/* Flagged the signature as to inspect the app layer data */
s->flags |= SIG_FLAG_APPLAYER;
if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) {
SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords.");
goto error;
}
s->alproto = ALPROTO_HTTP;
SCReturnInt(0);
error:
if (cd) SCFree(cd);
SCReturnInt(-1);
}
/**
* \brief Checks if the content sent as the argument, has a uricontent which
* has been provided in the rule. This match function matches the
* normalized http uri against the given rule using multi pattern
* search algorithms.
*
* \param t Pointer to the tv for this detection module instance
* \param det_ctx Pointer to the detection engine thread context
* \param content Pointer to the uri content currently being matched
* \param content_len Content_len of the received uri content
*
* \retval 1 if the uri contents match; 0 no match
*/
int DoDetectAppLayerUricontentMatch (ThreadVars *tv, DetectEngineThreadCtx *det_ctx,
uint8_t *uri, uint16_t uri_len)
{
int ret = 0;
/* run the pattern matcher against the uri */
if (det_ctx->sgh->mpm_uricontent_maxlen > uri_len) {
SCLogDebug("not searching as pkt payload is smaller than the "
"largest uricontent length we need to match");
} else {
SCLogDebug("search: (%p, maxlen %" PRIu32 ", sgh->sig_cnt "
"%" PRIu32 ")", det_ctx->sgh, det_ctx->sgh->
mpm_uricontent_maxlen, det_ctx->sgh->sig_cnt);
det_ctx->uris++;
if (det_ctx->sgh->mpm_uricontent_maxlen == 1) det_ctx->pkts_uri_searched1++;
else if (det_ctx->sgh->mpm_uricontent_maxlen == 2) det_ctx->pkts_uri_searched2++;
else if (det_ctx->sgh->mpm_uricontent_maxlen == 3) det_ctx->pkts_uri_searched3++;
else if (det_ctx->sgh->mpm_uricontent_maxlen == 4) det_ctx->pkts_uri_searched4++;
else det_ctx->pkts_uri_searched++;
ret += UriPatternSearch(tv, det_ctx, uri, uri_len);
SCLogDebug("post search: cnt %" PRIu32 ", searchable %" PRIu32 "",
ret, det_ctx->pmq.searchable);
det_ctx->pmq.searchable = 0;
}
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
* flag each sig that has a match. We need to do this for all uri(s)
* to not miss possible events.
*
* \warning Make sure the flow/state is locked
* \todo what should we return? Just the fact that we matched?
*/
uint32_t DetectUricontentInspectMpm(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, void *alstate) {
SCEnter();
uint32_t cnt = 0;
size_t idx = 0;
htp_tx_t *tx = NULL;
HtpState *htp_state = (HtpState *)alstate;
if (htp_state == NULL) {
SCLogDebug("no HTTP state");
SCReturnUInt(0U);
}
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;
cnt += DoDetectAppLayerUricontentMatch(tv, det_ctx, (uint8_t *)
bstr_ptr(tx->request_uri_normalized),
bstr_len(tx->request_uri_normalized));
}
SCReturnUInt(cnt);
}
/*
* UNITTTESTS
*/
#ifdef UNITTESTS
#include "stream-tcp-reassemble.h"
/** \test Test case where path traversal has been sent as a path string in the
* HTTP URL and normalized path string is checked */
static int HTTPUriTest01(void) {
int result = 1;
Flow f;
uint8_t httpbuf1[] = "GET /../../images.gif HTTP/1.1\r\nHost: www.ExA"
"mPlE.cOM\r\n\r\n";
uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
TcpSession ssn;
int r = 0;
memset(&f, 0, sizeof(f));
memset(&ssn, 0, sizeof(ssn));
f.protoctx = (void *)&ssn;
StreamTcpInitConfig(TRUE);
StreamL7DataPtrInit(&ssn);
r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|
STREAM_EOF, httpbuf1, httplen1);
HtpState *htp_state = ssn.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
if (htp_state == NULL) {
printf("no http state: ");
result = 0;
goto end;
}
htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, 0);
if (htp_state->connp == NULL || tx->request_method_number != M_GET ||
tx->request_protocol_number != HTTP_1_1)
{
printf("expected method GET and got %s: , expected protocol "
"HTTP/1.1 and got %s \n", bstr_tocstr(tx->request_method),
bstr_tocstr(tx->request_protocol));
result = 0;
goto end;
}
if ((tx->parsed_uri->hostname == NULL) ||
(bstr_cmpc(tx->parsed_uri->hostname, "www.example.com") != 0))
{
printf("expected www.example.com as hostname, but got: %s \n",
bstr_tocstr(tx->parsed_uri->hostname));
result = 0;
goto end;
}
if ((tx->parsed_uri->path == NULL) ||
(bstr_cmpc(tx->parsed_uri->path, "/images.gif") != 0))
{
printf("expected /images.gif as path, but got: %s \n",
bstr_tocstr(tx->parsed_uri->path));
result = 0;
goto end;
}
end:
StreamL7DataPtrFree(&ssn);
StreamTcpFreeConfig(TRUE);
return result;
}
/** \test Test case where path traversal has been sent in special characters in
* HEX encoding in the HTTP URL and normalized path string is checked */
static int HTTPUriTest02(void) {
int result = 1;
Flow f;
HtpState *htp_state = NULL;
uint8_t httpbuf1[] = "GET /%2e%2e/images.gif HTTP/1.1\r\nHost: www.ExA"
"mPlE.cOM\r\n\r\n";
uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
TcpSession ssn;
int r = 0;
memset(&f, 0, sizeof(f));
memset(&ssn, 0, sizeof(ssn));
f.protoctx = (void *)&ssn;
StreamTcpInitConfig(TRUE);
StreamL7DataPtrInit(&ssn);
r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|
STREAM_EOF, httpbuf1, httplen1);
htp_state = ssn.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
if (htp_state == NULL) {
printf("no http state: ");
result = 0;
goto end;
}
htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, 0);
if (htp_state->connp == NULL || tx->request_method_number != M_GET ||
tx->request_protocol_number != HTTP_1_1)
{
printf("expected method GET and got %s: , expected protocol "
"HTTP/1.1 and got %s \n", bstr_tocstr(tx->request_method),
bstr_tocstr(tx->request_protocol));
result = 0;
goto end;
}
if ((tx->parsed_uri->hostname == NULL) ||
(bstr_cmpc(tx->parsed_uri->hostname, "www.example.com") != 0))
{
printf("expected www.example.com as hostname, but got: %s \n",
bstr_tocstr(tx->parsed_uri->hostname));
result = 0;
goto end;
}
if ((tx->parsed_uri->path == NULL) ||
(bstr_cmpc(tx->parsed_uri->path, "/images.gif") != 0))
{
printf("expected /images.gif as path, but got: %s \n",
bstr_tocstr(tx->parsed_uri->path));
result = 0;
goto end;
}
end:
StreamL7DataPtrFree(&ssn);
StreamTcpFreeConfig(TRUE);
if (htp_state == NULL)
HTPStateFree(htp_state);
return result;
}
/** \test Test case where NULL character has been sent in HEX encoding in the
* HTTP URL and normalized path string is checked */
static int HTTPUriTest03(void) {
int result = 1;
Flow f;
uint8_t httpbuf1[] = "GET%00 /images.gif HTTP/1.1\r\nHost: www.ExA"
"mPlE.cOM\r\n\r\n";
uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
TcpSession ssn;
int r = 0;
memset(&f, 0, sizeof(f));
memset(&ssn, 0, sizeof(ssn));
f.protoctx = (void *)&ssn;
StreamTcpInitConfig(TRUE);
StreamL7DataPtrInit(&ssn);
r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|
STREAM_EOF, httpbuf1, httplen1);
HtpState *htp_state = ssn.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
if (htp_state == NULL) {
printf("no http state: ");
result = 0;
goto end;
}
htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, 0);
if (htp_state->connp == NULL || tx->request_method_number != M_UNKNOWN ||
tx->request_protocol_number != HTTP_1_1)
{
printf("expected method GET and got %s: , expected protocol "
"HTTP/1.1 and got %s \n", bstr_tocstr(tx->request_method),
bstr_tocstr(tx->request_protocol));
result = 0;
goto end;
}
if ((tx->parsed_uri->hostname == NULL) ||
(bstr_cmpc(tx->parsed_uri->hostname, "www.example.com") != 0))
{
printf("expected www.example.com as hostname, but got: %s \n",
bstr_tocstr(tx->parsed_uri->hostname));
result = 0;
goto end;
}
if ((tx->parsed_uri->path == NULL) ||
(bstr_cmpc(tx->parsed_uri->path, "/images.gif") != 0))
{
printf("expected /images.gif as path, but got: %s \n",
bstr_tocstr(tx->parsed_uri->path));
result = 0;
goto end;
}
end:
StreamL7DataPtrFree(&ssn);
StreamTcpFreeConfig(TRUE);
if (htp_state == NULL)
HTPStateFree(htp_state);
return result;
}
/** \test Test case where self referencing directories request has been sent
* in the HTTP URL and normalized path string is checked */
static int HTTPUriTest04(void) {
int result = 1;
Flow f;
uint8_t httpbuf1[] = "GET /./././images.gif HTTP/1.1\r\nHost: www.ExA"
"mPlE.cOM\r\n\r\n";
uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
TcpSession ssn;
int r = 0;
memset(&f, 0, sizeof(f));
memset(&ssn, 0, sizeof(ssn));
f.protoctx = (void *)&ssn;
StreamTcpInitConfig(TRUE);
StreamL7DataPtrInit(&ssn);
r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|
STREAM_EOF, httpbuf1, httplen1);
HtpState *htp_state = ssn.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
if (htp_state == NULL) {
printf("no http state: ");
result = 0;
goto end;
}
htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, 0);
if (htp_state->connp == NULL || tx->request_method_number != M_GET ||
tx->request_protocol_number != HTTP_1_1)
{
printf("expected method GET and got %s: , expected protocol "
"HTTP/1.1 and got %s \n", bstr_tocstr(tx->request_method),
bstr_tocstr(tx->request_protocol));
result = 0;
goto end;
}
if ((tx->parsed_uri->hostname == NULL) ||
(bstr_cmpc(tx->parsed_uri->hostname, "www.example.com") != 0))
{
printf("expected www.example.com as hostname, but got: %s \n",
bstr_tocstr(tx->parsed_uri->hostname));
result = 0;
goto end;
}
if ((tx->parsed_uri->path == NULL) ||
(bstr_cmpc(tx->parsed_uri->path, "/images.gif") != 0))
{
printf("expected /images.gif as path, but got: %s \n",
bstr_tocstr(tx->parsed_uri->path));
result = 0;
goto end;
}
end:
StreamL7DataPtrFree(&ssn);
StreamTcpFreeConfig(TRUE);
if (htp_state == NULL)
HTPStateFree(htp_state);
return result;
}
/**
* \test Checks if a uricontent is registered in a Signature
*/
int DetectUriSigTest01(void)
{
SigMatch *sm = NULL;
int result = 0;
ThreadVars th_v;
DetectEngineThreadCtx *det_ctx;
Signature *s = NULL;
memset(&th_v, 0, sizeof(th_v));
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
if (de_ctx == NULL) {
goto end;
}
de_ctx->flags |= DE_QUIET;
s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:"
"\" Test uricontent\"; "
"uricontent:\"me\"; sid:1;)");
if (s == NULL) {
goto end;
}
SigGroupBuild(de_ctx);
DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
BUG_ON(de_ctx->sig_list == NULL);
sm = de_ctx->sig_list->match;
if (sm->type == DETECT_URICONTENT) {
result = 1;
} else {
result = 0;
}
end:
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);
return result;
}
/** \test Check the signature working to alert when http_cookie is matched . */
static int DetectUriSigTest02(void) {
int result = 0;
Flow f;
uint8_t httpbuf1[] = "POST /one 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;
HtpState *http_state = NULL;
memset(&th_v, 0, sizeof(th_v));
memset(&p, 0, sizeof(p));
memset(&f, 0, sizeof(f));
memset(&ssn, 0, sizeof(ssn));
p.src.family = AF_INET;
p.dst.family = AF_INET;
p.payload = 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\"; sid:2;)");
if (s == NULL) {
goto end;
}
s = s->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:"
"\" Test uricontent\"; "
"uricontent:\"oisf\"; 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;
}
http_state = ssn.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
if (http_state == NULL) {
printf("no http state: ");
goto end;
}
/* do detect */
SigMatchSignatures(&th_v, de_ctx, det_ctx, &p);
if ((PacketAlertCheck(&p, 1))) {
printf("sig: 1 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 alerted, but it should not\n");
goto end;
}
result = 1;
end:
if (http_state != NULL) HTPStateFree(http_state);
if (de_ctx != NULL) SigCleanSignatures(de_ctx);
if (de_ctx != NULL) SigGroupCleanup(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 working of search once per packet only in applayer
* match */
static int DetectUriSigTest03(void) {
int result = 0;
Flow f;
HtpState *http_state = NULL;
uint8_t httpbuf1[] = "POST /one 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 */
uint8_t httpbuf2[] = "POST /oneself HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\nCookie:"
" hellocatch\r\n\r\n";
uint32_t httplen2 = sizeof(httpbuf2) - 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\"; sid:2;)");
if (s == NULL) {
goto end;
}
s = s->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:"
"\" Test uricontent\"; "
"uricontent:\"self\"; 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);
r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2);
if (r != 0) {
printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
goto end;
}
http_state = ssn.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
if (http_state == NULL) {
printf("no http state: ");
goto end;
}
/* do detect */
SigMatchSignatures(&th_v, de_ctx, det_ctx, &p);
if ((PacketAlertCheck(&p, 1))) {
printf("sig: 1 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) {
#ifdef UNITTESTS
UtRegisterTest("HTTPUriTest01", HTTPUriTest01, 1);
UtRegisterTest("HTTPUriTest02", HTTPUriTest02, 1);
UtRegisterTest("HTTPUriTest03", HTTPUriTest03, 1);
UtRegisterTest("HTTPUriTest04", HTTPUriTest04, 1);
UtRegisterTest("DetectUriSigTest01", DetectUriSigTest01, 1);
UtRegisterTest("DetectUriSigTest02", DetectUriSigTest02, 1);
UtRegisterTest("DetectUriSigTest03", DetectUriSigTest03, 1);
#endif /* UNITTESTS */
}