From f6b068229735383fc9f65833b7e430494956b5cb Mon Sep 17 00:00:00 2001
From: VakarisZ <vakarisz@yahoo.com>
Date: Mon, 8 Mar 2021 11:07:24 +0200
Subject: [PATCH] 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):
         """