]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
detect-dsize: Add ! operator for dsize matching
authorJoshua Lumb <joshua.lumb@gmail.com>
Tue, 9 Jun 2020 16:12:26 +0000 (12:12 -0400)
committerVictor Julien <victor@inliniac.net>
Wed, 1 Sep 2021 06:33:52 +0000 (08:33 +0200)
doc/userguide/rules/payload-keywords.rst
src/detect-dsize.c
src/detect-dsize.h
src/detect-engine-build.c
src/detect.c
src/detect.h

index 833c77c6d7741f9c7cf616ea6dab1b549712ae26..e36ed2b18401c88b96b6f16725a53e5a3b8a5ec8 100644 (file)
@@ -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' or greater than 'dsize:>n'
+This may be convenient in detecting buffer overflows.
 
 Format::
 
-  dsize:<number>;
+  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
 ---------
index 5879493df67b495734d585488a2ef135641fc249..542672c264d27b18d4f83ad82499305af9627165 100644 (file)
@@ -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);
 }
index ab8541afa9ed7c6206ea35c64558a552fe574257..d1bd3e85ed7263ca6b244a64ac8ad0f1533ecd21 100644 (file)
@@ -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__ */
 
index 9b9c0da7c199f68ef41cb42ab90c192c1eb2a378..6a2790f73e1fd961b245d9cbcf954cfbea53d370 100644 (file)
@@ -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;
             }
index 884dae8e657ff0114fd52a452f85f6b5e87a9e0c..beefebcc61969ff80137561c0144dd8c631e3172 100644 (file)
@@ -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)) {
index ce29e83e47e65518ebaadca858b276ed90e5e928..3cd601878dfa8d7cef4d797e1ac453bee1e3a481 100644 (file)
@@ -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 */