Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add CVE-2014-2120 #136

Merged
merged 4 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions agent/exploits/cve_2014_2120.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
"""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

# Check for reflected XSS payloads (both vulnerable strings)
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
106 changes: 106 additions & 0 deletions tests/exploits/cve_2014_2120_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
"""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."""
# Mock the secure response
deadly-panda marked this conversation as resolved.
Show resolved Hide resolved
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/+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/+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
nmasdoufi-ol marked this conversation as resolved.
Show resolved Hide resolved
Loading