generated from Ostorlab/template_agent
-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #46 from Ostorlab/exploit/CVE-2024-21733
Add detection for: CVE-2024-21733
- Loading branch information
Showing
2 changed files
with
173 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
"""Agent Asteroid implementation for CVE-2024-21733""" | ||
import re | ||
from urllib import parse as urlparse | ||
|
||
import requests | ||
from ostorlab.agent.kb import kb | ||
from ostorlab.agent.mixins import agent_report_vulnerability_mixin | ||
from packaging import version | ||
from requests import exceptions as requests_exceptions | ||
|
||
from agent import definitions | ||
from agent import exploits_registry | ||
|
||
VULNERABILITY_TITLE = "Apache Tomcat HTTP Request Smuggling (Client- Side Desync)" | ||
VULNERABILITY_REFERENCE = "CVE-2024-21733" | ||
VULNERABILITY_DESCRIPTION = ( | ||
"Apache Tomcat from 8.5.7 through 8.5.63, from 9.0.0-M11 through 9.0.43 are vulnerable to client-side de-sync " | ||
"attacks. Client-side de-sync (CSD) vulnerabilities occur when a web server fails to correctly process the " | ||
"Content-Length of POST requests. By exploiting this behavior, an attacker can force a victim's browser to " | ||
"de-synchronize its connection with the website, causing sensitive data to be smuggled from the server and/or " | ||
"client connections." | ||
) | ||
|
||
DEFAULT_TIMEOUT = 30 | ||
ACCEPT_ENDPOINTS = [ | ||
"/docs/RELEASE-NOTES.txt", | ||
"/manager/status", | ||
"/manager/html", | ||
"/docs/introduction.html", | ||
] | ||
CHECK_ENDPOINTS = ["/docs/RELEASE-NOTES.txt", "/404", "/"] | ||
VERSION_PATTERN = re.compile(r"(?i)Apache Tomcat.*([0-9]\.[0-9]+\.[0-9]+)") | ||
VULNERABLE_RANGES = [ | ||
(version.parse("8.5.7"), version.parse("8.5.63")), | ||
(version.parse("9.0.0"), version.parse("9.0.43")), | ||
] | ||
MAX_REDIRECTS = 2 | ||
|
||
|
||
# TODO (BlueSquare1): Improve detection as part of request smuggling research project (os-6717). | ||
@exploits_registry.register | ||
class CVE202421733Exploit(definitions.Exploit): | ||
""" | ||
CVE-2024-21733: Apache Tomcat HTTP Request Smuggling (Client- Side Desync) | ||
""" | ||
|
||
def accept(self, target: definitions.Target) -> bool: | ||
session = requests.Session() | ||
session.max_redirects = MAX_REDIRECTS | ||
session.verify = False | ||
for endpoint in ACCEPT_ENDPOINTS: | ||
try: | ||
resp = session.get( | ||
urlparse.urljoin(target.origin, endpoint), | ||
timeout=DEFAULT_TIMEOUT, | ||
) | ||
except requests_exceptions.RequestException: | ||
continue | ||
if resp.status_code != 404: | ||
return True | ||
return False | ||
|
||
def check(self, target: definitions.Target) -> list[definitions.Vulnerability]: | ||
session = requests.Session() | ||
session.max_redirects = MAX_REDIRECTS | ||
session.verify = False | ||
for endpoint in CHECK_ENDPOINTS: | ||
try: | ||
resp = session.get( | ||
urlparse.urljoin(target.origin, endpoint), | ||
timeout=DEFAULT_TIMEOUT, | ||
) | ||
except requests_exceptions.RequestException: | ||
continue | ||
|
||
target_version_match = VERSION_PATTERN.search(resp.text) | ||
if target_version_match is None: | ||
continue | ||
|
||
target_version = version.parse(target_version_match.group(1)) | ||
for version_range in VULNERABLE_RANGES: | ||
if version_range[0] <= target_version <= version_range[1]: | ||
vulnerability = self._create_vulnerability(target) | ||
return [vulnerability] | ||
|
||
return [] | ||
|
||
def _create_vulnerability( | ||
self, target: definitions.Target | ||
) -> definitions.Vulnerability: | ||
entry = kb.Entry( | ||
title=VULNERABILITY_TITLE, | ||
risk_rating="CRITICAL", | ||
short_description=VULNERABILITY_DESCRIPTION, | ||
description=VULNERABILITY_DESCRIPTION, | ||
references={ | ||
"nvd.nist.gov": f"https://nvd.nist.gov/vuln/detail/{VULNERABILITY_REFERENCE}", | ||
"hackerone.com": "https://hackerone.com/reports/2327341", | ||
}, | ||
recommendation=( | ||
"- Make sure to install the latest security patches from software vendor \n" | ||
"- Update to the latest software version" | ||
), | ||
security_issue=True, | ||
privacy_issue=False, | ||
has_public_exploit=True, | ||
targeted_by_malware=False, | ||
targeted_by_ransomware=False, | ||
targeted_by_nation_state=False, | ||
) | ||
technical_detail = ( | ||
f"{target.origin} is vulnerable to {VULNERABILITY_REFERENCE}, " | ||
f"{VULNERABILITY_TITLE}" | ||
) | ||
vulnerability = definitions.Vulnerability( | ||
entry=entry, | ||
technical_detail=technical_detail, | ||
risk_rating=agent_report_vulnerability_mixin.RiskRating.CRITICAL, | ||
) | ||
return vulnerability |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
"""Unit tests for Agent Asteroid: CVE-2024-21733""" | ||
import re | ||
|
||
import requests_mock as req_mock | ||
|
||
from agent import definitions | ||
from agent.exploits import cve_2024_21733 | ||
|
||
|
||
def testCVE202421733_whenVulnerable_reportFinding( | ||
requests_mock: req_mock.mocker.Mocker, | ||
) -> None: | ||
"""CVE-2024-21733 unit test: case when target is vulnerable.""" | ||
exploit_instance = cve_2024_21733.CVE202421733Exploit() | ||
requests_mock.get( | ||
re.compile("http://localhost:8085"), | ||
text="<title>HTTP Status 403</title><h3>Apache Tomcat/9.0.43</h3>", | ||
status_code=403, | ||
) | ||
target = definitions.Target("http", "localhost", 8085) | ||
|
||
accept = exploit_instance.accept(target) | ||
vulnerabilities = exploit_instance.check(target) | ||
|
||
assert accept is True | ||
vulnerability = vulnerabilities[0] | ||
assert ( | ||
vulnerability.entry.title | ||
== "Apache Tomcat HTTP Request Smuggling (Client- Side Desync)" | ||
) | ||
assert vulnerability.technical_detail == ( | ||
"http://localhost:8085 is vulnerable to CVE-2024-21733, Apache Tomcat HTTP " | ||
"Request Smuggling (Client- Side Desync)" | ||
) | ||
|
||
|
||
def testCVE202421733_whenSafe_reportNothing( | ||
requests_mock: req_mock.mocker.Mocker, | ||
) -> None: | ||
"""CVE-2024-21733 unit test: case when target is safe.""" | ||
exploit_instance = cve_2024_21733.CVE202421733Exploit() | ||
requests_mock.get( | ||
re.compile("http://localhost"), | ||
text="<title>HTTP Status 403</title><h3>Apache Tomcat/9.0.73</h3>", | ||
status_code=403, | ||
) | ||
target = definitions.Target("http", "localhost", 8089) | ||
|
||
accept = exploit_instance.accept(target) | ||
vulnerabilities = exploit_instance.check(target) | ||
|
||
assert accept is True | ||
assert len(vulnerabilities) == 0 |