]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
SNMP: add the "snmp.community" detection keyword
authorPierre Chifflier <chifflier@wzdftpd.net>
Tue, 11 Dec 2018 07:54:17 +0000 (08:54 +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-community.c [new file with mode: 0644]
src/detect-snmp-community.h [new file with mode: 0644]

index 4b246580305a7070747a4d3689dd05f8b4d82b5e..a0b1d70d8ba4403dc1fe732667d7f920cd558a7e 100644 (file)
@@ -20,3 +20,27 @@ Signature example::
 
  alert snmp any any -> any any (msg:"old SNMP version (<3)"; snmp.version:<3; sid:1; rev:1;)
 
+snmp.community
+--------------
+
+SNMP community strings are like passwords for SNMP messages in version 1 and 2c.
+In version 3, the community string is likely to be encrypted. This keyword will not
+match if the value is not accessible.
+
+The default value for the read-only community string is often "public", and
+"private" for the read-write community string.
+
+Comparison is case-sensitive.
+
+Syntax::
+
+ snmp.community; content:"private";
+
+Signature example::
+
+ alert snmp any any -> any any (msg:"SNMP community private"; snmp.community; content:"private"; sid:2; rev:1;)
+
+``snmp.community`` is a 'sticky buffer'.
+
+``snmp.community`` can be used as ``fast_pattern``.
+
index da36d584fad89d4b007641700a3ae32398bb8e94..c83a63b8d9fc93051f921f403e990309b89066ab 100644 (file)
@@ -30,3 +30,18 @@ pub extern "C" fn rs_snmp_tx_get_version(tx: &mut SNMPTransaction,
     }
 }
 
+#[no_mangle]
+pub extern "C" fn rs_snmp_tx_get_community(tx: &mut SNMPTransaction,
+                                           buf: *mut *const libc::uint8_t,
+                                           len: *mut libc::uint32_t)
+{
+    match tx.community {
+        Some(ref c) => {
+            unsafe {
+                *buf = (&c).as_ptr();
+                *len = c.len() as libc::uint32_t;
+            }
+        },
+        None        => ()
+    }
+}
index fc0322f7ac980b245300c648686beba74a461311..c471b2c313adc7490ffaff9d369093a1d42f62f8 100644 (file)
@@ -233,6 +233,7 @@ detect-rpc.c detect-rpc.h \
 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-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 d64f94275c54f10e92aa214814f0e0f48a5ebafe..ef472c93ab7bb0c19ad0c5786e7ad7f0f84b62aa 100644 (file)
 #include "detect-target.h"
 #include "detect-template-rust-buffer.h"
 #include "detect-snmp-version.h"
+#include "detect-snmp-community.h"
 #include "detect-template-buffer.h"
 #include "detect-bypass.h"
 #include "detect-ftpdata.h"
@@ -528,6 +529,7 @@ void SigTableSetup(void)
     DetectTargetRegister();
     DetectTemplateRustBufferRegister();
     DetectSNMPVersionRegister();
+    DetectSNMPCommunityRegister();
     DetectTemplateBufferRegister();
     DetectBypassRegister();
 
