detect/content: introduce startswith modifier

Add startswith modifier to simplify matching patterns at the start
of a buffer.

Instead of:
    content:"abc"; depth:3;
This enables:
    content:"abc"; startswith;

Especially with longer patterns this makes the intention of the rule
more clear and eases writing the rules.

Internally it's simply a shorthand for 'depth:<pattern len>;'.

Ticket https://redmine.openinfosecfoundation.org/issues/742
pull/3182/head
Victor Julien 8 years ago
parent 5e65d79be0
commit 07738af868

@ -126,6 +126,24 @@ Example:
.. image:: payload-keywords/content4.png .. image:: payload-keywords/content4.png
startswith
----------
The ``startswith`` keyword is similar to ``depth``. It takes no arguments
and must follow a ``content`` keyword. It modifies the ``content`` to match
exactly at the start of a buffer.
Example::
content:"GET|20|"; startswith;
``startswith`` is a short hand notation for::
content:"GET|20|"; depth:4; offset:0;
``startswith`` cannot be mixed with ``depth``, ``offset``, ``within`` or
``distance`` for the same pattern.
offset offset
------ ------

@ -56,6 +56,7 @@
#define DETECT_CONTENT_WITHIN_NEXT BIT_U32(17) #define DETECT_CONTENT_WITHIN_NEXT BIT_U32(17)
#define DETECT_CONTENT_DISTANCE_NEXT BIT_U32(18) #define DETECT_CONTENT_DISTANCE_NEXT BIT_U32(18)
#define DETECT_CONTENT_STARTS_WITH BIT_U32(19)
/** a relative match to this content is next, used in matching phase */ /** a relative match to this content is next, used in matching phase */
#define DETECT_CONTENT_RELATIVE_NEXT (DETECT_CONTENT_WITHIN_NEXT|DETECT_CONTENT_DISTANCE_NEXT) #define DETECT_CONTENT_RELATIVE_NEXT (DETECT_CONTENT_WITHIN_NEXT|DETECT_CONTENT_DISTANCE_NEXT)

@ -42,6 +42,7 @@
#include "util-debug.h" #include "util-debug.h"
static int DetectDepthSetup (DetectEngineCtx *, Signature *, const char *); static int DetectDepthSetup (DetectEngineCtx *, Signature *, const char *);
static int DetectStartsWithSetup (DetectEngineCtx *, Signature *, const char *);
void DetectDepthRegister (void) void DetectDepthRegister (void)
{ {
@ -52,6 +53,12 @@ void DetectDepthRegister (void)
sigmatch_table[DETECT_DEPTH].Setup = DetectDepthSetup; sigmatch_table[DETECT_DEPTH].Setup = DetectDepthSetup;
sigmatch_table[DETECT_DEPTH].Free = NULL; sigmatch_table[DETECT_DEPTH].Free = NULL;
sigmatch_table[DETECT_DEPTH].RegisterTests = NULL; sigmatch_table[DETECT_DEPTH].RegisterTests = NULL;
sigmatch_table[DETECT_STARTS_WITH].name = "startswith";
sigmatch_table[DETECT_STARTS_WITH].desc = "pattern must be at the start of a buffer (same as 'depth:<pattern len>';)";
sigmatch_table[DETECT_STARTS_WITH].url = DOC_URL DOC_VERSION "/rules/payload-keywords.html#startswith";
sigmatch_table[DETECT_STARTS_WITH].Setup = DetectStartsWithSetup;
sigmatch_table[DETECT_STARTS_WITH].flags |= SIGMATCH_NOOPT;
} }
static int DetectDepthSetup (DetectEngineCtx *de_ctx, Signature *s, const char *depthstr) static int DetectDepthSetup (DetectEngineCtx *de_ctx, Signature *s, const char *depthstr)
@ -128,3 +135,56 @@ static int DetectDepthSetup (DetectEngineCtx *de_ctx, Signature *s, const char *
end: end:
return ret; return ret;
} }
static int DetectStartsWithSetup (DetectEngineCtx *de_ctx, Signature *s, const char *unused)
{
SigMatch *pm = NULL;
int ret = -1;
/* retrieve the sm to apply the depth against */
pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, -1);
if (pm == NULL) {
SCLogError(SC_ERR_DEPTH_MISSING_CONTENT, "startswith needs a "
"preceding content option");
goto end;
}
/* verify other conditions. */
DetectContentData *cd = (DetectContentData *)pm->ctx;
if (cd->flags & DETECT_CONTENT_DEPTH) {
SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use multiple "
"depth/startswith settings for the same content");
goto end;
}
if ((cd->flags & DETECT_CONTENT_WITHIN) || (cd->flags & DETECT_CONTENT_DISTANCE)) {
SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use a relative "
"keyword like within/distance with a absolute "
"relative keyword like depth/offset for the same "
"content.");
goto end;
}
if (cd->flags & DETECT_CONTENT_NEGATED && cd->flags & DETECT_CONTENT_FAST_PATTERN) {
SCLogError(SC_ERR_INVALID_SIGNATURE, "can't have a relative "
"negated keyword set along with a fast_pattern");
goto end;
}
if (cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) {
SCLogError(SC_ERR_INVALID_SIGNATURE, "can't have a relative "
"keyword set along with a fast_pattern:only;");
goto end;
}
if (cd->flags & DETECT_CONTENT_OFFSET) {
SCLogError(SC_ERR_INVALID_SIGNATURE, "can't mix offset "
"with startswith");
goto end;
}
cd->depth = cd->content_len;
cd->flags |= DETECT_CONTENT_DEPTH;
cd->flags |= DETECT_CONTENT_STARTS_WITH;
ret = 0;
end:
return ret;
}

