From: Jason Ish Date: Sat, 29 Oct 2022 04:55:20 +0000 (-0600) Subject: matching: match on rule metadata X-Git-Tag: 1.3.0rc1~6 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=af17165b695c2a8f360ebc1904450ca260d46425;p=thirdparty%2Fsuricata-update.git matching: match on rule metadata Allow metadata matching for enable and disable. For example: metadata: deployment perimeter will match rules with "metadata: deployment Perimeter". Match is case insensitive. Ticket: #5561 --- diff --git a/CHANGELOG.md b/CHANGELOG.md index 095de59..ec4cbc6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ https://redmine.openinfosecfoundation.org/issues/5141 - Allow checksum URL to be specified by the index: https://redmine.openinfosecfoundation.org/issues/5684 +- Metadata rule matching for disable, enable and drop: + https://redmine.openinfosecfoundation.org/issues/5561 ## 1.2.5 - 2022-09-22 - Update entrypoint search path when not installed with distutils. This is diff --git a/doc/update.rst b/doc/update.rst index 19ab525..c3db62e 100644 --- a/doc/update.rst +++ b/doc/update.rst @@ -241,6 +241,24 @@ are allowed:: filename:rules/*deleted* filename:*/emerging-dos.rules +Metadata Matching +----------------- + +Rules can be enabled or disabled based on the metadata fields +contained in the rule, for example:: + + metadata: deployment perimeter + +Will match rules that have a metadata field of "deployment" with the +value of "perimeter" (case insensitive). This will match on a rule +with the provided metadata:: + + metadata:affected_product Any, attack_target Any, deployment Perimeter + +.. note:: Metadata matching can only be used to enable, disable or + convert rules to drop. It is not available for rule + modification. + Modifying Rules --------------- diff --git a/suricata/update/configs/disable.conf b/suricata/update/configs/disable.conf index 7639000..59d0e18 100644 --- a/suricata/update/configs/disable.conf +++ b/suricata/update/configs/disable.conf @@ -13,3 +13,7 @@ # group:emerging-icmp.rules # group:emerging-dos # group:emerging* + +# 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 diff --git a/suricata/update/configs/enable.conf b/suricata/update/configs/enable.conf index e549b4b..ad7b4e2 100644 --- a/suricata/update/configs/enable.conf +++ b/suricata/update/configs/enable.conf @@ -13,3 +13,7 @@ # group:emerging-icmp.rules # group:emerging-dos # group:emerging* + +# 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 diff --git a/suricata/update/matchers.py b/suricata/update/matchers.py index fae83f7..e886c79 100644 --- a/suricata/update/matchers.py +++ b/suricata/update/matchers.py @@ -184,6 +184,34 @@ class ReRuleMatcher(object): return None +class MetadataRuleMatch(object): + """ Matcher that matches on key/value style metadata fields. Case insensitive. """ + + def __init__(self, key, value): + self.key = key + self.value = value + + def match(self, rule): + for entry in rule.metadata: + parts = entry.strip().split(" ", 1) + if parts[0].strip().lower() == self.key and parts[1].strip().lower() == self.value: + print(rule) + return True + return False + + @classmethod + def parse(cls, buf): + print(buf) + if buf.startswith("metadata:"): + buf = buf.split(":", 1)[1].strip() + parts = buf.split(" ", 1) + if len(parts) == 2: + key = parts[0].strip().lower() + val = parts[1].strip().lower() + return cls(key, val) + return None + + class ModifyRuleFilter(object): """Filter to modify an idstools rule object. @@ -296,4 +324,8 @@ def parse_rule_match(match): if matcher: return matcher + matcher = MetadataRuleMatch.parse(match) + if matcher: + return matcher + return None diff --git a/tests/test_matchers.py b/tests/test_matchers.py index 7acec5a..ad64a54 100644 --- a/tests/test_matchers.py +++ b/tests/test_matchers.py @@ -119,3 +119,17 @@ class MetadataAddTestCase(unittest.TestCase): new_rule = metadata_filter.run(rule) self.assertIsNotNone(new_rule) self.assertTrue(new_rule.format().find("evebox.action") > -1) + +class MetadataMatchTestCase(unittest.TestCase): + + def test_match_metadata(self): + """ + Looking for: deployment Perimeter + """ + rule_string = b"""alert http $EXTERNAL_NET any -> $HOME_NET any (msg:"ET WEB_SPECIFIC_APPS PHPStudy Remote Code Execution Backdoor"; flow:established,to_server; http.method; content:"GET"; http.header; content:"Accept-Charset|3a 20|"; fast_pattern; nocase; pcre:"/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})\\x0d\\x0a/R"; reference:url,www.cnblogs.com/-qing-/p/11575622.html; reference:url,www.uedbox.com/post/59265/; classtype:attempted-admin; sid:2028629; rev:1; metadata:affected_product Web_Server_Applications, attack_target Server, created_at 2019_09_25, deployment Perimeter, former_category WEB_SPECIFIC_APPS, performance_impact Significant, signature_severity Major, updated_at 2019_09_25;)""" + rule = suricata.update.rule.parse(rule_string) + self.assertIsNotNone(rule) + filter_string = "metadata: deployment perimeter" + metadata_filter = matchers_mod.MetadataRuleMatch.parse(filter_string) + self.assertIsNotNone(metadata_filter) + self.assertTrue(metadata_filter.match(rule))