From 41a91c544ba5b8ebe8c6ce1aedd31669f0f76e1e Mon Sep 17 00:00:00 2001 From: Amy Schools Date: Thu, 19 Dec 2024 14:21:20 +0100 Subject: [PATCH 1/8] Add valid oids for new generators and win-vt-generator --- troubadix/plugins/valid_oid.py | 69 ++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/troubadix/plugins/valid_oid.py b/troubadix/plugins/valid_oid.py index 3de78cd7..1fdfca61 100644 --- a/troubadix/plugins/valid_oid.py +++ b/troubadix/plugins/valid_oid.py @@ -58,6 +58,7 @@ def check_content( security_template = "Security Advisory" family_template = "Local Security Checks" + windows_family_template = "Windows : Microsoft Bulletins" is_using_reserved = "is using an OID that is reserved for" invalid_oid = "is using an invalid OID" @@ -324,6 +325,33 @@ def check_content( plugin=self.name, ) return + elif vendor_number == "16": + if family != f"openEuler {family_template}": + yield LinterError( + f"script_oid() {is_using_reserved} openEuler " + f"'{str(oid)}'", + file=nasl_file, + plugin=self.name, + ) + return + elif vendor_number == "17": + if family != f"HCE {family_template}": + yield LinterError( + f"script_oid() {is_using_reserved} HCE " + f"'{str(oid)}'", + file=nasl_file, + plugin=self.name, + ) + return + elif vendor_number == "18": + if family != f"openSUSE {family_template}": + yield LinterError( + f"script_oid() {is_using_reserved} openSUSE " + f"'{str(oid)}'", + file=nasl_file, + plugin=self.name, + ) + return else: yield LinterError( @@ -377,6 +405,47 @@ def check_content( return return + if "1.3.6.1.4.1.25623.1.3." in oid: + family_pattern = get_special_script_tag_pattern( + SpecialScriptTag.FAMILY + ) + family_match = family_pattern.search(file_content) + if not family_match or not family_match.group("value"): + yield LinterError( + "VT is missing a script name!", + file=nasl_file, + plugin=self.name, + ) + return + + family = family_match.group("value") + + # Fixed OID-scheme for win-vt-generator + if "1.3.6.1.4.1.25623.1.3" in oid: + if family != windows_family_template: + yield LinterError( + f"script_oid() {is_using_reserved} 'Windows' (" + f"{str(oid)})", + file=nasl_file, + plugin=self.name, + ) + return + + windows_oid_match = re.search( + r"^1\.3\.6\.1\.4\.1\.25623\.1\.3\.[0-9]\.[0-9]\.[0-9]\.[0-9]", + oid, + ) + if not windows_oid_match: + yield LinterError( + f"script_oid() {invalid_oid} '{str(oid)}' " + "(Windows pattern: 1.3.6.1.4.1.25623.1.3." + "[product_id].[platform_id].[kb_article_id].[fixed_build_number])", + file=nasl_file, + plugin=self.name, + ) + return + + return oid_digit_match = re.search( r"^1\.3\.6\.1\.4\.1\.25623\.1\.0\.([0-9]+)", oid From 44365fcc3e5fcef7f6a1e9845e04c722dab0dde5 Mon Sep 17 00:00:00 2001 From: Amy Schools Date: Thu, 19 Dec 2024 15:50:26 +0100 Subject: [PATCH 2/8] add char counts for windows regex --- troubadix/plugins/valid_oid.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/troubadix/plugins/valid_oid.py b/troubadix/plugins/valid_oid.py index 1fdfca61..4c6f92d3 100644 --- a/troubadix/plugins/valid_oid.py +++ b/troubadix/plugins/valid_oid.py @@ -432,7 +432,7 @@ def check_content( return windows_oid_match = re.search( - r"^1\.3\.6\.1\.4\.1\.25623\.1\.3\.[0-9]\.[0-9]\.[0-9]\.[0-9]", + r"^1\.3\.6\.1\.4\.1\.25623\.1\.3\.[0-9]{5}\.[0-9]\.[0-9]{7}\.[0-9]{30}", oid, ) if not windows_oid_match: From da1b3fb0ebb4d397288ff778d1ae96f28d44e96e Mon Sep 17 00:00:00 2001 From: Amy Schools Date: Fri, 20 Dec 2024 13:06:44 +0100 Subject: [PATCH 3/8] add tests --- tests/plugins/test_valid_oid.py | 155 ++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) diff --git a/tests/plugins/test_valid_oid.py b/tests/plugins/test_valid_oid.py index 2762d3d2..c5918f36 100644 --- a/tests/plugins/test_valid_oid.py +++ b/tests/plugins/test_valid_oid.py @@ -672,6 +672,123 @@ def test_rocky(self): results[0].message, ) + def test_openeuler_ok(self): + path = Path("some/file.nasl") + content = ( + ' script_oid("1.3.6.1.4.1.25623.1.1.16.2022.123");\n' + ' script_family("openEuler Local Security Checks");\n' + ) + fake_context = self.create_file_plugin_context( + nasl_file=path, file_content=content + ) + plugin = CheckValidOID(fake_context) + + results = list(plugin.run()) + + self.assertEqual(len(results), 0) + + def test_openeuler_not_ok(self): + path = Path("some/file.nasl") + content = ( + ' script_oid("1.3.6.1.4.1.25623.1.1.16.2022.123");\n' + ' script_family("HCE Local Security Checks");\n' + ) + fake_context = self.create_file_plugin_context( + nasl_file=path, file_content=content + ) + plugin = CheckValidOID(fake_context) + + results = list(plugin.run()) + + self.assertEqual(len(results), 1) + + self.assertIsInstance(results[0], LinterError) + self.assertEqual( + ( + "script_oid() is using an OID that is reserved for " + "openEuler '1.3.6.1.4.1.25623.1.1.16.2022.123'" + ), + results[0].message, + ) + + def test_hce_ok(self): + path = Path("some/file.nasl") + content = ( + ' script_oid("1.3.6.1.4.1.25623.1.1.17.2022.123");\n' + ' script_family("HCE Local Security Checks");\n' + ) + fake_context = self.create_file_plugin_context( + nasl_file=path, file_content=content + ) + plugin = CheckValidOID(fake_context) + + results = list(plugin.run()) + + self.assertEqual(len(results), 0) + + def test_hce_not_ok(self): + path = Path("some/file.nasl") + content = ( + ' script_oid("1.3.6.1.4.1.25623.1.1.17.2022.123");\n' + ' script_family("openEuler Local Security Checks");\n' + ) + fake_context = self.create_file_plugin_context( + nasl_file=path, file_content=content + ) + plugin = CheckValidOID(fake_context) + + results = list(plugin.run()) + + self.assertEqual(len(results), 1) + + self.assertIsInstance(results[0], LinterError) + self.assertEqual( + ( + "script_oid() is using an OID that is reserved for " + "HCE '1.3.6.1.4.1.25623.1.1.17.2022.123'" + ), + results[0].message, + ) + + def test_opensuse_ok(self): + path = Path("some/file.nasl") + content = ( + ' script_oid("1.3.6.1.4.1.25623.1.1.18.2022.123");\n' + ' script_family("openSUSE Local Security Checks");\n' + ) + fake_context = self.create_file_plugin_context( + nasl_file=path, file_content=content + ) + plugin = CheckValidOID(fake_context) + + results = list(plugin.run()) + + self.assertEqual(len(results), 0) + + def test_opensuse_not_ok(self): + path = Path("some/file.nasl") + content = ( + ' script_oid("1.3.6.1.4.1.25623.1.1.18.2022.123");\n' + ' script_family("HCE Local Security Checks");\n' + ) + fake_context = self.create_file_plugin_context( + nasl_file=path, file_content=content + ) + plugin = CheckValidOID(fake_context) + + results = list(plugin.run()) + + self.assertEqual(len(results), 1) + + self.assertIsInstance(results[0], LinterError) + self.assertEqual( + ( + "script_oid() is using an OID that is reserved for " + "openSUSE '1.3.6.1.4.1.25623.1.1.18.2022.123'" + ), + results[0].message, + ) + def test_unknown(self): path = Path("some/file.nasl") content = ( @@ -757,3 +874,41 @@ def test_script_name__product_firefox(self): ), results[0].message, ) + + def test_script_family__product_microsoft_ok(self): + path = Path("some/file.nasl") + content = ( + ' script_oid("1.3.6.1.4.1.25623.1.3.11571.0.5019966.494846484649555554514651545348");' + "\n" + ' script_family("Windows : Microsoft Bulletins");\n' + ) + fake_context = self.create_file_plugin_context( + nasl_file=path, file_content=content + ) + plugin = CheckValidOID(fake_context) + + results = list(plugin.run()) + + self.assertEqual(len(results), 0) + + def test_script_family__product_microsoft_not_ok(self): + path = Path("some/file.nasl") + content = ( + ' script_oid("1.3.6.1.4.1.25623.1.3.11571.0.5019966.494846484649555554514651545348");' + "\n" + ' script_family("Windows : Microsoft");\n' + ) + fake_context = self.create_file_plugin_context( + nasl_file=path, file_content=content + ) + plugin = CheckValidOID(fake_context) + + results = list(plugin.run()) + self.assertIsInstance(results[0], LinterError) + self.assertEqual( + ( + "script_oid() is using an OID that is reserved for 'Windows' " + "(1.3.6.1.4.1.25623.1.3.11571.0.5019966.494846484649555554514651545348)" + ), + results[0].message, + ) From 714412e9e0a34564c2c64629544dd74f8bcab35b Mon Sep 17 00:00:00 2001 From: Amy Schools Date: Thu, 2 Jan 2025 11:16:54 +0100 Subject: [PATCH 4/8] Change: PR review updates --- troubadix/plugins/valid_oid.py | 63 +++++++++++++++------------------- 1 file changed, 28 insertions(+), 35 deletions(-) diff --git a/troubadix/plugins/valid_oid.py b/troubadix/plugins/valid_oid.py index 4c6f92d3..b5a3af8b 100644 --- a/troubadix/plugins/valid_oid.py +++ b/troubadix/plugins/valid_oid.py @@ -82,12 +82,11 @@ def check_content( ) return + family_pattern = get_special_script_tag_pattern(SpecialScriptTag.FAMILY) + family_match = family_pattern.search(file_content) + # Vendor-specific OIDs if "1.3.6.1.4.1.25623.1.1." in oid: - family_pattern = get_special_script_tag_pattern( - SpecialScriptTag.FAMILY - ) - family_match = family_pattern.search(file_content) if family_match is None or family_match.group("value") is None: yield LinterError( "VT is missing a script family!", @@ -405,47 +404,41 @@ def check_content( return return + + # Fixed OID-scheme for Windows OIDs if "1.3.6.1.4.1.25623.1.3." in oid: - family_pattern = get_special_script_tag_pattern( - SpecialScriptTag.FAMILY - ) - family_match = family_pattern.search(file_content) - if not family_match or not family_match.group("value"): + family = family_match.group("value") + if not family_match or not family: yield LinterError( - "VT is missing a script name!", + "VT is missing a script family!", file=nasl_file, plugin=self.name, ) return - family = family_match.group("value") - - # Fixed OID-scheme for win-vt-generator - if "1.3.6.1.4.1.25623.1.3" in oid: - if family != windows_family_template: - yield LinterError( - f"script_oid() {is_using_reserved} 'Windows' (" - f"{str(oid)})", - file=nasl_file, - plugin=self.name, - ) - return - - windows_oid_match = re.search( - r"^1\.3\.6\.1\.4\.1\.25623\.1\.3\.[0-9]{5}\.[0-9]\.[0-9]{7}\.[0-9]{30}", - oid, + if family != windows_family_template: + yield LinterError( + f"script_oid() {is_using_reserved} 'Windows' (" + f"{str(oid)})", + file=nasl_file, + plugin=self.name, ) - if not windows_oid_match: - yield LinterError( - f"script_oid() {invalid_oid} '{str(oid)}' " - "(Windows pattern: 1.3.6.1.4.1.25623.1.3." - "[product_id].[platform_id].[kb_article_id].[fixed_build_number])", - file=nasl_file, - plugin=self.name, - ) - return + return + windows_oid_match = re.search( + r"^1\.3\.6\.1\.4\.1\.25623\.1\.3\.[0-9]{5}\.[0-9]\.[0-9]{7}\.[0-9]{30}", + oid, + ) + if not windows_oid_match: + yield LinterError( + f"script_oid() {invalid_oid} '{str(oid)}' " + "(Windows pattern: 1.3.6.1.4.1.25623.1.3." + "[product_id].[platform_id].[kb_article_id].[fixed_build_number])", + file=nasl_file, + plugin=self.name, + ) return + return oid_digit_match = re.search( r"^1\.3\.6\.1\.4\.1\.25623\.1\.0\.([0-9]+)", oid From 1d5ae9c18e0dbe608c1ff9b48363ca1f5960fa8d Mon Sep 17 00:00:00 2001 From: Amy Schools Date: Wed, 8 Jan 2025 13:08:24 +0100 Subject: [PATCH 5/8] Remove HCE/openEuler valid oid checks because they don't have NASL --- tests/plugins/test_valid_oid.py | 78 --------------------------------- troubadix/plugins/valid_oid.py | 18 -------- 2 files changed, 96 deletions(-) diff --git a/tests/plugins/test_valid_oid.py b/tests/plugins/test_valid_oid.py index c5918f36..4504c323 100644 --- a/tests/plugins/test_valid_oid.py +++ b/tests/plugins/test_valid_oid.py @@ -672,84 +672,6 @@ def test_rocky(self): results[0].message, ) - def test_openeuler_ok(self): - path = Path("some/file.nasl") - content = ( - ' script_oid("1.3.6.1.4.1.25623.1.1.16.2022.123");\n' - ' script_family("openEuler Local Security Checks");\n' - ) - fake_context = self.create_file_plugin_context( - nasl_file=path, file_content=content - ) - plugin = CheckValidOID(fake_context) - - results = list(plugin.run()) - - self.assertEqual(len(results), 0) - - def test_openeuler_not_ok(self): - path = Path("some/file.nasl") - content = ( - ' script_oid("1.3.6.1.4.1.25623.1.1.16.2022.123");\n' - ' script_family("HCE Local Security Checks");\n' - ) - fake_context = self.create_file_plugin_context( - nasl_file=path, file_content=content - ) - plugin = CheckValidOID(fake_context) - - results = list(plugin.run()) - - self.assertEqual(len(results), 1) - - self.assertIsInstance(results[0], LinterError) - self.assertEqual( - ( - "script_oid() is using an OID that is reserved for " - "openEuler '1.3.6.1.4.1.25623.1.1.16.2022.123'" - ), - results[0].message, - ) - - def test_hce_ok(self): - path = Path("some/file.nasl") - content = ( - ' script_oid("1.3.6.1.4.1.25623.1.1.17.2022.123");\n' - ' script_family("HCE Local Security Checks");\n' - ) - fake_context = self.create_file_plugin_context( - nasl_file=path, file_content=content - ) - plugin = CheckValidOID(fake_context) - - results = list(plugin.run()) - - self.assertEqual(len(results), 0) - - def test_hce_not_ok(self): - path = Path("some/file.nasl") - content = ( - ' script_oid("1.3.6.1.4.1.25623.1.1.17.2022.123");\n' - ' script_family("openEuler Local Security Checks");\n' - ) - fake_context = self.create_file_plugin_context( - nasl_file=path, file_content=content - ) - plugin = CheckValidOID(fake_context) - - results = list(plugin.run()) - - self.assertEqual(len(results), 1) - - self.assertIsInstance(results[0], LinterError) - self.assertEqual( - ( - "script_oid() is using an OID that is reserved for " - "HCE '1.3.6.1.4.1.25623.1.1.17.2022.123'" - ), - results[0].message, - ) - def test_opensuse_ok(self): path = Path("some/file.nasl") content = ( diff --git a/troubadix/plugins/valid_oid.py b/troubadix/plugins/valid_oid.py index b5a3af8b..e3fe2ab2 100644 --- a/troubadix/plugins/valid_oid.py +++ b/troubadix/plugins/valid_oid.py @@ -324,24 +324,6 @@ def check_content( plugin=self.name, ) return - elif vendor_number == "16": - if family != f"openEuler {family_template}": - yield LinterError( - f"script_oid() {is_using_reserved} openEuler " - f"'{str(oid)}'", - file=nasl_file, - plugin=self.name, - ) - return - elif vendor_number == "17": - if family != f"HCE {family_template}": - yield LinterError( - f"script_oid() {is_using_reserved} HCE " - f"'{str(oid)}'", - file=nasl_file, - plugin=self.name, - ) - return elif vendor_number == "18": if family != f"openSUSE {family_template}": yield LinterError( From 7f5e932b3c58c86a26bc158406ab519fcdb3e808 Mon Sep 17 00:00:00 2001 From: Amy Schools Date: Fri, 10 Jan 2025 10:38:36 +0100 Subject: [PATCH 6/8] Change: update windows oid formatting regex --- tests/plugins/test_valid_oid.py | 40 +++++++++++++++++++++++++++++++++ troubadix/plugins/valid_oid.py | 2 +- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/tests/plugins/test_valid_oid.py b/tests/plugins/test_valid_oid.py index 4504c323..af3420df 100644 --- a/tests/plugins/test_valid_oid.py +++ b/tests/plugins/test_valid_oid.py @@ -834,3 +834,43 @@ def test_script_family__product_microsoft_not_ok(self): ), results[0].message, ) + + def test_oid_microsoft_ok(self): + path = Path("some/file.nasl") + content = ( + ' script_oid("1.3.6.1.4.1.25623.1.3.11571.0.5019966.494846484649555554514651545348");' + "\n" + ' script_family("Windows : Microsoft Bulletins");\n' + ) + fake_context = self.create_file_plugin_context( + nasl_file=path, file_content=content + ) + plugin = CheckValidOID(fake_context) + + results = list(plugin.run()) + + self.assertEqual(len(results), 0) + + def test_oid_microsoft_not_ok(self): + path = Path("some/file.nasl") + content = ( + ' script_oid("1.3.6.1.4.1.25623.1.3.11571.0.494846484649555554514651545348");' + "\n" + ' script_family("Windows : Microsoft Bulletins");\n' + ) + fake_context = self.create_file_plugin_context( + nasl_file=path, file_content=content + ) + plugin = CheckValidOID(fake_context) + results = list(plugin.run()) + + self.assertIsInstance(results[0], LinterError) + self.assertEqual( + ( + "script_oid() is using an invalid OID " + "'1.3.6.1.4.1.25623.1.3.11571.0.494846484649555554514651545348' " + "(Windows pattern: 1.3.6.1.4.1.25623.1.3.[product_id].[platform_id]." + "[kb_article_id].[fixed_build_number])" + ), + results[0].message, + ) diff --git a/troubadix/plugins/valid_oid.py b/troubadix/plugins/valid_oid.py index e3fe2ab2..c1605884 100644 --- a/troubadix/plugins/valid_oid.py +++ b/troubadix/plugins/valid_oid.py @@ -408,7 +408,7 @@ def check_content( return windows_oid_match = re.search( - r"^1\.3\.6\.1\.4\.1\.25623\.1\.3\.[0-9]{5}\.[0-9]\.[0-9]{7}\.[0-9]{30}", + r"^1\.3\.6\.1\.4\.1\.25623\.1\.3\.\d+\.\d+\.\d+\.\d+", oid, ) if not windows_oid_match: From 437fd08ef5e6d5fb60a9b6fdd6234b5c86c5c273 Mon Sep 17 00:00:00 2001 From: Amy Schools Date: Fri, 10 Jan 2025 13:02:20 +0100 Subject: [PATCH 7/8] Change: update windows oid matching code --- troubadix/plugins/valid_oid.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/troubadix/plugins/valid_oid.py b/troubadix/plugins/valid_oid.py index c1605884..5127a892 100644 --- a/troubadix/plugins/valid_oid.py +++ b/troubadix/plugins/valid_oid.py @@ -347,8 +347,8 @@ def check_content( # product-specific OIDs if "1.3.6.1.4.1.25623.1.2." in oid: - name_patter = get_special_script_tag_pattern(SpecialScriptTag.NAME) - name_match = name_patter.search(file_content) + name_pattern = get_special_script_tag_pattern(SpecialScriptTag.NAME) + name_match = name_pattern.search(file_content) if not name_match or not name_match.group("value"): yield LinterError( "VT is missing a script name!", @@ -389,8 +389,7 @@ def check_content( # Fixed OID-scheme for Windows OIDs if "1.3.6.1.4.1.25623.1.3." in oid: - family = family_match.group("value") - if not family_match or not family: + if not family_match or not family_match.group("value"): yield LinterError( "VT is missing a script family!", file=nasl_file, @@ -398,7 +397,7 @@ def check_content( ) return - if family != windows_family_template: + if family_match.group("value") != windows_family_template: yield LinterError( f"script_oid() {is_using_reserved} 'Windows' (" f"{str(oid)})", From bd2f8fcfabdae80e9d011965274ec7dcf29226ae Mon Sep 17 00:00:00 2001 From: Amy Schools Date: Fri, 10 Jan 2025 14:48:31 +0100 Subject: [PATCH 8/8] Change: move check for script family to top level --- tests/plugins/test_valid_oid.py | 7 ++++++- troubadix/plugins/valid_oid.py | 25 ++++++++----------------- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/tests/plugins/test_valid_oid.py b/tests/plugins/test_valid_oid.py index af3420df..966743e5 100644 --- a/tests/plugins/test_valid_oid.py +++ b/tests/plugins/test_valid_oid.py @@ -26,7 +26,10 @@ class CheckValidOIDTestCase(PluginTestCase): def test_ok(self): path = Path("some/file.nasl") - content = ' script_oid("1.3.6.1.4.1.25623.1.0.100376");\n' + content = ( + ' script_oid("1.3.6.1.4.1.25623.1.0.100376");\n' + ' script_family("Huawei EulerOS Local Security Checks");\n' + ) fake_context = self.create_file_plugin_context( nasl_file=path, file_content=content ) @@ -764,6 +767,7 @@ def test_script_name__product_firefox_ok(self): content = ( ' script_oid("1.3.6.1.4.1.25623.1.2.1.2020.255");\n' ' script_name("Mozilla Firefox Security Advisory");\n' + ' script_family("General");' ) fake_context = self.create_file_plugin_context( nasl_file=path, file_content=content @@ -779,6 +783,7 @@ def test_script_name__product_firefox(self): content = ( ' script_oid("1.3.6.1.4.1.25623.1.2.1.2020.255");\n' ' script_name("AdaptBB Detection (HTTP)");\n' + ' script_family("General");' ) fake_context = self.create_file_plugin_context( nasl_file=path, file_content=content diff --git a/troubadix/plugins/valid_oid.py b/troubadix/plugins/valid_oid.py index 5127a892..6a9b36fb 100644 --- a/troubadix/plugins/valid_oid.py +++ b/troubadix/plugins/valid_oid.py @@ -85,18 +85,17 @@ def check_content( family_pattern = get_special_script_tag_pattern(SpecialScriptTag.FAMILY) family_match = family_pattern.search(file_content) + if family_match is None or family_match.group("value") is None: + yield LinterError( + "VT is missing a script family!", + file=nasl_file, + plugin=self.name, + ) + return + # Vendor-specific OIDs if "1.3.6.1.4.1.25623.1.1." in oid: - if family_match is None or family_match.group("value") is None: - yield LinterError( - "VT is missing a script family!", - file=nasl_file, - plugin=self.name, - ) - return - family = family_match.group("value") - vendor_number_match = re.search( r"^1\.3\.6\.1\.4\.1\.25623\.1\.1\.([0-9]+)\.", oid ) @@ -389,14 +388,6 @@ def check_content( # Fixed OID-scheme for Windows OIDs if "1.3.6.1.4.1.25623.1.3." in oid: - if not family_match or not family_match.group("value"): - yield LinterError( - "VT is missing a script family!", - file=nasl_file, - plugin=self.name, - ) - return - if family_match.group("value") != windows_family_template: yield LinterError( f"script_oid() {is_using_reserved} 'Windows' ("