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 #136 from Ostorlab/feature/cve-2014-2120
Add CVE-2014-2120
- Loading branch information
Showing
2 changed files
with
177 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,70 @@ | ||
"""Agent Asteroid implementation for CVE-2014-2120""" | ||
|
||
import re | ||
from urllib import parse as urlparse | ||
import datetime | ||
|
||
from requests import exceptions as requests_exceptions | ||
|
||
from agent import definitions | ||
from agent.exploits import webexploit | ||
from agent import exploits_registry | ||
|
||
VULNERABILITY_TITLE = "Cisco ASA WebVPN Login Page XSS Vulnerability" | ||
VULNERABILITY_REFERENCE = "CVE-2014-2120" | ||
VULNERABILITY_DESCRIPTION = ( | ||
"Cisco Cisco Adaptive Security Appliance (ASA) SSL VPN is prone to a cross-site scripting (XSS) vulnerability." | ||
"The flaw is due to an error in password recovery form which fails to filter properly the hidden inputs." | ||
) | ||
RISK_RATING = "HIGH" | ||
DEFAULT_TIMEOUT = datetime.timedelta(seconds=90) | ||
|
||
REFLECTED_XSS_TEST_STRING = "test123\"'" | ||
SAFE_STRING = "test123"" | ||
VULNERABLE_STRINGS = ["test123\"'", "test123\\\"'"] | ||
|
||
|
||
@exploits_registry.register | ||
class CVE20142120XSSExploit(webexploit.WebExploit): | ||
accept_request = definitions.Request( | ||
method="GET", | ||
path="/+CSCOE+/logon.html?reason=2&a0=63&a1=&a2=&a3=0&next=&auth_handle=&status=0&username=test&password_min=0&state=&tgroup=&serverType=0&password_", | ||
) | ||
accept_pattern = [ | ||
re.compile("Password expired, you must enter a new password to continue.") | ||
] | ||
|
||
check_request = definitions.Request( | ||
method="GET", | ||
path="/+CSCOE+/logon.html?reason=2&a0=63&a1=&a2=&a3=0&next=&auth_handle={}&status=0&username={}&password_min=0&state=&tgroup=&serverType=0&password_days=0".format( | ||
REFLECTED_XSS_TEST_STRING, REFLECTED_XSS_TEST_STRING | ||
), | ||
) | ||
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 if the target reflects unsanitized input in the response.""" | ||
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 | ||
) | ||
response.raise_for_status() | ||
|
||
except requests_exceptions.RequestException: | ||
return vulnerabilities | ||
|
||
for vuln_str in VULNERABLE_STRINGS: | ||
if vuln_str in response.text and SAFE_STRING not in response.text: | ||
vulnerability = self._create_vulnerability(target) | ||
vulnerabilities.append(vulnerability) | ||
break | ||
|
||
return vulnerabilities |
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,107 @@ | ||
"""Unit tests for Agent Asteroid: CVE-2014-2120""" | ||
|
||
import requests | ||
import requests_mock as req_mock | ||
|
||
from agent import definitions | ||
from agent.exploits import cve_2014_2120 | ||
|
||
|
||
def create_mock_vulnerable_response() -> str: | ||
"""Create a mock HTML response with the XSS vulnerability reflected.""" | ||
return """ | ||
<html> | ||
<body> | ||
<input type="hidden" name="auth_handle" value="test123"'"> | ||
<input type="hidden" name="username" value="test123"'"> | ||
</body> | ||
</html> | ||
""" | ||
|
||
|
||
def create_mock_secure_response() -> str: | ||
"""Create a mock HTML response without the XSS vulnerability reflected.""" | ||
return """ | ||
<html> | ||
<body> | ||
<input type="hidden" name="auth_handle" value="test123""> | ||
<input type="hidden" name="username" value=""test123"> | ||
</body> | ||
</html> | ||
""" | ||
|
||
|
||
def testCVE20142120_whenVulnerable_reportFinding( | ||
requests_mock: req_mock.mocker.Mocker, | ||
) -> None: | ||
"""Unit test for CVE-2014-2120: case when target is vulnerable.""" | ||
|
||
requests_mock.get( | ||
"http://localhost:80/+CSCOE+/logon.html?reason=2&a0=63&a1=&a2=&a3=0&next=&auth_handle=test123%22'&status=0&username=test123%22'&password_min=0&state=&tgroup=&serverType=0&password_days=0", | ||
text=create_mock_vulnerable_response(), | ||
status_code=200, | ||
) | ||
|
||
exploit_instance = cve_2014_2120.CVE20142120XSSExploit() | ||
target = definitions.Target("http", "localhost", 80) | ||
|
||
vulnerabilities = exploit_instance.check(target) | ||
|
||
assert len(vulnerabilities) > 0 | ||
vulnerability = vulnerabilities[0] | ||
assert vulnerability.entry.title == "Cisco ASA WebVPN Login Page XSS Vulnerability" | ||
assert vulnerability.technical_detail == ( | ||
"http://localhost:80 is vulnerable to CVE-2014-2120, Cisco ASA WebVPN Login Page XSS Vulnerability" | ||
) | ||
|
||
|
||
def testCVE20142120_whenSecure_reportNothing( | ||
requests_mock: req_mock.mocker.Mocker, | ||
) -> None: | ||
"""Unit test for CVE-2014-2120: case when target is secure.""" | ||
requests_mock.get( | ||
"http://localhost:80/+CSCOE+/logon.html?reason=2&a0=63&a1=&a2=&a3=0&next=&auth_handle=test123\"'&status=0&username=test123\"'&password_min=0&state=&tgroup=&serverType=0&password_days=0", | ||
text=create_mock_secure_response(), | ||
status_code=200, | ||
) | ||
|
||
exploit_instance = cve_2014_2120.CVE20142120XSSExploit() | ||
target = definitions.Target("http", "localhost", 80) | ||
|
||
vulnerabilities = exploit_instance.check(target) | ||
|
||
assert len(vulnerabilities) == 0 | ||
|
||
|
||
def testCVE20142120_whenConnectionError_reportNothing( | ||
requests_mock: req_mock.mocker.Mocker, | ||
) -> None: | ||
"""Unit test for CVE-2014-2120: case when a connection error occurs.""" | ||
requests_mock.get( | ||
"http://localhost:80/+CSCOE+/logon.html?reason=2&a0=63&a1=&a2=&a3=0&next=&auth_handle=test123\"'&status=0&username=test123\"'&password_min=0&state=&tgroup=&serverType=0&password_days=0", | ||
exc=requests.exceptions.ConnectionError, | ||
) | ||
|
||
exploit_instance = cve_2014_2120.CVE20142120XSSExploit() | ||
target = definitions.Target("http", "localhost", 80) | ||
|
||
vulnerabilities = exploit_instance.check(target) | ||
|
||
assert len(vulnerabilities) == 0 | ||
|
||
|
||
def testCVE20142120_whenTimeout_reportNothing( | ||
requests_mock: req_mock.mocker.Mocker, | ||
) -> None: | ||
"""Unit test for CVE-2014-2120: case when a timeout occurs.""" | ||
requests_mock.get( | ||
"http://localhost:80/+CSCOE+/logon.html?reason=2&a0=63&a1=&a2=&a3=0&next=&auth_handle=test123\"'&status=0&username=test123\"'&password_min=0&state=&tgroup=&serverType=0&password_days=0", | ||
exc=requests.exceptions.Timeout, | ||
) | ||
|
||
exploit_instance = cve_2014_2120.CVE20142120XSSExploit() | ||
target = definitions.Target("http", "localhost", 80) | ||
|
||
vulnerabilities = exploit_instance.check(target) | ||
|
||
assert len(vulnerabilities) == 0 |