index 44a698045b63615452026e24f6d296901155332e..83e2a30dc9625d51561f5f699392d1b5112d1176 100644 (file)
@@ -229,6 +229,7 @@ enum {
     DETECT_TARGET,
     DETECT_AL_TEMPLATE_RUST_BUFFER,
     DETECT_AL_SNMP_VERSION,
+    DETECT_AL_SNMP_COMMUNITY,
     DETECT_AL_TEMPLATE_BUFFER,
 
     DETECT_BYPASS,
diff --git a/src/detect-snmp-community.c b/src/detect-snmp-community.c
new file mode 100644 (file)
index 0000000..aba8c59
--- /dev/null
@@ -0,0 +1,226 @@
+/* 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>
+ *
+ * Set up of the "snmp_community" keyword to allow content
+ * inspections on the decoded snmp community.
+ */
+
+#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-community.h"
+#include "app-layer-parser.h"
+
+#ifndef HAVE_RUST
+
+void DetectSNMPCommunityRegister(void)
+{
+}
+
+#else
+
+#include "rust-snmp-snmp-gen.h"
+#include "rust-snmp-detect-gen.h"
+
+static int DetectSNMPCommunitySetup(DetectEngineCtx *, Signature *,
+    const char *);
+static int DetectEngineInspectSNMPCommunity(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 void DetectSNMPCommunityRegisterTests(void);
+static int g_snmp_rust_id = 0;
+
+void DetectSNMPCommunityRegister(void)
+{
+    sigmatch_table[DETECT_AL_SNMP_COMMUNITY].name = "snmp_community";
+    sigmatch_table[DETECT_AL_SNMP_COMMUNITY].desc =
+        "SNMP content modififier to match on the snmp community";
+    sigmatch_table[DETECT_AL_SNMP_COMMUNITY].Setup =
+        DetectSNMPCommunitySetup;
+    sigmatch_table[DETECT_AL_SNMP_COMMUNITY].RegisterTests =
+        DetectSNMPCommunityRegisterTests;
+    sigmatch_table[DETECT_AL_SNMP_COMMUNITY].url = DOC_URL DOC_VERSION "/rules/snmp-keywords.html#snmp_community";
+
+    sigmatch_table[DETECT_AL_SNMP_COMMUNITY].flags |= SIGMATCH_NOOPT;
+
+    /* register inspect engines */
+    DetectAppLayerInspectEngineRegister("snmp_community",
+            ALPROTO_SNMP, SIG_FLAG_TOSERVER, 0,
+            DetectEngineInspectSNMPCommunity);
+    DetectAppLayerInspectEngineRegister("snmp_community",
+            ALPROTO_SNMP, SIG_FLAG_TOCLIENT, 0,
+            DetectEngineInspectSNMPCommunity);
+
+    g_snmp_rust_id = DetectBufferTypeGetByName("snmp_community");
+
+    SCLogDebug("SNMP community detect registered.");
+}
+
+static int DetectSNMPCommunitySetup(DetectEngineCtx *de_ctx, Signature *s,
+    const char *str)
+{
+    s->init_data->list = g_snmp_rust_id;
+
+    if (DetectSignatureSetAppProto(s, ALPROTO_SNMP) != 0)
+        return -1;
+
+    return 0;
+}
+
+static int DetectEngineInspectSNMPCommunity(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)
+{
+    int ret = 0;
+    const uint8_t *data = NULL;
+    uint32_t data_len = 0;
+
+    if (flags & STREAM_TOSERVER) {
+        rs_snmp_tx_get_community(txv, (uint8_t **)&data, &data_len);
+    } else if (flags & STREAM_TOCLIENT) {
+        rs_snmp_tx_get_community(txv, (uint8_t **)&data, &data_len);
+    }
+
+    if (data != NULL) {
+        ret = DetectEngineContentInspection(de_ctx, det_ctx, s, smd,
+            f, (uint8_t *)data, data_len, 0, DETECT_CI_FLAGS_SINGLE,
+            DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL);
+    }
+
+    return ret;
+}
+
+#ifdef UNITTESTS
+
+#include "util-unittest.h"
+#include "util-unittest-helper.h"
+#include "app-layer-parser.h"
+#include "detect-engine.h"
+#include "detect-parse.h"
+#include "flow-util.h"
+#include "stream-tcp.h"
+
+static int DetectSNMPCommunityTest(void)
+{
+    AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+    DetectEngineThreadCtx *det_ctx = NULL;
+    DetectEngineCtx *de_ctx = NULL;
+    Flow f;
+    Packet *p;
+    TcpSession tcp;
+    ThreadVars tv;
+    Signature *s;
+
+    /*uint8_t request[] = "\x30\x27\x02\x01\x01\x04\x0b\x5b\x52\x30\x5f\x43\x40\x63\x74\x69" \
+                        "\x21\x5d\xa1\x15\x02\x04\x2b\x13\x3f\x85\x02\x01\x00\x02\x01\x00" \
+                        "\x30\x07\x30\x05\x06\x01\x01\x05\x00";*/
+    uint8_t request[] = {
+        0x30, 0x27, 0x02, 0x01, 0x01, 0x04, 0x0b, 0x5b,
+        0x52, 0x30, 0x5f, 0x43, 0x40, 0x63, 0x74, 0x69,
+        0x21, 0x5d, 0xa1, 0x15, 0x02, 0x04, 0x2b, 0x13,
+        0x3f, 0x85, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00,
+        0x30, 0x07, 0x30, 0x05, 0x06, 0x01, 0x01, 0x05,
+        0x00
+    };
+
+    /* Setup flow. */
+    memset(&f, 0, sizeof(Flow));
+    memset(&tcp, 0, sizeof(TcpSession));
+    memset(&tv, 0, sizeof(ThreadVars));
+    p = UTHBuildPacket(request, sizeof(request), IPPROTO_UDP);
+    FLOW_INITIALIZE(&f);
+    f.alproto = ALPROTO_SNMP;
+    f.protoctx = (void *)&tcp;
+    f.proto = IPPROTO_UDP;
+    f.protomap = FlowGetProtoMapping(f.proto);
+    f.flags |= FLOW_IPV4;
+    p->flow = &f;
+    p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST;
+    p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED;
+    StreamTcpInitConfig(TRUE);
+
+    de_ctx = DetectEngineCtxInit();
+    FAIL_IF_NULL(de_ctx);
+
+    /* This rule should match. */
+    s = DetectEngineAppendSig(de_ctx,
+        "alert snmp any any -> any any ("
+        "msg:\"SNMP Test Rule\"; "
+        "snmp_community; content:\"[R0_C@cti!]\"; "
+        "sid:1; rev:1;)");
+    FAIL_IF_NULL(s);
+
+    /* This rule should not match. */
+    s = DetectEngineAppendSig(de_ctx,
+        "alert snmp any any -> any any ("
+        "msg:\"SNMP Test Rule\"; "
+        "snmp_community; content:\"private\"; "
+        "sid:2; rev:1;)");
+    FAIL_IF_NULL(s);
+
+    SigGroupBuild(de_ctx);
+    DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
+
+    FLOWLOCK_WRLOCK(&f);
+    AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SNMP,
+                        STREAM_TOSERVER, request, sizeof(request));
+    FLOWLOCK_UNLOCK(&f);
+
+    /* Check that we have app-layer state. */
+    FAIL_IF_NULL(f.alstate);
+
+    SigMatchSignatures(&tv, de_ctx, det_ctx, p);
+    FAIL_IF(!PacketAlertCheck(p, 1));
+    FAIL_IF(PacketAlertCheck(p, 2));
+
+    /* Cleanup. */
+    if (alp_tctx != NULL)
+        AppLayerParserThreadCtxFree(alp_tctx);
+    if (det_ctx != NULL)
+        DetectEngineThreadCtxDeinit(&tv, det_ctx);
+    if (de_ctx != NULL)
+        SigGroupCleanup(de_ctx);
+    if (de_ctx != NULL)
+        DetectEngineCtxFree(de_ctx);
+    StreamTcpFreeConfig(TRUE);
+    FLOW_DESTROY(&f);
+    UTHFreePacket(p);
+
+    PASS;
+}
+
+#endif
+
+static void DetectSNMPCommunityRegisterTests(void)
+{
+#ifdef UNITTESTS
+    UtRegisterTest("DetectSNMPCommunityTest",
+        DetectSNMPCommunityTest);
+#endif /* UNITTESTS */
+}
+
+#endif
diff --git a/src/detect-snmp-community.h b/src/detect-snmp-community.h
new file mode 100644 (file)
index 0000000..c7b82c8
--- /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 FirstName LastName <yourname@domain>
+ */
+
+#ifndef __DETECT_SNMP_COMMUNITY_H__
+#define __DETECT_SNMP_COMMUNITY_H__
+
+#include "app-layer-snmp.h"
+
+void DetectSNMPCommunityRegister(void);
+
+#endif /* __DETECT_SNMP_COMMUNITY_H__ */