diff --git a/agent/exploits/cve_2024_11667.py b/agent/exploits/cve_2024_11667.py new file mode 100644 index 0000000..2110cd3 --- /dev/null +++ b/agent/exploits/cve_2024_11667.py @@ -0,0 +1,100 @@ +"""Agent Asteroid implementation for CVE-2024-11667""" + +import re +import datetime +from urllib import parse as urlparse + +from requests import exceptions as requests_exceptions + +from agent import definitions +from agent import exploits_registry +from agent.exploits import webexploit + +VULNERABILITY_TITLE = ( + "Zyxel ATP/USG FLEX/USG FLEX 50(W)/USG20(W)-VPN UP TO 5.38 URL PATH TRAVERSAL" +) +VULNERABILITY_REFERENCE = "CVE-2024-11667" +VULNERABILITY_DESCRIPTION = ( + "A directory traversal vulnerability in the web management interface of " + "Zyxel ATP series firmware versions V5.00 through V5.38, USG FLEX series " + "firmware versions V5.00 through V5.38, USG FLEX 50(W) series firmware " + "versions V5.10 through V5.38, and USG20(W)-VPN series firmware versions " + "V5.10 through V5.38 could allow an attacker to download or upload files via a crafted URL." +) +RISK_RATING = "CRITICAL" +DEFAULT_TIMEOUT = datetime.timedelta(seconds=90) + +VERSION_THRESHOLDS = { + "USG FLEX ATP": 210507, + "USG 20W": 210928, + "USG FLEX 50": 210928, + "USG FLEX 50W": 210928, + "USG FLEX 100": 210513, + "USG FLEX 200": 210513, + "USG FLEX 500": 210513, + "USG FLEX 700": 210513, +} + +MAX_VULNERABLE_VERSION = 240329 +FAVICON_VERSION_PATTERN = re.compile(r"/favicon.ico\?v=(\d+)") + + +@exploits_registry.register +class CVE202411667Exploit(webexploit.WebExploit): + accept_request = definitions.Request(method="GET", path="/") + check_request = definitions.Request(method="GET", path="/") + # Clear without const + accept_pattern = [ + re.compile(r"USG FLEX (50|100|200|500|700|50W)"), + re.compile(r"USG FLEX ATP (700|100|200)"), + re.compile(r"USG 20W"), + ] + + 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]: + """Check for vulnerability in the target.""" + vulnerabilities: list[definitions.Vulnerability] = [] + target_endpoint = urlparse.urljoin(target.origin, self.check_request.path) + + try: + response = self.session.get( + target_endpoint, timeout=DEFAULT_TIMEOUT.seconds, verify=False + ) + response.raise_for_status() + except requests_exceptions.RequestException: + return vulnerabilities + + # Determine the minimum threshold for a detected device type + min_vulnerable_version = None + for device_type, threshold in VERSION_THRESHOLDS.items(): + if device_type in response.text: + min_vulnerable_version = threshold + break + + if min_vulnerable_version is None: + return vulnerabilities + + # Extract and validate the favicon version + favicon_match = FAVICON_VERSION_PATTERN.search(response.text) + if favicon_match is None: + return vulnerabilities + + try: + extracted_version = int( + favicon_match.group(1)[:6] + ) # Keep only the first 6 digits + except ValueError: + return vulnerabilities + + # Check if the version is within the vulnerable range + if min_vulnerable_version <= extracted_version <= MAX_VULNERABLE_VERSION: + vulnerability = self._create_vulnerability(target) + vulnerabilities.append(vulnerability) + + return vulnerabilities diff --git a/tests/exploits/cve_2024_11667_test.py b/tests/exploits/cve_2024_11667_test.py new file mode 100644 index 0000000..0e7795e --- /dev/null +++ b/tests/exploits/cve_2024_11667_test.py @@ -0,0 +1,115 @@ +"""Unit tests for Agent Asteroid: CVE-2024-11667""" + +import requests +import requests_mock as req_mock + +from agent import definitions +from agent.exploits import cve_2024_11667 + + +def create_mock_response(device_type: str, version: str) -> str: + """Create a mock HTML response with the given device type and version.""" + return f""" + + +
+