From b17b6290eb3ea9743a4122f7c26b98242795406a Mon Sep 17 00:00:00 2001 From: ybadaoui-ostorlab Date: Tue, 15 Oct 2024 13:43:24 +0100 Subject: [PATCH 01/11] dd detection for CVE-2024-9487 --- agent/exploits/cve_2024_9487.py | 87 ++++++++++++++++++++++++++++ tests/exploits/cve_2024_9487_test.py | 57 ++++++++++++++++++ 2 files changed, 144 insertions(+) create mode 100644 agent/exploits/cve_2024_9487.py create mode 100644 tests/exploits/cve_2024_9487_test.py diff --git a/agent/exploits/cve_2024_9487.py b/agent/exploits/cve_2024_9487.py new file mode 100644 index 0000000..2b2c0ab --- /dev/null +++ b/agent/exploits/cve_2024_9487.py @@ -0,0 +1,87 @@ +"""Agent Asteroid implementation for CVE-2024-9487""" + +import re +from packaging import version +from agent.exploits import webexploit +from agent import exploits_registry +from agent import definitions +import requests +from urllib import parse as urlparse +from requests import exceptions as requests_exceptions + + +MAX_REDIRECTS = 2 +DEFAULT_TIMEOUT = 90 +VULNERABILITY_TITLE = "GITHUB ENTERPRISE SERVER AUTHENTICATION BYPASS" +VULNERABILITY_REFERENCE = "CVE-2024-9487" +VULNERABILITY_DESCRIPTION = """A cryptographic signature verification flaw in GitHub Enterprise Server allowed bypassing SAML SSO authentication, +leading to unauthorized user access. Exploitation required encrypted assertions, direct network access, and a signed SAML response or metadata. +It affected versions before 3.15 and was fixed in 3.11.16, 3.12.10, 3.13.5, and 3.14.2. The vulnerability was reported through GitHub's Bug Bounty program.""" +RISK_RATING = "CRITICAL" +FIXED_VERSIONS = { + "3.11": "3.11.6", + "3.12": "3.12.10", + "3.13": "3.13.5", + "3.14": "3.14.2", +} + + +@exploits_registry.register +class CVE20249487Exploit(webexploit.WebExploit): + accept_request = definitions.Request(method="GET", path="/") + check_request = definitions.Request(method="GET", path="/") + accept_pattern = [re.compile("GitHub\sEnterprise\sServer\s\d+\.\d+\.\d+")] + version_pattern = re.compile("GitHub\sEnterprise\sServer\s(\d+\.\d+\.\d+)") + + metadata = definitions.VulnerabilityMetadata( + title=VULNERABILITY_TITLE, + description=VULNERABILITY_DESCRIPTION, + reference=VULNERABILITY_REFERENCE, + risk_rating=RISK_RATING, + ) + + def check(self, target: definitions.Target) -> list[definitions.Vulnerability]: + """Rule to detect specific vulnerability on a specific target. + + Args: + target: Target to scan + + Returns: + List of identified vulnerabilities. + """ + session = requests.Session() + session.max_redirects = MAX_REDIRECTS + session.verify = False + + vulnerabilities: list[definitions.Vulnerability] = [] + + target_endpoint = urlparse.urljoin(target.origin, self.check_request.path) + + try: + req = requests.Request( + method=self.check_request.method, + url=target_endpoint, + data=self.check_request.data, + ).prepare() + if self.check_request.headers is not None: + self.check_request.headers.update(req.headers) + req.headers = self.check_request.headers # type: ignore + resp = session.send(req, timeout=DEFAULT_TIMEOUT) + except requests_exceptions.RequestException: + return vulnerabilities + + if (matched := self.version_pattern.findall(resp.text)) is not None: + for extracted_version in matched: + if isinstance(extracted_version, tuple): + extracted_version = extracted_version[0] + if version.parse(extracted_version) < version.parse("3.15"): + if version.parse(extracted_version) < version.parse("3.10"): + vulnerability = self._create_vulnerability(target) + vulnerabilities.append(vulnerability) + version_prefix = ".".join(extracted_version.split(".")[:2]) + if version.parse(extracted_version) < version.parse( + FIXED_VERSIONS[version_prefix] + ): + vulnerability = self._create_vulnerability(target) + vulnerabilities.append(vulnerability) + return vulnerabilities diff --git a/tests/exploits/cve_2024_9487_test.py b/tests/exploits/cve_2024_9487_test.py new file mode 100644 index 0000000..b3d041c --- /dev/null +++ b/tests/exploits/cve_2024_9487_test.py @@ -0,0 +1,57 @@ +"""Unit tests for Agent Asteroid: CVE_2024_9487""" + +import requests_mock as req_mock + +from agent import definitions +from agent.exploits import cve_2024_9487 + + +def testCVE20249487_whenVulnerable_reportFinding( + requests_mock: req_mock.mocker.Mocker, +) -> None: + """CVE_2024_9487 unit test: case when target is vulnerable.""" + requests_mock.get( + "http://localhost:80/", + text=""" +
+ GitHub Enterprise Server 3.14.1 +
+ """, + status_code=200, + ) + exploit_instance = cve_2024_9487.CVE20249487Exploit() + target = definitions.Target("http", "localhost", 80) + + accept = exploit_instance.accept(target) + vulnerabilities = exploit_instance.check(target) + + assert accept is True + vulnerability = vulnerabilities[0] + assert vulnerability.entry.title == "GITHUB ENTERPRISE SERVER AUTHENTICATION BYPASS" + assert vulnerability.technical_detail == ( + "http://localhost:80 is vulnerable to CVE-2024-9487, " + "GITHUB ENTERPRISE SERVER AUTHENTICATION BYPASS" + ) + + +def testCVE20249487_whenNotVulnerable_reportNothing( + requests_mock: req_mock.mocker.Mocker, +) -> None: + """CVE_2024_9487 unit test: case when target is vulnerable.""" + requests_mock.get( + "http://localhost:80/", + text=""" +
+ GitHub Enterprise Server 3.14.2 +
+ """, + status_code=200, + ) + exploit_instance = cve_2024_9487.CVE20249487Exploit() + target = definitions.Target("http", "localhost", 80) + + accept = exploit_instance.accept(target) + vulnerabilities = exploit_instance.check(target) + + assert accept is True + assert len(vulnerabilities) == 0 From a121edd414c689b3a94d0537f8c33de524f85666 Mon Sep 17 00:00:00 2001 From: ybadaoui-ostorlab Date: Tue, 15 Oct 2024 14:30:18 +0100 Subject: [PATCH 02/11] add unitest for when version is older than the 3.10 --- agent/exploits/cve_2024_9487.py | 15 +++++++-------- tests/exploits/cve_2024_9487_test.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/agent/exploits/cve_2024_9487.py b/agent/exploits/cve_2024_9487.py index 2b2c0ab..0475bfc 100644 --- a/agent/exploits/cve_2024_9487.py +++ b/agent/exploits/cve_2024_9487.py @@ -1,14 +1,15 @@ """Agent Asteroid implementation for CVE-2024-9487""" import re -from packaging import version -from agent.exploits import webexploit -from agent import exploits_registry -from agent import definitions -import requests from urllib import parse as urlparse + +import requests +from packaging import version from requests import exceptions as requests_exceptions +from agent import definitions +from agent import exploits_registry +from agent.exploits import webexploit MAX_REDIRECTS = 2 DEFAULT_TIMEOUT = 90 @@ -63,9 +64,6 @@ def check(self, target: definitions.Target) -> list[definitions.Vulnerability]: url=target_endpoint, data=self.check_request.data, ).prepare() - if self.check_request.headers is not None: - self.check_request.headers.update(req.headers) - req.headers = self.check_request.headers # type: ignore resp = session.send(req, timeout=DEFAULT_TIMEOUT) except requests_exceptions.RequestException: return vulnerabilities @@ -78,6 +76,7 @@ def check(self, target: definitions.Target) -> list[definitions.Vulnerability]: if version.parse(extracted_version) < version.parse("3.10"): vulnerability = self._create_vulnerability(target) vulnerabilities.append(vulnerability) + continue version_prefix = ".".join(extracted_version.split(".")[:2]) if version.parse(extracted_version) < version.parse( FIXED_VERSIONS[version_prefix] diff --git a/tests/exploits/cve_2024_9487_test.py b/tests/exploits/cve_2024_9487_test.py index b3d041c..fa1967e 100644 --- a/tests/exploits/cve_2024_9487_test.py +++ b/tests/exploits/cve_2024_9487_test.py @@ -55,3 +55,31 @@ def testCVE20249487_whenNotVulnerable_reportNothing( assert accept is True assert len(vulnerabilities) == 0 + + +def testCVE20249487_whenVersionVeryOld_reportFinding( + requests_mock: req_mock.mocker.Mocker, +) -> None: + """CVE_2024_9487 unit test: case when target is vulnerable.""" + requests_mock.get( + "http://localhost:80/", + text=""" +
+ GitHub Enterprise Server 3.9.1 +
+ """, + status_code=200, + ) + exploit_instance = cve_2024_9487.CVE20249487Exploit() + target = definitions.Target("http", "localhost", 80) + + accept = exploit_instance.accept(target) + vulnerabilities = exploit_instance.check(target) + + assert accept is True + vulnerability = vulnerabilities[0] + assert vulnerability.entry.title == "GITHUB ENTERPRISE SERVER AUTHENTICATION BYPASS" + assert vulnerability.technical_detail == ( + "http://localhost:80 is vulnerable to CVE-2024-9487, " + "GITHUB ENTERPRISE SERVER AUTHENTICATION BYPASS" + ) From 1e3084be6dd3a1e3d68d21f5f7e10a5ec866e0b5 Mon Sep 17 00:00:00 2001 From: ybadaoui-ostorlab Date: Tue, 15 Oct 2024 15:16:35 +0100 Subject: [PATCH 03/11] fix codecoverge by adding a test for when the body have two versions that match the version pattern --- tests/exploits/cve_2024_9487_test.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/exploits/cve_2024_9487_test.py b/tests/exploits/cve_2024_9487_test.py index fa1967e..79fce5c 100644 --- a/tests/exploits/cve_2024_9487_test.py +++ b/tests/exploits/cve_2024_9487_test.py @@ -83,3 +83,27 @@ def testCVE20249487_whenVersionVeryOld_reportFinding( "http://localhost:80 is vulnerable to CVE-2024-9487, " "GITHUB ENTERPRISE SERVER AUTHENTICATION BYPASS" ) + + +def testCVE20249487_whenMultiVersions_doNotCrash( + requests_mock: req_mock.mocker.Mocker, +) -> None: + """CVE_2024_9487 unit test: case when target is vulnerable.""" + requests_mock.get( + "http://localhost:80/", + text=""" +
+ GitHub Enterprise Server 3.14.2 + GitHub Enterprise Server 3.14.3 +
+ """, + status_code=200, + ) + exploit_instance = cve_2024_9487.CVE20249487Exploit() + target = definitions.Target("http", "localhost", 80) + + accept = exploit_instance.accept(target) + vulnerabilities = exploit_instance.check(target) + + assert accept is True + assert len(vulnerabilities) == 0 \ No newline at end of file From 4062d23d67a56201d6ceba35b69347a5e84029fd Mon Sep 17 00:00:00 2001 From: ybadaoui-ostorlab Date: Tue, 15 Oct 2024 15:25:28 +0100 Subject: [PATCH 04/11] fix lint --- tests/exploits/cve_2024_9487_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/exploits/cve_2024_9487_test.py b/tests/exploits/cve_2024_9487_test.py index 79fce5c..8b61c15 100644 --- a/tests/exploits/cve_2024_9487_test.py +++ b/tests/exploits/cve_2024_9487_test.py @@ -106,4 +106,4 @@ def testCVE20249487_whenMultiVersions_doNotCrash( vulnerabilities = exploit_instance.check(target) assert accept is True - assert len(vulnerabilities) == 0 \ No newline at end of file + assert len(vulnerabilities) == 0 From f8c2e2ecb2dc10bbbb003769aa3193699fec74af Mon Sep 17 00:00:00 2001 From: ybadaoui-ostorlab Date: Wed, 16 Oct 2024 15:50:36 +0100 Subject: [PATCH 05/11] resolve comments --- agent/exploits/cve_2024_9487.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/agent/exploits/cve_2024_9487.py b/agent/exploits/cve_2024_9487.py index 0475bfc..763f9bc 100644 --- a/agent/exploits/cve_2024_9487.py +++ b/agent/exploits/cve_2024_9487.py @@ -1,5 +1,6 @@ """Agent Asteroid implementation for CVE-2024-9487""" +import datetime import re from urllib import parse as urlparse @@ -12,7 +13,7 @@ from agent.exploits import webexploit MAX_REDIRECTS = 2 -DEFAULT_TIMEOUT = 90 +DEFAULT_TIMEOUT = datetime.timedelta(seconds=90) VULNERABILITY_TITLE = "GITHUB ENTERPRISE SERVER AUTHENTICATION BYPASS" VULNERABILITY_REFERENCE = "CVE-2024-9487" VULNERABILITY_DESCRIPTION = """A cryptographic signature verification flaw in GitHub Enterprise Server allowed bypassing SAML SSO authentication, @@ -26,6 +27,9 @@ "3.14": "3.14.2", } +MAX_FIXED_VERSION = "3.15" +MAX_NONFIXED_VERSION = "3.10" + @exploits_registry.register class CVE20249487Exploit(webexploit.WebExploit): @@ -64,16 +68,18 @@ def check(self, target: definitions.Target) -> list[definitions.Vulnerability]: url=target_endpoint, data=self.check_request.data, ).prepare() - resp = session.send(req, timeout=DEFAULT_TIMEOUT) + resp = session.send(req, timeout=DEFAULT_TIMEOUT.seconds) except requests_exceptions.RequestException: return vulnerabilities - if (matched := self.version_pattern.findall(resp.text)) is not None: + if (matched := self.version_pattern.findall(resp.text)) != []: for extracted_version in matched: if isinstance(extracted_version, tuple): extracted_version = extracted_version[0] - if version.parse(extracted_version) < version.parse("3.15"): - if version.parse(extracted_version) < version.parse("3.10"): + if version.parse(extracted_version) < version.parse(MAX_FIXED_VERSION): + if version.parse(extracted_version) < version.parse( + MAX_NONFIXED_VERSION + ): vulnerability = self._create_vulnerability(target) vulnerabilities.append(vulnerability) continue From c349e5aecf1232660bec76aa0f218506d2d50950 Mon Sep 17 00:00:00 2001 From: ybadaoui-ostorlab Date: Wed, 16 Oct 2024 16:45:50 +0100 Subject: [PATCH 06/11] fix unittest docstrings --- tests/exploits/cve_2024_9487_test.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/exploits/cve_2024_9487_test.py b/tests/exploits/cve_2024_9487_test.py index 8b61c15..30f47f6 100644 --- a/tests/exploits/cve_2024_9487_test.py +++ b/tests/exploits/cve_2024_9487_test.py @@ -37,7 +37,7 @@ def testCVE20249487_whenVulnerable_reportFinding( def testCVE20249487_whenNotVulnerable_reportNothing( requests_mock: req_mock.mocker.Mocker, ) -> None: - """CVE_2024_9487 unit test: case when target is vulnerable.""" + """CVE_2024_9487 unit test: case when target is not vulnerable.""" requests_mock.get( "http://localhost:80/", text=""" @@ -60,7 +60,7 @@ def testCVE20249487_whenNotVulnerable_reportNothing( def testCVE20249487_whenVersionVeryOld_reportFinding( requests_mock: req_mock.mocker.Mocker, ) -> None: - """CVE_2024_9487 unit test: case when target is vulnerable.""" + """CVE_2024_9487 unit test: case when matched version is older that 3.11.""" requests_mock.get( "http://localhost:80/", text=""" @@ -88,7 +88,7 @@ def testCVE20249487_whenVersionVeryOld_reportFinding( def testCVE20249487_whenMultiVersions_doNotCrash( requests_mock: req_mock.mocker.Mocker, ) -> None: - """CVE_2024_9487 unit test: case when target is vulnerable.""" + """CVE_2024_9487 unit test: case when multible versions matched.""" requests_mock.get( "http://localhost:80/", text=""" From a489d16439ba9c6b146dc5ca04e34716afa88226 Mon Sep 17 00:00:00 2001 From: ybadaoui-ostorlab Date: Thu, 17 Oct 2024 11:55:43 +0100 Subject: [PATCH 07/11] remove multiversions handlers --- agent/exploits/cve_2024_9487.py | 29 +++++++++++++--------------- tests/exploits/cve_2024_9487_test.py | 25 +----------------------- 2 files changed, 14 insertions(+), 40 deletions(-) diff --git a/agent/exploits/cve_2024_9487.py b/agent/exploits/cve_2024_9487.py index 763f9bc..2d86ca6 100644 --- a/agent/exploits/cve_2024_9487.py +++ b/agent/exploits/cve_2024_9487.py @@ -73,20 +73,17 @@ def check(self, target: definitions.Target) -> list[definitions.Vulnerability]: return vulnerabilities if (matched := self.version_pattern.findall(resp.text)) != []: - for extracted_version in matched: - if isinstance(extracted_version, tuple): - extracted_version = extracted_version[0] - if version.parse(extracted_version) < version.parse(MAX_FIXED_VERSION): - if version.parse(extracted_version) < version.parse( - MAX_NONFIXED_VERSION - ): - vulnerability = self._create_vulnerability(target) - vulnerabilities.append(vulnerability) - continue - version_prefix = ".".join(extracted_version.split(".")[:2]) - if version.parse(extracted_version) < version.parse( - FIXED_VERSIONS[version_prefix] - ): - vulnerability = self._create_vulnerability(target) - vulnerabilities.append(vulnerability) + extracted_version = matched[0] + if version.parse(extracted_version) < version.parse(MAX_FIXED_VERSION): + version_prefix = ".".join(extracted_version.split(".")[:2]) + if version.parse(extracted_version) < version.parse( + MAX_NONFIXED_VERSION + ): + vulnerability = self._create_vulnerability(target) + vulnerabilities.append(vulnerability) + elif version.parse(extracted_version) < version.parse( + FIXED_VERSIONS[version_prefix] + ): + vulnerability = self._create_vulnerability(target) + vulnerabilities.append(vulnerability) return vulnerabilities diff --git a/tests/exploits/cve_2024_9487_test.py b/tests/exploits/cve_2024_9487_test.py index 30f47f6..422f422 100644 --- a/tests/exploits/cve_2024_9487_test.py +++ b/tests/exploits/cve_2024_9487_test.py @@ -83,27 +83,4 @@ def testCVE20249487_whenVersionVeryOld_reportFinding( "http://localhost:80 is vulnerable to CVE-2024-9487, " "GITHUB ENTERPRISE SERVER AUTHENTICATION BYPASS" ) - - -def testCVE20249487_whenMultiVersions_doNotCrash( - requests_mock: req_mock.mocker.Mocker, -) -> None: - """CVE_2024_9487 unit test: case when multible versions matched.""" - requests_mock.get( - "http://localhost:80/", - text=""" -
- GitHub Enterprise Server 3.14.2 - GitHub Enterprise Server 3.14.3 -
- """, - status_code=200, - ) - exploit_instance = cve_2024_9487.CVE20249487Exploit() - target = definitions.Target("http", "localhost", 80) - - accept = exploit_instance.accept(target) - vulnerabilities = exploit_instance.check(target) - - assert accept is True - assert len(vulnerabilities) == 0 + \ No newline at end of file From 91adb47c4057e26896416a8d0ed231eea2a38626 Mon Sep 17 00:00:00 2001 From: ybadaoui-ostorlab Date: Thu, 17 Oct 2024 12:01:37 +0100 Subject: [PATCH 08/11] fix lint --- tests/exploits/cve_2024_9487_test.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/exploits/cve_2024_9487_test.py b/tests/exploits/cve_2024_9487_test.py index 422f422..68513e6 100644 --- a/tests/exploits/cve_2024_9487_test.py +++ b/tests/exploits/cve_2024_9487_test.py @@ -83,4 +83,3 @@ def testCVE20249487_whenVersionVeryOld_reportFinding( "http://localhost:80 is vulnerable to CVE-2024-9487, " "GITHUB ENTERPRISE SERVER AUTHENTICATION BYPASS" ) - \ No newline at end of file From d8a11b3ca05e3617f14c88a593df99808d995159 Mon Sep 17 00:00:00 2001 From: ybadaoui-ostorlab Date: Thu, 17 Oct 2024 14:42:24 +0100 Subject: [PATCH 09/11] Resolve comments: put the vulnerabel versions on ranges and check if the extracted version is in one of them --- agent/exploits/cve_2024_9487.py | 55 +++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/agent/exploits/cve_2024_9487.py b/agent/exploits/cve_2024_9487.py index 2d86ca6..599a228 100644 --- a/agent/exploits/cve_2024_9487.py +++ b/agent/exploits/cve_2024_9487.py @@ -1,5 +1,3 @@ -"""Agent Asteroid implementation for CVE-2024-9487""" - import datetime import re from urllib import parse as urlparse @@ -20,16 +18,14 @@ leading to unauthorized user access. Exploitation required encrypted assertions, direct network access, and a signed SAML response or metadata. It affected versions before 3.15 and was fixed in 3.11.16, 3.12.10, 3.13.5, and 3.14.2. The vulnerability was reported through GitHub's Bug Bounty program.""" RISK_RATING = "CRITICAL" -FIXED_VERSIONS = { - "3.11": "3.11.6", - "3.12": "3.12.10", - "3.13": "3.13.5", - "3.14": "3.14.2", -} - -MAX_FIXED_VERSION = "3.15" -MAX_NONFIXED_VERSION = "3.10" +VULNERABLE_RANGES = [ + (None, "3.10"), + ("3.11.0", "3.11.5"), + ("3.12.0", "3.12.9"), + ("3.13.0", "3.13.4"), + ("3.14.0", "3.14.1"), +] @exploits_registry.register class CVE20249487Exploit(webexploit.WebExploit): @@ -74,16 +70,29 @@ def check(self, target: definitions.Target) -> list[definitions.Vulnerability]: if (matched := self.version_pattern.findall(resp.text)) != []: extracted_version = matched[0] - if version.parse(extracted_version) < version.parse(MAX_FIXED_VERSION): - version_prefix = ".".join(extracted_version.split(".")[:2]) - if version.parse(extracted_version) < version.parse( - MAX_NONFIXED_VERSION - ): - vulnerability = self._create_vulnerability(target) - vulnerabilities.append(vulnerability) - elif version.parse(extracted_version) < version.parse( - FIXED_VERSIONS[version_prefix] - ): - vulnerability = self._create_vulnerability(target) - vulnerabilities.append(vulnerability) + + if self.is_vulnerable(extracted_version): + vulnerability = self._create_vulnerability(target) + vulnerabilities.append(vulnerability) + return vulnerabilities + + def is_vulnerable(self, extracted_version: str) -> bool: + """Check if the extracted version is in the list of vulnerable ranges. + + Args: + extracted_version: Version of GitHub Enterprise Server + + Returns: + True if the version is vulnerable, False otherwise. + """ + extracted_ver = version.parse(extracted_version) + + for min_version, max_version in VULNERABLE_RANGES: + min_ver = version.parse(min_version) if min_version else None + max_ver = version.parse(max_version) + + if (min_ver is None or extracted_ver >= min_ver) and extracted_ver <= max_ver: + return True + + return False \ No newline at end of file From d5e53a6e87a10da2d4c37a5fc9d6af7927171f20 Mon Sep 17 00:00:00 2001 From: ybadaoui-ostorlab Date: Thu, 17 Oct 2024 14:43:01 +0100 Subject: [PATCH 10/11] fix lint --- agent/exploits/cve_2024_9487.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/agent/exploits/cve_2024_9487.py b/agent/exploits/cve_2024_9487.py index 599a228..a632864 100644 --- a/agent/exploits/cve_2024_9487.py +++ b/agent/exploits/cve_2024_9487.py @@ -27,6 +27,7 @@ ("3.14.0", "3.14.1"), ] + @exploits_registry.register class CVE20249487Exploit(webexploit.WebExploit): accept_request = definitions.Request(method="GET", path="/") @@ -92,7 +93,9 @@ def is_vulnerable(self, extracted_version: str) -> bool: min_ver = version.parse(min_version) if min_version else None max_ver = version.parse(max_version) - if (min_ver is None or extracted_ver >= min_ver) and extracted_ver <= max_ver: + if ( + min_ver is None or extracted_ver >= min_ver + ) and extracted_ver <= max_ver: return True - return False \ No newline at end of file + return False From 15c11db1678c24db5f673a1240f87ae86bd9bdd0 Mon Sep 17 00:00:00 2001 From: ybadaoui-ostorlab Date: Fri, 18 Oct 2024 09:50:55 +0100 Subject: [PATCH 11/11] resolve comments/use semver instead of packaging version and move _is_vulnerable function outside the class --- agent/exploits/cve_2024_9487.py | 37 ++++++++++++++++----------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/agent/exploits/cve_2024_9487.py b/agent/exploits/cve_2024_9487.py index a632864..569fb72 100644 --- a/agent/exploits/cve_2024_9487.py +++ b/agent/exploits/cve_2024_9487.py @@ -3,8 +3,8 @@ from urllib import parse as urlparse import requests -from packaging import version from requests import exceptions as requests_exceptions +from semver import Version from agent import definitions from agent import exploits_registry @@ -20,7 +20,7 @@ RISK_RATING = "CRITICAL" VULNERABLE_RANGES = [ - (None, "3.10"), + (None, "3.10.17"), ("3.11.0", "3.11.5"), ("3.12.0", "3.12.9"), ("3.13.0", "3.13.4"), @@ -72,30 +72,29 @@ def check(self, target: definitions.Target) -> list[definitions.Vulnerability]: if (matched := self.version_pattern.findall(resp.text)) != []: extracted_version = matched[0] - if self.is_vulnerable(extracted_version): + if _is_vulnerable(extracted_version) is True: vulnerability = self._create_vulnerability(target) vulnerabilities.append(vulnerability) return vulnerabilities - def is_vulnerable(self, extracted_version: str) -> bool: - """Check if the extracted version is in the list of vulnerable ranges. - Args: - extracted_version: Version of GitHub Enterprise Server +def _is_vulnerable(extracted_version: str) -> bool: + """Check if the extracted version is in the list of vulnerable ranges. - Returns: - True if the version is vulnerable, False otherwise. - """ - extracted_ver = version.parse(extracted_version) + Args: + extracted_version: Version of GitHub Enterprise Server + + Returns: + True if the version is vulnerable, False otherwise. + """ + extracted_ver = Version.parse(extracted_version) - for min_version, max_version in VULNERABLE_RANGES: - min_ver = version.parse(min_version) if min_version else None - max_ver = version.parse(max_version) + for min_version, max_version in VULNERABLE_RANGES: + min_ver = Version.parse(min_version) if min_version else None + max_ver = Version.parse(max_version) - if ( - min_ver is None or extracted_ver >= min_ver - ) and extracted_ver <= max_ver: - return True + if (min_ver is None or extracted_ver >= min_ver) and extracted_ver <= max_ver: + return True - return False + return False