From 0ff1791a7039d4eea2515019d9d8298a90b1c3ed Mon Sep 17 00:00:00 2001 From: Christian Fischer Date: Thu, 24 Oct 2024 14:52:59 +0200 Subject: [PATCH] Change: Extend invalid URL plugin and relevant tests. --- tests/plugins/test_script_xref_url.py | 121 +++++++++++++++++++++++++- troubadix/plugins/script_xref_url.py | 64 +++++++++++++- 2 files changed, 180 insertions(+), 5 deletions(-) diff --git a/tests/plugins/test_script_xref_url.py b/tests/plugins/test_script_xref_url.py index e5b46f16..a1af757b 100644 --- a/tests/plugins/test_script_xref_url.py +++ b/tests/plugins/test_script_xref_url.py @@ -49,6 +49,15 @@ def test_ok(self): ' script_xref(name:"URL", value:"http://speedtouch.sourceforge.io/index.php?/news.en.html");\n' ' script_xref(name:"URL", value:"https://support.k7computing.com/index.php?/Knowledgebase/Article/View/173/41/advisory-issued-on-6th-november-2017");\n' ' script_xref(name:"URL", value:"http://support.novell.com/cgi-bin/search/searchtid.cgi?/10077872.htm");\n' + ' script_xref(name:"URL", value:"https://blog.fuzzing-project.org/54-Update-on-MatrixSSL-miscalculation-CVE-2016-8671,-incomplete-fix-for-CVE-2016-6887.html");\n' + ' script_xref(name:"URL", value:"http://www.scaprepo.com/view.jsp?id=oval:org.secpod.oval:def:701638");\n' + ' script_xref(name:"URL", value:"https://blog.fuzzing-project.org/46-Various-invalid-memory-reads-in-ImageMagick-WPG,-DDS,-DCM.html");\n' + ' script_xref(name:"URL", value:"http://forum.wampserver.com/read.php?2,153491");\n' + ' script_xref(name:"URL", value:"https://secure1.securityspace.com/smysecure/catid.html?in=FreeBSD-SA-10:04.jail.asc");\n' + ' script_xref(name:"URL", value:"http://www.corelan.be:8800/index.php/forum/security-advisories/corelan-10-004-turboftp-server-1-00-712-dos/");\n' + ' script_xref(name:"URL", value:"http://core.yehg.net/lab/pr0js/advisories/dll_hijacking/[flash_player]_10.1.x_insecure_dll_hijacking_(dwmapi.dll)");\n' + ' script_xref(name:"URL", value:"http://mail-archives.apache.org/mod_mbox/perl-advocacy/200904.mbox/");\n' + ' script_xref(name:"URL", value:"https://confluence.atlassian.com/security/security-bulletin-may-21-2024-1387867145.html");\n' # pylint: enable=line-too-long ) fake_context = self.create_file_plugin_context( @@ -69,7 +78,7 @@ def test_exclude_inc_file(self): self.assertEqual(len(results), 0) - def test_invalid_url(self): + def test_generic_invalid_url(self): content = ' script_xref(name:"URL", value:"www.example.com");\n' fake_context = self.create_file_plugin_context( nasl_file=self.path, file_content=content @@ -85,3 +94,113 @@ def test_invalid_url(self): " value", results[0].message, ) + + def test_invalid_url_trailing_angle_bracket(self): + content = ' script_xref(name:"URL", value:"https://docs.docker.com/engine/release-notes/24.0/#2407>");\n' + fake_context = self.create_file_plugin_context( + nasl_file=self.path, file_content=content + ) + plugin = CheckScriptXrefUrl(fake_context) + + results = list(plugin.run()) + + self.assertEqual(len(results), 1) + self.assertIsInstance(results[0], LinterError) + self.assertEqual( + 'script_xref(name:"URL", value:"https://docs.docker.com/engine/' + 'release-notes/24.0/#2407>");: Invalid URL' + " value (trailing '>')", + results[0].message, + ) + + def test_invalid_url_trailing_comma(self): + content = ' script_xref(name:"URL", value:"https://dev.mysql.com/doc/refman/5.7/en/mysql-stmt-fetch.html,");\n' + fake_context = self.create_file_plugin_context( + nasl_file=self.path, file_content=content + ) + plugin = CheckScriptXrefUrl(fake_context) + + results = list(plugin.run()) + + self.assertEqual(len(results), 1) + self.assertIsInstance(results[0], LinterError) + self.assertEqual( + 'script_xref(name:"URL", value:"https://dev.mysql.com/doc/refman/5.7/en/' + 'mysql-stmt-fetch.html,");: Invalid URL' + " value (trailing ',')", + results[0].message, + ) + + def test_invalid_url_trailing_punctuation_mark(self): + content = ' script_xref(name:"URL", value:"http://isec.pl/vulnerabilities/isec-0017-binfmt_elf.txt:");\n' + fake_context = self.create_file_plugin_context( + nasl_file=self.path, file_content=content + ) + plugin = CheckScriptXrefUrl(fake_context) + + results = list(plugin.run()) + + self.assertEqual(len(results), 1) + self.assertIsInstance(results[0], LinterError) + self.assertEqual( + 'script_xref(name:"URL", value:"http://isec.pl/vulnerabilities/' + 'isec-0017-binfmt_elf.txt:");: Invalid URL' + " value (trailing ':')", + results[0].message, + ) + + def test_invalid_url_trailing_square_bracket(self): + content = ( + ' script_xref(name:"URL", value:"https://example.com/foo/bar]");\n' + ) + fake_context = self.create_file_plugin_context( + nasl_file=self.path, file_content=content + ) + plugin = CheckScriptXrefUrl(fake_context) + + results = list(plugin.run()) + + self.assertEqual(len(results), 1) + self.assertIsInstance(results[0], LinterError) + self.assertEqual( + 'script_xref(name:"URL", value:"https://example.com/foo/bar]");: Invalid URL' + " value (trailing ']')", + results[0].message, + ) + + def test_invalid_url_trailing_round_bracket(self): + content = ( + ' script_xref(name:"URL", value:"https://example.com/foo/bar)");\n' + ) + fake_context = self.create_file_plugin_context( + nasl_file=self.path, file_content=content + ) + plugin = CheckScriptXrefUrl(fake_context) + + results = list(plugin.run()) + + self.assertEqual(len(results), 1) + self.assertIsInstance(results[0], LinterError) + self.assertEqual( + 'script_xref(name:"URL", value:"https://example.com/foo/bar)");: Invalid URL' + " value (trailing ')')", + results[0].message, + ) + + def test_invalid_url_wrong_ending(self): + content = ' script_xref(name:"URL", value:"https://confluence.atlassian.com/security/security-bulletin-may-21-2024-1387867145.htmll");\n' + fake_context = self.create_file_plugin_context( + nasl_file=self.path, file_content=content + ) + plugin = CheckScriptXrefUrl(fake_context) + + results = list(plugin.run()) + + self.assertEqual(len(results), 1) + self.assertIsInstance(results[0], LinterError) + self.assertEqual( + 'script_xref(name:"URL", value:"https://confluence.atlassian.com/security/' + 'security-bulletin-may-21-2024-1387867145.htmll");: Invalid URL' + " value (wrong file extension)", + results[0].message, + ) diff --git a/troubadix/plugins/script_xref_url.py b/troubadix/plugins/script_xref_url.py index 165ef8ed..046e4475 100644 --- a/troubadix/plugins/script_xref_url.py +++ b/troubadix/plugins/script_xref_url.py @@ -63,11 +63,67 @@ def check_content( ) for match in matches: if match: - if match.group("value") not in ALLOWED_URLS and not url( - match.group("value"), strict_query=False - ): + url_value = match.group("value") + if url_value in ALLOWED_URLS: + continue + + full_xref = match.group(0) + + # First a few possible malformed URLs introduced by e.g. some automatic + # extraction or by copy'n'paste + if url_value.endswith(">") and "<" not in url_value: + yield LinterError( + f"{full_xref}: Invalid URL value (trailing '>')", + file=nasl_file, + plugin=self.name, + ) + continue + + if url_value.endswith(","): + yield LinterError( + f"{full_xref}: Invalid URL value (trailing ',')", + file=nasl_file, + plugin=self.name, + ) + continue + + if url_value.endswith(":"): + yield LinterError( + f"{full_xref}: Invalid URL value (trailing ':')", + file=nasl_file, + plugin=self.name, + ) + continue + + if url_value.endswith("]") and "[" not in url_value: + yield LinterError( + f"{full_xref}: Invalid URL value (trailing ']')", + file=nasl_file, + plugin=self.name, + ) + continue + + if url_value.endswith(")") and "(" not in url_value: + yield LinterError( + f"{full_xref}: Invalid URL value (trailing ')')", + file=nasl_file, + plugin=self.name, + ) + continue + + if url_value.endswith(".htmll"): + yield LinterError( + f"{full_xref}: Invalid URL value (wrong file extension)", + file=nasl_file, + plugin=self.name, + ) + continue + + # Additional standard check via the validators package + if not url(url_value, strict_query=False): yield LinterError( - f"{match.group(0)}: Invalid URL value", + f"{full_xref}: Invalid URL value", file=nasl_file, plugin=self.name, ) + continue