mirror of https://github.com/OISF/suricata
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.
3958 lines
117 KiB
C
3958 lines
117 KiB
C
/* Copyright (C) 2007-2010 Open Information Security Foundation
|
|
*
|
|
* You can copy, redistribute or modify this Program under the terms of
|
|
* the GNU General Public License version 2 as published by the Free
|
|
* Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* version 2 along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
* 02110-1301, USA.
|
|
*/
|
|
|
|
/**
|
|
* \file
|
|
*
|
|
* \author Victor Julien <victor@inliniac.net>
|
|
*
|
|
* Implements the pcre keyword
|
|
*/
|
|
|
|
#include "suricata-common.h"
|
|
#include "debug.h"
|
|
#include "decode.h"
|
|
#include "detect.h"
|
|
|
|
#include "pkt-var.h"
|
|
#include "flow-var.h"
|
|
#include "flow-alert-sid.h"
|
|
#include "flow-util.h"
|
|
|
|
#include "detect-pcre.h"
|
|
|
|
#include "detect-parse.h"
|
|
#include "detect-engine.h"
|
|
#include "detect-engine-mpm.h"
|
|
#include "detect-engine-state.h"
|
|
|
|
#include "util-var-name.h"
|
|
#include "util-unittest-helper.h"
|
|
#include "util-debug.h"
|
|
#include "util-unittest.h"
|
|
#include "util-print.h"
|
|
#include "util-pool.h"
|
|
|
|
#include "conf.h"
|
|
#include "app-layer-htp.h"
|
|
#include "stream.h"
|
|
#include "stream-tcp.h"
|
|
#include "stream-tcp-private.h"
|
|
#include "stream-tcp-reassemble.h"
|
|
#include "app-layer-protos.h"
|
|
#include "app-layer-parser.h"
|
|
#include "app-layer-htp.h"
|
|
|
|
#include <htp/htp.h>
|
|
#include "stream.h"
|
|
|
|
|
|
#define PARSE_CAPTURE_REGEX "\\(\\?P\\<([A-z]+)\\_([A-z0-9_]+)\\>"
|
|
#define PARSE_REGEX "(?<!\\\\)/(.*(?<!(?<!\\\\)\\\\))/([^\"]*)"
|
|
|
|
#define SC_MATCH_LIMIT_DEFAULT 3500
|
|
#define SC_MATCH_LIMIT_RECURSION_DEFAULT 1500
|
|
|
|
static int pcre_match_limit = 0;
|
|
static int pcre_match_limit_recursion = 0;
|
|
|
|
static pcre *parse_regex;
|
|
static pcre_extra *parse_regex_study;
|
|
static pcre *parse_capture_regex;
|
|
static pcre_extra *parse_capture_regex_study;
|
|
|
|
int DetectPcreMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *);
|
|
int DetectPcreALMatchCookie(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m);
|
|
int DetectPcreALMatchMethod(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m);
|
|
static int DetectPcreSetup (DetectEngineCtx *, Signature *, char *);
|
|
void DetectPcreFree(void *);
|
|
void DetectPcreRegisterTests(void);
|
|
|
|
void DetectPcreRegister (void) {
|
|
sigmatch_table[DETECT_PCRE].name = "pcre";
|
|
sigmatch_table[DETECT_PCRE].Match = DetectPcreMatch;
|
|
sigmatch_table[DETECT_PCRE].AppLayerMatch = NULL;
|
|
sigmatch_table[DETECT_PCRE].alproto = ALPROTO_HTTP;
|
|
sigmatch_table[DETECT_PCRE].Setup = DetectPcreSetup;
|
|
sigmatch_table[DETECT_PCRE].Free = DetectPcreFree;
|
|
sigmatch_table[DETECT_PCRE].RegisterTests = DetectPcreRegisterTests;
|
|
|
|
sigmatch_table[DETECT_PCRE].flags |= SIGMATCH_PAYLOAD;
|
|
|
|
const char *eb;
|
|
int eo;
|
|
int opts = 0;
|
|
intmax_t val = 0;
|
|
|
|
if (!ConfGetInt("pcre.match-limit", &val)) {
|
|
pcre_match_limit = SC_MATCH_LIMIT_DEFAULT;
|
|
SCLogDebug("Using PCRE match-limit setting of: %i", pcre_match_limit);
|
|
}
|
|
else {
|
|
pcre_match_limit = val;
|
|
if (pcre_match_limit != SC_MATCH_LIMIT_DEFAULT) {
|
|
SCLogInfo("Using PCRE match-limit setting of: %i", pcre_match_limit);
|
|
} else {
|
|
SCLogDebug("Using PCRE match-limit setting of: %i", pcre_match_limit);
|
|
}
|
|
}
|
|
|
|
val = 0;
|
|
|
|
if (!ConfGetInt("pcre.match-limit-recursion", &val)) {
|
|
pcre_match_limit_recursion = SC_MATCH_LIMIT_RECURSION_DEFAULT;
|
|
SCLogDebug("Using PCRE match-limit-recursion setting of: %i", pcre_match_limit_recursion);
|
|
}
|
|
else {
|
|
pcre_match_limit_recursion = val;
|
|
if (pcre_match_limit_recursion != SC_MATCH_LIMIT_RECURSION_DEFAULT) {
|
|
SCLogInfo("Using PCRE match-limit-recursion setting of: %i", pcre_match_limit_recursion);
|
|
} else {
|
|
SCLogDebug("Using PCRE match-limit-recursion setting of: %i", pcre_match_limit_recursion);
|
|
}
|
|
}
|
|
|
|
parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL);
|
|
if(parse_regex == NULL)
|
|
{
|
|
SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb);
|
|
goto error;
|
|
}
|
|
|
|
parse_regex_study = pcre_study(parse_regex, 0, &eb);
|
|
if(eb != NULL)
|
|
{
|
|
SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb);
|
|
goto error;
|
|
}
|
|
|
|
opts |= PCRE_UNGREEDY; /* pkt_http_ua should be pkt, http_ua, for this reason the UNGREEDY */
|
|
parse_capture_regex = pcre_compile(PARSE_CAPTURE_REGEX, opts, &eb, &eo, NULL);
|
|
if(parse_capture_regex == NULL)
|
|
{
|
|
SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_CAPTURE_REGEX, eo, eb);
|
|
goto error;
|
|
}
|
|
|
|
parse_capture_regex_study = pcre_study(parse_capture_regex, 0, &eb);
|
|
if(eb != NULL)
|
|
{
|
|
SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb);
|
|
goto error;
|
|
}
|
|
return;
|
|
|
|
error:
|
|
/* XXX */
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* \brief Match a regex on data sent at an http method (needs the l7 parser).
|
|
*
|
|
* \param det_ctx Thread detection ctx.
|
|
* \param s Signature.
|
|
* \param sm SigMatch to match against.
|
|
* \param data Data to match against.
|
|
* \param data_len Data length.
|
|
*
|
|
* \retval 1: match
|
|
* \retval 0: no match
|
|
*/
|
|
int DetectPcreALDoMatchMethod(DetectEngineThreadCtx *det_ctx, Signature *s,
|
|
SigMatch *m, Flow *f, uint8_t flags,
|
|
void *state)
|
|
{
|
|
SCEnter();
|
|
|
|
int ret = 0;
|
|
int toret = 0;
|
|
int idx;
|
|
|
|
#define MAX_SUBSTRINGS 30
|
|
int ov[MAX_SUBSTRINGS];
|
|
uint8_t *ptr = NULL;
|
|
uint16_t len = 0;
|
|
|
|
DetectPcreData *pe = (DetectPcreData *)m->ctx;
|
|
|
|
/* define ptr & len */
|
|
SCMutexLock(&f->m);
|
|
SCLogDebug("got lock %p", &f->m);
|
|
|
|
HtpState *htp_state = (HtpState *)state;
|
|
if (htp_state == NULL) {
|
|
SCLogDebug("no HTTP layer state has been received, so no match");
|
|
goto end;
|
|
}
|
|
|
|
if (!(htp_state->flags & HTP_FLAG_STATE_OPEN)) {
|
|
SCLogDebug("HTP state not yet properly setup, so no match");
|
|
goto end;
|
|
}
|
|
|
|
SCLogDebug("htp_state %p, flow %p", htp_state, f);
|
|
SCLogDebug("htp_state->connp %p", htp_state->connp);
|
|
SCLogDebug("htp_state->connp->conn %p", htp_state->connp->conn);
|
|
|
|
if (htp_state->connp == NULL || htp_state->connp->conn == NULL) {
|
|
SCLogDebug("HTTP connection structure is NULL");
|
|
goto end;
|
|
}
|
|
|
|
htp_tx_t *tx = NULL;
|
|
|
|
idx = AppLayerTransactionGetInspectId(f);
|
|
if (idx == -1) {
|
|
goto end;
|
|
}
|
|
|
|
int size = (int)list_size(htp_state->connp->conn->transactions);
|
|
for (; idx < size; idx++)
|
|
{
|
|
tx = list_get(htp_state->connp->conn->transactions, idx);
|
|
if (tx == NULL)
|
|
continue;
|
|
|
|
ptr = (uint8_t *) bstr_ptr(tx->request_method);
|
|
len = bstr_size(tx->request_method);
|
|
if (ptr == NULL)
|
|
continue;
|
|
|
|
//printf("Matching Method");
|
|
//PrintRawUriFp(stdout, (uint8_t*)ptr, len);
|
|
|
|
/* run the actual pcre detection */
|
|
ret = pcre_exec(pe->re, pe->sd, (char *)ptr, len, 0, 0, ov, MAX_SUBSTRINGS);
|
|
SCLogDebug("ret %d (negating %s)", ret, (pe->flags & DETECT_PCRE_NEGATE) ? "set" : "not set");
|
|
|
|
if (ret == PCRE_ERROR_NOMATCH) {
|
|
if (pe->flags & DETECT_PCRE_NEGATE) {
|
|
/* regex didn't match with negate option means we
|
|
* consider it a match */
|
|
ret = 1;
|
|
toret |= ret;
|
|
break;
|
|
} else {
|
|
ret = 0;
|
|
}
|
|
toret |= ret;
|
|
} else if (ret >= 0) {
|
|
if (pe->flags & DETECT_PCRE_NEGATE) {
|
|
/* regex matched but we're negated, so not
|
|
* considering it a match */
|
|
ret = 0;
|
|
} else {
|
|
/* regex matched and we're not negated,
|
|
* considering it a match */
|
|
ret = 1;
|
|
toret |= ret;
|
|
break;
|
|
}
|
|
} else {
|
|
SCLogDebug("pcre had matching error");
|
|
ret = 0;
|
|
}
|
|
}
|
|
|
|
end:
|
|
SCMutexUnlock(&f->m);
|
|
SCLogDebug("released lock %p", &f->m);
|
|
|
|
SCReturnInt(toret);
|
|
}
|
|
|
|
/**
|
|
* \brief Match a regex on data sent at an http cookie (needs the l7 parser).
|
|
*
|
|
* \param det_ctx Thread detection ctx.
|
|
* \param s Signature.
|
|
* \param sm SigMatch to match against.
|
|
* \param data Data to match against.
|
|
* \param data_len Data length.
|
|
*
|
|
* \retval 1: match
|
|
* \retval 0: no match
|
|
*/
|
|
int DetectPcreALDoMatchCookie(DetectEngineThreadCtx *det_ctx, Signature *s,
|
|
SigMatch *m, Flow *f, uint8_t flags,
|
|
void *state)
|
|
{
|
|
SCEnter();
|
|
|
|
int ret = 0;
|
|
int toret = 0;
|
|
int idx;
|
|
|
|
#define MAX_SUBSTRINGS 30
|
|
int ov[MAX_SUBSTRINGS];
|
|
uint8_t *ptr = NULL;
|
|
uint16_t len = 0;
|
|
|
|
DetectPcreData *pe = (DetectPcreData *)m->ctx;
|
|
|
|
/* define ptr & len */
|
|
SCMutexLock(&f->m);
|
|
SCLogDebug("got lock %p", &f->m);
|
|
|
|
HtpState *htp_state = (HtpState *)state;
|
|
if (htp_state == NULL) {
|
|
SCLogDebug("no HTTP layer state has been received, so no match");
|
|
goto end;
|
|
}
|
|
|
|
if (!(htp_state->flags & HTP_FLAG_STATE_OPEN)) {
|
|
SCLogDebug("HTP state not yet properly setup, so no match");
|
|
goto end;
|
|
}
|
|
|
|
SCLogDebug("htp_state %p, flow %p", htp_state, f);
|
|
SCLogDebug("htp_state->connp %p", htp_state->connp);
|
|
SCLogDebug("htp_state->connp->conn %p", htp_state->connp->conn);
|
|
|
|
if (htp_state->connp == NULL || htp_state->connp->conn == NULL) {
|
|
SCLogDebug("HTTP connection structure is NULL");
|
|
goto end;
|
|
}
|
|
|
|
htp_tx_t *tx = NULL;
|
|
|
|
idx = AppLayerTransactionGetInspectId(f);
|
|
if (idx == -1) {
|
|
goto end;
|
|
}
|
|
|
|
int size = (int)list_size(htp_state->connp->conn->transactions);
|
|
for (; idx < size; idx++)
|
|
{
|
|
tx = list_get(htp_state->connp->conn->transactions, idx);
|
|
if (tx == NULL)
|
|
continue;
|
|
|
|
htp_header_t *h = NULL;
|
|
h = (htp_header_t *) table_getc(tx->request_headers, "Cookie");
|
|
if (h == NULL) {
|
|
SCLogDebug("no HTTP Cookie header in the received request");
|
|
goto end;
|
|
}
|
|
ptr = (uint8_t *) bstr_ptr(h->value);
|
|
len = bstr_size(h->value);
|
|
|
|
if (ptr == NULL)
|
|
continue;
|
|
|
|
//printf("Matching Cookie");
|
|
//PrintRawUriFp(stdout, (uint8_t*)ptr, len);
|
|
|
|
SCLogDebug("we have a cookie header");
|
|
|
|
/* run the actual pcre detection */
|
|
ret = pcre_exec(pe->re, pe->sd, (char *)ptr, len, 0, 0, ov, MAX_SUBSTRINGS);
|
|
SCLogDebug("ret %d (negating %s)", ret, (pe->flags & DETECT_PCRE_NEGATE) ? "set" : "not set");
|
|
|
|
if (ret == PCRE_ERROR_NOMATCH) {
|
|
if (pe->flags & DETECT_PCRE_NEGATE) {
|
|
/* regex didn't match with negate option means we
|
|
* consider it a match */
|
|
ret = 1;
|
|
toret |= ret;
|
|
break;
|
|
} else {
|
|
ret = 0;
|
|
}
|
|
toret |= ret;
|
|
} else if (ret >= 0) {
|
|
if (pe->flags & DETECT_PCRE_NEGATE) {
|
|
/* regex matched but we're negated, so not
|
|
* considering it a match */
|
|
ret = 0;
|
|
} else {
|
|
/* regex matched and we're not negated,
|
|
* considering it a match */
|
|
ret = 1;
|
|
toret |= ret;
|
|
break;
|
|
}
|
|
} else {
|
|
SCLogDebug("pcre had matching error");
|
|
if (pe->flags & DETECT_PCRE_NEGATE) {
|
|
ret = 1;
|
|
toret |= ret;
|
|
break;
|
|
} else {
|
|
ret = 0;
|
|
}
|
|
toret |= ret;
|
|
}
|
|
}
|
|
|
|
end:
|
|
SCMutexUnlock(&f->m);
|
|
SCLogDebug("released lock %p", &f->m);
|
|
|
|
SCReturnInt(toret);
|
|
}
|
|
|
|
/**
|
|
* \brief match the specified pcre at http method, requesting it from htp/L7
|
|
*
|
|
* \param t pointer to thread vars
|
|
* \param det_ctx pointer to the pattern matcher thread
|
|
* \param p pointer to the current packet
|
|
* \param m pointer to the sigmatch that we will cast into DetectPcreData
|
|
*
|
|
* \retval int 0 no match; 1 match
|
|
*/
|
|
int DetectPcreALMatchMethod(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f,
|
|
uint8_t flags, void *state, Signature *s, SigMatch *m)
|
|
{
|
|
int r = DetectPcreALDoMatchMethod(det_ctx, s, m, f, flags, state);
|
|
SCReturnInt(r);
|
|
}
|
|
|
|
/**
|
|
* \brief match the specified pcre at http cookie, requesting it from htp/L7
|
|
*
|
|
* \param t pointer to thread vars
|
|
* \param det_ctx pointer to the pattern matcher thread
|
|
* \param p pointer to the current packet
|
|
* \param m pointer to the sigmatch that we will cast into DetectPcreData
|
|
*
|
|
* \retval int 0 no match; 1 match
|
|
*/
|
|
int DetectPcreALMatchCookie(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f,
|
|
uint8_t flags, void *state, Signature *s, SigMatch *m)
|
|
{
|
|
int r = DetectPcreALDoMatchCookie(det_ctx, s, m, f, flags, state);
|
|
SCReturnInt(r);
|
|
}
|
|
|
|
/**
|
|
* \brief Match a regex on a single payload.
|
|
*
|
|
* \param det_ctx Thread detection ctx.
|
|
* \param s Signature.
|
|
* \param sm Sig match to match against.
|
|
* \param p Packet to set PktVars if any.
|
|
* \param f Flow to set FlowVars if any.
|
|
* \param payload Payload to inspect.
|
|
* \param payload_len Length of the payload.
|
|
*
|
|
* \retval 1 Match.
|
|
* \retval 0 No match.
|
|
*/
|
|
int DetectPcrePayloadMatch(DetectEngineThreadCtx *det_ctx, Signature *s,
|
|
SigMatch *sm, Packet *p, Flow *f, uint8_t *payload,
|
|
uint32_t payload_len)
|
|
{
|
|
SCEnter();
|
|
#define MAX_SUBSTRINGS 30
|
|
int ret = 0;
|
|
int ov[MAX_SUBSTRINGS];
|
|
uint8_t *ptr = NULL;
|
|
uint16_t len = 0;
|
|
|
|
DetectPcreData *pe = (DetectPcreData *)sm->ctx;
|
|
|
|
/* If we want to inspect the http body, we will use HTP L7 parser */
|
|
//if (pe->flags & DETECT_PCRE_HTTP_BODY_AL)
|
|
// SCReturnInt(0);
|
|
|
|
if (pe->flags & DETECT_PCRE_RELATIVE) {
|
|
ptr = payload + det_ctx->buffer_offset;
|
|
len = payload_len - det_ctx->buffer_offset;
|
|
} else {
|
|
ptr = payload;
|
|
len = payload_len;
|
|
}
|
|
|
|
if (det_ctx->pcre_match_start_offset != 0) {
|
|
ptr = payload + det_ctx->pcre_match_start_offset;
|
|
len = payload_len - det_ctx->pcre_match_start_offset;
|
|
}
|
|
|
|
/* run the actual pcre detection */
|
|
ret = pcre_exec(pe->re, pe->sd, (char *)ptr, len, 0, 0, ov, MAX_SUBSTRINGS);
|
|
SCLogDebug("ret %d (negating %s)", ret, (pe->flags & DETECT_PCRE_NEGATE) ? "set" : "not set");
|
|
|
|
if (ret == PCRE_ERROR_NOMATCH) {
|
|
if (pe->flags & DETECT_PCRE_NEGATE) {
|
|
/* regex didn't match with negate option means we
|
|
* consider it a match */
|
|
ret = 1;
|
|
} else {
|
|
ret = 0;
|
|
}
|
|
} else if (ret >= 0) {
|
|
if (pe->flags & DETECT_PCRE_NEGATE) {
|
|
/* regex matched but we're negated, so not
|
|
* considering it a match */
|
|
ret = 0;
|
|
} else {
|
|
/* regex matched and we're not negated,
|
|
* considering it a match */
|
|
|
|
/* see if we need to do substring capturing. */
|
|
if (ret > 1 && pe->capidx != 0) {
|
|
const char *str_ptr;
|
|
ret = pcre_get_substring((char *)ptr, ov, MAX_SUBSTRINGS, 1, &str_ptr);
|
|
if (ret) {
|
|
if (pe->flags & DETECT_PCRE_CAPTURE_PKT) {
|
|
if (p != NULL) {
|
|
PktVarAdd(p, pe->capname, (uint8_t *)str_ptr, ret);
|
|
}
|
|
} else if (pe->flags & DETECT_PCRE_CAPTURE_FLOW) {
|
|
if (f != NULL) {
|
|
/* flow will be locked be FlowVarAddStr */
|
|
FlowVarAddStr(f, pe->capidx, (uint8_t *)str_ptr, ret);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* update offset for pcre RELATIVE */
|
|
det_ctx->buffer_offset = (ptr + ov[1]) - payload;
|
|
det_ctx->pcre_match_start_offset = (ptr + ov[0] + 1) - payload;
|
|
|
|
ret = 1;
|
|
}
|
|
|
|
} else {
|
|
SCLogDebug("pcre had matching error");
|
|
ret = 0;
|
|
}
|
|
SCReturnInt(ret);
|
|
}
|
|
|
|
/**
|
|
* \brief match a regex on a single payload'
|
|
*
|
|
* \param det_ctx thread detection ctx
|
|
* \param p packet
|
|
* \param s signature
|
|
* \param sm sig match to match against
|
|
*
|
|
* \retval 1 match
|
|
* \retval 0 no match
|
|
*/
|
|
int DetectPcrePacketPayloadMatch(DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *sm) {
|
|
SCEnter();
|
|
#define MAX_SUBSTRINGS 30
|
|
int ret = 0;
|
|
int ov[MAX_SUBSTRINGS];
|
|
uint8_t *ptr = NULL;
|
|
uint16_t len = 0;
|
|
|
|
if (p->payload_len == 0)
|
|
SCReturnInt(0);
|
|
|
|
DetectPcreData *pe = (DetectPcreData *)sm->ctx;
|
|
|
|
/* If we want to inspect the http body, we will use HTP L7 parser */
|
|
if (pe->flags & DETECT_PCRE_HTTP_CLIENT_BODY)
|
|
SCReturnInt(0);
|
|
|
|
if (pe->flags & DETECT_PCRE_RELATIVE) {
|
|
ptr = p->payload + det_ctx->buffer_offset;
|
|
len = p->payload_len - det_ctx->buffer_offset;
|
|
if (ptr == NULL || len == 0)
|
|
SCReturnInt(0);
|
|
} else {
|
|
ptr = p->payload;
|
|
len = p->payload_len;
|
|
}
|
|
|
|
/* run the actual pcre detection */
|
|
ret = pcre_exec(pe->re, pe->sd, (char *)ptr, len, 0, 0, ov, MAX_SUBSTRINGS);
|
|
SCLogDebug("ret %d (negating %s)", ret, (pe->flags & DETECT_PCRE_NEGATE) ? "set" : "not set");
|
|
|
|
if (ret == PCRE_ERROR_NOMATCH) {
|
|
if (pe->flags & DETECT_PCRE_NEGATE) {
|
|
/* regex didn't match with negate option means we
|
|
* consider it a match */
|
|
ret = 1;
|
|
} else {
|
|
ret = 0;
|
|
}
|
|
} else if (ret >= 0) {
|
|
if (pe->flags & DETECT_PCRE_NEGATE) {
|
|
/* regex matched but we're negated, so not
|
|
* considering it a match */
|
|
ret = 0;
|
|
} else {
|
|
/* regex matched and we're not negated,
|
|
* considering it a match */
|
|
|
|
/* see if we need to do substring capturing. */
|
|
if (ret > 1 && pe->capidx != 0) {
|
|
const char *str_ptr;
|
|
ret = pcre_get_substring((char *)ptr, ov, MAX_SUBSTRINGS, 1, &str_ptr);
|
|
if (ret) {
|
|
if (pe->flags & DETECT_PCRE_CAPTURE_PKT) {
|
|
PktVarAdd(p, pe->capname, (uint8_t *)str_ptr, ret);
|
|
} else if (pe->flags & DETECT_PCRE_CAPTURE_FLOW) {
|
|
FlowVarAddStr(p->flow, pe->capidx, (uint8_t *)str_ptr, ret);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* update offset for pcre RELATIVE */
|
|
det_ctx->buffer_offset = (ptr+ov[1]) - p->payload;
|
|
|
|
ret = 1;
|
|
}
|
|
|
|
} else {
|
|
SCLogDebug("pcre had matching error");
|
|
ret = 0;
|
|
}
|
|
SCReturnInt(ret);
|
|
}
|
|
|
|
/**
|
|
* \brief Match a regex on data sent as arg.
|
|
*
|
|
* \param det_ctx Thread detection ctx.
|
|
* \param s Signature.
|
|
* \param sm SigMatch to match against.
|
|
* \param data Data to match against.
|
|
* \param data_len Data length.
|
|
*
|
|
* \retval 1: match
|
|
* \retval 0: no match
|
|
*/
|
|
int DetectPcrePayloadDoMatch(DetectEngineThreadCtx *det_ctx, Signature *s,
|
|
SigMatch *sm, Packet *p, uint8_t *data,
|
|
uint16_t data_len)
|
|
{
|
|
SCEnter();
|
|
|
|
#define MAX_SUBSTRINGS 30
|
|
int ret = 0;
|
|
int ov[MAX_SUBSTRINGS];
|
|
uint8_t *ptr = NULL;
|
|
uint16_t len = 0;
|
|
|
|
if (data_len == 0)
|
|
SCReturnInt(0);
|
|
|
|
DetectPcreData *pe = (DetectPcreData *)sm->ctx;
|
|
|
|
/* If we want to inspect the http body, we will use HTP L7 parser */
|
|
if (pe->flags & DETECT_PCRE_HTTP_CLIENT_BODY)
|
|
SCReturnInt(0);
|
|
|
|
if (pe->flags & DETECT_PCRE_RELATIVE) {
|
|
ptr = data + det_ctx->buffer_offset;
|
|
len = data_len - det_ctx->buffer_offset;
|
|
if (ptr == NULL || len == 0)
|
|
SCReturnInt(0);
|
|
} else {
|
|
ptr = data;
|
|
len = data_len;
|
|
}
|
|
|
|
/* run the actual pcre detection */
|
|
ret = pcre_exec(pe->re, pe->sd, (char *)ptr, len, 0, 0, ov, MAX_SUBSTRINGS);
|
|
SCLogDebug("ret %d (negating %s)", ret, (pe->flags & DETECT_PCRE_NEGATE) ? "set" : "not set");
|
|
|
|
if (ret == PCRE_ERROR_NOMATCH) {
|
|
if (pe->flags & DETECT_PCRE_NEGATE) {
|
|
/* regex didn't match with negate option means we
|
|
* consider it a match */
|
|
ret = 1;
|
|
} else {
|
|
ret = 0;
|
|
}
|
|
} else if (ret >= 0) {
|
|
if (pe->flags & DETECT_PCRE_NEGATE) {
|
|
/* regex matched but we're negated, so not
|
|
* considering it a match */
|
|
ret = 0;
|
|
} else {
|
|
/* regex matched and we're not negated,
|
|
* considering it a match */
|
|
|
|
/* see if we need to do substring capturing. */
|
|
if (ret > 1 && pe->capidx != 0) {
|
|
const char *str_ptr;
|
|
ret = pcre_get_substring((char *)ptr, ov, MAX_SUBSTRINGS, 1, &str_ptr);
|
|
if (ret) {
|
|
if (pe->flags & DETECT_PCRE_CAPTURE_PKT) {
|
|
PktVarAdd(p, pe->capname, (uint8_t *)str_ptr, ret);
|
|
} else if (pe->flags & DETECT_PCRE_CAPTURE_FLOW) {
|
|
FlowVarAddStr(p->flow, pe->capidx, (uint8_t *)str_ptr, ret);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* update offset for pcre RELATIVE */
|
|
det_ctx->buffer_offset = (ptr + ov[1]) - data;
|
|
|
|
ret = 1;
|
|
}
|
|
|
|
} else {
|
|
SCLogDebug("pcre had matching error");
|
|
ret = 0;
|
|
}
|
|
SCReturnInt(ret);
|
|
}
|
|
|
|
/**
|
|
* \brief DetectPcreMatch will try to match a regex on a single packet;
|
|
* DetectPcreALMatch is used if we parse the option 'P'
|
|
*
|
|
* \param t pointer to the threadvars structure
|
|
* \param det_ctx thread detection ctx
|
|
* \param p packet
|
|
* \param s signature
|
|
* \param sm sig match to match against
|
|
*
|
|
* \retval 1: match
|
|
* \retval 0: no match
|
|
*/
|
|
int DetectPcreMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p,
|
|
Signature *s, SigMatch *sm)
|
|
{
|
|
SCEnter();
|
|
int r = DetectPcrePacketPayloadMatch(det_ctx, p, s, sm);
|
|
SCReturnInt(r);
|
|
}
|
|
|
|
DetectPcreData *DetectPcreParse (char *regexstr)
|
|
{
|
|
int ec;
|
|
const char *eb;
|
|
int eo;
|
|
int opts = 0;
|
|
DetectPcreData *pd = NULL;
|
|
char *re = NULL, *op_ptr = NULL, *op = NULL;
|
|
#define MAX_SUBSTRINGS 30
|
|
int ret = 0, res = 0;
|
|
int ov[MAX_SUBSTRINGS];
|
|
|
|
uint16_t slen = strlen(regexstr);
|
|
uint16_t pos = 0;
|
|
uint8_t negate = 0;
|
|
|
|
while (pos < slen && isspace(regexstr[pos])) {
|
|
pos++;
|
|
}
|
|
|
|
if (regexstr[pos] == '!') {
|
|
negate = 1;
|
|
pos++;
|
|
}
|
|
|
|
ret = pcre_exec(parse_regex, parse_regex_study, regexstr + pos, slen-pos,
|
|
0, 0, ov, MAX_SUBSTRINGS);
|
|
if (ret < 0) {
|
|
SCLogError(SC_ERR_PCRE_MATCH, "parse error");
|
|
goto error;
|
|
}
|
|
|
|
if (ret > 1) {
|
|
const char *str_ptr;
|
|
res = pcre_get_substring((char *)regexstr + pos, ov, MAX_SUBSTRINGS,
|
|
1, &str_ptr);
|
|
if (res < 0) {
|
|
SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
|
|
return NULL;
|
|
}
|
|
re = (char *)str_ptr;
|
|
|
|
if (ret > 2) {
|
|
res = pcre_get_substring((char *)regexstr + pos, ov, MAX_SUBSTRINGS,
|
|
2, &str_ptr);
|
|
if (res < 0) {
|
|
SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
|
|
return NULL;
|
|
}
|
|
op_ptr = op = (char *)str_ptr;
|
|
}
|
|
}
|
|
//printf("ret %" PRId32 " re \'%s\', op \'%s\'\n", ret, re, op);
|
|
|
|
pd = SCMalloc(sizeof(DetectPcreData));
|
|
if (pd == NULL)
|
|
goto error;
|
|
memset(pd, 0, sizeof(DetectPcreData));
|
|
|
|
if (negate)
|
|
pd->flags |= DETECT_PCRE_NEGATE;
|
|
|
|
if (op != NULL) {
|
|
while (*op) {
|
|
SCLogDebug("regex option %c", *op);
|
|
|
|
switch (*op) {
|
|
case 'A':
|
|
opts |= PCRE_ANCHORED;
|
|
break;
|
|
case 'E':
|
|
opts |= PCRE_DOLLAR_ENDONLY;
|
|
break;
|
|
case 'G':
|
|
opts |= PCRE_UNGREEDY;
|
|
break;
|
|
|
|
case 'i':
|
|
opts |= PCRE_CASELESS;
|
|
break;
|
|
case 'm':
|
|
opts |= PCRE_MULTILINE;
|
|
break;
|
|
case 's':
|
|
opts |= PCRE_DOTALL;
|
|
break;
|
|
case 'x':
|
|
opts |= PCRE_EXTENDED;
|
|
break;
|
|
|
|
case 'B': /* snort's option */
|
|
pd->flags |= DETECT_PCRE_RAWBYTES;
|
|
break;
|
|
case 'R': /* snort's option */
|
|
pd->flags |= DETECT_PCRE_RELATIVE;
|
|
break;
|
|
case 'U': /* snort's option */
|
|
if (pd->flags & DETECT_PCRE_HTTP_RAW_URI) {
|
|
SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier '%c' inconsistent with 'U'", *op);
|
|
goto error;
|
|
}
|
|
pd->flags |= DETECT_PCRE_URI;
|
|
break;
|
|
case 'H': /* snort's option */
|
|
if (pd->flags & DETECT_PCRE_RAW_HEADER) {
|
|
SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier '%c' inconsistent with 'H'", *op);
|
|
goto error;
|
|
}
|
|
pd->flags |= DETECT_PCRE_HEADER;
|
|
break;
|
|
case 'I': /* snort's option */
|
|
if (pd->flags & DETECT_PCRE_URI) {
|
|
SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier '%c' inconsistent with 'I'", *op);
|
|
goto error;
|
|
}
|
|
pd->flags |= DETECT_PCRE_HTTP_RAW_URI;
|
|
break;
|
|
case 'D': /* snort's option */
|
|
if (pd->flags & DETECT_PCRE_HEADER) {
|
|
SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier '%c' inconsistent with 'D'", *op);
|
|
goto error;
|
|
}
|
|
pd->flags |= DETECT_PCRE_RAW_HEADER;
|
|
break;
|
|
case 'M': /* snort's option */
|
|
pd->flags |= DETECT_PCRE_METHOD;
|
|
break;
|
|
case 'C': /* snort's option */
|
|
pd->flags |= DETECT_PCRE_COOKIE;
|
|
break;
|
|
case 'O':
|
|
pd->flags |= DETECT_PCRE_MATCH_LIMIT;
|
|
break;
|
|
case 'P':
|
|
/* snort's option (http request body inspection) */
|
|
pd->flags |= DETECT_PCRE_HTTP_CLIENT_BODY;
|
|
break;
|
|
case 'Q':
|
|
/* suricata extension (http response body inspection) */
|
|
pd->flags |= DETECT_PCRE_HTTP_SERVER_BODY;
|
|
break;
|
|
case 'Y':
|
|
/* snort's option */
|
|
pd->flags |= DETECT_PCRE_HTTP_STAT_MSG;
|
|
break;
|
|
case 'S':
|
|
/* snort's option */
|
|
pd->flags |= DETECT_PCRE_HTTP_STAT_CODE;
|
|
break;
|
|
default:
|
|
SCLogError(SC_ERR_UNKNOWN_REGEX_MOD, "unknown regex modifier '%c'", *op);
|
|
goto error;
|
|
}
|
|
op++;
|
|
}
|
|
}
|
|
|
|
//printf("DetectPcreParse: \"%s\"\n", re);
|
|
|
|
/* Try to compile as if all (...) groups had been meant as (?:...),
|
|
* which is the common case in most rules.
|
|
* If we fail because a capture group is later referenced (e.g., \1),
|
|
* PCRE will let us know.
|
|
*/
|
|
pd->re = pcre_compile2(re, opts | PCRE_NO_AUTO_CAPTURE, &ec, &eb, &eo, NULL);
|
|
if (pd->re == NULL && ec == 15) { // reference to non-existent subpattern
|
|
pd->re = pcre_compile(re, opts, &eb, &eo, NULL);
|
|
}
|
|
|
|
if(pd->re == NULL) {
|
|
SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", regexstr, eo, eb);
|
|
goto error;
|
|
}
|
|
#ifdef PCRE_HAVE_JIT
|
|
pd->sd = pcre_study(pd->re, PCRE_STUDY_JIT_COMPILE, &eb);
|
|
if(eb != NULL) {
|
|
SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed : %s", eb);
|
|
goto error;
|
|
}
|
|
|
|
int jit = 0;
|
|
ret = pcre_fullinfo(pd->re, pd->sd, PCRE_INFO_JIT, &jit);
|
|
if (ret != 0 || jit != 1) {
|
|
SCLogWarning(SC_ERR_PCRE_STUDY, "PCRE JIT compiler does not support: %s", regexstr);
|
|
}
|
|
#else
|
|
pd->sd = pcre_study(pd->re, 0, &eb);
|
|
if(eb != NULL) {
|
|
SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed : %s", eb);
|
|
goto error;
|
|
}
|
|
#endif /*PCRE_HAVE_SLJIT*/
|
|
|
|
if(pd->sd == NULL)
|
|
pd->sd = (pcre_extra *) SCCalloc(1,sizeof(pcre_extra));
|
|
|
|
if(pd->sd) {
|
|
|
|
if(pd->flags & DETECT_PCRE_MATCH_LIMIT) {
|
|
|
|
if(pcre_match_limit >= -1) {
|
|
pd->sd->match_limit = pcre_match_limit;
|
|
pd->sd->flags |= PCRE_EXTRA_MATCH_LIMIT;
|
|
}
|
|
#ifndef NO_PCRE_MATCH_RLIMIT
|
|
if(pcre_match_limit_recursion >= -1) {
|
|
pd->sd->match_limit_recursion = pcre_match_limit_recursion;
|
|
pd->sd->flags |= PCRE_EXTRA_MATCH_LIMIT_RECURSION;
|
|
}
|
|
#endif /* NO_PCRE_MATCH_RLIMIT */
|
|
}
|
|
else {
|
|
|
|
pd->sd->match_limit = SC_MATCH_LIMIT_DEFAULT;
|
|
pd->sd->flags |= PCRE_EXTRA_MATCH_LIMIT;
|
|
#ifndef NO_PCRE_MATCH_RLIMIT
|
|
pd->sd->match_limit_recursion = SC_MATCH_LIMIT_RECURSION_DEFAULT;
|
|
pd->sd->flags |= PCRE_EXTRA_MATCH_LIMIT_RECURSION;
|
|
#endif /* NO_PCRE_MATCH_RLIMIT */
|
|
}
|
|
|
|
} else {
|
|
goto error;
|
|
}
|
|
|
|
if (re != NULL) SCFree(re);
|
|
if (op_ptr != NULL) SCFree(op_ptr);
|
|
return pd;
|
|
|
|
error:
|
|
if (re != NULL) SCFree(re);
|
|
if (op_ptr != NULL) SCFree(op_ptr);
|
|
if (pd != NULL && pd->re != NULL) pcre_free(pd->re);
|
|
if (pd != NULL && pd->sd != NULL) pcre_free(pd->sd);
|
|
if (pd) SCFree(pd);
|
|
return NULL;
|
|
}
|
|
|
|
DetectPcreData *DetectPcreParseCapture(char *regexstr, DetectEngineCtx *de_ctx, DetectPcreData *pd)
|
|
{
|
|
int ret = 0, res = 0;
|
|
int ov[MAX_SUBSTRINGS];
|
|
const char *capture_str_ptr = NULL, *type_str_ptr = NULL;
|
|
|
|
if(pd == NULL)
|
|
goto error;
|
|
|
|
if(de_ctx == NULL)
|
|
goto error;
|
|
//printf("DetectPcreParseCapture: \'%s\'\n", regexstr);
|
|
|
|
ret = pcre_exec(parse_capture_regex, parse_capture_regex_study, regexstr, strlen(regexstr), 0, 0, ov, MAX_SUBSTRINGS);
|
|
if (ret > 1) {
|
|
res = pcre_get_substring((char *)regexstr, ov, MAX_SUBSTRINGS, 1, &type_str_ptr);
|
|
if (res < 0) {
|
|
SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
|
|
goto error;
|
|
}
|
|
res = pcre_get_substring((char *)regexstr, ov, MAX_SUBSTRINGS, 2, &capture_str_ptr);
|
|
if (res < 0) {
|
|
SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
|
|
goto error;
|
|
}
|
|
}
|
|
//printf("DetectPcreParseCapture: type \'%s\'\n", type_str_ptr ? type_str_ptr : "NULL");
|
|
//printf("DetectPcreParseCapture: capture \'%s\'\n", capture_str_ptr ? capture_str_ptr : "NULL");
|
|
|
|
if (capture_str_ptr != NULL) {
|
|
pd->capname = SCStrdup((char *)capture_str_ptr);
|
|
}
|
|
|
|
if (type_str_ptr != NULL) {
|
|
if (strcmp(type_str_ptr,"pkt") == 0) {
|
|
pd->flags |= DETECT_PCRE_CAPTURE_PKT;
|
|
} else if (strcmp(type_str_ptr,"flow") == 0) {
|
|
pd->flags |= DETECT_PCRE_CAPTURE_FLOW;
|
|
}
|
|
if (capture_str_ptr != NULL) {
|
|
if (pd->flags & DETECT_PCRE_CAPTURE_PKT)
|
|
pd->capidx = VariableNameGetIdx((char *)capture_str_ptr,DETECT_PKTVAR);
|
|
else if (pd->flags & DETECT_PCRE_CAPTURE_FLOW)
|
|
pd->capidx = VariableNameGetIdx((char *)capture_str_ptr,DETECT_FLOWVAR);
|
|
}
|
|
}
|
|
//printf("DetectPcreParseCapture: pd->capname %s\n", pd->capname ? pd->capname : "NULL");
|
|
|
|
if (type_str_ptr != NULL) pcre_free((char *)type_str_ptr);
|
|
if (capture_str_ptr != NULL) pcre_free((char *)capture_str_ptr);
|
|
return pd;
|
|
|
|
error:
|
|
if (pd != NULL && pd->capname != NULL) SCFree(pd->capname);
|
|
if (pd) SCFree(pd);
|
|
return NULL;
|
|
|
|
}
|
|
|
|
static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexstr)
|
|
{
|
|
SCEnter();
|
|
DetectPcreData *pd = NULL;
|
|
SigMatch *sm = NULL;
|
|
SigMatch *prev_sm = NULL;
|
|
|
|
pd = DetectPcreParse(regexstr);
|
|
if (pd == NULL)
|
|
goto error;
|
|
|
|
/* check pcre modifiers against the signature alproto. In case they conflict
|
|
* chuck out invalid signature */
|
|
switch (s->alproto) {
|
|
case ALPROTO_DCERPC:
|
|
if ( (pd->flags & DETECT_PCRE_URI) ||
|
|
(pd->flags & DETECT_PCRE_METHOD) ||
|
|
(pd->flags & DETECT_PCRE_HEADER) ||
|
|
(pd->flags & DETECT_PCRE_RAW_HEADER) ||
|
|
(pd->flags & DETECT_PCRE_COOKIE) ||
|
|
(pd->flags & DETECT_PCRE_HTTP_STAT_MSG) ||
|
|
(pd->flags & DETECT_PCRE_HTTP_STAT_CODE) ||
|
|
(pd->flags & DETECT_PCRE_HTTP_CLIENT_BODY) ||
|
|
(pd->flags & DETECT_PCRE_HTTP_SERVER_BODY) ||
|
|
(pd->flags & DETECT_PCRE_HTTP_RAW_URI) ) {
|
|
SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "Invalid option. "
|
|
"DCERPC rule has pcre keyword with http related modifier.");
|
|
goto error;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
pd = DetectPcreParseCapture(regexstr, de_ctx, pd);
|
|
if (pd == NULL)
|
|
goto error;
|
|
|
|
sm = SigMatchAlloc();
|
|
if (sm == NULL)
|
|
goto error;
|
|
|
|
sm->type = DETECT_PCRE;
|
|
sm->ctx = (void *)pd;
|
|
|
|
if (pd->flags & DETECT_PCRE_HEADER) {
|
|
SCLogDebug("Header inspection modifier set");
|
|
s->flags |= SIG_FLAG_APPLAYER;
|
|
s->alproto = ALPROTO_HTTP;
|
|
|
|
SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HHDMATCH);
|
|
} else if (pd->flags & DETECT_PCRE_RAW_HEADER) {
|
|
SCLogDebug("Raw header inspection modifier set");
|
|
s->flags |= SIG_FLAG_APPLAYER;
|
|
s->alproto = ALPROTO_HTTP;
|
|
|
|
SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HRHDMATCH);
|
|
} else if (pd->flags & DETECT_PCRE_COOKIE) {
|
|
//sm->type = DETECT_PCRE_HTTPCOOKIE;
|
|
|
|
SCLogDebug("Cookie inspection modifier set");
|
|
s->flags |= SIG_FLAG_APPLAYER;
|
|
s->alproto = ALPROTO_HTTP;
|
|
|
|
SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HCDMATCH);
|
|
} else if (pd->flags & DETECT_PCRE_METHOD) {
|
|
//sm->type = DETECT_PCRE_HTTPMETHOD;
|
|
|
|
SCLogDebug("Method inspection modifier set");
|
|
s->flags |= SIG_FLAG_APPLAYER;
|
|
s->alproto = ALPROTO_HTTP;
|
|
|
|
SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HMDMATCH);
|
|
} else if (pd->flags & DETECT_PCRE_HTTP_CLIENT_BODY) {
|
|
SCLogDebug("Request body inspection modifier set");
|
|
s->flags |= SIG_FLAG_APPLAYER;
|
|
s->alproto = ALPROTO_HTTP;
|
|
AppLayerHtpEnableRequestBodyCallback();
|
|
|
|
SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HCBDMATCH);
|
|
} else if (pd->flags & DETECT_PCRE_HTTP_SERVER_BODY) {
|
|
SCLogDebug("Response body inspection modifier set");
|
|
s->flags |= SIG_FLAG_APPLAYER;
|
|
s->alproto = ALPROTO_HTTP;
|
|
AppLayerHtpEnableResponseBodyCallback();
|
|
|
|
SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HSBDMATCH);
|
|
} else if (pd->flags & DETECT_PCRE_URI) {
|
|
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;
|
|
|
|
SigMatchAppendUricontent(s, sm);
|
|
} else if (pd->flags & DETECT_PCRE_HTTP_RAW_URI) {
|
|
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;
|
|
|
|
SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HRUDMATCH);
|
|
} else if (pd->flags & DETECT_PCRE_HTTP_STAT_MSG) {
|
|
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;
|
|
|
|
SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HSMDMATCH);
|
|
} else if (pd->flags & DETECT_PCRE_HTTP_STAT_CODE) {
|
|
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;
|
|
|
|
SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HSCDMATCH);
|
|
} else {
|
|
if (s->alproto == ALPROTO_DCERPC && pd->flags & DETECT_PCRE_RELATIVE) {
|
|
SigMatch *pm = NULL;
|
|
SigMatch *dm = NULL;
|
|
|
|
pm = SigMatchGetLastSMFromLists(s, 6,
|
|
DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH],
|
|
DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH],
|
|
DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]);
|
|
dm = SigMatchGetLastSMFromLists(s, 6,
|
|
DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH],
|
|
DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH],
|
|
DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]);
|
|
|
|
if (pm == NULL) {
|
|
SigMatchAppendDcePayload(s, sm);
|
|
} else if (dm == NULL) {
|
|
SigMatchAppendDcePayload(s, sm);
|
|
} else if (pm->idx > dm->idx) {
|
|
SigMatchAppendPayload(s, sm);
|
|
} else {
|
|
SigMatchAppendDcePayload(s, sm);
|
|
}
|
|
} else {
|
|
if (s->init_flags & SIG_FLAG_INIT_FILE_DATA) {
|
|
SCLogDebug("adding to http server body list because of file data");
|
|
s->flags |= SIG_FLAG_APPLAYER;
|
|
AppLayerHtpEnableResponseBodyCallback();
|
|
|
|
SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HSBDMATCH);
|
|
} else {
|
|
SigMatchAppendPayload(s, sm);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!(pd->flags & DETECT_PCRE_RELATIVE)) {
|
|
SCReturnInt(0);
|
|
}
|
|
|
|
prev_sm = SigMatchGetLastSMFromLists(s, 24,
|
|
DETECT_CONTENT, sm->prev,
|
|
DETECT_URICONTENT, sm->prev,
|
|
DETECT_AL_HTTP_CLIENT_BODY, sm->prev,
|
|
DETECT_AL_HTTP_SERVER_BODY, sm->prev,
|
|
DETECT_AL_HTTP_HEADER, sm->prev,
|
|
DETECT_AL_HTTP_RAW_HEADER, sm->prev,
|
|
DETECT_AL_HTTP_RAW_URI, sm->prev,
|
|
DETECT_AL_HTTP_COOKIE, sm->prev,
|
|
DETECT_AL_HTTP_METHOD, sm->prev,
|
|
DETECT_PCRE, sm->prev,
|
|
DETECT_AL_HTTP_STAT_MSG, sm->prev,
|
|
DETECT_AL_HTTP_STAT_CODE, sm->prev);
|
|
if (prev_sm == NULL) {
|
|
if (s->alproto == ALPROTO_DCERPC) {
|
|
SCLogDebug("No preceding content or pcre keyword. Possible "
|
|
"since this is an alproto sig.");
|
|
SCReturnInt(0);
|
|
} else {
|
|
if (s->init_flags & SIG_FLAG_INIT_FILE_DATA) {
|
|
SCLogDebug("removing relative flag as we are relative to file_data");
|
|
pd->flags &= ~DETECT_PCRE_RELATIVE;
|
|
SCReturnInt(0);
|
|
} else {
|
|
SCLogError(SC_ERR_INVALID_SIGNATURE, "No preceding content "
|
|
"or uricontent or pcre option");
|
|
SCReturnInt(-1);
|
|
}
|
|
}
|
|
}
|
|
|
|
DetectContentData *cd = NULL;
|
|
DetectPcreData *pe = NULL;
|
|
|
|
switch (prev_sm->type) {
|
|
case DETECT_CONTENT:
|
|
case DETECT_URICONTENT:
|
|
case DETECT_AL_HTTP_CLIENT_BODY:
|
|
case DETECT_AL_HTTP_SERVER_BODY:
|
|
case DETECT_AL_HTTP_HEADER:
|
|
case DETECT_AL_HTTP_RAW_HEADER:
|
|
case DETECT_AL_HTTP_STAT_MSG:
|
|
case DETECT_AL_HTTP_STAT_CODE:
|
|
case DETECT_AL_HTTP_RAW_URI:
|
|
case DETECT_AL_HTTP_COOKIE:
|
|
case DETECT_AL_HTTP_METHOD:
|
|
/* Set the relative next flag on the prev sigmatch */
|
|
cd = (DetectContentData *)prev_sm->ctx;
|
|
if (cd == NULL) {
|
|
SCLogError(SC_ERR_INVALID_SIGNATURE, "content not setup properly");
|
|
SCReturnInt(-1);
|
|
}
|
|
cd->flags |= DETECT_CONTENT_RELATIVE_NEXT;
|
|
|
|
break;
|
|
|
|
case DETECT_PCRE:
|
|
pe = (DetectPcreData *) prev_sm->ctx;
|
|
if (pe == NULL) {
|
|
SCLogError(SC_ERR_INVALID_SIGNATURE, "pcre not setup properly");
|
|
SCReturnInt(-1);
|
|
}
|
|
pe->flags |= DETECT_PCRE_RELATIVE_NEXT;
|
|
|
|
break;
|
|
|
|
default:
|
|
/* this will never hit */
|
|
SCLogError(SC_ERR_INVALID_SIGNATURE, "prev sigmatch has unknown type: %"PRIu16,
|
|
prev_sm->type);
|
|
SCReturnInt(-1);
|
|
break;
|
|
} /* switch (prev_sm->type) */
|
|
|
|
SCReturnInt(0);
|
|
|
|
error:
|
|
if (pd != NULL)
|
|
DetectPcreFree(pd);
|
|
if (sm != NULL)
|
|
SCFree(sm);
|
|
|
|
SCReturnInt(-1);
|
|
}
|
|
|
|
void DetectPcreFree(void *ptr) {
|
|
DetectPcreData *pd = (DetectPcreData *)ptr;
|
|
|
|
if (pd->capname != NULL)
|
|
SCFree(pd->capname);
|
|
if (pd->re != NULL)
|
|
pcre_free(pd->re);
|
|
if (pd->sd != NULL)
|
|
pcre_free(pd->sd);
|
|
|
|
SCFree(pd);
|
|
return;
|
|
}
|
|
|
|
#ifdef UNITTESTS /* UNITTESTS */
|
|
|
|
/**
|
|
* \test DetectPcreParseTest01 make sure we don't allow invalid opts 7.
|
|
*/
|
|
static int DetectPcreParseTest01 (void) {
|
|
int result = 1;
|
|
DetectPcreData *pd = NULL;
|
|
char *teststring = "/blah/7";
|
|
|
|
pd = DetectPcreParse(teststring);
|
|
if (pd != NULL) {
|
|
printf("expected NULL: got %p", pd);
|
|
result = 0;
|
|
DetectPcreFree(pd);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* \test DetectPcreParseTest02 make sure we don't allow invalid opts Ui$.
|
|
*/
|
|
static int DetectPcreParseTest02 (void) {
|
|
int result = 1;
|
|
DetectPcreData *pd = NULL;
|
|
char *teststring = "/blah/Ui$";
|
|
|
|
pd = DetectPcreParse(teststring);
|
|
if (pd != NULL) {
|
|
printf("expected NULL: got %p", pd);
|
|
result = 0;
|
|
DetectPcreFree(pd);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* \test DetectPcreParseTest03 make sure we don't allow invalid opts UZi.
|
|
*/
|
|
static int DetectPcreParseTest03 (void) {
|
|
int result = 1;
|
|
DetectPcreData *pd = NULL;
|
|
char *teststring = "/blah/UZi";
|
|
|
|
pd = DetectPcreParse(teststring);
|
|
if (pd != NULL) {
|
|
printf("expected NULL: got %p", pd);
|
|
result = 0;
|
|
DetectPcreFree(pd);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* \test DetectPcreParseTest04 make sure we allow escaped "
|
|
*/
|
|
static int DetectPcreParseTest04 (void) {
|
|
int result = 1;
|
|
DetectPcreData *pd = NULL;
|
|
char *teststring = "/b\\\"lah/i";
|
|
|
|
pd = DetectPcreParse(teststring);
|
|
if (pd == NULL) {
|
|
printf("expected %p: got NULL", pd);
|
|
result = 0;
|
|
}
|
|
|
|
DetectPcreFree(pd);
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* \test DetectPcreParseTest05 make sure we parse pcre with no opts
|
|
*/
|
|
static int DetectPcreParseTest05 (void) {
|
|
int result = 1;
|
|
DetectPcreData *pd = NULL;
|
|
char *teststring = "/b(l|a)h/";
|
|
|
|
pd = DetectPcreParse(teststring);
|
|
if (pd == NULL) {
|
|
printf("expected %p: got NULL", pd);
|
|
result = 0;
|
|
}
|
|
|
|
DetectPcreFree(pd);
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* \test DetectPcreParseTest06 make sure we parse pcre with smi opts
|
|
*/
|
|
static int DetectPcreParseTest06 (void) {
|
|
int result = 1;
|
|
DetectPcreData *pd = NULL;
|
|
char *teststring = "/b(l|a)h/smi";
|
|
|
|
pd = DetectPcreParse(teststring);
|
|
if (pd == NULL) {
|
|
printf("expected %p: got NULL", pd);
|
|
result = 0;
|
|
}
|
|
|
|
DetectPcreFree(pd);
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* \test DetectPcreParseTest07 make sure we parse pcre with /Ui opts
|
|
*/
|
|
static int DetectPcreParseTest07 (void) {
|
|
int result = 1;
|
|
DetectPcreData *pd = NULL;
|
|
char *teststring = "/blah/Ui";
|
|
|
|
pd = DetectPcreParse(teststring);
|
|
if (pd == NULL) {
|
|
printf("expected %p: got NULL", pd);
|
|
result = 0;
|
|
}
|
|
|
|
DetectPcreFree(pd);
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* \test DetectPcreParseTest08 make sure we parse pcre with O opts
|
|
*/
|
|
static int DetectPcreParseTest08 (void) {
|
|
int result = 1;
|
|
DetectPcreData *pd = NULL;
|
|
char *teststring = "/b(l|a)h/O";
|
|
|
|
pd = DetectPcreParse(teststring);
|
|
if (pd == NULL) {
|
|
printf("expected %p: got NULL", pd);
|
|
result = 0;
|
|
}
|
|
|
|
DetectPcreFree(pd);
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* \test DetectPcreParseTest09 make sure we parse pcre with a content
|
|
* that has slashes
|
|
*/
|
|
static int DetectPcreParseTest09 (void) {
|
|
int result = 1;
|
|
DetectPcreData *pd = NULL;
|
|
char *teststring = "/lala\\\\/";
|
|
|
|
pd = DetectPcreParse(teststring);
|
|
if (pd == NULL) {
|
|
printf("expected %p: got NULL", pd);
|
|
result = 0;
|
|
}
|
|
|
|
DetectPcreFree(pd);
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* \test Test pcre option for dce sig(yeah I'm bored of writing test titles).
|
|
*/
|
|
int DetectPcreParseTest10(void)
|
|
{
|
|
Signature *s = SigAlloc();
|
|
int result = 1;
|
|
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
|
|
if (de_ctx == NULL) {
|
|
result = 0;
|
|
goto end;
|
|
}
|
|
|
|
s->alproto = ALPROTO_DCERPC;
|
|
|
|
result &= (DetectPcreSetup(de_ctx, s, "/bamboo/") == 0);
|
|
result &= (s->sm_lists[DETECT_SM_LIST_DMATCH] == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL);
|
|
|
|
SigFree(s);
|
|
|
|
s = SigAlloc();
|
|
/* failure since we have no preceding content/pcre/bytejump */
|
|
result &= (DetectPcreSetup(de_ctx, s, "/bamboo/") == 0);
|
|
result &= (s->sm_lists[DETECT_SM_LIST_DMATCH] == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL);
|
|
|
|
end:
|
|
SigFree(s);
|
|
DetectEngineCtxFree(de_ctx);
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* \test Test pcre option for dce sig.
|
|
*/
|
|
int DetectPcreParseTest11(void)
|
|
{
|
|
DetectEngineCtx *de_ctx = NULL;
|
|
int result = 1;
|
|
Signature *s = NULL;
|
|
DetectPcreData *data = NULL;
|
|
|
|
de_ctx = DetectEngineCtxInit();
|
|
if (de_ctx == NULL)
|
|
goto end;
|
|
|
|
de_ctx->flags |= DE_QUIET;
|
|
de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any "
|
|
"(msg:\"Testing bytejump_body\"; "
|
|
"dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; "
|
|
"dce_stub_data; "
|
|
"pcre:/bamboo/R; sid:1;)");
|
|
if (de_ctx->sig_list == NULL) {
|
|
result = 0;
|
|
goto end;
|
|
}
|
|
s = de_ctx->sig_list;
|
|
if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) {
|
|
result = 0;
|
|
goto end;
|
|
}
|
|
result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_PCRE);
|
|
data = (DetectPcreData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx;
|
|
if (data->flags & DETECT_PCRE_RAWBYTES ||
|
|
!(data->flags & DETECT_PCRE_RELATIVE) ||
|
|
data->flags & DETECT_PCRE_URI) {
|
|
result = 0;
|
|
goto end;
|
|
}
|
|
|
|
s->next = SigInit(de_ctx, "alert tcp any any -> any any "
|
|
"(msg:\"Testing bytejump_body\"; "
|
|
"dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; "
|
|
"dce_stub_data; "
|
|
"pcre:/bamboo/R; sid:1;)");
|
|
if (s->next == NULL) {
|
|
result = 0;
|
|
goto end;
|
|
}
|
|
s = s->next;
|
|
if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) {
|
|
result = 0;
|
|
goto end;
|
|
}
|
|
result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_PCRE);
|
|
data = (DetectPcreData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx;
|
|
if (data->flags & DETECT_PCRE_RAWBYTES ||
|
|
!(data->flags & DETECT_PCRE_RELATIVE) ||
|
|
data->flags & DETECT_PCRE_URI) {
|
|
result = 0;
|
|
goto end;
|
|
}
|
|
|
|
s->next = SigInit(de_ctx, "alert tcp any any -> any any "
|
|
"(msg:\"Testing bytejump_body\"; "
|
|
"dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; "
|
|
"dce_stub_data; "
|
|
"pcre:/bamboo/RB; sid:1;)");
|
|
if (s->next == NULL) {
|
|
result = 0;
|
|
goto end;
|
|
}
|
|
s = s->next;
|
|
if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) {
|
|
result = 0;
|
|
goto end;
|
|
}
|
|
result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_PCRE);
|
|
data = (DetectPcreData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx;
|
|
if (!(data->flags & DETECT_PCRE_RAWBYTES) ||
|
|
!(data->flags & DETECT_PCRE_RELATIVE) ||
|
|
data->flags & DETECT_PCRE_URI) {
|
|
result = 0;
|
|
goto end;
|
|
}
|
|
|
|
s->next = SigInit(de_ctx, "alert tcp any any -> any any "
|
|
"(msg:\"Testing bytejump_body\"; "
|
|
"content:\"one\"; pcre:/bamboo/; sid:1;)");
|
|
if (s->next == NULL) {
|
|
result = 0;
|
|
goto end;
|
|
}
|
|
s = s->next;
|
|
if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] != NULL) {
|
|
result = 0;
|
|
goto end;
|
|
}
|
|
|
|
end:
|
|
SigGroupCleanup(de_ctx);
|
|
SigCleanSignatures(de_ctx);
|
|
DetectEngineCtxFree(de_ctx);
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* \test Test pcre option with file data. pcre is relative to file_data,
|
|
* so relative flag should be unset.
|
|
*/
|
|
static int DetectPcreParseTest12(void)
|
|
{
|
|
DetectEngineCtx *de_ctx = NULL;
|
|
int result = 0;
|
|
Signature *s = NULL;
|
|
DetectPcreData *data = NULL;
|
|
|
|
de_ctx = DetectEngineCtxInit();
|
|
if (de_ctx == NULL)
|
|
goto end;
|
|
|
|
de_ctx->flags |= DE_QUIET;
|
|
de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any "
|
|
"(file_data; pcre:/abc/R; sid:1;)");
|
|
if (de_ctx->sig_list == NULL) {
|
|
printf("sig parse failed: ");
|
|
goto end;
|
|
}
|
|
|
|
s = de_ctx->sig_list;
|
|
if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] == NULL) {
|
|
printf("empty server body list: ");
|
|
goto end;
|
|
}
|
|
|
|
if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->type != DETECT_PCRE) {
|
|
printf("last sm not pcre: ");
|
|
goto end;
|
|
}
|
|
|
|
data = (DetectPcreData *)s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx;
|
|
if (data->flags & DETECT_PCRE_RAWBYTES ||
|
|
data->flags & DETECT_PCRE_RELATIVE ||
|
|
data->flags & DETECT_PCRE_URI) {
|
|
printf("flags not right: ");
|
|
goto end;
|
|
}
|
|
|
|
result = 1;
|
|
end:
|
|
SigGroupCleanup(de_ctx);
|
|
SigCleanSignatures(de_ctx);
|
|
DetectEngineCtxFree(de_ctx);
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* \test Test pcre option with file data.
|
|
*/
|
|
static int DetectPcreParseTest13(void)
|
|
{
|
|
DetectEngineCtx *de_ctx = NULL;
|
|
int result = 0;
|
|
Signature *s = NULL;
|
|
DetectPcreData *data = NULL;
|
|
|
|
de_ctx = DetectEngineCtxInit();
|
|
if (de_ctx == NULL)
|
|
goto end;
|
|
|
|
de_ctx->flags |= DE_QUIET;
|
|
de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any "
|
|
"(file_data; content:\"abc\"; pcre:/def/R; sid:1;)");
|
|
if (de_ctx->sig_list == NULL) {
|
|
printf("sig parse failed: ");
|
|
goto end;
|
|
}
|
|
|
|
s = de_ctx->sig_list;
|
|
if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] == NULL) {
|
|
printf("empty server body list: ");
|
|
goto end;
|
|
}
|
|
|
|
if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->type != DETECT_PCRE) {
|
|
printf("last sm not pcre: ");
|
|
goto end;
|
|
}
|
|
|
|
data = (DetectPcreData *)s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx;
|
|
if (data->flags & DETECT_PCRE_RAWBYTES ||
|
|
!(data->flags & DETECT_PCRE_RELATIVE) ||
|
|
data->flags & DETECT_PCRE_URI) {
|
|
printf("flags not right: ");
|
|
goto end;
|
|
}
|
|
|
|
result = 1;
|
|
end:
|
|
SigGroupCleanup(de_ctx);
|
|
SigCleanSignatures(de_ctx);
|
|
DetectEngineCtxFree(de_ctx);
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* \test Test pcre option with file data.
|
|
*/
|
|
static int DetectPcreParseTest14(void)
|
|
{
|
|
DetectEngineCtx *de_ctx = NULL;
|
|
int result = 0;
|
|
Signature *s = NULL;
|
|
DetectPcreData *data = NULL;
|
|
|
|
de_ctx = DetectEngineCtxInit();
|
|
if (de_ctx == NULL)
|
|
goto end;
|
|
|
|
de_ctx->flags |= DE_QUIET;
|
|
de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any "
|
|
"(file_data; pcre:/def/; sid:1;)");
|
|
if (de_ctx->sig_list == NULL) {
|
|
printf("sig parse failed: ");
|
|
goto end;
|
|
}
|
|
|
|
s = de_ctx->sig_list;
|
|
if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] == NULL) {
|
|
printf("empty server body list: ");
|
|
goto end;
|
|
}
|
|
|
|
if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->type != DETECT_PCRE) {
|
|
printf("last sm not pcre: ");
|
|
goto end;
|
|
}
|
|
|
|
data = (DetectPcreData *)s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx;
|
|
if (data->flags & DETECT_PCRE_RAWBYTES ||
|
|
data->flags & DETECT_PCRE_RELATIVE ||
|
|
data->flags & DETECT_PCRE_URI) {
|
|
printf("flags not right: ");
|
|
goto end;
|
|
}
|
|
|
|
result = 1;
|
|
end:
|
|
SigGroupCleanup(de_ctx);
|
|
SigCleanSignatures(de_ctx);
|
|
DetectEngineCtxFree(de_ctx);
|
|
|
|
return result;
|
|
}
|
|
|
|
/** \test Check a signature with pcre relative method */
|
|
int DetectPcreParseTest15(void)
|
|
{
|
|
DetectEngineCtx *de_ctx = NULL;
|
|
int result = 0;
|
|
|
|
if ( (de_ctx = DetectEngineCtxInit()) == NULL)
|
|
goto end;
|
|
|
|
de_ctx->flags |= DE_QUIET;
|
|
de_ctx->sig_list = SigInit(de_ctx,
|
|
"alert tcp any any -> any any "
|
|
"(msg:\"Testing pcre relative http_method\"; "
|
|
"content:\"GET\"; "
|
|
"http_method; pcre:\"/abc/RM\"; sid:1;)");
|
|
|
|
if (de_ctx->sig_list != NULL) {
|
|
result = 1;
|
|
} else {
|
|
printf("sig parse failed: ");
|
|
}
|
|
|
|
end:
|
|
if (de_ctx != NULL)
|
|
SigCleanSignatures(de_ctx);
|
|
if (de_ctx != NULL)
|
|
DetectEngineCtxFree(de_ctx);
|
|
return result;
|
|
}
|
|
|
|
|
|
/** \test Check a signature with pcre relative cookie */
|
|
int DetectPcreParseTest16(void)
|
|
{
|
|
DetectEngineCtx *de_ctx = NULL;
|
|
int result = 0;
|
|
|
|
if ( (de_ctx = DetectEngineCtxInit()) == NULL)
|
|
goto end;
|
|
|
|
de_ctx->flags |= DE_QUIET;
|
|
de_ctx->sig_list = SigInit(de_ctx,
|
|
"alert tcp any any -> any any "
|
|
"(msg:\"Testing pcre relative http_cookie\"; "
|
|
"content:\"test\"; "
|
|
"http_cookie; pcre:\"/abc/RC\"; sid:1;)");
|
|
|
|
if (de_ctx->sig_list != NULL) {
|
|
result = 1;
|
|
} else {
|
|
printf("sig parse failed: ");
|
|
}
|
|
|
|
end:
|
|
if (de_ctx != NULL)
|
|
SigCleanSignatures(de_ctx);
|
|
if (de_ctx != NULL)
|
|
DetectEngineCtxFree(de_ctx);
|
|
return result;
|
|
}
|
|
|
|
/** \test Check a signature with pcre relative raw header */
|
|
int DetectPcreParseTest17(void)
|
|
{
|
|
DetectEngineCtx *de_ctx = NULL;
|
|
int result = 0;
|
|
|
|
if ( (de_ctx = DetectEngineCtxInit()) == NULL)
|
|
goto end;
|
|
|
|
de_ctx->flags |= DE_QUIET;
|
|
de_ctx->sig_list = SigInit(de_ctx,
|
|
"alert tcp any any -> any any "
|
|
"(msg:\"Testing pcre relative http_raw_header\"; "
|
|
"flow:to_server; content:\"test\"; "
|
|
"http_raw_header; pcre:\"/abc/RD\"; sid:1;)");
|
|
|
|
if (de_ctx->sig_list != NULL) {
|
|
result = 1;
|
|
} else {
|
|
printf("sig parse failed: ");
|
|
}
|
|
|
|
end:
|
|
if (de_ctx != NULL)
|
|
SigCleanSignatures(de_ctx);
|
|
if (de_ctx != NULL)
|
|
DetectEngineCtxFree(de_ctx);
|
|
return result;
|
|
}
|
|
|
|
/** \test Check a signature with pcre relative header */
|
|
int DetectPcreParseTest18(void)
|
|
{
|
|
DetectEngineCtx *de_ctx = NULL;
|
|
int result = 0;
|
|
|
|
if ( (de_ctx = DetectEngineCtxInit()) == NULL)
|
|
goto end;
|
|
|
|
de_ctx->flags |= DE_QUIET;
|
|
de_ctx->sig_list = SigInit(de_ctx,
|
|
"alert tcp any any -> any any "
|
|
"(msg:\"Testing pcre relative http_header\"; "
|
|
"content:\"test\"; "
|
|
"http_header; pcre:\"/abc/RH\"; sid:1;)");
|
|
|
|
if (de_ctx->sig_list != NULL) {
|
|
result = 1;
|
|
} else {
|
|
printf("sig parse failed: ");
|
|
}
|
|
|
|
end:
|
|
if (de_ctx != NULL)
|
|
SigCleanSignatures(de_ctx);
|
|
if (de_ctx != NULL)
|
|
DetectEngineCtxFree(de_ctx);
|
|
return result;
|
|
}
|
|
|
|
/** \test Check a signature with pcre relative client-body */
|
|
int DetectPcreParseTest19(void)
|
|
{
|
|
DetectEngineCtx *de_ctx = NULL;
|
|
int result = 0;
|
|
|
|
if ( (de_ctx = DetectEngineCtxInit()) == NULL)
|
|
goto end;
|
|
|
|
de_ctx->flags |= DE_QUIET;
|
|
de_ctx->sig_list = SigInit(de_ctx,
|
|
"alert tcp any any -> any any "
|
|
"(msg:\"Testing pcre relativie http_client_body\"; "
|
|
"content:\"test\"; "
|
|
"http_client_body; pcre:\"/abc/RP\"; sid:1;)");
|
|
|
|
if (de_ctx->sig_list != NULL) {
|
|
result = 1;
|
|
} else {
|
|
printf("sig parse failed: ");
|
|
}
|
|
|
|
end:
|
|
if (de_ctx != NULL)
|
|
SigCleanSignatures(de_ctx);
|
|
if (de_ctx != NULL)
|
|
DetectEngineCtxFree(de_ctx);
|
|
return result;
|
|
}
|
|
|
|
/** \test Check a signature with pcre relative raw uri */
|
|
int DetectPcreParseTest20(void)
|
|
{
|
|
DetectEngineCtx *de_ctx = NULL;
|
|
int result = 0;
|
|
|
|
if ( (de_ctx = DetectEngineCtxInit()) == NULL)
|
|
goto end;
|
|
|
|
de_ctx->flags |= DE_QUIET;
|
|
de_ctx->sig_list = SigInit(de_ctx,
|
|
"alert tcp any any -> any any "
|
|
"(msg:\"Testing http_raw_uri\"; "
|
|
"content:\"test\"; "
|
|
"http_raw_uri; pcre:\"/abc/RI\"; sid:1;)");
|
|
|
|
if (de_ctx->sig_list != NULL) {
|
|
result = 1;
|
|
} else {
|
|
printf("sig parse failed: ");
|
|
}
|
|
|
|
end:
|
|
if (de_ctx != NULL)
|
|
SigCleanSignatures(de_ctx);
|
|
if (de_ctx != NULL)
|
|
DetectEngineCtxFree(de_ctx);
|
|
return result;
|
|
}
|
|
|
|
/** \test Check a signature with pcre relative uricontent */
|
|
int DetectPcreParseTest21(void)
|
|
{
|
|
DetectEngineCtx *de_ctx = NULL;
|
|
int result = 0;
|
|
|
|
if ( (de_ctx = DetectEngineCtxInit()) == NULL)
|
|
goto end;
|
|
|
|
de_ctx->flags |= DE_QUIET;
|
|
de_ctx->sig_list = SigInit(de_ctx,
|
|
"alert tcp any any -> any any "
|
|
"(msg:\"Testing pcre relative uricontent\"; "
|
|
"uricontent:\"test\"; "
|
|
"pcre:\"/abc/RU\"; sid:1;)");
|
|
|
|
if (de_ctx->sig_list != NULL) {
|
|
result = 1;
|
|
} else {
|
|
printf("sig parse failed: ");
|
|
}
|
|
|
|
end:
|
|
if (de_ctx != NULL)
|
|
SigCleanSignatures(de_ctx);
|
|
if (de_ctx != NULL)
|
|
DetectEngineCtxFree(de_ctx);
|
|
return result;
|
|
}
|
|
|
|
/** \test Check a signature with pcre relative http_uri */
|
|
int DetectPcreParseTest22(void)
|
|
{
|
|
DetectEngineCtx *de_ctx = NULL;
|
|
int result = 0;
|
|
|
|
if ( (de_ctx = DetectEngineCtxInit()) == NULL)
|
|
goto end;
|
|
|
|
de_ctx->flags |= DE_QUIET;
|
|
de_ctx->sig_list = SigInit(de_ctx,
|
|
"alert tcp any any -> any any "
|
|
"(msg:\"Testing pcre relative http_uri\"; "
|
|
"content:\"test\"; "
|
|
"http_uri; pcre:\"/abc/RU\"; sid:1;)");
|
|
|
|
if (de_ctx->sig_list != NULL) {
|
|
result = 1;
|
|
} else {
|
|
printf("sig parse failed: ");
|
|
}
|
|
|
|
end:
|
|
if (de_ctx != NULL)
|
|
SigCleanSignatures(de_ctx);
|
|
if (de_ctx != NULL)
|
|
DetectEngineCtxFree(de_ctx);
|
|
return result;
|
|
}
|
|
|
|
/** \test Check a signature with inconsistent pcre relative */
|
|
int DetectPcreParseTest23(void)
|
|
{
|
|
DetectEngineCtx *de_ctx = NULL;
|
|
int result = 0;
|
|
|
|
if ( (de_ctx = DetectEngineCtxInit()) == NULL)
|
|
goto end;
|
|
|
|
de_ctx->flags |= DE_QUIET;
|
|
de_ctx->sig_list = SigInit(de_ctx,
|
|
"alert tcp any any -> any any "
|
|
"(msg:\"Testing inconsistent pcre relative\"; "
|
|
"content:\"GET\"; "
|
|
"http_cookie; pcre:\"/abc/RM\"; sid:1;)");
|
|
|
|
if (de_ctx->sig_list == NULL) {
|
|
result = 1;
|
|
} else {
|
|
printf("sig parse should have failed: ");
|
|
}
|
|
|
|
end:
|
|
if (de_ctx != NULL)
|
|
SigCleanSignatures(de_ctx);
|
|
if (de_ctx != NULL)
|
|
DetectEngineCtxFree(de_ctx);
|
|
return result;
|
|
}
|
|
|
|
/** \test Check a signature with inconsistent pcre modifiers */
|
|
int DetectPcreParseTest24(void)
|
|
{
|
|
DetectEngineCtx *de_ctx = NULL;
|
|
int result = 0;
|
|
|
|
if ( (de_ctx = DetectEngineCtxInit()) == NULL)
|
|
goto end;
|
|
|
|
de_ctx->flags |= DE_QUIET;
|
|
de_ctx->sig_list = SigInit(de_ctx,
|
|
"alert tcp any any -> any any "
|
|
"(msg:\"Testing inconsistent pcre modifiers\"; "
|
|
"pcre:\"/abc/UI\"; sid:1;)");
|
|
|
|
if (de_ctx->sig_list == NULL) {
|
|
result = 1;
|
|
} else {
|
|
printf("sig parse should have failed: ");
|
|
}
|
|
|
|
end:
|
|
if (de_ctx != NULL)
|
|
SigCleanSignatures(de_ctx);
|
|
if (de_ctx != NULL)
|
|
DetectEngineCtxFree(de_ctx);
|
|
return result;
|
|
}
|
|
|
|
/** \test Check a signature with inconsistent pcre modifiers */
|
|
int DetectPcreParseTest25(void)
|
|
{
|
|
DetectEngineCtx *de_ctx = NULL;
|
|
int result = 0;
|
|
|
|
if ( (de_ctx = DetectEngineCtxInit()) == NULL)
|
|
goto end;
|
|
|
|
de_ctx->flags |= DE_QUIET;
|
|
de_ctx->sig_list = SigInit(de_ctx,
|
|
"alert tcp any any -> any any "
|
|
"(msg:\"Testing inconsistent pcre modifiers\"; "
|
|
"pcre:\"/abc/DH\"; sid:1;)");
|
|
|
|
if (de_ctx->sig_list == NULL) {
|
|
result = 1;
|
|
} else {
|
|
printf("sig parse should have failed: ");
|
|
}
|
|
|
|
end:
|
|
if (de_ctx != NULL)
|
|
SigCleanSignatures(de_ctx);
|
|
if (de_ctx != NULL)
|
|
DetectEngineCtxFree(de_ctx);
|
|
return result;
|
|
}
|
|
|
|
static int DetectPcreTestSig01Real(int mpm_type) {
|
|
uint8_t *buf = (uint8_t *)
|
|
"GET /one/ HTTP/1.1\r\n"
|
|
"Host: one.example.org\r\n"
|
|
"\r\n\r\n"
|
|
"GET /two/ HTTP/1.1\r\n"
|
|
"Host: two.example.org\r\n"
|
|
"\r\n\r\n";
|
|
uint16_t buflen = strlen((char *)buf);
|
|
TcpSession ssn;
|
|
Packet *p = NULL;
|
|
ThreadVars th_v;
|
|
DetectEngineThreadCtx *det_ctx = NULL;
|
|
int result = 0;
|
|
Flow f;
|
|
|
|
memset(&f, 0, sizeof(f));
|
|
memset(&th_v, 0, sizeof(th_v));
|
|
memset(&ssn, 0, sizeof(TcpSession));
|
|
|
|
FLOW_INITIALIZE(&f);
|
|
f.protoctx = (void *)&ssn;
|
|
f.flags |= FLOW_IPV4;
|
|
f.alproto = ALPROTO_HTTP;
|
|
|
|
p = UTHBuildPacket(buf, buflen, IPPROTO_TCP);
|
|
p->flow = &f;
|
|
p->flowflags |= FLOW_PKT_TOSERVER;
|
|
p->flowflags |= FLOW_PKT_ESTABLISHED;
|
|
p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
|
|
|
|
StreamTcpInitConfig(TRUE);
|
|
|
|
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
|
|
if (de_ctx == NULL) {
|
|
goto end;
|
|
}
|
|
|
|
de_ctx->mpm_matcher = mpm_type;
|
|
de_ctx->flags |= DE_QUIET;
|
|
|
|
de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP TEST\"; pcre:\"/^gEt/i\"; pcre:\"/\\/two\\//U; pcre:\"/GET \\/two\\//\"; pcre:\"/\\s+HTTP/R\"; sid:1;)");
|
|
if (de_ctx->sig_list == NULL) {
|
|
result = 0;
|
|
goto end;
|
|
}
|
|
|
|
SigGroupBuild(de_ctx);
|
|
DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
|
|
|
|
int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, buf, buflen);
|
|
if (r != 0) {
|
|
printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
|
|
result = 0;
|
|
goto end;
|
|
}
|
|
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
|
|
if (PacketAlertCheck(p, 1) == 1) {
|
|
result = 1;
|
|
}
|
|
|
|
end:
|
|
SigGroupCleanup(de_ctx);
|
|
SigCleanSignatures(de_ctx);
|
|
|
|
DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
|
|
DetectEngineCtxFree(de_ctx);
|
|
|
|
StreamTcpFreeConfig(TRUE);
|
|
|
|
FLOW_DESTROY(&f);
|
|
|
|
UTHFreePackets(&p, 1);
|
|
return result;
|
|
}
|
|
static int DetectPcreTestSig01B2g (void) {
|
|
return DetectPcreTestSig01Real(MPM_B2G);
|
|
}
|
|
static int DetectPcreTestSig01B3g (void) {
|
|
return DetectPcreTestSig01Real(MPM_B3G);
|
|
}
|
|
static int DetectPcreTestSig01Wm (void) {
|
|
return DetectPcreTestSig01Real(MPM_WUMANBER);
|
|
}
|
|
|
|
static int DetectPcreTestSig02Real(int mpm_type) {
|
|
uint8_t *buf = (uint8_t *)
|
|
"GET /one/ HTTP/1.1\r\n"
|
|
"Host: one.example.org\r\n"
|
|
"\r\n\r\n"
|
|
"GET /two/ HTTP/1.1\r\n"
|
|
"Host: two.example.org\r\n"
|
|
"\r\n\r\n";
|
|
uint16_t buflen = strlen((char *)buf);
|
|
Packet *p = NULL;
|
|
Flow f;
|
|
ThreadVars th_v;
|
|
DetectEngineThreadCtx *det_ctx;
|
|
int result = 0;
|
|
|
|
memset(&th_v, 0, sizeof(th_v));
|
|
memset(&f, 0, sizeof(f));
|
|
|
|
FLOW_INITIALIZE(&f);
|
|
|
|
p = UTHBuildPacket(buf, buflen, IPPROTO_TCP);
|
|
p->flow = &f;
|
|
p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
|
|
|
|
pcre_match_limit = 100;
|
|
pcre_match_limit_recursion = 100;
|
|
|
|
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
|
|
if (de_ctx == NULL) {
|
|
goto end;
|
|
}
|
|
|
|
de_ctx->mpm_matcher = mpm_type;
|
|
de_ctx->flags |= DE_QUIET;
|
|
|
|
de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP TEST\"; pcre:\"/two/O\"; sid:2;)");
|
|
if (de_ctx->sig_list == NULL) {
|
|
result = 0;
|
|
goto end;
|
|
}
|
|
|
|
SigGroupBuild(de_ctx);
|
|
DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
|
|
|
|
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
|
|
if (PacketAlertCheck(p, 2) == 1) {
|
|
result = 1;
|
|
}
|
|
|
|
SigGroupCleanup(de_ctx);
|
|
SigCleanSignatures(de_ctx);
|
|
|
|
DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
|
|
DetectEngineCtxFree(de_ctx);
|
|
FLOW_DESTROY(&f);
|
|
end:
|
|
UTHFreePackets(&p, 1);
|
|
return result;
|
|
}
|
|
static int DetectPcreTestSig02B2g (void) {
|
|
return DetectPcreTestSig02Real(MPM_B2G);
|
|
}
|
|
static int DetectPcreTestSig02B3g (void) {
|
|
return DetectPcreTestSig02Real(MPM_B3G);
|
|
}
|
|
static int DetectPcreTestSig02Wm (void) {
|
|
return DetectPcreTestSig02Real(MPM_WUMANBER);
|
|
}
|
|
|
|
/**
|
|
* \test DetectPcreTestSig03Real negation test ! outside of "" this sig should not match
|
|
*/
|
|
static int DetectPcreTestSig03Real(int mpm_type) {
|
|
uint8_t *buf = (uint8_t *)
|
|
"GET /one/ HTTP/1.1\r\n"
|
|
"Host: one.example.org\r\n"
|
|
"\r\n\r\n"
|
|
"GET /two/ HTTP/1.1\r\n"
|
|
"Host: two.example.org\r\n"
|
|
"\r\n\r\n";
|
|
uint16_t buflen = strlen((char *)buf);
|
|
Packet *p = NULL;
|
|
ThreadVars th_v;
|
|
DetectEngineThreadCtx *det_ctx;
|
|
int result = 1;
|
|
|
|
memset(&th_v, 0, sizeof(th_v));
|
|
|
|
p = UTHBuildPacket(buf, buflen, IPPROTO_TCP);
|
|
|
|
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
|
|
if (de_ctx == NULL) {
|
|
result = 0;
|
|
goto end;
|
|
}
|
|
|
|
de_ctx->mpm_matcher = mpm_type;
|
|
de_ctx->flags |= DE_QUIET;
|
|
|
|
de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP TEST\"; content:\"GET\"; pcre:!\"/two/\"; sid:1;)");
|
|
if (de_ctx->sig_list == NULL) {
|
|
result = 0;
|
|
goto end;
|
|
}
|
|
|
|
SigGroupBuild(de_ctx);
|
|
DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
|
|
|
|
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
|
|
if (PacketAlertCheck(p, 1)){
|
|
printf("sid 1 matched even though it shouldn't have:");
|
|
result = 0;
|
|
}
|
|
SigGroupCleanup(de_ctx);
|
|
SigCleanSignatures(de_ctx);
|
|
|
|
DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
|
|
DetectEngineCtxFree(de_ctx);
|
|
end:
|
|
UTHFreePackets(&p, 1);
|
|
return result;
|
|
}
|
|
|
|
static int DetectPcreTestSig03B2g (void) {
|
|
return DetectPcreTestSig03Real(MPM_B2G);
|
|
}
|
|
static int DetectPcreTestSig03B3g (void) {
|
|
return DetectPcreTestSig03Real(MPM_B3G);
|
|
}
|
|
static int DetectPcreTestSig03Wm (void) {
|
|
return DetectPcreTestSig03Real(MPM_WUMANBER);
|
|
}
|
|
|
|
/**
|
|
* \test Check the signature with pcre modifier P (match with L7 to http body data)
|
|
*/
|
|
static int DetectPcreModifPTest04(void) {
|
|
int result = 0;
|
|
uint8_t httpbuf1[] =
|
|
"GET / HTTP/1.1\r\n"
|
|
"Host: www.emergingthreats.net\r\n"
|
|
"User-Agent: Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.9.0.13) Gecko/2009080315 Ubuntu/8.10 (intrepid) Firefox/3.0.13\r\n"
|
|
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9;q=0.8\r\n"
|
|
"Accept-Language: es-es,es;q=0.8,en-us;q=0.5,en;q=0.3\r\n"
|
|
"Accept-Encoding: gzip,deflate\r\n"
|
|
"Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n"
|
|
"Date: Tue, 22 Sep 2009 19:24:48 GMT\r\n"
|
|
"Server: Apache\r\n"
|
|
"X-Powered-By: PHP/5.2.5\r\n"
|
|
"P3P: CP=\"NOI ADM DEV PSAi COM NAV OUR OTRo STP IND DEM\"\r\n"
|
|
"Expires: Mon, 1 Jan 2001 00:00:00 GMT\r\n"
|
|
"Last-Modified: Tue, 22 Sep 2009 19:24:48 GMT\r\n"
|
|
"Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0\r\n"
|
|
"Pragma: no-cache\r\n"
|
|
"Keep-Alive: timeout=15, max=100\r\n"
|
|
"Connection: Keep-Alive\r\n"
|
|
"Transfer-Encoding: chunked\r\n"
|
|
"Content-Type: text/html; charset=utf-8\r\n"
|
|
"\r\n"
|
|
"15"
|
|
"\r\n"
|
|
"<!DOCTYPE html PUBLIC\r\n"
|
|
"0\r\n";
|
|
|
|
uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
|
|
TcpSession ssn;
|
|
Packet *p = NULL;
|
|
Flow f;
|
|
Signature *s = NULL;
|
|
ThreadVars th_v;
|
|
DetectEngineThreadCtx *det_ctx;
|
|
|
|
memset(&th_v, 0, sizeof(th_v));
|
|
memset(&f, 0, sizeof(f));
|
|
memset(&ssn, 0, sizeof(ssn));
|
|
|
|
p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
|
|
|
|
FLOW_INITIALIZE(&f);
|
|
f.protoctx = (void *)&ssn;
|
|
f.flags |= FLOW_IPV4;
|
|
|
|
p->flow = &f;
|
|
p->flowflags |= FLOW_PKT_TOSERVER;
|
|
p->flowflags |= FLOW_PKT_ESTABLISHED;
|
|
p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
|
|
f.alproto = ALPROTO_HTTP;
|
|
|
|
StreamTcpInitConfig(TRUE);
|
|
|
|
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:"
|
|
"\"Pcre modifier P\"; pcre:\"/DOCTYPE/P\"; "
|
|
"sid:1;)");
|
|
if (s == NULL) {
|
|
goto end;
|
|
}
|
|
|
|
s->next = SigInit(de_ctx,"alert http any any -> any any (msg:\""
|
|
"Pcre modifier P (no match)\"; pcre:\"/blah/P\"; sid:2;)");
|
|
if (s->next == NULL) {
|
|
goto end;
|
|
}
|
|
|
|
SigGroupBuild(de_ctx);
|
|
DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
|
|
|
|
int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1);
|
|
if (r != 0) {
|
|
printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
|
|
result = 0;
|
|
goto end;
|
|
}
|
|
|
|
HtpState *http_state = f.alstate;
|
|
if (http_state == NULL) {
|
|
printf("no http state: ");
|
|
result = 0;
|
|
goto end;
|
|
}
|
|
|
|
/* do detect */
|
|
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
|
|
|
|
if (!(PacketAlertCheck(p, 1))) {
|
|
printf("sid 1 didn't match but should have: ");
|
|
goto end;
|
|
}
|
|
if (PacketAlertCheck(p, 2)) {
|
|
printf("sid 2 matched but shouldn't: ");
|
|
goto end;
|
|
}
|
|
|
|
result = 1;
|
|
end:
|
|
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(&p, 1);
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* \test Check the signature with pcre modifier P (match with L7 to http body data)
|
|
* over fragmented chunks (DOCTYPE fragmented)
|
|
*/
|
|
static int DetectPcreModifPTest05(void) {
|
|
int result = 0;
|
|
uint8_t httpbuf1[] =
|
|
"GET / HTTP/1.1\r\n"
|
|
"Host: www.emergingthreats.net\r\n"
|
|
"User-Agent: Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.9.0.13) Gecko/2009080315 Ubuntu/8.10 (intrepid) Firefox/3.0.13\r\n"
|
|
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9;q=0.8\r\n"
|
|
"Accept-Language: es-es,es;q=0.8,en-us;q=0.5,en;q=0.3\r\n"
|
|
"Accept-Encoding: gzip,deflate\r\n"
|
|
"Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n"
|
|
"Date: Tue, 22 Sep 2009 19:24:48 GMT\r\n"
|
|
"Server: Apache\r\n"
|
|
"X-Powered-By: PHP/5.2.5\r\n"
|
|
"P3P: CP=\"NOI ADM DEV PSAi COM NAV OUR OTRo STP IND DEM\"\r\n"
|
|
"Expires: Mon, 1 Jan 2001 00:00:00 GMT\r\n"
|
|
"Last-Modified: Tue, 22 Sep 2009 19:24:48 GMT\r\n"
|
|
"Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0\r\n"
|
|
"Pragma: no-cache\r\n"
|
|
"Keep-Alive: timeout=15, max=100\r\n"
|
|
"Connection: Keep-Alive\r\n"
|
|
"Transfer-Encoding: chunked\r\n"
|
|
"Content-Type: text/html; charset=utf-8\r\n"
|
|
"\r\n"
|
|
"15"
|
|
"\r\n"
|
|
"<!DOC";
|
|
|
|
uint8_t httpbuf2[] = "<!DOCTYPE html PUBLIC\r\n0\r\n";
|
|
|
|
uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
|
|
uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
|
|
TcpSession ssn;
|
|
Packet *p1 = NULL;
|
|
Packet *p2 = NULL;
|
|
Flow f;
|
|
Signature *s = NULL;
|
|
ThreadVars th_v;
|
|
DetectEngineThreadCtx *det_ctx;
|
|
|
|
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);
|
|
|
|
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:"
|
|
"\"Pcre modifier P\"; pcre:\"/DOC/P\"; "
|
|
"sid:1;)");
|
|
if (s == NULL) {
|
|
goto end;
|
|
}
|
|
|
|
s->next = SigInit(de_ctx,"alert http any any -> any any (msg:\""
|
|
"Pcre modifier P (no match)\"; pcre:\"/DOCTYPE/P\"; sid:2;)");
|
|
if (s->next == NULL) {
|
|
goto end;
|
|
}
|
|
|
|
SigGroupBuild(de_ctx);
|
|
DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
|
|
|
|
int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1);
|
|
if (r != 0) {
|
|
printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
|
|
result = 0;
|
|
goto end;
|
|
}
|
|
|
|
/* do detect for p1 */
|
|
SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
|
|
|
|
HtpState *http_state = f.alstate;
|
|
if (http_state == NULL) {
|
|
printf("no http state: ");
|
|
result = 0;
|
|
goto end;
|
|
}
|
|
|
|
if (PacketAlertCheck(p1, 1)) {
|
|
printf("sid 1 didn't match on p1 but should have: ");
|
|
goto end;
|
|
}
|
|
|
|
if (PacketAlertCheck(p1, 2)) {
|
|
printf("sid 2 did match on p1 but shouldn't have: ");
|
|
/* It's a partial match over 2 chunks*/
|
|
goto end;
|
|
}
|
|
|
|
r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2);
|
|
if (r != 0) {
|
|
printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
|
|
result = 0;
|
|
goto end;
|
|
}
|
|
|
|
/* do detect for p2 */
|
|
SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
|
|
|
|
if (!(PacketAlertCheck(p2, 1))) {
|
|
printf("sid 1 did match on p2 but should have: ");
|
|
goto end;
|
|
}
|
|
|
|
if (!(PacketAlertCheck(p2, 2))) {
|
|
printf("sid 2 didn't match on p2 but should have: ");
|
|
/* It's a partial match over 2 chunks*/
|
|
goto end;
|
|
}
|
|
|
|
result = 1;
|
|
end:
|
|
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;
|
|
}
|
|
|
|
int DetectPcreTestSig06() {
|
|
uint8_t *buf = (uint8_t *)
|
|
"lalala lalala\\ lala\n";
|
|
uint16_t buflen = strlen((char *)buf);
|
|
Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP);
|
|
int result = 0;
|
|
|
|
char sig[] = "alert tcp any any -> any any (msg:\"pcre with an ending slash\"; pcre:\"/ lalala\\\\/\"; sid:1;)";
|
|
if (UTHPacketMatchSig(p, sig) == 0) {
|
|
result = 0;
|
|
goto end;
|
|
}
|
|
result = 1;
|
|
end:
|
|
if (p != NULL)
|
|
UTHFreePacket(p);
|
|
return result;
|
|
}
|
|
|
|
/** \test anchored pcre */
|
|
int DetectPcreTestSig07() {
|
|
uint8_t *buf = (uint8_t *)
|
|
"lalala\n";
|
|
uint16_t buflen = strlen((char *)buf);
|
|
Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP);
|
|
int result = 0;
|
|
|
|
char sig[] = "alert tcp any any -> any any (msg:\"pcre with an ending slash\"; pcre:\"/^(la)+$/\"; sid:1;)";
|
|
if (UTHPacketMatchSig(p, sig) == 0) {
|
|
result = 0;
|
|
goto end;
|
|
}
|
|
result = 1;
|
|
end:
|
|
if (p != NULL)
|
|
UTHFreePacket(p);
|
|
return result;
|
|
}
|
|
|
|
/** \test anchored pcre */
|
|
int DetectPcreTestSig08() {
|
|
/* test it also without ending in a newline "\n" */
|
|
uint8_t *buf = (uint8_t *)
|
|
"lalala";
|
|
uint16_t buflen = strlen((char *)buf);
|
|
Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP);
|
|
int result = 0;
|
|
|
|
char sig[] = "alert tcp any any -> any any (msg:\"pcre with an ending slash\"; pcre:\"/^(la)+$/\"; sid:1;)";
|
|
if (UTHPacketMatchSig(p, sig) == 0) {
|
|
result = 0;
|
|
goto end;
|
|
}
|
|
result = 1;
|
|
end:
|
|
if (p != NULL)
|
|
UTHFreePacket(p);
|
|
return result;
|
|
}
|
|
|
|
/** \test Check the signature working to alert when cookie modifier is
|
|
* passed to pcre
|
|
*/
|
|
static int DetectPcreTestSig09(void) {
|
|
int result = 0;
|
|
Flow f;
|
|
uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"
|
|
"Cookie: dummy\r\n\r\n";
|
|
uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
|
|
TcpSession ssn;
|
|
Packet *p = NULL;
|
|
Signature *s = NULL;
|
|
ThreadVars th_v;
|
|
DetectEngineThreadCtx *det_ctx = NULL;
|
|
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 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
|
|
|
|
FLOW_INITIALIZE(&f);
|
|
f.protoctx = (void *)&ssn;
|
|
f.flags |= FLOW_IPV4;
|
|
|
|
p->flow = &f;
|
|
p->flowflags |= FLOW_PKT_TOSERVER;
|
|
p->flowflags |= FLOW_PKT_ESTABLISHED;
|
|
p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
|
|
f.alproto = ALPROTO_HTTP;
|
|
|
|
StreamTcpInitConfig(TRUE);
|
|
|
|
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
|
|
if (de_ctx == NULL) {
|
|
goto end;
|
|
}
|
|
|
|
de_ctx->flags |= DE_QUIET;
|
|
|
|
s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:"
|
|
"\"HTTP cookie\"; pcre:\"/dummy/C\"; "
|
|
" sid:1;)");
|
|
if (s == NULL) {
|
|
printf("sig parse failed: ");
|
|
goto end;
|
|
}
|
|
|
|
SigGroupBuild(de_ctx);
|
|
DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
|
|
|
|
int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1);
|
|
if (r != 0) {
|
|
printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
|
|
goto end;
|
|
}
|
|
|
|
http_state = f.alstate;
|
|
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 failed to match: ");
|
|
goto end;
|
|
}
|
|
|
|
result = 1;
|
|
end:
|
|
if (det_ctx != NULL) {
|
|
DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
|
|
}
|
|
if (de_ctx != NULL) {
|
|
SigGroupCleanup(de_ctx);
|
|
DetectEngineCtxFree(de_ctx);
|
|
}
|
|
|
|
StreamTcpFreeConfig(TRUE);
|
|
UTHFreePackets(&p, 1);
|
|
return result;
|
|
}
|
|
|
|
/** \test Check the signature working to alert when cookie modifier is
|
|
* passed to a negated pcre
|
|
*/
|
|
static int DetectPcreTestSig10(void) {
|
|
int result = 0;
|
|
Flow f;
|
|
uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"
|
|
"Cookie: dummoOOooooO\r\n\r\n";
|
|
uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
|
|
TcpSession ssn;
|
|
Packet *p = NULL;
|
|
Signature *s = NULL;
|
|
ThreadVars th_v;
|
|
DetectEngineThreadCtx *det_ctx = NULL;
|
|
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 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
|
|
|
|
FLOW_INITIALIZE(&f);
|
|
f.protoctx = (void *)&ssn;
|
|
f.flags |= FLOW_IPV4;
|
|
|
|
p->flow = &f;
|
|
p->flowflags |= FLOW_PKT_TOSERVER;
|
|
p->flowflags |= FLOW_PKT_ESTABLISHED;
|
|
p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
|
|
f.alproto = ALPROTO_HTTP;
|
|
|
|
StreamTcpInitConfig(TRUE);
|
|
|
|
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
|
|
if (de_ctx == NULL) {
|
|
goto end;
|
|
}
|
|
|
|
de_ctx->flags |= DE_QUIET;
|
|
|
|
s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:"
|
|
"\"HTTP cookie\"; pcre:!\"/dummy/C\"; "
|
|
" sid:1;)");
|
|
if (s == NULL) {
|
|
printf("sig parse failed: ");
|
|
goto end;
|
|
}
|
|
|
|
SigGroupBuild(de_ctx);
|
|
DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
|
|
|
|
int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1);
|
|
if (r != 0) {
|
|
printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
|
|
goto end;
|
|
}
|
|
|
|
http_state = f.alstate;
|
|
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 should match: ");
|
|
goto end;
|
|
}
|
|
|
|
result = 1;
|
|
end:
|
|
if (det_ctx != NULL) {
|
|
DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
|
|
}
|
|
if (de_ctx != NULL) {
|
|
SigGroupCleanup(de_ctx);
|
|
DetectEngineCtxFree(de_ctx);
|
|
}
|
|
|
|
StreamTcpFreeConfig(TRUE);
|
|
UTHFreePackets(&p, 1);
|
|
return result;
|
|
}
|
|
|
|
/** \test Check the signature working to alert when method modifier is
|
|
* passed to pcre
|
|
*/
|
|
static int DetectPcreTestSig11(void) {
|
|
int result = 0;
|
|
Flow f;
|
|
uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"
|
|
"Cookie: dummy\r\n\r\n";
|
|
uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
|
|
TcpSession ssn;
|
|
Packet *p = NULL;
|
|
Signature *s = NULL;
|
|
ThreadVars th_v;
|
|
DetectEngineThreadCtx *det_ctx = NULL;
|
|
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 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
|
|
|
|
FLOW_INITIALIZE(&f);
|
|
f.protoctx = (void *)&ssn;
|
|
f.flags |= FLOW_IPV4;
|
|
|
|
p->flow = &f;
|
|
p->flowflags |= FLOW_PKT_TOSERVER;
|
|
p->flowflags |= FLOW_PKT_ESTABLISHED;
|
|
p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
|
|
f.alproto = ALPROTO_HTTP;
|
|
|
|
StreamTcpInitConfig(TRUE);
|
|
|
|
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
|
|
if (de_ctx == NULL) {
|
|
goto end;
|
|
}
|
|
|
|
de_ctx->flags |= DE_QUIET;
|
|
|
|
s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:"
|
|
"\"HTTP method\"; pcre:\"/POST/M\"; "
|
|
" sid:1;)");
|
|
if (s == NULL) {
|
|
printf("sig parse failed: ");
|
|
goto end;
|
|
}
|
|
|
|
SigGroupBuild(de_ctx);
|
|
DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
|
|
|
|
int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1);
|
|
if (r != 0) {
|
|
printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
|
|
goto end;
|
|
}
|
|
|
|
http_state = f.alstate;
|
|
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 failed to match: ");
|
|
goto end;
|
|
}
|
|
|
|
result = 1;
|
|
end:
|
|
if (det_ctx != NULL) {
|
|
DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
|
|
}
|
|
if (de_ctx != NULL) {
|
|
SigGroupCleanup(de_ctx);
|
|
DetectEngineCtxFree(de_ctx);
|
|
}
|
|
|
|
StreamTcpFreeConfig(TRUE);
|
|
UTHFreePackets(&p, 1);
|
|
return result;
|
|
}
|
|
|
|
/** \test Check the signature working to alert when method modifier is
|
|
* passed to a negated pcre
|
|
*/
|
|
static int DetectPcreTestSig12(void) {
|
|
int result = 0;
|
|
Flow f;
|
|
uint8_t httpbuf1[] = "GET / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"
|
|
"Cookie: dummoOOooooO\r\n\r\n";
|
|
uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
|
|
TcpSession ssn;
|
|
Packet *p = NULL;
|
|
Signature *s = NULL;
|
|
ThreadVars th_v;
|
|
DetectEngineThreadCtx *det_ctx = NULL;
|
|
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 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
|
|
|
|
FLOW_INITIALIZE(&f);
|
|
f.protoctx = (void *)&ssn;
|
|
f.flags |= FLOW_IPV4;
|
|
|
|
p->flow = &f;
|
|
p->flowflags |= FLOW_PKT_TOSERVER;
|
|
p->flowflags |= FLOW_PKT_ESTABLISHED;
|
|
p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
|
|
f.alproto = ALPROTO_HTTP;
|
|
|
|
StreamTcpInitConfig(TRUE);
|
|
|
|
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
|
|
if (de_ctx == NULL) {
|
|
goto end;
|
|
}
|
|
|
|
de_ctx->flags |= DE_QUIET;
|
|
|
|
s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:"
|
|
"\"HTTP method\"; pcre:!\"/POST/M\"; "
|
|
" sid:1;)");
|
|
if (s == NULL) {
|
|
printf("sig parse failed: ");
|
|
goto end;
|
|
}
|
|
|
|
SigGroupBuild(de_ctx);
|
|
DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
|
|
|
|
int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1);
|
|
if (r != 0) {
|
|
printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
|
|
goto end;
|
|
}
|
|
|
|
http_state = f.alstate;
|
|
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 should match: ");
|
|
goto end;
|
|
}
|
|
|
|
result = 1;
|
|
end:
|
|
if (det_ctx != NULL) {
|
|
DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
|
|
}
|
|
if (de_ctx != NULL) {
|
|
SigGroupCleanup(de_ctx);
|
|
DetectEngineCtxFree(de_ctx);
|
|
}
|
|
|
|
StreamTcpFreeConfig(TRUE);
|
|
UTHFreePackets(&p, 1);
|
|
return result;
|
|
}
|
|
|
|
/** \test Check the signature working to alert when header modifier is
|
|
* passed to pcre
|
|
*/
|
|
static int DetectPcreTestSig13(void) {
|
|
int result = 0;
|
|
Flow f;
|
|
uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"
|
|
"Cookie: dummy\r\n\r\n";
|
|
uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
|
|
TcpSession ssn;
|
|
Packet *p = NULL;
|
|
Signature *s = NULL;
|
|
ThreadVars th_v;
|
|
DetectEngineThreadCtx *det_ctx = NULL;
|
|
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 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
|
|
|
|
FLOW_INITIALIZE(&f);
|
|
f.protoctx = (void *)&ssn;
|
|
f.flags |= FLOW_IPV4;
|
|
|
|
p->flow = &f;
|
|
p->flowflags |= FLOW_PKT_TOSERVER;
|
|
p->flowflags |= FLOW_PKT_ESTABLISHED;
|
|
p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
|
|
f.alproto = ALPROTO_HTTP;
|
|
|
|
StreamTcpInitConfig(TRUE);
|
|
|
|
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
|
|
if (de_ctx == NULL) {
|
|
goto end;
|
|
}
|
|
|
|
de_ctx->flags |= DE_QUIET;
|
|
|
|
s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:"
|
|
"\"HTTP header\"; pcre:\"/User[-_]Agent[:]?\\sMozilla/H\"; "
|
|
" sid:1;)");
|
|
if (s == NULL) {
|
|
printf("sig parse failed: ");
|
|
goto end;
|
|
}
|
|
|
|
SigGroupBuild(de_ctx);
|
|
DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
|
|
|
|
int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1);
|
|
if (r != 0) {
|
|
printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
|
|
goto end;
|
|
}
|
|
|
|
http_state = f.alstate;
|
|
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 failed to match: ");
|
|
goto end;
|
|
}
|
|
|
|
result = 1;
|
|
end:
|
|
if (det_ctx != NULL) {
|
|
DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
|
|
}
|
|
if (de_ctx != NULL) {
|
|
SigGroupCleanup(de_ctx);
|
|
DetectEngineCtxFree(de_ctx);
|
|
}
|
|
|
|
StreamTcpFreeConfig(TRUE);
|
|
UTHFreePackets(&p, 1);
|
|
return result;
|
|
}
|
|
|
|
/** \test Check the signature working to alert when header modifier is
|
|
* passed to a negated pcre
|
|
*/
|
|
static int DetectPcreTestSig14(void) {
|
|
int result = 0;
|
|
Flow f;
|
|
uint8_t httpbuf1[] = "GET / HTTP/1.0\r\nUser-Agent: IEXPLORER/1.0\r\n"
|
|
"Cookie: dummoOOooooO\r\n\r\n";
|
|
uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
|
|
TcpSession ssn;
|
|
Packet *p = NULL;
|
|
Signature *s = NULL;
|
|
ThreadVars th_v;
|
|
DetectEngineThreadCtx *det_ctx = NULL;
|
|
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 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
|
|
|
|
FLOW_INITIALIZE(&f);
|
|
f.protoctx = (void *)&ssn;
|
|
f.flags |= FLOW_IPV4;
|
|
|
|
p->flow = &f;
|
|
p->flowflags |= FLOW_PKT_TOSERVER;
|
|
p->flowflags |= FLOW_PKT_ESTABLISHED;
|
|
p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
|
|
f.alproto = ALPROTO_HTTP;
|
|
|
|
StreamTcpInitConfig(TRUE);
|
|
|
|
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
|
|
if (de_ctx == NULL) {
|
|
goto end;
|
|
}
|
|
|
|
de_ctx->flags |= DE_QUIET;
|
|
|
|
s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:"
|
|
"\"HTTP header\"; pcre:!\"/User-Agent[:]?\\s+Mozilla/H\"; "
|
|
" sid:1;)");
|
|
if (s == NULL) {
|
|
printf("sig parse failed: ");
|
|
goto end;
|
|
}
|
|
|
|
SigGroupBuild(de_ctx);
|
|
DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
|
|
|
|
int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1);
|
|
if (r != 0) {
|
|
printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
|
|
goto end;
|
|
}
|
|
|
|
http_state = f.alstate;
|
|
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 should match: ");
|
|
goto end;
|
|
}
|
|
|
|
result = 1;
|
|
end:
|
|
if (det_ctx != NULL) {
|
|
DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
|
|
}
|
|
if (de_ctx != NULL) {
|
|
SigGroupCleanup(de_ctx);
|
|
DetectEngineCtxFree(de_ctx);
|
|
}
|
|
|
|
StreamTcpFreeConfig(TRUE);
|
|
UTHFreePackets(&p, 1);
|
|
return result;
|
|
}
|
|
|
|
/** \test Check the signature working to alert when cookie and relative modifiers are
|
|
* passed to pcre
|
|
*/
|
|
static int DetectPcreTestSig15(void) {
|
|
int result = 0;
|
|
Flow f;
|
|
uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"
|
|
"Cookie: dummy 1234\r\n\r\n";
|
|
uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
|
|
TcpSession ssn;
|
|
Packet *p = NULL;
|
|
Signature *s = NULL;
|
|
ThreadVars th_v;
|
|
DetectEngineThreadCtx *det_ctx = NULL;
|
|
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 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
|
|
|
|
FLOW_INITIALIZE(&f);
|
|
f.protoctx = (void *)&ssn;
|
|
f.flags |= FLOW_IPV4;
|
|
|
|
p->flow = &f;
|
|
p->flowflags |= FLOW_PKT_TOSERVER;
|
|
p->flowflags |= FLOW_PKT_ESTABLISHED;
|
|
p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
|
|
f.alproto = ALPROTO_HTTP;
|
|
|
|
StreamTcpInitConfig(TRUE);
|
|
|
|
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:"
|
|
"\"pcre relative HTTP cookie\"; content:\"dummy\";"
|
|
" http_cookie; pcre:\"/1234/RC\"; "
|
|
" sid:1;)");
|
|
if (s == NULL) {
|
|
printf("sig parse failed: ");
|
|
goto end;
|
|
}
|
|
|
|
SigGroupBuild(de_ctx);
|
|
DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
|
|
|
|
int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1);
|
|
if (r != 0) {
|
|
printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
|
|
goto end;
|
|
}
|
|
|
|
http_state = f.alstate;
|
|
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 failed to match: ");
|
|
goto end;
|
|
}
|
|
|
|
result = 1;
|
|
end:
|
|
if (det_ctx != NULL) {
|
|
DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
|
|
}
|
|
if (de_ctx != NULL) {
|
|
SigGroupCleanup(de_ctx);
|
|
DetectEngineCtxFree(de_ctx);
|
|
}
|
|
|
|
StreamTcpFreeConfig(TRUE);
|
|
UTHFreePackets(&p, 1);
|
|
return result;
|
|
}
|
|
|
|
/** \test Check the signature working to alert when method and relative modifiers are
|
|
* passed to pcre
|
|
*/
|
|
static int DetectPcreTestSig16(void) {
|
|
int result = 0;
|
|
Flow f;
|
|
uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"
|
|
"Cookie: dummy 1234\r\n\r\n";
|
|
uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
|
|
TcpSession ssn;
|
|
Packet *p = NULL;
|
|
Signature *s = NULL;
|
|
ThreadVars th_v;
|
|
DetectEngineThreadCtx *det_ctx = NULL;
|
|
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 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
|
|
|
|
FLOW_INITIALIZE(&f);
|
|
f.protoctx = (void *)&ssn;
|
|
f.flags |= FLOW_IPV4;
|
|
|
|
p->flow = &f;
|
|
p->flowflags |= FLOW_PKT_TOSERVER;
|
|
p->flowflags |= FLOW_PKT_ESTABLISHED;
|
|
p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
|
|
f.alproto = ALPROTO_HTTP;
|
|
|
|
StreamTcpInitConfig(TRUE);
|
|
|
|
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:"
|
|
"\"pcre relative HTTP method\"; content:\"PO\";"
|
|
" http_method; pcre:\"/ST/RM\"; "
|
|
" sid:1;)");
|
|
if (s == NULL) {
|
|
printf("sig parse failed: ");
|
|
goto end;
|
|
}
|
|
|
|
SigGroupBuild(de_ctx);
|
|
DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
|
|
|
|
int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1);
|
|
if (r != 0) {
|
|
printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
|
|
goto end;
|
|
}
|
|
|
|
http_state = f.alstate;
|
|
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 failed to match: ");
|
|
goto end;
|
|
}
|
|
|
|
result = 1;
|
|
end:
|
|
if (det_ctx != NULL) {
|
|
DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
|
|
}
|
|
if (de_ctx != NULL) {
|
|
SigGroupCleanup(de_ctx);
|
|
DetectEngineCtxFree(de_ctx);
|
|
}
|
|
|
|
StreamTcpFreeConfig(TRUE);
|
|
UTHFreePackets(&p, 1);
|
|
return result;
|
|
}
|
|
|
|
/** \test Test tracking of body chunks per transactions (on requests)
|
|
*/
|
|
static int DetectPcreTxBodyChunksTest01(void) {
|
|
int result = 0;
|
|
Flow f;
|
|
TcpSession ssn;
|
|
Packet *p = NULL;
|
|
uint8_t httpbuf1[] = "GET / HTTP/1.1\r\n";
|
|
uint8_t httpbuf2[] = "User-Agent: Mozilla/1.0\r\nContent-Length: 10\r\n";
|
|
uint8_t httpbuf3[] = "Cookie: dummy\r\n\r\n";
|
|
uint8_t httpbuf4[] = "Body one!!";
|
|
uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
|
|
uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
|
|
uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
|
|
uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
|
|
uint8_t httpbuf5[] = "GET /?var=val HTTP/1.1\r\n";
|
|
uint8_t httpbuf6[] = "User-Agent: Firefox/1.0\r\n";
|
|
uint8_t httpbuf7[] = "Cookie: dummy2\r\nContent-Length: 10\r\n\r\nBody two!!";
|
|
uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
|
|
uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */
|
|
uint32_t httplen7 = sizeof(httpbuf7) - 1; /* minus the \0 */
|
|
|
|
memset(&f, 0, sizeof(f));
|
|
memset(&ssn, 0, sizeof(ssn));
|
|
|
|
p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
|
|
|
|
FLOW_INITIALIZE(&f);
|
|
f.protoctx = (void *)&ssn;
|
|
f.proto = IPPROTO_TCP;
|
|
f.flags |= FLOW_IPV4;
|
|
|
|
p->flow = &f;
|
|
p->flowflags |= FLOW_PKT_TOSERVER;
|
|
p->flowflags |= FLOW_PKT_ESTABLISHED;
|
|
p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
|
|
f.alproto = ALPROTO_HTTP;
|
|
|
|
StreamTcpInitConfig(TRUE);
|
|
|
|
AppLayerHtpEnableRequestBodyCallback();
|
|
|
|
int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1);
|
|
if (r != 0) {
|
|
printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
|
|
goto end;
|
|
}
|
|
|
|
r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2);
|
|
if (r != 0) {
|
|
printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
|
|
goto end;
|
|
}
|
|
|
|
r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3);
|
|
if (r != 0) {
|
|
printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
|
|
goto end;
|
|
}
|
|
|
|
r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4);
|
|
if (r != 0) {
|
|
printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
|
|
result = 0;
|
|
goto end;
|
|
}
|
|
|
|
r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5);
|
|
if (r != 0) {
|
|
printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r);
|
|
goto end;
|
|
}
|
|
|
|
r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6);
|
|
if (r != 0) {
|
|
printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r);
|
|
goto end;
|
|
}
|
|
|
|
r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf7, httplen7);
|
|
if (r != 0) {
|
|
printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r);
|
|
goto end;
|
|
}
|
|
|
|
/* Now we should have 2 transactions, each with it's own list
|
|
* of request body chunks (let's test it) */
|
|
|
|
HtpState *htp_state = f.alstate;
|
|
if (htp_state == NULL) {
|
|
printf("no http state: ");
|
|
result = 0;
|
|
goto end;
|
|
}
|
|
|
|
/* hardcoded check of the transactions and it's client body chunks */
|
|
if (list_size(htp_state->connp->conn->transactions) != 2) {
|
|
printf("The http app layer doesn't have 2 transactions, but it should: ");
|
|
goto end;
|
|
}
|
|
|
|
htp_tx_t *t1 = list_get(htp_state->connp->conn->transactions, 0);
|
|
htp_tx_t *t2 = list_get(htp_state->connp->conn->transactions, 1);
|
|
|
|
HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(t1);
|
|
if (htud == NULL) {
|
|
printf("No body data in t1 (it should be removed only when the tx is destroyed): ");
|
|
goto end;
|
|
}
|
|
|
|
HtpBodyChunk *cur = htud->request_body.first;
|
|
if (htud->request_body.nchunks == 0) {
|
|
SCLogDebug("No body data in t1 (it should be removed only when the tx is destroyed): ");
|
|
goto end;
|
|
}
|
|
|
|
if (memcmp(cur->data, "Body one!!", strlen("Body one!!")) != 0) {
|
|
SCLogDebug("Body data in t1 is not correctly set: ");
|
|
goto end;
|
|
}
|
|
|
|
htud = (HtpTxUserData *) htp_tx_get_user_data(t2);
|
|
|
|
cur = htud->request_body.first;
|
|
if (htud->request_body.nchunks == 0) {
|
|
SCLogDebug("No body data in t1 (it should be removed only when the tx is destroyed): ");
|
|
goto end;
|
|
}
|
|
|
|
if (memcmp(cur->data, "Body two!!", strlen("Body two!!")) != 0) {
|
|
SCLogDebug("Body data in t1 is not correctly set: ");
|
|
goto end;
|
|
}
|
|
|
|
|
|
result = 1;
|
|
end:
|
|
|
|
StreamTcpFreeConfig(TRUE);
|
|
FLOW_DESTROY(&f);
|
|
UTHFreePacket(p);
|
|
return result;
|
|
}
|
|
|
|
/** \test test pcre P modifier with multiple pipelined http transactions */
|
|
static int DetectPcreTxBodyChunksTest02(void) {
|
|
int result = 0;
|
|
Signature *s = NULL;
|
|
DetectEngineThreadCtx *det_ctx = NULL;
|
|
ThreadVars th_v;
|
|
Flow f;
|
|
TcpSession ssn;
|
|
Packet *p = NULL;
|
|
uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n";
|
|
uint8_t httpbuf2[] = "User-Agent: Mozilla/1.0\r\nContent-Length: 10\r\n";
|
|
uint8_t httpbuf3[] = "Cookie: dummy\r\n\r\n";
|
|
uint8_t httpbuf4[] = "Body one!!";
|
|
uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
|
|
uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
|
|
uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
|
|
uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
|
|
uint8_t httpbuf5[] = "GET /?var=val HTTP/1.1\r\n";
|
|
uint8_t httpbuf6[] = "User-Agent: Firefox/1.0\r\n";
|
|
uint8_t httpbuf7[] = "Cookie: dummy2\r\nContent-Length: 10\r\n\r\nBody two!!";
|
|
uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
|
|
uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */
|
|
uint32_t httplen7 = sizeof(httpbuf7) - 1; /* minus the \0 */
|
|
|
|
memset(&th_v, 0, sizeof(th_v));
|
|
memset(&f, 0, sizeof(f));
|
|
memset(&ssn, 0, sizeof(ssn));
|
|
|
|
p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
|
|
|
|
FLOW_INITIALIZE(&f);
|
|
f.protoctx = (void *)&ssn;
|
|
f.proto = IPPROTO_TCP;
|
|
f.flags |= FLOW_IPV4;
|
|
|
|
p->flow = &f;
|
|
p->flowflags |= FLOW_PKT_TOSERVER;
|
|
p->flowflags |= FLOW_PKT_ESTABLISHED;
|
|
p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
|
|
f.alproto = ALPROTO_HTTP;
|
|
|
|
StreamTcpInitConfig(TRUE);
|
|
|
|
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
|
|
if (de_ctx == NULL) {
|
|
goto end;
|
|
}
|
|
|
|
de_ctx->flags |= DE_QUIET;
|
|
|
|
s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"Mozilla\"; http_header; content:\"dummy\"; http_cookie; pcre:\"/one/P\"; sid:1; rev:1;)");
|
|
if (s == NULL) {
|
|
printf("sig parse failed: ");
|
|
goto end;
|
|
}
|
|
s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"Firefox\"; http_header; content:\"dummy2\"; http_cookie; pcre:\"/two/P\"; sid:2; rev:1;)");
|
|
if (s == NULL) {
|
|
printf("sig2 parse failed: ");
|
|
goto end;
|
|
}
|
|
|
|
SigGroupBuild(de_ctx);
|
|
DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
|
|
|
|
int r = AppLayerParse(NULL, &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);
|
|
if (PacketAlertCheck(p, 1)) {
|
|
printf("sig 1 alerted: ");
|
|
goto end;
|
|
}
|
|
p->alerts.cnt = 0;
|
|
|
|
r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2);
|
|
if (r != 0) {
|
|
printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
|
|
goto end;
|
|
}
|
|
|
|
/* do detect */
|
|
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
|
|
if (PacketAlertCheck(p, 1)) {
|
|
printf("sig 1 alerted (2): ");
|
|
goto end;
|
|
}
|
|
p->alerts.cnt = 0;
|
|
|
|
r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3);
|
|
if (r != 0) {
|
|
printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
|
|
goto end;
|
|
}
|
|
|
|
/* do detect */
|
|
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
|
|
if (PacketAlertCheck(p, 1)) {
|
|
printf("signature matched, but shouldn't have: ");
|
|
goto end;
|
|
}
|
|
p->alerts.cnt = 0;
|
|
|
|
r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4);
|
|
if (r != 0) {
|
|
printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
|
|
result = 0;
|
|
goto end;
|
|
}
|
|
|
|
/* do detect */
|
|
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
|
|
if (!(PacketAlertCheck(p, 1))) {
|
|
printf("sig 1 didn't alert: ");
|
|
goto end;
|
|
}
|
|
p->alerts.cnt = 0;
|
|
|
|
r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5);
|
|
if (r != 0) {
|
|
printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r);
|
|
goto end;
|
|
}
|
|
|
|
/* do detect */
|
|
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
|
|
if (PacketAlertCheck(p, 1)) {
|
|
printf("sig 1 alerted (5): ");
|
|
goto end;
|
|
}
|
|
p->alerts.cnt = 0;
|
|
|
|
r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6);
|
|
if (r != 0) {
|
|
printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r);
|
|
goto end;
|
|
}
|
|
|
|
/* do detect */
|
|
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
|
|
if ((PacketAlertCheck(p, 1)) || (PacketAlertCheck(p, 2))) {
|
|
printf("sig 1 alerted (request 2, chunk 6): ");
|
|
goto end;
|
|
}
|
|
p->alerts.cnt = 0;
|
|
|
|
SCLogDebug("sending data chunk 7");
|
|
|
|
r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf7, httplen7);
|
|
if (r != 0) {
|
|
printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r);
|
|
goto end;
|
|
}
|
|
|
|
/* do detect */
|
|
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
|
|
if (!(PacketAlertCheck(p, 2))) {
|
|
printf("signature 2 didn't match, but should have: ");
|
|
goto end;
|
|
}
|
|
p->alerts.cnt = 0;
|
|
|
|
HtpState *htp_state = f.alstate;
|
|
if (htp_state == NULL) {
|
|
printf("no http state: ");
|
|
result = 0;
|
|
goto end;
|
|
}
|
|
|
|
/* hardcoded check of the transactions and it's client body chunks */
|
|
if (list_size(htp_state->connp->conn->transactions) != 2) {
|
|
printf("The http app layer doesn't have 2 transactions, but it should: ");
|
|
goto end;
|
|
}
|
|
|
|
htp_tx_t *t1 = list_get(htp_state->connp->conn->transactions, 0);
|
|
htp_tx_t *t2 = list_get(htp_state->connp->conn->transactions, 1);
|
|
|
|
HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(t1);
|
|
|
|
HtpBodyChunk *cur = htud->request_body.first;
|
|
if (htud->request_body.nchunks == 0) {
|
|
SCLogDebug("No body data in t1 (it should be removed only when the tx is destroyed): ");
|
|
goto end;
|
|
}
|
|
|
|
if (memcmp(cur->data, "Body one!!", strlen("Body one!!")) != 0) {
|
|
SCLogDebug("Body data in t1 is not correctly set: ");
|
|
goto end;
|
|
}
|
|
|
|
htud = (HtpTxUserData *) htp_tx_get_user_data(t2);
|
|
|
|
cur = htud->request_body.first;
|
|
if (htud->request_body.nchunks == 0) {
|
|
SCLogDebug("No body data in t1 (it should be removed only when the tx is destroyed): ");
|
|
goto end;
|
|
}
|
|
|
|
if (memcmp(cur->data, "Body two!!", strlen("Body two!!")) != 0) {
|
|
SCLogDebug("Body data in t1 is not correctly set: ");
|
|
goto end;
|
|
}
|
|
|
|
result = 1;
|
|
end:
|
|
if (det_ctx != NULL) {
|
|
DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
|
|
}
|
|
if (de_ctx != NULL) {
|
|
SigGroupCleanup(de_ctx);
|
|
DetectEngineCtxFree(de_ctx);
|
|
}
|
|
|
|
StreamTcpFreeConfig(TRUE);
|
|
FLOW_DESTROY(&f);
|
|
UTHFreePacket(p);
|
|
return result;
|
|
}
|
|
|
|
/** \test multiple http transactions and body chunks of request handling */
|
|
static int DetectPcreTxBodyChunksTest03(void) {
|
|
int result = 0;
|
|
Signature *s = NULL;
|
|
DetectEngineThreadCtx *det_ctx = NULL;
|
|
ThreadVars th_v;
|
|
Flow f;
|
|
TcpSession ssn;
|
|
Packet *p = NULL;
|
|
uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n";
|
|
uint8_t httpbuf2[] = "User-Agent: Mozilla/1.0\r\nContent-Length: 10\r\n";
|
|
uint8_t httpbuf3[] = "Cookie: dummy\r\n\r\n";
|
|
uint8_t httpbuf4[] = "Body one!!";
|
|
uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
|
|
uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
|
|
uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
|
|
uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
|
|
uint8_t httpbuf5[] = "GET /?var=val HTTP/1.1\r\n";
|
|
uint8_t httpbuf6[] = "User-Agent: Firefox/1.0\r\n";
|
|
uint8_t httpbuf7[] = "Cookie: dummy2\r\nContent-Length: 10\r\n\r\nBody two!!";
|
|
uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
|
|
uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */
|
|
uint32_t httplen7 = sizeof(httpbuf7) - 1; /* minus the \0 */
|
|
|
|
memset(&th_v, 0, sizeof(th_v));
|
|
memset(&f, 0, sizeof(f));
|
|
memset(&ssn, 0, sizeof(ssn));
|
|
|
|
p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
|
|
|
|
FLOW_INITIALIZE(&f);
|
|
f.protoctx = (void *)&ssn;
|
|
f.proto = IPPROTO_TCP;
|
|
f.flags |= FLOW_IPV4;
|
|
|
|
p->flow = &f;
|
|
p->flowflags |= FLOW_PKT_TOSERVER;
|
|
p->flowflags |= FLOW_PKT_ESTABLISHED;
|
|
p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
|
|
f.alproto = ALPROTO_HTTP;
|
|
|
|
StreamTcpInitConfig(TRUE);
|
|
|
|
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
|
|
if (de_ctx == NULL) {
|
|
goto end;
|
|
}
|
|
|
|
de_ctx->flags |= DE_QUIET;
|
|
|
|
s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"Mozilla\"; http_header; content:\"dummy\"; http_cookie; pcre:\"/one/P\"; sid:1; rev:1;)");
|
|
if (s == NULL) {
|
|
printf("sig parse failed: ");
|
|
goto end;
|
|
}
|
|
s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"Firefox\"; http_header; content:\"dummy2\"; http_cookie; pcre:\"/two/P\"; sid:2; rev:1;)");
|
|
if (s == NULL) {
|
|
printf("sig2 parse failed: ");
|
|
goto end;
|
|
}
|
|
|
|
SigGroupBuild(de_ctx);
|
|
DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
|
|
|
|
int r = AppLayerParse(NULL, &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);
|
|
if (PacketAlertCheck(p, 1)) {
|
|
printf("sig 1 alerted: ");
|
|
goto end;
|
|
}
|
|
p->alerts.cnt = 0;
|
|
|
|
r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2);
|
|
if (r != 0) {
|
|
printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
|
|
goto end;
|
|
}
|
|
|
|
/* do detect */
|
|
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
|
|
if (PacketAlertCheck(p, 1)) {
|
|
printf("sig 1 alerted (2): ");
|
|
goto end;
|
|
}
|
|
p->alerts.cnt = 0;
|
|
|
|
r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3);
|
|
if (r != 0) {
|
|
printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
|
|
goto end;
|
|
}
|
|
|
|
/* do detect */
|
|
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
|
|
if (PacketAlertCheck(p, 1)) {
|
|
printf("signature matched, but shouldn't have: ");
|
|
goto end;
|
|
}
|
|
p->alerts.cnt = 0;
|
|
|
|
r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4);
|
|
if (r != 0) {
|
|
printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
|
|
result = 0;
|
|
goto end;
|
|
}
|
|
|
|
/* do detect */
|
|
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
|
|
if (!(PacketAlertCheck(p, 1))) {
|
|
printf("sig 1 didn't alert: ");
|
|
goto end;
|
|
}
|
|
p->alerts.cnt = 0;
|
|
|
|
r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5);
|
|
if (r != 0) {
|
|
printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r);
|
|
goto end;
|
|
}
|
|
|
|
/* do detect */
|
|
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
|
|
if (PacketAlertCheck(p, 1)) {
|
|
printf("sig 1 alerted (5): ");
|
|
goto end;
|
|
}
|
|
p->alerts.cnt = 0;
|
|
|
|
r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6);
|
|
if (r != 0) {
|
|
printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r);
|
|
goto end;
|
|
}
|
|
|
|
/* do detect */
|
|
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
|
|
if ((PacketAlertCheck(p, 1)) || (PacketAlertCheck(p, 2))) {
|
|
printf("sig 1 alerted (request 2, chunk 6): ");
|
|
goto end;
|
|
}
|
|
p->alerts.cnt = 0;
|
|
|
|
SCLogDebug("sending data chunk 7");
|
|
|
|
r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf7, httplen7);
|
|
if (r != 0) {
|
|
printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r);
|
|
goto end;
|
|
}
|
|
|
|
/* do detect */
|
|
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
|
|
if (!(PacketAlertCheck(p, 2))) {
|
|
printf("signature 2 didn't match, but should have: ");
|
|
goto end;
|
|
}
|
|
p->alerts.cnt = 0;
|
|
|
|
HtpState *htp_state = f.alstate;
|
|
if (htp_state == NULL) {
|
|
printf("no http state: ");
|
|
result = 0;
|
|
goto end;
|
|
}
|
|
|
|
if (list_size(htp_state->connp->conn->transactions) != 2) {
|
|
printf("The http app layer doesn't have 2 transactions, but it should: ");
|
|
goto end;
|
|
}
|
|
|
|
result = 1;
|
|
end:
|
|
if (det_ctx != NULL) {
|
|
DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
|
|
}
|
|
if (de_ctx != NULL) {
|
|
SigGroupCleanup(de_ctx);
|
|
DetectEngineCtxFree(de_ctx);
|
|
}
|
|
|
|
StreamTcpFreeConfig(TRUE);
|
|
FLOW_DESTROY(&f);
|
|
UTHFreePacket(p);
|
|
return result;
|
|
}
|
|
|
|
#endif /* UNITTESTS */
|
|
|
|
/**
|
|
* \brief this function registers unit tests for DetectPcre
|
|
*/
|
|
void DetectPcreRegisterTests(void) {
|
|
#ifdef UNITTESTS /* UNITTESTS */
|
|
UtRegisterTest("DetectPcreParseTest01", DetectPcreParseTest01, 1);
|
|
UtRegisterTest("DetectPcreParseTest02", DetectPcreParseTest02, 1);
|
|
UtRegisterTest("DetectPcreParseTest03", DetectPcreParseTest03, 1);
|
|
UtRegisterTest("DetectPcreParseTest04", DetectPcreParseTest04, 1);
|
|
UtRegisterTest("DetectPcreParseTest05", DetectPcreParseTest05, 1);
|
|
UtRegisterTest("DetectPcreParseTest06", DetectPcreParseTest06, 1);
|
|
UtRegisterTest("DetectPcreParseTest07", DetectPcreParseTest07, 1);
|
|
UtRegisterTest("DetectPcreParseTest08", DetectPcreParseTest08, 1);
|
|
UtRegisterTest("DetectPcreParseTest09", DetectPcreParseTest09, 1);
|
|
UtRegisterTest("DetectPcreParseTest10", DetectPcreParseTest10, 1);
|
|
UtRegisterTest("DetectPcreParseTest11", DetectPcreParseTest11, 1);
|
|
UtRegisterTest("DetectPcreParseTest12", DetectPcreParseTest12, 1);
|
|
UtRegisterTest("DetectPcreParseTest13", DetectPcreParseTest13, 1);
|
|
UtRegisterTest("DetectPcreParseTest14", DetectPcreParseTest14, 1);
|
|
UtRegisterTest("DetectPcreParseTest15", DetectPcreParseTest15, 1);
|
|
UtRegisterTest("DetectPcreParseTest16", DetectPcreParseTest16, 1);
|
|
UtRegisterTest("DetectPcreParseTest17", DetectPcreParseTest17, 1);
|
|
UtRegisterTest("DetectPcreParseTest18", DetectPcreParseTest18, 1);
|
|
UtRegisterTest("DetectPcreParseTest19", DetectPcreParseTest19, 1);
|
|
UtRegisterTest("DetectPcreParseTest20", DetectPcreParseTest20, 1);
|
|
UtRegisterTest("DetectPcreParseTest21", DetectPcreParseTest21, 1);
|
|
UtRegisterTest("DetectPcreParseTest22", DetectPcreParseTest22, 1);
|
|
UtRegisterTest("DetectPcreParseTest23", DetectPcreParseTest23, 1);
|
|
UtRegisterTest("DetectPcreParseTest24", DetectPcreParseTest24, 1);
|
|
UtRegisterTest("DetectPcreParseTest25", DetectPcreParseTest25, 1);
|
|
|
|
UtRegisterTest("DetectPcreTestSig01B2g -- pcre test", DetectPcreTestSig01B2g, 1);
|
|
UtRegisterTest("DetectPcreTestSig01B3g -- pcre test", DetectPcreTestSig01B3g, 1);
|
|
UtRegisterTest("DetectPcreTestSig01Wm -- pcre test", DetectPcreTestSig01Wm, 1);
|
|
UtRegisterTest("DetectPcreTestSig02B2g -- pcre test", DetectPcreTestSig02B2g, 1);
|
|
UtRegisterTest("DetectPcreTestSig02B3g -- pcre test", DetectPcreTestSig02B3g, 1);
|
|
UtRegisterTest("DetectPcreTestSig02Wm -- pcre test", DetectPcreTestSig02Wm, 1);
|
|
UtRegisterTest("DetectPcreTestSig03B2g -- negated pcre test", DetectPcreTestSig03B2g, 1);
|
|
UtRegisterTest("DetectPcreTestSig03B3g -- negated pcre test", DetectPcreTestSig03B3g, 1);
|
|
UtRegisterTest("DetectPcreTestSig03Wm -- negated pcre test", DetectPcreTestSig03Wm, 1);
|
|
|
|
UtRegisterTest("DetectPcreModifPTest04 -- Modifier P", DetectPcreModifPTest04, 1);
|
|
UtRegisterTest("DetectPcreModifPTest05 -- Modifier P fragmented", DetectPcreModifPTest05, 1);
|
|
UtRegisterTest("DetectPcreTestSig06", DetectPcreTestSig06, 1);
|
|
UtRegisterTest("DetectPcreTestSig07 -- anchored pcre", DetectPcreTestSig07, 1);
|
|
UtRegisterTest("DetectPcreTestSig08 -- anchored pcre", DetectPcreTestSig08, 1);
|
|
UtRegisterTest("DetectPcreTestSig09 -- Cookie modifier", DetectPcreTestSig09, 1);
|
|
UtRegisterTest("DetectPcreTestSig10 -- negated Cookie modifier", DetectPcreTestSig10, 1);
|
|
UtRegisterTest("DetectPcreTestSig11 -- Method modifier", DetectPcreTestSig11, 1);
|
|
UtRegisterTest("DetectPcreTestSig12 -- negated Method modifier", DetectPcreTestSig12, 1);
|
|
UtRegisterTest("DetectPcreTestSig13 -- Header modifier", DetectPcreTestSig13, 1);
|
|
UtRegisterTest("DetectPcreTestSig14 -- negated Header modifier", DetectPcreTestSig14, 1);
|
|
UtRegisterTest("DetectPcreTestSig15 -- relative Cookie modifier", DetectPcreTestSig15, 1);
|
|
UtRegisterTest("DetectPcreTestSig16 -- relative Method modifier", DetectPcreTestSig16, 1);
|
|
|
|
UtRegisterTest("DetectPcreTxBodyChunksTest01", DetectPcreTxBodyChunksTest01, 1);
|
|
UtRegisterTest("DetectPcreTxBodyChunksTest02 -- modifier P, body chunks per tx", DetectPcreTxBodyChunksTest02, 1);
|
|
UtRegisterTest("DetectPcreTxBodyChunksTest03 -- modifier P, body chunks per tx", DetectPcreTxBodyChunksTest03, 1);
|
|
#endif /* UNITTESTS */
|
|
}
|
|
|