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 Detection for CVE-2024-11639 #158

Merged
merged 3 commits into from
Dec 13, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
"""Agent Asteroid implementation for CVE-2024-8963"""

import re
import logging
import datetime
Expand All @@ -12,22 +10,21 @@
from agent import exploits_registry
from agent import definitions


VULNERABILITY_TITLE = "Path Traversal in Ivanti CSA"
VULNERABILITY_REFERENCE = "CVE-2024-8963"
VULNERABILITY_DESCRIPTION = """Path Traversal in the Ivanti CSA before 4.6 Patch 519 allows a remote unauthenticated attacker to access restricted functionality."""
VULNERABILITY_TITLE = "Authentication Bypass in Ivanti CSA Admin Console"
VULNERABILITY_REFERENCE = "CVE-2024-11639"
VULNERABILITY_DESCRIPTION = """An authentication bypass in the admin web console of Ivanti CSA before 5.0.3 allows a remote unauthenticated attacker to gain administrative access."""
RISK_RATING = "CRITICAL"

"""Ivanti has released a security advisory for CVE-2024-8963, a critical vulnerability in Ivanti CSA 4.6 which was
incidentally addressed in its patch for CVE-2024-8190, which was released on September 10, 2024 (CSA 4.6 Patch 519)."""
PATCH_DATE = datetime.datetime(2024, 9, 10)
PATCH_DATE = datetime.datetime(
2024, 12, 10, 17, 58, 17
) # Based on Last Modified Date in advisory

nmasdoufi-ol marked this conversation as resolved.
Show resolved Hide resolved
DEFAULT_TIMEOUT = 90
HEADER_LAST_MODIFIED = "Last-Modified"
HEADER_IF_MODIFIED_SINCE = "Last-Modified"


