Skip to content

Commit

Permalink
Merge pull request #136 from Ostorlab/feature/cve-2014-2120
Browse files Browse the repository at this point in the history
  • Loading branch information
3asm authored Nov 15, 2024
2 parents 197f8e6 + d02683c commit 96ba13a
Show file tree
Hide file tree
Showing 2 changed files with 177 additions and 0 deletions.
70 changes: 70 additions & 0 deletions agent/exploits/cve_2014_2120.py
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
107 changes: 107 additions & 0 deletions tests/exploits/cve_2014_2120_test.py
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&quot;">
<input type="hidden" name="username" value="&quot;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

0 comments on commit 96ba13a

Please sign in to comment.