From: Joshua Lumb Date: Tue, 9 Jun 2020 16:12:26 +0000 (-0400) Subject: detect-dsize: Add ! operator for dsize matching X-Git-Tag: suricata-7.0.0-beta1~1451 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cf9b2b5fd1ea85290848630a4b1856fdb01d3de2;p=thirdparty%2Fsuricata.git detect-dsize: Add ! operator for dsize matching --- diff --git a/doc/userguide/rules/payload-keywords.rst b/doc/userguide/rules/payload-keywords.rst index 833c77c6d7..e36ed2b184 100644 --- a/doc/userguide/rules/payload-keywords.rst +++ b/doc/userguide/rules/payload-keywords.rst @@ -290,18 +290,20 @@ dsize With the dsize keyword, you can match on the size of the packet payload. You can use the keyword for example to look for abnormal -sizes of payloads. This may be convenient in detecting buffer -overflows. +sizes of payloads which are equal to some n i.e. 'dsize:n' +not equal 'dsize:!n' less than 'dsize:n' +This may be convenient in detecting buffer overflows. Format:: - dsize:; + dsize:[<>!]number; || dsize:min<>max; Example of dsize in a rule: .. container:: example-rule alert udp $EXTERNAL_NET any -> $HOME_NET 65535 (msg:"GPL DELETED EXPLOIT LANDesk Management Suite Alerting Service buffer overflow"; :example-rule-emphasis:`dsize:>268;` reference: bugtraq,23483; reference: cve,2007-1674; classtype: attempted-admin; sid:100000928; rev:1;) + alert tcp $EXTERNAL_NET any -> $HOME_NET 8081 (msg:"Example Negation"; :example-rule-emphasis:`dsize:!10;` sid:123; rev:1;) byte_test --------- diff --git a/src/detect-dsize.c b/src/detect-dsize.c index 5879493df6..542672c264 100644 --- a/src/detect-dsize.c +++ b/src/detect-dsize.c @@ -44,9 +44,9 @@ #include "util-profiling.h" /** - * dsize:[<>]<0-65535>[<><0-65535>]; + * dsize:[<>!]<0-65535>[<><0-65535>]; */ -#define PARSE_REGEX "^\\s*(<|>)?\\s*([0-9]{1,5})\\s*(?:(<>)\\s*([0-9]{1,5}))?\\s*$" +#define PARSE_REGEX "^\\s*(<|>|!)?\\s*([0-9]{1,5})\\s*(?:(<>)\\s*([0-9]{1,5}))?\\s*$" static DetectParseRegex parse_regex; static int DetectDsizeMatch (DetectEngineThreadCtx *, Packet *, @@ -92,6 +92,8 @@ DsizeMatch(const uint16_t psize, const uint8_t mode, return 1; else if (mode == DETECTDSIZE_RA && psize > dsize && psize < dsize2) return 1; + else if (mode == DETECTDSIZE_NE && dsize != psize) + return 1; return 0; } @@ -190,16 +192,7 @@ static DetectDsizeData *DetectDsizeParse (const char *rawstr) goto error; dd->dsize = 0; dd->dsize2 = 0; - dd->mode = DETECTDSIZE_EQ; // default - - if (strlen(mode) > 0) { - if (mode[0] == '<') - dd->mode = DETECTDSIZE_LT; - else if (mode[0] == '>') - dd->mode = DETECTDSIZE_GT; - else - dd->mode = DETECTDSIZE_EQ; - } + dd->mode = 0; if (strcmp("<>", range) == 0) { if (strlen(mode) != 0) { @@ -207,6 +200,17 @@ static DetectDsizeData *DetectDsizeParse (const char *rawstr) goto error; } dd->mode = DETECTDSIZE_RA; + } else if (strlen(mode) > 0) { + if (mode[0] == '<') + dd->mode = DETECTDSIZE_LT; + else if (mode[0] == '>') + dd->mode = DETECTDSIZE_GT; + else if (mode[0] == '!') + dd->mode = DETECTDSIZE_NE; + else + dd->mode = DETECTDSIZE_EQ; + } else { + dd->mode = DETECTDSIZE_EQ; // default } /** set the first dsize value */ @@ -387,6 +391,7 @@ int SigParseGetMaxDsize(const Signature *s) switch (dd->mode) { case DETECTDSIZE_LT: case DETECTDSIZE_EQ: + case DETECTDSIZE_NE: return dd->dsize; case DETECTDSIZE_RA: return dd->dsize2; @@ -415,6 +420,7 @@ void SigParseSetDsizePair(Signature *s) high = dd->dsize; break; case DETECTDSIZE_EQ: + case DETECTDSIZE_NE: low = dd->dsize; high = dd->dsize; break; @@ -427,10 +433,11 @@ void SigParseSetDsizePair(Signature *s) high = 65535; break; } + s->dsize_mode = dd->mode; s->dsize_low = low; s->dsize_high = high; - SCLogDebug("low %u, high %u", low, high); + SCLogDebug("low %u, high %u, mode %u", low, high, dd->mode); } } @@ -866,6 +873,89 @@ static int DsizeTestParse20 (void) return result; } +/** + * \test this is a test for a valid dsize value !1 + * + * \retval 1 on success + * \retval 0 on failure + */ +static int DsizeTestParse21(void) +{ + DetectDsizeData *dd = NULL; + dd = DetectDsizeParse("!1"); + FAIL_IF_NULL(dd); + DetectDsizeFree(NULL, dd); + PASS; +} + +/** + * \test this is a test for a valid dsize value ! 1 + * + * \retval 1 on success + * \retval 0 on failure + */ +static int DsizeTestParse22(void) +{ + DetectDsizeData *dd = NULL; + dd = DetectDsizeParse("! 1"); + FAIL_IF_NULL(dd); + DetectDsizeFree(NULL, dd); + PASS; +} + +/** + * \test this is a test for a invalid dsize value 1! + * + * \retval 1 on success + * \retval 0 on failure + */ +static int DsizeTestParse23(void) +{ + DetectDsizeData *dd = NULL; + dd = DetectDsizeParse("1!"); + if (dd) { + DetectDsizeFree(NULL, dd); + FAIL; + } + PASS; +} + +/** + * \test this is a test for positive ! dsize matching + * + * \retval 1 on success + * \retval 0 on failure + */ +static int DsizeTestMatch01(void) +{ + uint16_t psize = 1; + uint16_t dsizelow = 2; + uint16_t dsizehigh = 0; + int result = 0; + + result = DsizeMatch(psize, DETECTDSIZE_NE, dsizelow, dsizehigh); + + PASS_IF(result); +} + +/** + * \test this is a test for negative ! dsize matching + * + * \retval 1 on success + * \retval 0 on failure + */ +static int DsizeTestMatch02(void) +{ + uint16_t psize = 1; + uint16_t dsizelow = 1; + uint16_t dsizehigh = 0; + int result = 0; + + result = !DsizeMatch(psize, DETECTDSIZE_NE, dsizelow, dsizehigh); + + PASS_IF(result); +} + /** * \test DetectDsizeIcmpv6Test01 is a test for checking the working of * dsize keyword by creating 2 rules and matching a crafted packet @@ -984,6 +1074,11 @@ static void DsizeRegisterTests(void) UtRegisterTest("DsizeTestParse18", DsizeTestParse18); UtRegisterTest("DsizeTestParse19", DsizeTestParse19); UtRegisterTest("DsizeTestParse20", DsizeTestParse20); + UtRegisterTest("DsizeTestParse21", DsizeTestParse21); + UtRegisterTest("DsizeTestParse22", DsizeTestParse22); + UtRegisterTest("DsizeTestParse23", DsizeTestParse23); + UtRegisterTest("DsizeTestMatch01", DsizeTestMatch01); + UtRegisterTest("DsizeTestMatch02", DsizeTestMatch02); UtRegisterTest("DetectDsizeIcmpv6Test01", DetectDsizeIcmpv6Test01); } diff --git a/src/detect-dsize.h b/src/detect-dsize.h index ab8541afa9..d1bd3e85ed 100644 --- a/src/detect-dsize.h +++ b/src/detect-dsize.h @@ -28,6 +28,7 @@ #define DETECTDSIZE_EQ 1 #define DETECTDSIZE_GT 2 #define DETECTDSIZE_RA 3 +#define DETECTDSIZE_NE 4 typedef struct DetectDsizeData_ { uint16_t dsize; @@ -42,5 +43,21 @@ int SigParseGetMaxDsize(const Signature *s); void SigParseSetDsizePair(Signature *s); void SigParseApplyDsizeToContent(Signature *s); +/** Determine if a packet p should be kicked out during prefilter due + * to dsize outside the range specified in signature s */ +static inline bool SigDsizePrefilter(const Packet *p, const Signature *s, uint32_t sflags) +{ + if (unlikely(sflags & SIG_FLAG_DSIZE)) { + if (likely(p->payload_len < s->dsize_low || p->payload_len > s->dsize_high)) { + if (!(s->dsize_mode == DETECTDSIZE_NE)) { + SCLogDebug("kicked out as p->payload_len %u, dsize low %u, hi %u", p->payload_len, + s->dsize_low, s->dsize_high); + return true; + } + } + } + return false; +} + #endif /* __DETECT_DSIZE_H__ */ diff --git a/src/detect-engine-build.c b/src/detect-engine-build.c index 9b9c0da7c1..6a2790f73e 100644 --- a/src/detect-engine-build.c +++ b/src/detect-engine-build.c @@ -534,26 +534,23 @@ static int SignatureCreateMask(Signature *s) case DETECT_DSIZE: { DetectDsizeData *ds = (DetectDsizeData *)sm->ctx; - switch (ds->mode) { - case DETECTDSIZE_LT: - /* LT will include 0, so no payload. - * if GT is used in the same rule the - * flag will be set anyway. */ - break; - case DETECTDSIZE_RA: - case DETECTDSIZE_GT: + /* LT will include 0, so no payload. + * if GT is used in the same rule the + * flag will be set anyway. */ + if (ds->mode == DETECTDSIZE_RA || ds->mode == DETECTDSIZE_GT || + ds->mode == DETECTDSIZE_NE) { + + s->mask |= SIG_MASK_REQUIRE_PAYLOAD; + SCLogDebug("sig requires payload"); + + } else if (ds->mode == DETECTDSIZE_EQ) { + if (ds->dsize > 0) { s->mask |= SIG_MASK_REQUIRE_PAYLOAD; SCLogDebug("sig requires payload"); - break; - case DETECTDSIZE_EQ: - if (ds->dsize > 0) { - s->mask |= SIG_MASK_REQUIRE_PAYLOAD; - SCLogDebug("sig requires payload"); - } else if (ds->dsize == 0) { - s->mask |= SIG_MASK_REQUIRE_NO_PAYLOAD; - SCLogDebug("sig requires no payload"); - } - break; + } else { + s->mask |= SIG_MASK_REQUIRE_NO_PAYLOAD; + SCLogDebug("sig requires no payload"); + } } break; } diff --git a/src/detect.c b/src/detect.c index 884dae8e65..beefebcc61 100644 --- a/src/detect.c +++ b/src/detect.c @@ -34,6 +34,7 @@ #include "app-layer-parser.h" #include "detect.h" +#include "detect-dsize.h" #include "detect-engine.h" #include "detect-engine-profile.h" @@ -769,13 +770,8 @@ static inline void DetectRulePacketRules( goto next; } - if (unlikely(sflags & SIG_FLAG_DSIZE)) { - if (likely(p->payload_len < s->dsize_low || p->payload_len > s->dsize_high)) { - SCLogDebug("kicked out as p->payload_len %u, dsize low %u, hi %u", - p->payload_len, s->dsize_low, s->dsize_high); - goto next; - } - } + if (SigDsizePrefilter(p, s, sflags)) + goto next; /* if the sig has alproto and the session as well they should match */ if (likely(sflags & SIG_FLAG_APPLAYER)) { diff --git a/src/detect.h b/src/detect.h index ce29e83e47..3cd601878d 100644 --- a/src/detect.h +++ b/src/detect.h @@ -522,6 +522,7 @@ typedef struct Signature_ { uint16_t dsize_low; uint16_t dsize_high; + uint8_t dsize_mode; SignatureMask mask; SigIntId num; /**< signature number, internal id */