@exploits_registry.register
class CVE20248963Exploit(webexploit.WebExploit):
class CVE202411639Exploit(webexploit.WebExploit):
accept_request = definitions.Request(method="GET", path="/")
check_request = definitions.Request(method="GET", path="/allowed/ivanti-logo.png")
accept_pattern = [
Expand Down Expand Up @@ -61,12 +58,12 @@ def check(self, target: definitions.Target) -> list[definitions.Vulnerability]:
logging.error("HTTP Request failed: %s", e)
return []

if HEADER_LAST_MODIFIED not in resp.headers:
if HEADER_IF_MODIFIED_SINCE not in resp.headers:
return []
nmasdoufi-ol marked this conversation as resolved.
Show resolved Hide resolved
nmasdoufi-ol marked this conversation as resolved.
Show resolved Hide resolved

try:
last_modified = datetime.datetime.strptime(
resp.headers[HEADER_LAST_MODIFIED], "%a, %d %b %Y %H:%M:%S %Z"
resp.headers[HEADER_IF_MODIFIED_SINCE], "%a, %d %b %Y %H:%M:%S %Z"
)
nmasdoufi-ol marked this conversation as resolved.
Show resolved Hide resolved
except ValueError as e:
logging.error("Couldn't parse date string and format: %s", e)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
"""Unit tests for Agent Asteroid: CVE-2024-8963"""
"""Unit tests for Agent Asteroid: CVE-2024-11639"""

import requests
import requests_mock as req_mock

from agent import definitions
from agent.exploits import cve_2024_8963
from agent.exploits import cve_2024_11639


def testCVE20248963_whenVulnerable_reportFinding(
def testCVE202411639_whenVulnerable_reportFinding(
requests_mock: req_mock.mocker.Mocker,
nmasdoufi-ol marked this conversation as resolved.
Show resolved Hide resolved
) -> None:
"""CVE-2024-8963 unit test: case when target is vulnerable."""
"""CVE-2024-11639 unit test: case when target is vulnerable."""
vulnerable_date = "Fri, 03 Dec 2021 19:45:52 GMT"
requests_mock.get(
"http://localhost:80/",
Expand All @@ -23,44 +23,46 @@ def testCVE20248963_whenVulnerable_reportFinding(
content=b"PNG",
status_code=200,
)
exploit_instance = cve_2024_8963.CVE20248963Exploit()
exploit_instance = cve_2024_11639.CVE202411639Exploit()
target = definitions.Target("http", "localhost", 80)

accept = exploit_instance.accept(target)
vulnerabilities = exploit_instance.check(target)

assert accept is True
vulnerability = vulnerabilities[0]
assert vulnerability.entry.title == "Path Traversal in Ivanti CSA"
assert (
vulnerability.entry.title == "Authentication Bypass in Ivanti CSA Admin Console"
)
assert vulnerability.technical_detail == (
"http://localhost:80 is vulnerable to CVE-2024-8963, "
"Path Traversal in Ivanti CSA"
"http://localhost:80 is vulnerable to CVE-2024-11639, "
"Authentication Bypass in Ivanti CSA Admin Console"
)


def testCVE20248963_whenSafe_reportNothing(
def testCVE202411639_whenSafe_reportNothing(
requests_mock: req_mock.mocker.Mocker,
nmasdoufi-ol marked this conversation as resolved.
Show resolved Hide resolved
) -> None:
"""CVE-2024-8963 unit test: case when target is safe."""
safe_date = "Fri, 03 Dec 2024 19:45:52 GMT"
"""CVE-2024-11639 unit test: case when target is safe."""
safe_date = "Fri, 11 Dec 2024 19:45:52 GMT"
requests_mock.get(
"http://localhost:80/allowed/ivanti-logo.png",
headers={"Last-Modified": safe_date},
content=b"PNG",
status_code=200,
)
exploit_instance = cve_2024_8963.CVE20248963Exploit()
exploit_instance = cve_2024_11639.CVE202411639Exploit()
target = definitions.Target("http", "localhost", 80)

vulnerabilities = exploit_instance.check(target)

assert len(vulnerabilities) == 0


def testCVE20248963_whenInvalidLastModifiedFormat_doesNotCrash(
def testCVE202411639_whenInvalidIfModifiedSinceFormat_doesNotCrash(
requests_mock: req_mock.mocker.Mocker,
nmasdoufi-ol marked this conversation as resolved.
Show resolved Hide resolved
) -> None:
"""CVE-2024-8963 unit test: case when Last-Modified header has invalid format."""
"""CVE-2024-11639 unit test: case when Last-Modified header has invalid format."""
requests_mock.get(
"http://localhost:80/",
text="<title>Ivanti(R) Cloud Services Appliance</title>",
Expand All @@ -72,7 +74,7 @@ def testCVE20248963_whenInvalidLastModifiedFormat_doesNotCrash(
content=b"PNG",
status_code=200,
)
exploit_instance = cve_2024_8963.CVE20248963Exploit()
exploit_instance = cve_2024_11639.CVE202411639Exploit()
target = definitions.Target("http", "localhost", 80)

accept = exploit_instance.accept(target)
Expand All @@ -82,32 +84,32 @@ def testCVE20248963_whenInvalidLastModifiedFormat_doesNotCrash(
assert len(vulnerabilities) == 0


def testCVE20248963_whenRequestException_doesNotCrash(
def testCVE202411639_whenRequestException_doesNotCrash(
requests_mock: req_mock.mocker.Mocker,
nmasdoufi-ol marked this conversation as resolved.
Show resolved Hide resolved
) -> None:
"""CVE-2024-8963 unit test: case when a request exception occurs."""
"""CVE-2024-11639 unit test: case when a request exception occurs."""
requests_mock.get(
"http://localhost:80/allowed/ivanti-logo.png",
exc=requests.RequestException("Connection error"),
)
exploit_instance = cve_2024_8963.CVE20248963Exploit()
exploit_instance = cve_2024_11639.CVE202411639Exploit()
target = definitions.Target("http", "localhost", 80)

vulnerabilities = exploit_instance.check(target)

assert len(vulnerabilities) == 0


def testCVE20248963_whenNotIvantiCSA_doesNotAccept(
def testCVE202411639_whenNotIvantiCSA_doesNotAccept(
requests_mock: req_mock.mocker.Mocker,
nmasdoufi-ol marked this conversation as resolved.
Show resolved Hide resolved
) -> None:
"""CVE-2024-8963 unit test: case when target is not Ivanti CSA."""
"""CVE-2024-11639 unit test: case when target is not Ivanti CSA."""
requests_mock.get(
"http://localhost:80/",
text="<title>Not Ivanti CSA</title>",
status_code=200,
)
exploit_instance = cve_2024_8963.CVE20248963Exploit()
exploit_instance = cve_2024_11639.CVE202411639Exploit()
target = definitions.Target("http", "localhost", 80)

accept = exploit_instance.accept(target)
Expand Down
Loading