]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
SNMP: add the "snmp.pdu_type" detection keyword
authorPierre Chifflier <chifflier@wzdftpd.net>
Tue, 11 Dec 2018 16:21:44 +0000 (17:21 +0100)
committerPierre Chifflier <chifflier@wzdftpd.net>
Thu, 6 Jun 2019 08:15:59 +0000 (10:15 +0200)
doc/userguide/rules/snmp-keywords.rst
rust/src/snmp/detect.rs
src/Makefile.am
src/detect-engine-register.c
src/detect-engine-register.h
src/detect-snmp-pdu_type.c [new file with mode: 0644]
src/detect-snmp-pdu_type.h [new file with mode: 0644]

index a0b1d70d8ba4403dc1fe732667d7f920cd558a7e..ccf78ccbd1a38fbaccd32ae798d237d44f278a22 100644 (file)
@@ -44,3 +44,32 @@ Signature example::
 
 ``snmp.community`` can be used as ``fast_pattern``.
 
+snmp.pdu_type
+-------------
+
+SNMP PDU type (integer).
+
+Common values are:
+
+ - 0: GetRequest
+ - 1: GetNextRequest
+ - 2: Response
+ - 3: SetRequest
+ - 4: TrapV1 (obsolete, was the old Trap-PDU in SNMPv1)
+ - 5: GetBulkRequest
+ - 6: InformRequest
+ - 7: TrapV2
+ - 8: Report
+
+This keyword will not match if the value is not accessible within (for ex, an encrypted
+SNMP v3 message).
+
+
+Syntax::
+
+ snmp.pdu_type:<number>
+
+Signature example::
+
+ alert snmp any any -> any any (msg:"SNMP response"; snmp.pdu_type:2; sid:3; rev:1;)
+
index c83a63b8d9fc93051f921f403e990309b89066ab..ceefecb153daf1eb522c3c47d61ebb455dd79155 100644 (file)
@@ -45,3 +45,19 @@ pub extern "C" fn rs_snmp_tx_get_community(tx: &mut SNMPTransaction,
         None        => ()
     }
 }
+
+#[no_mangle]
+pub extern "C" fn rs_snmp_tx_get_pdu_type(tx: &mut SNMPTransaction,
+                                          pdu_type: *mut libc::uint32_t)
+{
+    unsafe {
+        match tx.info {
+            Some(ref info) => {
+                *pdu_type = info.pdu_type.0 as libc::uint32_t;
+            },
+            None           => {
+                *pdu_type = 0xffffffff;
+            }
+        }
+    }
+}
index c471b2c313adc7490ffaff9d369093a1d42f62f8..64510343a0dc65245df07a0bbad0e7de8f45ea50 100644 (file)
@@ -234,6 +234,7 @@ detect-sameip.c detect-sameip.h \
 detect-seq.c detect-seq.h \
 detect-sid.c detect-sid.h \
 detect-snmp-community.c detect-snmp-community.h \
+detect-snmp-pdu_type.c detect-snmp-pdu_type.h \
 detect-snmp-version.c detect-snmp-version.h \
 detect-ssh-proto.c detect-ssh-proto.h \
 detect-ssh-proto-version.c detect-ssh-proto-version.h \
index ef472c93ab7bb0c19ad0c5786e7ad7f0f84b62aa..09f104b779a8051d0773c311931ec610e4a435e8 100644 (file)
 #include "detect-template-rust-buffer.h"
 #include "detect-snmp-version.h"
 #include "detect-snmp-community.h"
+#include "detect-snmp-pdu_type.h"
 #include "detect-template-buffer.h"
 #include "detect-bypass.h"
 #include "detect-ftpdata.h"
@@ -530,6 +531,7 @@ void SigTableSetup(void)
     DetectTemplateRustBufferRegister();
     DetectSNMPVersionRegister();
     DetectSNMPCommunityRegister();
+    DetectSNMPPduTypeRegister();
     DetectTemplateBufferRegister();
     DetectBypassRegister();
 
