From: Pierre Chifflier Date: Tue, 11 Dec 2018 16:21:44 +0000 (+0100) Subject: SNMP: add the "snmp.pdu_type" detection keyword X-Git-Tag: suricata-5.0.0-rc1~423 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9dfec7e73411d2884b36da5c156726445e54bc86;p=thirdparty%2Fsuricata.git SNMP: add the "snmp.pdu_type" detection keyword --- diff --git a/doc/userguide/rules/snmp-keywords.rst b/doc/userguide/rules/snmp-keywords.rst index a0b1d70d8b..ccf78ccbd1 100644 --- a/doc/userguide/rules/snmp-keywords.rst +++ b/doc/userguide/rules/snmp-keywords.rst @@ -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: + +Signature example:: + + alert snmp any any -> any any (msg:"SNMP response"; snmp.pdu_type:2; sid:3; rev:1;) + diff --git a/rust/src/snmp/detect.rs b/rust/src/snmp/detect.rs index c83a63b8d9..ceefecb153 100644 --- a/rust/src/snmp/detect.rs +++ b/rust/src/snmp/detect.rs @@ -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; + } + } + } +} diff --git a/src/Makefile.am b/src/Makefile.am index c471b2c313..64510343a0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 \ diff --git a/src/detect-engine-register.c b/src/detect-engine-register.c index ef472c93ab..09f104b779 100644 --- a/src/detect-engine-register.c +++ b/src/detect-engine-register.c @@ -175,6 +175,7 @@ #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(); diff --git a/src/detect-engine-register.h b/src/detect-engine-register.h index 83e2a30dc9..504ba07d9d 100644 --- a/src/detect-engine-register.h +++ b/src/detect-engine-register.h @@ -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 index 0000000000..e8a0254727 --- /dev/null +++ b/src/detect-snmp-pdu_type.c @@ -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 + */ + +#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]:; + */ +#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 index 0000000000..8aee17fb0d --- /dev/null +++ b/src/detect-snmp-pdu_type.h @@ -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 + */ + +#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__ */