From 1a2d3a4f66148b319a1cc2f6b13dd04b84ca54af Mon Sep 17 00:00:00 2001 From: Julian Wecke Date: Mon, 31 Jul 2023 14:41:40 +0200 Subject: [PATCH] matching: multi match support This adds support to specify multiple conditions to match a rule. Syntax: multi:;;...; Examples: Match all rules including the term "nmap" but just from the "emerging-scan.rules" file. multi:filename:rule/emerging-scan.rules; re:nmap; Match all rules with a recent cve reference and a perimeter deployment multi:re:cve-202[23];metadata: deployment perimeter; Ticket: #2509 --- doc/update.rst | 9 ++++++++ suricata/update/configs/disable.conf | 6 ++++- suricata/update/configs/drop.conf | 4 ++++ suricata/update/configs/enable.conf | 6 ++++- suricata/update/matchers.py | 33 ++++++++++++++++++++++++++++ 5 files changed, 56 insertions(+), 2 deletions(-) diff --git a/doc/update.rst b/doc/update.rst index c3db62e3..d3f6e3ae 100644 --- a/doc/update.rst +++ b/doc/update.rst @@ -259,6 +259,15 @@ with the provided metadata:: convert rules to drop. It is not available for rule modification. +Multi Matching +-------------- + +The above matching methods can also be combined. It's logical AND, so all combined matcher need to match a given rule:: + + multi:filename:*/emerging-scan.rule;re:nmap; + multi:group:emerging-web_specific_apps;re:wordpress;re:cve[-,]201[6-9]; + multi:re:cve[-_]202[23];metadata: deployment perimeter; + Modifying Rules --------------- diff --git a/suricata/update/configs/disable.conf b/suricata/update/configs/disable.conf index 59d0e18a..b2631814 100644 --- a/suricata/update/configs/disable.conf +++ b/suricata/update/configs/disable.conf @@ -16,4 +16,8 @@ # Disable all rules with a metadata of "deployment perimeter". Note that metadata # matches are case insensitive. -# metadata: deployment perimeter \ No newline at end of file +# metadata: deployment perimeter + +# Example of multi matching +# Disable all rules with significant performance impact (metadata match) from emerging-policy (group match) +multi:metadata: performance_impact Significant;group:emerging-policy; \ No newline at end of file diff --git a/suricata/update/configs/drop.conf b/suricata/update/configs/drop.conf index a93268da..72dad53b 100644 --- a/suricata/update/configs/drop.conf +++ b/suricata/update/configs/drop.conf @@ -9,3 +9,7 @@ # # re:heartbleed # re:MS(0[7-9]|10)-\d+ + +# Example of multi matching +# Set phishing related (metadata match) rules from emerging-current_events (group match) to drop +multi:metadata: tag Phishing;group:emerging-current_events; diff --git a/suricata/update/configs/enable.conf b/suricata/update/configs/enable.conf index ad7b4e2a..22e0e38e 100644 --- a/suricata/update/configs/enable.conf +++ b/suricata/update/configs/enable.conf @@ -16,4 +16,8 @@ # Enable all rules with a metadata of "deployment perimeter". Note that metadata # matches are case insensitive. -# metadata: deployment perimeter \ No newline at end of file +# metadata: deployment perimeter + +# Example of multi matching +# Enable all rules with a recent cve reference (regular expression match) and a perimeter deployment (metadata match) +multi:re:cve[-_]202[23];metadata: deployment perimeter; \ No newline at end of file diff --git a/suricata/update/matchers.py b/suricata/update/matchers.py index e886c797..beef6d50 100644 --- a/suricata/update/matchers.py +++ b/suricata/update/matchers.py @@ -211,6 +211,35 @@ def parse(cls, buf): return cls(key, val) return None +class MultiRuleMatcher(object): + """Matcher that build a container around other matchers. All childmatchers have to match for a true match. + Config syntax is "multi:;;".""" + + def __init__(self, childmatchers): + self.childmatchers = childmatchers + + def match(self, rule): + for matcher in self.childmatchers: + if not matcher.match(rule): + return False + return True + + @classmethod + def parse(cls, buf): + if buf.startswith("multi:"): + try: + logger.debug("Parsing multi matcher: %s", buf) + childmatcherstrs = filter(None, buf.split(":", 1)[1].strip().split(";")) + childmatchers = [] + for childstr in childmatcherstrs: + matcher = parse_rule_match(childstr.strip()) + if matcher: + childmatchers.append(matcher) + return cls(childmatchers) + except Exception as e: + raise e + return None + class ModifyRuleFilter(object): """Filter to modify an idstools rule object. @@ -328,4 +357,8 @@ def parse_rule_match(match): if matcher: return matcher + matcher = MultiRuleMatcher.parse(match) + if matcher: + return matcher + return None