index 83e2a30dc9625d51561f5f699392d1b5112d1176..504ba07d9d3dc65e963ae18071e304bfddeb1cbc 100644 (file)
@@ -230,6 +230,7 @@ enum {
     DETECT_AL_TEMPLATE_RUST_BUFFER,
     DETECT_AL_SNMP_VERSION,
     DETECT_AL_SNMP_COMMUNITY,
+    DETECT_AL_SNMP_PDU_TYPE,
     DETECT_AL_TEMPLATE_BUFFER,
 
     DETECT_BYPASS,
diff --git a/src/detect-snmp-pdu_type.c b/src/detect-snmp-pdu_type.c
new file mode 100644 (file)
index 0000000..e8a0254
--- /dev/null
@@ -0,0 +1,278 @@
+/* Copyright (C) 2015-2019 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 Pierre Chifflier <chifflier@wzdftpd.net>
+ */
+
+#include "suricata-common.h"
+#include "conf.h"
+#include "detect.h"
+#include "detect-parse.h"
+#include "detect-engine.h"
+#include "detect-engine-content-inspection.h"
+#include "detect-snmp-pdu_type.h"
+#include "app-layer-parser.h"
+
+#ifndef HAVE_RUST
+
+void DetectSNMPPduTypeRegister(void)
+{
+}
+
+#else
+
+#include "rust-snmp-snmp-gen.h"
+#include "rust-snmp-detect-gen.h"
+
+/**
+ *   [snmp_pdu_type]:<type>;
+ */
+#define PARSE_REGEX "^\\s*([0-9]+)\\s*$"
+static pcre *parse_regex;
+static pcre_extra *parse_regex_study;
+
+typedef struct DetectSNMPPduTypeData_ {
+    uint32_t pdu_type;
+} DetectSNMPPduTypeData;
+
+static DetectSNMPPduTypeData *DetectSNMPPduTypeParse (const char *);
+static int DetectSNMPPduTypeSetup (DetectEngineCtx *, Signature *s, const char *str);
+static void DetectSNMPPduTypeFree(void *);
+static void DetectSNMPPduTypeRegisterTests(void);
+static int g_snmp_pdu_type_buffer_id = 0;
+
+static int DetectEngineInspectSNMPRequestGeneric(ThreadVars *tv,
+        DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
+        const Signature *s, const SigMatchData *smd,
+        Flow *f, uint8_t flags, void *alstate,
+        void *txv, uint64_t tx_id);
+
+static int DetectSNMPPduTypeMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *,
+                                   uint8_t, void *, void *, const Signature *,
+                                   const SigMatchCtx *);
+
+void DetectSNMPPduTypeRegister(void)
+{
+    sigmatch_table[DETECT_AL_SNMP_PDU_TYPE].name = "snmp_pdu_type";
+    sigmatch_table[DETECT_AL_SNMP_PDU_TYPE].desc = "match SNMP Pdu type";
+    sigmatch_table[DETECT_AL_SNMP_PDU_TYPE].url = DOC_URL DOC_VERSION "/rules/snmp-keywords.html#snmp_pdu_type";
+    sigmatch_table[DETECT_AL_SNMP_PDU_TYPE].Match = NULL;
+    sigmatch_table[DETECT_AL_SNMP_PDU_TYPE].AppLayerTxMatch = DetectSNMPPduTypeMatch;
+    sigmatch_table[DETECT_AL_SNMP_PDU_TYPE].Setup = DetectSNMPPduTypeSetup;
+    sigmatch_table[DETECT_AL_SNMP_PDU_TYPE].Free = DetectSNMPPduTypeFree;
+    sigmatch_table[DETECT_AL_SNMP_PDU_TYPE].RegisterTests = DetectSNMPPduTypeRegisterTests;
+
+    DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study);
+
+    DetectAppLayerInspectEngineRegister("snmp_pdu_type",
+            ALPROTO_SNMP, SIG_FLAG_TOSERVER, 0,
+            DetectEngineInspectSNMPRequestGeneric);
+
+    DetectAppLayerInspectEngineRegister("snmp_pdu_type",
+            ALPROTO_SNMP, SIG_FLAG_TOCLIENT, 0,
+            DetectEngineInspectSNMPRequestGeneric);
+
+    g_snmp_pdu_type_buffer_id = DetectBufferTypeGetByName("snmp_pdu_type");
+
+    SCLogDebug("g_snmp_pdu_type_buffer_id %d", g_snmp_pdu_type_buffer_id);
+}
+
+static int DetectEngineInspectSNMPRequestGeneric(ThreadVars *tv,
+        DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
+        const Signature *s, const SigMatchData *smd,
+        Flow *f, uint8_t flags, void *alstate,
+        void *txv, uint64_t tx_id)
+{
+    return DetectEngineInspectGenericList(tv, de_ctx, det_ctx, s, smd,
+                                          f, flags, alstate, txv, tx_id);
+}
+
+/**
+ * \internal
+ * \brief Function to match pdu_type of a TX
+ *
+ * \param t       Pointer to thread vars.
+ * \param det_ctx Pointer to the pattern matcher thread.
+ * \param f       Pointer to the current flow.
+ * \param flags   Flags.
+ * \param state   App layer state.
+ * \param s       Pointer to the Signature.
+ * \param m       Pointer to the sigmatch that we will cast into
+ *                DetectSNMPPduTypeData.
+ *
+ * \retval 0 no match.
+ * \retval 1 match.
+ */
+static int DetectSNMPPduTypeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx,
+                                   Flow *f, uint8_t flags, void *state,
+                                   void *txv, const Signature *s,
+                                   const SigMatchCtx *ctx)
+{
+    SCEnter();
+
+    const DetectSNMPPduTypeData *dd = (const DetectSNMPPduTypeData *)ctx;
+    uint32_t pdu_type;
+    rs_snmp_tx_get_pdu_type(txv, &pdu_type);
+    SCLogDebug("pdu_type %u ref_pdu_type %d",
+            pdu_type, dd->pdu_type);
+    if (pdu_type == dd->pdu_type)
+        SCReturnInt(1);
+    SCReturnInt(0);
+}
+
+/**
+ * \internal
+ * \brief Function to parse options passed via snmp_pdu_type keywords.
+ *
+ * \param rawstr Pointer to the user provided options.
+ *
+ * \retval dd pointer to DetectSNMPPduTypeData on success.
+ * \retval NULL on failure.
+ */
+static DetectSNMPPduTypeData *DetectSNMPPduTypeParse (const char *rawstr)
+{
+    DetectSNMPPduTypeData *dd = NULL;
+#define MAX_SUBSTRINGS 30
+    int ret = 0, res = 0;
+    int ov[MAX_SUBSTRINGS];
+    char value1[20] = "";
+    char *endptr = NULL;
+
+    ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr), 0,
+                    0, ov, MAX_SUBSTRINGS);
+    if (ret != 2) {
+        SCLogError(SC_ERR_PCRE_MATCH, "Parse error %s", rawstr);
+        goto error;
+    }
+
+    res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 1, value1,
+                              sizeof(value1));
+    if (res < 0) {
+        SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed");
+        goto error;
+    }
+
+    dd = SCCalloc(1, sizeof(DetectSNMPPduTypeData));
+    if (unlikely(dd == NULL))
+        goto error;
+
+    /* set the value */
+    dd->pdu_type = strtoul(value1, &endptr, 10);
+    if (endptr == NULL || *endptr != '\0') {
+        SCLogError(SC_ERR_INVALID_SIGNATURE, "invalid character as arg "
+                   "to snmp_pdu_type keyword");
+        goto error;
+    }
+
+    return dd;
+
+error:
+    if (dd)
+        SCFree(dd);
+    return NULL;
+}
+
+/**
+ * \brief Function to add the parsed snmp pdu_type field into the current signature.
+ *
+ * \param de_ctx Pointer to the Detection Engine Context.
+ * \param s      Pointer to the Current Signature.
+ * \param rawstr Pointer to the user provided flags options.
+ * \param type   Defines if this is notBefore or notAfter.
+ *
+ * \retval 0 on Success.
+ * \retval -1 on Failure.
+ */
+static int DetectSNMPPduTypeSetup (DetectEngineCtx *de_ctx, Signature *s,
+                                   const char *rawstr)
+{
+    DetectSNMPPduTypeData *dd = NULL;
+    SigMatch *sm = NULL;
+
+    if (DetectSignatureSetAppProto(s, ALPROTO_SNMP) != 0)
+        return -1;
+
+    dd = DetectSNMPPduTypeParse(rawstr);
+    if (dd == NULL) {
+        SCLogError(SC_ERR_INVALID_ARGUMENT,"Parsing \'%s\' failed", rawstr);
+        goto error;
+    }
+
+    /* okay so far so good, lets get this into a SigMatch
+     * and put it in the Signature. */
+    sm = SigMatchAlloc();
+    if (sm == NULL)
+        goto error;
+
+    sm->type = DETECT_AL_SNMP_PDU_TYPE;
+    sm->ctx = (void *)dd;
+
+    SCLogDebug("snmp_pdu_type %d", dd->pdu_type);
+    SigMatchAppendSMToList(s, sm, g_snmp_pdu_type_buffer_id);
+    return 0;
+
+error:
+    DetectSNMPPduTypeFree(dd);
+    return -1;
+}
+
+/**
+ * \internal
+ * \brief Function to free memory associated with DetectSNMPPduTypeData.
+ *
+ * \param de_ptr Pointer to DetectSNMPPduTypeData.
+ */
+static void DetectSNMPPduTypeFree(void *ptr)
+{
+    SCFree(ptr);
+}
+
+
+#ifdef UNITTESTS
+
+#include "util-unittest.h"
+#include "util-unittest-helper.h"
+
+/**
+ * \test This is a test for a valid value 2.
+ *
+ * \retval 1 on success.
+ * \retval 0 on failure.
+ */
+static int SNMPValidityTestParse01 (void)
+{
+    DetectSNMPPduTypeData *dd = NULL;
+    dd = DetectSNMPPduTypeParse("2");
+    FAIL_IF_NULL(dd);
+    FAIL_IF_NOT(dd->pdu_type == 2);
+    DetectSNMPPduTypeFree(dd);
+    PASS;
+}
+
+#endif
+
+static void DetectSNMPPduTypeRegisterTests(void)
+{
+#ifdef UNITTESTS
+    UtRegisterTest("SNMPValidityTestParse01", SNMPValidityTestParse01);
+#endif /* UNITTESTS */
+}
+
+#endif
diff --git a/src/detect-snmp-pdu_type.h b/src/detect-snmp-pdu_type.h
new file mode 100644 (file)
index 0000000..8aee17f
--- /dev/null
@@ -0,0 +1,31 @@
+/* Copyright (C) 2015-2019 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 Pierre Chifflier <chifflier@wzdftpd.net>
+ */
+
+#ifndef __DETECT_SNMP_PDU_TYPE_H__
+#define __DETECT_SNMP_PDU_TYPE_H__
+
+#include "app-layer-snmp.h"
+
+void DetectSNMPPduTypeRegister(void);
+
+#endif /* __DETECT_SNMP_PDU_TYPE_H__ */