From 3f687f6aea0ff5c824a43eb894a92bfd555df90e Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Mon, 8 Mar 2021 11:02:15 +0200 Subject: [PATCH 1/7] Moved common config value paths to common --- .../config_schema => common}/config_value_paths.py | 0 .../cc/services/attack/technique_reports/T1065.py | 2 +- monkey/monkey_island/cc/services/config.py | 8 ++++---- monkey/monkey_island/cc/services/configuration/utils.py | 2 +- monkey/monkey_island/cc/services/reporting/report.py | 6 +++--- .../zero_trust/scoutsuite/scoutsuite_auth_service.py | 2 +- .../zero_trust/scoutsuite/test_scoutsuite_auth_service.py | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) rename monkey/{monkey_island/cc/services/config_schema => common}/config_value_paths.py (100%) diff --git a/monkey/monkey_island/cc/services/config_schema/config_value_paths.py b/monkey/common/config_value_paths.py similarity index 100% rename from monkey/monkey_island/cc/services/config_schema/config_value_paths.py rename to monkey/common/config_value_paths.py diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1065.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1065.py index c3fcd03e8..3b18be488 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1065.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1065.py @@ -4,7 +4,7 @@ from monkey_island.cc.services.config import ConfigService __author__ = "VakarisZ" -from monkey_island.cc.services.config_schema.config_value_paths import CURRENT_SERVER_PATH +from common.config_value_paths import CURRENT_SERVER_PATH class T1065(AttackTechnique): diff --git a/monkey/monkey_island/cc/services/config.py b/monkey/monkey_island/cc/services/config.py index b4370a63b..390380131 100644 --- a/monkey/monkey_island/cc/services/config.py +++ b/monkey/monkey_island/cc/services/config.py @@ -14,10 +14,10 @@ from monkey_island.cc.services.config_schema.config_schema import SCHEMA __author__ = "itay.mizeretz" -from monkey_island.cc.services.config_schema.config_value_paths import (AWS_KEYS_PATH, EXPORT_MONKEY_TELEMS_PATH, - LM_HASH_LIST_PATH, NTLM_HASH_LIST_PATH, - PASSWORD_LIST_PATH, SSH_KEYS_PATH, - STARTED_ON_ISLAND_PATH, USER_LIST_PATH) +from common.config_value_paths import (AWS_KEYS_PATH, EXPORT_MONKEY_TELEMS_PATH, + LM_HASH_LIST_PATH, NTLM_HASH_LIST_PATH, + PASSWORD_LIST_PATH, SSH_KEYS_PATH, + STARTED_ON_ISLAND_PATH, USER_LIST_PATH) logger = logging.getLogger(__name__) diff --git a/monkey/monkey_island/cc/services/configuration/utils.py b/monkey/monkey_island/cc/services/configuration/utils.py index 48857e2e3..493d5af03 100644 --- a/monkey/monkey_island/cc/services/configuration/utils.py +++ b/monkey/monkey_island/cc/services/configuration/utils.py @@ -1,5 +1,5 @@ from monkey_island.cc.services.config import ConfigService -from monkey_island.cc.services.config_schema.config_value_paths import INACCESSIBLE_SUBNETS_PATH +from common.config_value_paths import INACCESSIBLE_SUBNETS_PATH def get_config_network_segments_as_subnet_groups(): diff --git a/monkey/monkey_island/cc/services/reporting/report.py b/monkey/monkey_island/cc/services/reporting/report.py index 5970a33b7..a23aa6d85 100644 --- a/monkey/monkey_island/cc/services/reporting/report.py +++ b/monkey/monkey_island/cc/services/reporting/report.py @@ -12,9 +12,9 @@ from monkey_island.cc.database import mongo from monkey_island.cc.models import Monkey from monkey_island.cc.services.utils.network_utils import get_subnets, local_ip_addresses from monkey_island.cc.services.config import ConfigService -from monkey_island.cc.services.config_schema.config_value_paths import (EXPLOITER_CLASSES_PATH, LOCAL_NETWORK_SCAN_PATH, - PASSWORD_LIST_PATH, SUBNET_SCAN_LIST_PATH, - USER_LIST_PATH) +from common.config_value_paths import (EXPLOITER_CLASSES_PATH, LOCAL_NETWORK_SCAN_PATH, + PASSWORD_LIST_PATH, SUBNET_SCAN_LIST_PATH, + USER_LIST_PATH) from monkey_island.cc.services.configuration.utils import get_config_network_segments_as_subnet_groups from monkey_island.cc.services.node import NodeService from monkey_island.cc.services.reporting.pth_report import PTHReportService diff --git a/monkey/monkey_island/cc/services/zero_trust/scoutsuite/scoutsuite_auth_service.py b/monkey/monkey_island/cc/services/zero_trust/scoutsuite/scoutsuite_auth_service.py index dc3f8d5ee..b5d405234 100644 --- a/monkey/monkey_island/cc/services/zero_trust/scoutsuite/scoutsuite_auth_service.py +++ b/monkey/monkey_island/cc/services/zero_trust/scoutsuite/scoutsuite_auth_service.py @@ -6,7 +6,7 @@ from common.cloud.scoutsuite_consts import CloudProviders from common.utils.exceptions import InvalidAWSKeys from monkey_island.cc.server_utils.encryptor import encryptor from monkey_island.cc.services.config import ConfigService -from monkey_island.cc.services.config_schema.config_value_paths import AWS_KEYS_PATH +from common.config_value_paths import AWS_KEYS_PATH def is_cloud_authentication_setup(provider: CloudProviders) -> Tuple[bool, str]: diff --git a/monkey/monkey_island/cc/services/zero_trust/scoutsuite/test_scoutsuite_auth_service.py b/monkey/monkey_island/cc/services/zero_trust/scoutsuite/test_scoutsuite_auth_service.py index 24e700ce6..c35e55a8f 100644 --- a/monkey/monkey_island/cc/services/zero_trust/scoutsuite/test_scoutsuite_auth_service.py +++ b/monkey/monkey_island/cc/services/zero_trust/scoutsuite/test_scoutsuite_auth_service.py @@ -6,7 +6,7 @@ import dpath.util from monkey_island.cc.database import mongo from monkey_island.cc.server_utils import encryptor from monkey_island.cc.services.config import ConfigService -from monkey_island.cc.services.config_schema.config_value_paths import AWS_KEYS_PATH +from common.config_value_paths import AWS_KEYS_PATH from monkey_island.cc.services.zero_trust.scoutsuite.scoutsuite_auth_service import is_aws_keys_setup from monkey_island.cc.test_common.fixtures import FixtureEnum From f6b068229735383fc9f65833b7e430494956b5cb Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Mon, 8 Mar 2021 11:07:24 +0200 Subject: [PATCH 2/7] Added ZeroLogon test to the BlackBox infrastructure. --- .../monkey_zoo/blackbox/analyzers/analyzer.py | 2 +- .../blackbox/analyzers/zerologon_analyzer.py | 42 +++++++++++++++++++ .../blackbox/island_configs/zerologon.py | 13 ++++++ envs/monkey_zoo/blackbox/test_blackbox.py | 17 ++++++++ 4 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 envs/monkey_zoo/blackbox/analyzers/zerologon_analyzer.py create mode 100644 envs/monkey_zoo/blackbox/island_configs/zerologon.py diff --git a/envs/monkey_zoo/blackbox/analyzers/analyzer.py b/envs/monkey_zoo/blackbox/analyzers/analyzer.py index d6043feeb..13db46cb3 100644 --- a/envs/monkey_zoo/blackbox/analyzers/analyzer.py +++ b/envs/monkey_zoo/blackbox/analyzers/analyzer.py @@ -4,5 +4,5 @@ from abc import ABCMeta, abstractmethod class Analyzer(object, metaclass=ABCMeta): @abstractmethod - def analyze_test_results(self): + def analyze_test_results(self) -> bool: raise NotImplementedError() diff --git a/envs/monkey_zoo/blackbox/analyzers/zerologon_analyzer.py b/envs/monkey_zoo/blackbox/analyzers/zerologon_analyzer.py new file mode 100644 index 000000000..691724830 --- /dev/null +++ b/envs/monkey_zoo/blackbox/analyzers/zerologon_analyzer.py @@ -0,0 +1,42 @@ +from typing import List + +import dpath.util + +from common.config_value_paths import USER_LIST_PATH, PASSWORD_LIST_PATH, NTLM_HASH_LIST_PATH, LM_HASH_LIST_PATH +from envs.monkey_zoo.blackbox.analyzers.analyzer import Analyzer +from envs.monkey_zoo.blackbox.analyzers.analyzer_log import AnalyzerLog +from envs.monkey_zoo.blackbox.island_client.monkey_island_client import MonkeyIslandClient + +# Query for telemetry collection to see if password restoration was successful +TELEM_QUERY = {'telem_category': 'exploit', + 'data.exploiter': 'ZerologonExploiter', + 'data.info.password_restored': True} + + +class ZeroLogonAnalyzer(Analyzer): + + def __init__(self, island_client: MonkeyIslandClient, expected_credentials: List[str]): + self.island_client = island_client + self.expected_credentials = expected_credentials + self.log = AnalyzerLog(self.__class__.__name__) + + def analyze_test_results(self): + self.log.clear() + return self._analyze_credential_gathering() and self._analyze_credential_restore() + + def _analyze_credential_gathering(self) -> bool: + credentials_on_island = [] + config = self.island_client.get_config() + credentials_on_island.extend(dpath.util.get(config['configuration'], USER_LIST_PATH)) + credentials_on_island.extend(dpath.util.get(config['configuration'], NTLM_HASH_LIST_PATH)) + credentials_on_island.extend(dpath.util.get(config['configuration'], LM_HASH_LIST_PATH)) + return ZeroLogonAnalyzer._is_all_credentials_in_list(self.expected_credentials, + credentials_on_island) + + @staticmethod + def _is_all_credentials_in_list(expected_creds: List[str], + all_creds: List[str]) -> bool: + return all((cred in all_creds) for cred in expected_creds) + + def _analyze_credential_restore(self) -> bool: + return bool(self.island_client.find_telems_in_db(TELEM_QUERY)) diff --git a/envs/monkey_zoo/blackbox/island_configs/zerologon.py b/envs/monkey_zoo/blackbox/island_configs/zerologon.py new file mode 100644 index 000000000..725fa91b9 --- /dev/null +++ b/envs/monkey_zoo/blackbox/island_configs/zerologon.py @@ -0,0 +1,13 @@ +from copy import copy + +from envs.monkey_zoo.blackbox.island_configs.base_template import BaseTemplate + + +class ZeroLogon(BaseTemplate): + + config_values = copy(BaseTemplate.config_values) + + config_values.update({ + "basic.exploiters.exploiter_classes": ["ZerologonExploiter"], + "basic_network.scope.subnet_scan_list": ["10.2.2.25"] + }) diff --git a/envs/monkey_zoo/blackbox/test_blackbox.py b/envs/monkey_zoo/blackbox/test_blackbox.py index d895f7cfe..7560b5d42 100644 --- a/envs/monkey_zoo/blackbox/test_blackbox.py +++ b/envs/monkey_zoo/blackbox/test_blackbox.py @@ -7,6 +7,7 @@ from typing_extensions import Type 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.island_client.island_config_parser import \ IslandConfigParser from envs.monkey_zoo.blackbox.island_client.monkey_island_client import \ @@ -25,6 +26,7 @@ from envs.monkey_zoo.blackbox.island_configs.tunneling import Tunneling from envs.monkey_zoo.blackbox.island_configs.weblogic import Weblogic from envs.monkey_zoo.blackbox.island_configs.wmi_mimikatz import WmiMimikatz from envs.monkey_zoo.blackbox.island_configs.wmi_pth import WmiPth +from envs.monkey_zoo.blackbox.island_configs.zerologon import ZeroLogon from envs.monkey_zoo.blackbox.log_handlers.test_logs_handler import \ TestLogsHandler from envs.monkey_zoo.blackbox.tests.exploitation import ExploitationTest @@ -160,6 +162,21 @@ class TestMonkeyBlackbox: def test_wmi_pth(self, island_client): TestMonkeyBlackbox.run_exploitation_test(island_client, WmiPth, "WMI_PTH") + def test_zerologon_exploiter(self, island_client): + test_name = "ZeroLogon_exploiter" + expected_creds = ["test_username", "test_ntlm_hash"] + raw_config = IslandConfigParser.get_raw_config(ZeroLogon, island_client) + analyzer = ZeroLogonAnalyzer(island_client, expected_creds) + log_handler = TestLogsHandler(test_name, island_client, TestMonkeyBlackbox.get_log_dir_path()) + ExploitationTest( + name=test_name, + island_client=island_client, + raw_config=raw_config, + analyzers=[analyzer], + timeout=DEFAULT_TIMEOUT_SECONDS, + log_handler=log_handler).run() + TestMonkeyBlackbox.run_exploitation_test(island_client, ZeroLogon, "ZeroLogon_exploiter") + @pytest.mark.skip(reason="Perfomance test that creates env from fake telemetries is faster, use that instead.") def test_report_generation_performance(self, island_client, quick_performance_tests): """ From 263fa53ea558d9e5065135827ea7375d8c377640 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Mon, 8 Mar 2021 11:13:31 +0200 Subject: [PATCH 3/7] Added an endpoint on the island for telemetry tests. This allows for tests like blackbox tests to send queries and check whether a certain telemetry is in the database or not --- .../blackbox/island_client/monkey_island_client.py | 11 ++++++++++- monkey/monkey_island/cc/app.py | 3 +++ .../cc/resources/test/telemetry_test.py | 13 +++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 monkey/monkey_island/cc/resources/test/telemetry_test.py diff --git a/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py b/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py index 050cfe04c..304996ebd 100644 --- a/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py +++ b/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py @@ -1,6 +1,7 @@ import json import logging from time import sleep +from typing import Union from bson import json_util @@ -8,6 +9,7 @@ from envs.monkey_zoo.blackbox.island_client.monkey_island_requests import Monkey SLEEP_BETWEEN_REQUESTS_SECONDS = 0.5 MONKEY_TEST_ENDPOINT = 'api/test/monkey' +TELEMETRY_TEST_ENDPOINT = 'api/test/telemetry' LOG_TEST_ENDPOINT = 'api/test/log' LOGGER = logging.getLogger(__name__) @@ -67,6 +69,13 @@ class MonkeyIslandClient(object): MonkeyIslandClient.form_find_query_for_request(query)) return MonkeyIslandClient.get_test_query_results(response) + def find_telems_in_db(self, query: dict): + if query is None: + raise TypeError + response = self.requests.get(TELEMETRY_TEST_ENDPOINT, + MonkeyIslandClient.form_find_query_for_request(query)) + return MonkeyIslandClient.get_test_query_results(response) + def get_all_monkeys_from_db(self): response = self.requests.get(MONKEY_TEST_ENDPOINT, MonkeyIslandClient.form_find_query_for_request(None)) @@ -78,7 +87,7 @@ class MonkeyIslandClient(object): return MonkeyIslandClient.get_test_query_results(response) @staticmethod - def form_find_query_for_request(query): + def form_find_query_for_request(query: Union[dict, None]) -> dict: return {'find_query': json_util.dumps(query)} @staticmethod diff --git a/monkey/monkey_island/cc/app.py b/monkey/monkey_island/cc/app.py index c53c04caa..c7fd0006f 100644 --- a/monkey/monkey_island/cc/app.py +++ b/monkey/monkey_island/cc/app.py @@ -7,6 +7,7 @@ from werkzeug.exceptions import NotFound import monkey_island.cc.environment.environment_singleton as env_singleton from common.common_consts.api_url_consts import T1216_PBA_FILE_DOWNLOAD_PATH +from monkey_island.cc.resources.test.telemetry_test import TelemetryTest from monkey_island.cc.resources.zero_trust.zero_trust_report import ZeroTrustReport from monkey_island.cc.server_utils.consts import MONKEY_ISLAND_ABS_PATH from monkey_island.cc.server_utils.custom_json_encoder import CustomJSONEncoder @@ -145,9 +146,11 @@ def init_api_resources(api): api.add_resource(ScoutSuiteAuth, '/api/scoutsuite_auth/') api.add_resource(AWSKeys, '/api/aws_keys') + # Resources used by black box tests api.add_resource(MonkeyTest, '/api/test/monkey') api.add_resource(ClearCaches, '/api/test/clear_caches') api.add_resource(LogTest, '/api/test/log') + api.add_resource(TelemetryTest, '/api/test/telemetry') def init_app(mongo_url): diff --git a/monkey/monkey_island/cc/resources/test/telemetry_test.py b/monkey/monkey_island/cc/resources/test/telemetry_test.py new file mode 100644 index 000000000..29108070e --- /dev/null +++ b/monkey/monkey_island/cc/resources/test/telemetry_test.py @@ -0,0 +1,13 @@ +import flask_restful +from bson import json_util +from flask import request + +from monkey_island.cc.database import mongo +from monkey_island.cc.resources.auth.auth import jwt_required + + +class TelemetryTest(flask_restful.Resource): + @jwt_required + def get(self, **kw): + find_query = json_util.loads(request.args.get('find_query')) + return {'results': list(mongo.db.telemetry.find(find_query))} From 44f6ce36b6c60064d318f590484521fb8ecf5fd0 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Mon, 8 Mar 2021 12:05:00 +0200 Subject: [PATCH 4/7] Fixed credentials in zerologon exploiter to match. --- envs/monkey_zoo/blackbox/island_configs/zerologon.py | 4 +++- envs/monkey_zoo/blackbox/test_blackbox.py | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/envs/monkey_zoo/blackbox/island_configs/zerologon.py b/envs/monkey_zoo/blackbox/island_configs/zerologon.py index 725fa91b9..3c31e3d6a 100644 --- a/envs/monkey_zoo/blackbox/island_configs/zerologon.py +++ b/envs/monkey_zoo/blackbox/island_configs/zerologon.py @@ -9,5 +9,7 @@ class ZeroLogon(BaseTemplate): config_values.update({ "basic.exploiters.exploiter_classes": ["ZerologonExploiter"], - "basic_network.scope.subnet_scan_list": ["10.2.2.25"] + "basic_network.scope.subnet_scan_list": ["10.2.2.25"], + # Empty list to make sure ZeroLogon adds "Administrator" username + "basic.credentials.exploit_user_list": [] }) diff --git a/envs/monkey_zoo/blackbox/test_blackbox.py b/envs/monkey_zoo/blackbox/test_blackbox.py index 7560b5d42..d3496a519 100644 --- a/envs/monkey_zoo/blackbox/test_blackbox.py +++ b/envs/monkey_zoo/blackbox/test_blackbox.py @@ -164,7 +164,9 @@ class TestMonkeyBlackbox: def test_zerologon_exploiter(self, island_client): test_name = "ZeroLogon_exploiter" - expected_creds = ["test_username", "test_ntlm_hash"] + expected_creds = ["Administrator", + "aad3b435b51404eeaad3b435b51404ee", + "2864b62ea4496934a5d6e86f50b834a5"] raw_config = IslandConfigParser.get_raw_config(ZeroLogon, island_client) analyzer = ZeroLogonAnalyzer(island_client, expected_creds) log_handler = TestLogsHandler(test_name, island_client, TestMonkeyBlackbox.get_log_dir_path()) From b43f6690812216fffe4ee02f21320d1a22363bcd Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Mon, 8 Mar 2021 12:35:31 +0200 Subject: [PATCH 5/7] Bugfix: removed unneeded exploitation test run in ZeroLogon BB test --- envs/monkey_zoo/blackbox/test_blackbox.py | 1 - 1 file changed, 1 deletion(-) diff --git a/envs/monkey_zoo/blackbox/test_blackbox.py b/envs/monkey_zoo/blackbox/test_blackbox.py index d3496a519..4d083907f 100644 --- a/envs/monkey_zoo/blackbox/test_blackbox.py +++ b/envs/monkey_zoo/blackbox/test_blackbox.py @@ -177,7 +177,6 @@ class TestMonkeyBlackbox: analyzers=[analyzer], timeout=DEFAULT_TIMEOUT_SECONDS, log_handler=log_handler).run() - TestMonkeyBlackbox.run_exploitation_test(island_client, ZeroLogon, "ZeroLogon_exploiter") @pytest.mark.skip(reason="Perfomance test that creates env from fake telemetries is faster, use that instead.") def test_report_generation_performance(self, island_client, quick_performance_tests): From 70ec513f51ac9a26702cb3a07252cad0998ee243 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Mon, 8 Mar 2021 13:10:14 +0200 Subject: [PATCH 6/7] Added logging to the ZeroLogon analyzer --- .../blackbox/analyzers/zerologon_analyzer.py | 37 +++++++++++++++---- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/envs/monkey_zoo/blackbox/analyzers/zerologon_analyzer.py b/envs/monkey_zoo/blackbox/analyzers/zerologon_analyzer.py index 691724830..20fdac468 100644 --- a/envs/monkey_zoo/blackbox/analyzers/zerologon_analyzer.py +++ b/envs/monkey_zoo/blackbox/analyzers/zerologon_analyzer.py @@ -1,4 +1,5 @@ from typing import List +from pprint import pformat import dpath.util @@ -22,7 +23,9 @@ class ZeroLogonAnalyzer(Analyzer): def analyze_test_results(self): self.log.clear() - return self._analyze_credential_gathering() and self._analyze_credential_restore() + is_creds_gathered = self._analyze_credential_gathering() + is_creds_restored = self._analyze_credential_restore() + return is_creds_gathered and is_creds_restored def _analyze_credential_gathering(self) -> bool: credentials_on_island = [] @@ -30,13 +33,33 @@ class ZeroLogonAnalyzer(Analyzer): credentials_on_island.extend(dpath.util.get(config['configuration'], USER_LIST_PATH)) credentials_on_island.extend(dpath.util.get(config['configuration'], NTLM_HASH_LIST_PATH)) credentials_on_island.extend(dpath.util.get(config['configuration'], LM_HASH_LIST_PATH)) - return ZeroLogonAnalyzer._is_all_credentials_in_list(self.expected_credentials, - credentials_on_island) + return self._is_all_credentials_in_list(credentials_on_island) - @staticmethod - def _is_all_credentials_in_list(expected_creds: List[str], + def _is_all_credentials_in_list(self, all_creds: List[str]) -> bool: - return all((cred in all_creds) for cred in expected_creds) + credentials_missing = [cred for cred in self.expected_credentials if cred not in all_creds] + self._log_creds_not_gathered(credentials_missing) + return not credentials_missing + + def _log_creds_not_gathered(self, missing_creds: List[str]): + if not missing_creds: + self.log.add_entry("ZeroLogon exploiter gathered all credentials expected.") + else: + for cred in missing_creds: + self.log.add_entry(f"Credential ZeroLogon exploiter failed to gathered:{cred}.") def _analyze_credential_restore(self) -> bool: - return bool(self.island_client.find_telems_in_db(TELEM_QUERY)) + cred_restore_telems = self.island_client.find_telems_in_db(TELEM_QUERY) + self._log_credential_restore(cred_restore_telems) + return bool(cred_restore_telems) + + def _log_credential_restore(self, telem_list: List[dict]): + if telem_list: + self.log.add_entry("ZeroLogon exploiter telemetry contains indicators that credentials " + "were successfully restored.") + else: + self.log.add_entry("Credential restore failed or credential restore " + "telemetry not found on the Monkey Island.") + self.log.add_entry(f"Query for credential restore telem: {pformat(TELEM_QUERY)}") + + From f43d9fe035685eb785ec8db69491cd2626485c20 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Mon, 8 Mar 2021 13:58:11 +0200 Subject: [PATCH 7/7] ZL BB tests: Renamed "ZeroLogon" to "Zerologon" for cinsistency, extracted relevant credential extortion from island config into a separate method. --- .../blackbox/analyzers/zerologon_analyzer.py | 17 +++++++++++------ .../blackbox/island_configs/zerologon.py | 2 +- envs/monkey_zoo/blackbox/test_blackbox.py | 10 +++++----- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/envs/monkey_zoo/blackbox/analyzers/zerologon_analyzer.py b/envs/monkey_zoo/blackbox/analyzers/zerologon_analyzer.py index 20fdac468..f5da3a2e1 100644 --- a/envs/monkey_zoo/blackbox/analyzers/zerologon_analyzer.py +++ b/envs/monkey_zoo/blackbox/analyzers/zerologon_analyzer.py @@ -14,7 +14,7 @@ TELEM_QUERY = {'telem_category': 'exploit', 'data.info.password_restored': True} -class ZeroLogonAnalyzer(Analyzer): +class ZerologonAnalyzer(Analyzer): def __init__(self, island_client: MonkeyIslandClient, expected_credentials: List[str]): self.island_client = island_client @@ -28,12 +28,17 @@ class ZeroLogonAnalyzer(Analyzer): return is_creds_gathered and is_creds_restored def _analyze_credential_gathering(self) -> bool: - credentials_on_island = [] config = self.island_client.get_config() + credentials_on_island = ZerologonAnalyzer._get_relevant_credentials(config) + return self._is_all_credentials_in_list(credentials_on_island) + + @staticmethod + def _get_relevant_credentials(config: dict): + credentials_on_island = [] credentials_on_island.extend(dpath.util.get(config['configuration'], USER_LIST_PATH)) credentials_on_island.extend(dpath.util.get(config['configuration'], NTLM_HASH_LIST_PATH)) credentials_on_island.extend(dpath.util.get(config['configuration'], LM_HASH_LIST_PATH)) - return self._is_all_credentials_in_list(credentials_on_island) + return credentials_on_island def _is_all_credentials_in_list(self, all_creds: List[str]) -> bool: @@ -43,10 +48,10 @@ class ZeroLogonAnalyzer(Analyzer): def _log_creds_not_gathered(self, missing_creds: List[str]): if not missing_creds: - self.log.add_entry("ZeroLogon exploiter gathered all credentials expected.") + self.log.add_entry("Zerologon exploiter gathered all credentials expected.") else: for cred in missing_creds: - self.log.add_entry(f"Credential ZeroLogon exploiter failed to gathered:{cred}.") + self.log.add_entry(f"Credential Zerologon exploiter failed to gathered:{cred}.") def _analyze_credential_restore(self) -> bool: cred_restore_telems = self.island_client.find_telems_in_db(TELEM_QUERY) @@ -55,7 +60,7 @@ class ZeroLogonAnalyzer(Analyzer): def _log_credential_restore(self, telem_list: List[dict]): if telem_list: - self.log.add_entry("ZeroLogon exploiter telemetry contains indicators that credentials " + self.log.add_entry("Zerologon exploiter telemetry contains indicators that credentials " "were successfully restored.") else: self.log.add_entry("Credential restore failed or credential restore " diff --git a/envs/monkey_zoo/blackbox/island_configs/zerologon.py b/envs/monkey_zoo/blackbox/island_configs/zerologon.py index 3c31e3d6a..6b84589fb 100644 --- a/envs/monkey_zoo/blackbox/island_configs/zerologon.py +++ b/envs/monkey_zoo/blackbox/island_configs/zerologon.py @@ -3,7 +3,7 @@ from copy import copy from envs.monkey_zoo.blackbox.island_configs.base_template import BaseTemplate -class ZeroLogon(BaseTemplate): +class Zerologon(BaseTemplate): config_values = copy(BaseTemplate.config_values) diff --git a/envs/monkey_zoo/blackbox/test_blackbox.py b/envs/monkey_zoo/blackbox/test_blackbox.py index 4d083907f..b54fa5393 100644 --- a/envs/monkey_zoo/blackbox/test_blackbox.py +++ b/envs/monkey_zoo/blackbox/test_blackbox.py @@ -7,7 +7,7 @@ from typing_extensions import Type 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.island_client.island_config_parser import \ IslandConfigParser from envs.monkey_zoo.blackbox.island_client.monkey_island_client import \ @@ -26,7 +26,7 @@ from envs.monkey_zoo.blackbox.island_configs.tunneling import Tunneling from envs.monkey_zoo.blackbox.island_configs.weblogic import Weblogic from envs.monkey_zoo.blackbox.island_configs.wmi_mimikatz import WmiMimikatz from envs.monkey_zoo.blackbox.island_configs.wmi_pth import WmiPth -from envs.monkey_zoo.blackbox.island_configs.zerologon import ZeroLogon +from envs.monkey_zoo.blackbox.island_configs.zerologon import Zerologon from envs.monkey_zoo.blackbox.log_handlers.test_logs_handler import \ TestLogsHandler from envs.monkey_zoo.blackbox.tests.exploitation import ExploitationTest @@ -163,12 +163,12 @@ class TestMonkeyBlackbox: TestMonkeyBlackbox.run_exploitation_test(island_client, WmiPth, "WMI_PTH") def test_zerologon_exploiter(self, island_client): - test_name = "ZeroLogon_exploiter" + test_name = "Zerologon_exploiter" expected_creds = ["Administrator", "aad3b435b51404eeaad3b435b51404ee", "2864b62ea4496934a5d6e86f50b834a5"] - raw_config = IslandConfigParser.get_raw_config(ZeroLogon, island_client) - analyzer = ZeroLogonAnalyzer(island_client, expected_creds) + raw_config = IslandConfigParser.get_raw_config(Zerologon, island_client) + analyzer = ZerologonAnalyzer(island_client, expected_creds) log_handler = TestLogsHandler(test_name, island_client, TestMonkeyBlackbox.get_log_dir_path()) ExploitationTest( name=test_name,