From 97b89c0a5492417efad8374c4bfb9515e4a5887c Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 16 Dec 2016 19:26:58 +0100 Subject: [PATCH] detect-target: introduce new keyword The target keyword allows rules writer to specify information about target of the attack. Using this keyword in a signature causes some fields to be added in the EVE output. It also fixes ambiguity in the Prelude output. --- src/Makefile.am | 1 + src/detect-target.c | 167 ++++++++++++++++++++++++++++++++++++++++++++ src/detect-target.h | 29 ++++++++ src/detect.c | 2 + src/detect.h | 8 +++ 5 files changed, 207 insertions(+) create mode 100644 src/detect-target.c create mode 100644 src/detect-target.h diff --git a/src/Makefile.am b/src/Makefile.am index b1d789f2e5..c2a95c0865 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -234,6 +234,7 @@ detect-ssl-state.c detect-ssl-state.h \ detect-ssl-version.c detect-ssl-version.h \ detect-stream_size.c detect-stream_size.h \ detect-tag.c detect-tag.h \ +detect-target.c detect-target.h \ detect-template.c detect-template.h \ detect-template-buffer.c detect-template-buffer.h \ detect-threshold.c detect-threshold.h \ diff --git a/src/detect-target.c b/src/detect-target.c new file mode 100644 index 0000000000..6a10671b7e --- /dev/null +++ b/src/detect-target.c @@ -0,0 +1,167 @@ +/* Copyright (C) 2017 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 Eric Leblond + * + * target keyword allow rules writer to specify information about target of the attack + */ + +#include "suricata-common.h" +#include "util-unittest.h" + +#include "detect-parse.h" +#include "detect-engine.h" + +#include "detect-target.h" + +/** + * \brief Regex for parsing our keyword options + */ +#define PARSE_REGEX "^\\s*(src_ip|dest_ip)\\s*$" + +static pcre *parse_regex; +static pcre_extra *parse_regex_study; + +/* Prototypes of functions registered in DetectTargetRegister below */ +static int DetectTargetSetup (DetectEngineCtx *, Signature *, const char *); +static void DetectTargetRegisterTests (void); + +/** + * \brief Registration function for target keyword + * + */ +void DetectTargetRegister(void) { + /* keyword name: this is how the keyword is used in a rule */ + sigmatch_table[DETECT_TARGET].name = "target"; + /* description: listed in "suricata --list-keywords=all" */ + sigmatch_table[DETECT_TARGET].desc = "indicate to output module which side is the target of the attack"; + /* link to further documentation of the keyword. Normally on the Suricata redmine/wiki */ + sigmatch_table[DETECT_TARGET].url = DOC_URL DOC_VERSION "/rules/meta.html#target"; + /* match function is called when the signature is inspected on a packet */ + sigmatch_table[DETECT_TARGET].Match = NULL; + /* setup function is called during signature parsing, when the target + * keyword is encountered in the rule */ + sigmatch_table[DETECT_TARGET].Setup = DetectTargetSetup; + /* free function is called when the detect engine is freed. Normally at + * shutdown, but also during rule reloads. */ + sigmatch_table[DETECT_TARGET].Free = NULL; + /* registers unittests into the system */ + sigmatch_table[DETECT_TARGET].RegisterTests = DetectTargetRegisterTests; + + /* set up the PCRE for keyword parsing */ + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); +} + +/** + * \brief This function is used to parse target options passed via target: keyword + * + * \param targetstr Pointer to the user provided target options + * + * \retval targetd pointer to DetectTargetData on success + * \retval NULL on failure + */ +static int DetectTargetParse(Signature *s, const char *targetstr) +{ +#define MAX_SUBSTRINGS 30 + int ret = 0, res = 0; + int ov[MAX_SUBSTRINGS]; + char value[10]; + + ret = pcre_exec(parse_regex, parse_regex_study, + targetstr, strlen(targetstr), 0, 0, ov, MAX_SUBSTRINGS); + if (ret < 1) { + SCLogError(SC_ERR_PCRE_MATCH, "pcre_exec parse error, ret %" PRId32 ", string %s", ret, targetstr); + return -1; + } + + res = pcre_copy_substring(targetstr, ov, MAX_SUBSTRINGS, 1, + value, sizeof(value)); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + return -1; + } + + /* now check key value */ + if (!strcmp(value, "src_ip")) { + if (s->flags & SIG_FLAG_DEST_IS_TARGET) { + SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, + "Conflicting values of target keyword"); + return -1; + } + s->flags |= SIG_FLAG_SRC_IS_TARGET; + } else if (!strcmp(value, "dest_ip")) { + if (s->flags & SIG_FLAG_SRC_IS_TARGET) { + SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, + "Conflicting values of target keyword"); + return -1; + } + s->flags |= SIG_FLAG_DEST_IS_TARGET; + } else { + SCLogError(SC_ERR_INVALID_VALUE, "only 'src_ip' and 'dest_ip' are supported as target value"); + return -1; + } + return 0; +} + +/** + * \brief parse the options from the 'target' keyword in the rule into + * the Signature data structure. + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param targetstr pointer to the user provided target options + * + * \retval 0 on Success + * \retval -1 on Failure + */ +static int DetectTargetSetup(DetectEngineCtx *de_ctx, Signature *s, const char *targetstr) +{ + int ret = DetectTargetParse(s, targetstr); + if (ret < 0) + return -1; + + return 0; +} + +#ifdef UNITTESTS + +static int DetectTargetSignatureTest01(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + Signature *sig = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any (target: dest_ip; sid:1; rev:1;)"); + FAIL_IF_NULL(sig); + + DetectEngineCtxFree(de_ctx); + PASS; +} + +#endif /* UNITTESTS */ + +/** + * \brief this function registers unit tests for DetectTarget + */ +void DetectTargetRegisterTests(void) { +#ifdef UNITTESTS + UtRegisterTest("DetectTargetSignatureTest01", + DetectTargetSignatureTest01); +#endif /* UNITTESTS */ +} diff --git a/src/detect-target.h b/src/detect-target.h new file mode 100644 index 0000000000..8c4e5c215e --- /dev/null +++ b/src/detect-target.h @@ -0,0 +1,29 @@ +/* Copyright (C) 2017 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 Eric Leblond + */ + +#ifndef __DETECT_TARGET_H__ +#define __DETECT_TARGET_H__ + +void DetectTargetRegister(void); + +#endif /* __DETECT_TARGET_H__ */ diff --git a/src/detect.c b/src/detect.c index de83999ce1..775e724003 100644 --- a/src/detect.c +++ b/src/detect.c @@ -173,6 +173,7 @@ #include "detect-geoip.h" #include "detect-app-layer-protocol.h" #include "detect-template.h" +#include "detect-target.h" #include "detect-template-buffer.h" #include "detect-bypass.h" #include "detect-engine-content-inspection.h" @@ -3930,6 +3931,7 @@ void SigTableSetup(void) DetectBase64DecodeRegister(); DetectBase64DataRegister(); DetectTemplateRegister(); + DetectTargetRegister(); DetectTemplateBufferRegister(); DetectBypassRegister(); DetectHttpRequestLineRegister(); diff --git a/src/detect.h b/src/detect.h index ccb99a017e..0abadec098 100644 --- a/src/detect.h +++ b/src/detect.h @@ -240,6 +240,12 @@ typedef struct DetectPort_ { /** Proto detect only signature. * Inspected once per direction when protocol detection is done. */ #define SIG_FLAG_PDONLY (1<<24) +/** Info for Source and Target identification */ +#define SIG_FLAG_SRC_IS_TARGET (1<<25) +/** Info for Source and Target identification */ +#define SIG_FLAG_DEST_IS_TARGET (1<<26) + +#define SIG_FLAG_HAS_TARGET (SIG_FLAG_DEST_IS_TARGET|SIG_FLAG_SRC_IS_TARGET) /* signature init flags */ #define SIG_FLAG_INIT_DEONLY 1 /**< decode event only signature */ @@ -909,6 +915,7 @@ typedef struct DetectEngineThreadCtx_ { uint8_t *base64_decoded; int base64_decoded_len; int base64_decoded_len_max; + #ifdef DEBUG uint64_t pkt_stream_add_cnt; uint64_t payload_mpm_cnt; @@ -1342,6 +1349,7 @@ enum { DETECT_BASE64_DATA, DETECT_TEMPLATE, + DETECT_TARGET, DETECT_AL_TEMPLATE_BUFFER, DETECT_BYPASS,