@ -60,6 +60,7 @@ enum {
DETECT_URICONTENT, DETECT_URICONTENT,
DETECT_PCRE, DETECT_PCRE,
DETECT_DEPTH, DETECT_DEPTH,
DETECT_STARTS_WITH,
DETECT_DISTANCE, DETECT_DISTANCE,
DETECT_WITHIN, DETECT_WITHIN,
DETECT_OFFSET, DETECT_OFFSET,

@ -69,6 +69,10 @@ int DetectOffsetSetup (DetectEngineCtx *de_ctx, Signature *s, const char *offset
/* verify other conditions */ /* verify other conditions */
DetectContentData *cd = (DetectContentData *)pm->ctx; DetectContentData *cd = (DetectContentData *)pm->ctx;
if (cd->flags & DETECT_CONTENT_STARTS_WITH) {
SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use offset with startswith");
goto end;
}
if (cd->flags & DETECT_CONTENT_OFFSET) { if (cd->flags & DETECT_CONTENT_OFFSET) {
SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use multiple offsets for the same content. "); SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use multiple offsets for the same content. ");
goto end; goto end;

@ -225,6 +225,16 @@ static int DetectEngineContentInspectionTest10(void) {
TEST_FOOTER; TEST_FOOTER;
} }
static int DetectEngineContentInspectionTest11(void) {
TEST_HEADER;
TEST_RUN("ab", 2, "content:\"a\"; startswith; content:\"b\";", true, 2);
TEST_RUN("ab", 2, "content:\"a\"; startswith; content:\"b\"; within:1; distance:0;", true, 2);
TEST_RUN("ab", 2, "content:\"ab\"; startswith;", true, 1);
TEST_RUN("ab", 2, "content:\"a\"; startswith;", true, 1);
TEST_RUN("ab", 2, "content:\"b\"; startswith;", false, 1);
TEST_FOOTER;
}
void DetectEngineContentInspectionRegisterTests(void) void DetectEngineContentInspectionRegisterTests(void)
{ {
UtRegisterTest("DetectEngineContentInspectionTest01", UtRegisterTest("DetectEngineContentInspectionTest01",
@ -247,6 +257,8 @@ void DetectEngineContentInspectionRegisterTests(void)
DetectEngineContentInspectionTest09); DetectEngineContentInspectionTest09);
UtRegisterTest("DetectEngineContentInspectionTest10", UtRegisterTest("DetectEngineContentInspectionTest10",
DetectEngineContentInspectionTest10); DetectEngineContentInspectionTest10);
UtRegisterTest("DetectEngineContentInspectionTest11 startswith",
DetectEngineContentInspectionTest11);
} }
#undef TEST_HEADER #undef TEST_HEADER

Loading…
Cancel
Save