From: Victor Julien Date: Tue, 19 Dec 2017 15:14:33 +0000 (+0100) Subject: detect/content: implement endswith X-Git-Tag: suricata-4.1.0-beta1~306 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d5882372357e957fd38c658f012b5d5943c9923e;p=thirdparty%2Fsuricata.git detect/content: implement endswith --- diff --git a/src/detect-engine-register.h b/src/detect-engine-register.h index 4b6310d3cd..bc9673decf 100644 --- a/src/detect-engine-register.h +++ b/src/detect-engine-register.h @@ -61,6 +61,7 @@ enum { DETECT_PCRE, DETECT_DEPTH, DETECT_STARTS_WITH, + DETECT_ENDS_WITH, DETECT_DISTANCE, DETECT_WITHIN, DETECT_OFFSET, diff --git a/src/detect-isdataat.c b/src/detect-isdataat.c index 01631d8dbb..8cca5571a2 100644 --- a/src/detect-isdataat.c +++ b/src/detect-isdataat.c @@ -59,6 +59,8 @@ int DetectIsdataatSetup (DetectEngineCtx *, Signature *, const char *); void DetectIsdataatRegisterTests(void); void DetectIsdataatFree(void *); +static int DetectEndsWithSetup (DetectEngineCtx *de_ctx, Signature *s, const char *nullstr); + /** * \brief Registration function for isdataat: keyword */ @@ -73,6 +75,12 @@ void DetectIsdataatRegister(void) sigmatch_table[DETECT_ISDATAAT].Free = DetectIsdataatFree; sigmatch_table[DETECT_ISDATAAT].RegisterTests = DetectIsdataatRegisterTests; + sigmatch_table[DETECT_ENDS_WITH].name = "endswith"; + sigmatch_table[DETECT_ENDS_WITH].desc = "make sure the previous content matches exactly at the end of the buffer"; + sigmatch_table[DETECT_ENDS_WITH].url = DOC_URL DOC_VERSION "/rules/payload-keywords.html#endswith"; + sigmatch_table[DETECT_ENDS_WITH].Setup = DetectEndsWithSetup; + sigmatch_table[DETECT_ENDS_WITH].flags = SIGMATCH_NOOPT; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } @@ -299,6 +307,28 @@ void DetectIsdataatFree(void *ptr) SCFree(idad); } +static int DetectEndsWithSetup (DetectEngineCtx *de_ctx, Signature *s, const char *nullstr) +{ + 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, "endswith needs a " + "preceding content option"); + goto end; + } + + /* verify other conditions. */ + DetectContentData *cd = (DetectContentData *)pm->ctx; + + cd->flags |= DETECT_CONTENT_ENDS_WITH; + + ret = 0; + end: + return ret; +} #ifdef UNITTESTS static int g_dce_stub_data_buffer_id = 0; diff --git a/src/tests/detect-engine-content-inspection.c b/src/tests/detect-engine-content-inspection.c index 214c5c3fa8..c920657f9d 100644 --- a/src/tests/detect-engine-content-inspection.c +++ b/src/tests/detect-engine-content-inspection.c @@ -235,6 +235,34 @@ static int DetectEngineContentInspectionTest11(void) { TEST_FOOTER; } +/** \test endswith (isdataat) recursion logic + * based on DetectEngineContentInspectionTest06 */ +static int DetectEngineContentInspectionTest12(void) { + TEST_HEADER; + // 6 steps: (1) a, (2) 1st b, (3) c not found, (4) 2nd b, (5) c found, endswith + TEST_RUN("ababc", 5, "content:\"a\"; content:\"b\"; distance:0; within:1; content:\"c\"; distance:0; within:1; endswith;", true, 5); + + TEST_RUN("ababcabc", 8, "content:\"a\"; content:\"b\"; distance:0; within:1; content:\"c\"; distance:0; within:1; endswith;", true, 7); + + TEST_RUN("abcXYZ", 6, "content:\"abc\"; content:\"XYZ\"; distance:0; within:3; endswith;", true, 2); + TEST_RUN("abcXYZ", 6, "content:\"XYZ\"; distance:3; within:3; endswith;", true, 1); + TEST_RUN("abcXYZ", 6, "content:\"cXY\"; distance:2; within:3; endswith;", false, 1); + + TEST_RUN("xxxxxxxxxxxxxxxxxyYYYYYYYYYYYYYYYY", 34, "content:\"yYYYYYYYYYYYYYYYY\"; distance:9; within:29; endswith;", true, 1); + TEST_FOOTER; +} + +static int DetectEngineContentInspectionTest13(void) { + TEST_HEADER; + TEST_RUN("ab", 2, "content:\"a\"; startswith; content:\"b\"; endswith;", true, 2); + TEST_RUN("ab", 2, "content:\"a\"; startswith; content:\"b\"; within:1; distance:0; endswith;", true, 2); + TEST_RUN("ab", 2, "content:\"ab\"; startswith; endswith;", true, 1); + TEST_RUN("ab", 2, "content:\"a\"; startswith; endswith;", false, 1); + TEST_RUN("ab", 2, "content:\"b\"; startswith;", false, 1); + TEST_RUN("ab", 2, "content:\"b\"; startswith; endswith;", false, 1); + TEST_FOOTER; +} + void DetectEngineContentInspectionRegisterTests(void) { UtRegisterTest("DetectEngineContentInspectionTest01", @@ -259,6 +287,10 @@ void DetectEngineContentInspectionRegisterTests(void) DetectEngineContentInspectionTest10); UtRegisterTest("DetectEngineContentInspectionTest11 startswith", DetectEngineContentInspectionTest11); + UtRegisterTest("DetectEngineContentInspectionTest12 endswith", + DetectEngineContentInspectionTest12); + UtRegisterTest("DetectEngineContentInspectionTest13 mix startswith/endswith", + DetectEngineContentInspectionTest13); } #undef TEST_HEADER