From bb6716df18b094298e750ebba210790c4a063cca Mon Sep 17 00:00:00 2001 From: Kekoa Kaaikala Date: Wed, 5 Oct 2022 13:23:13 +0000 Subject: [PATCH 1/8] Common: Add attack technique T1059 --- monkey/common/tags/__init__.py | 1 + monkey/common/tags/attack.py | 1 + 2 files changed, 2 insertions(+) diff --git a/monkey/common/tags/__init__.py b/monkey/common/tags/__init__.py index ea08aa9f5..fb30c71df 100644 --- a/monkey/common/tags/__init__.py +++ b/monkey/common/tags/__init__.py @@ -2,6 +2,7 @@ from .attack import ( T1003_ATTACK_TECHNIQUE_TAG, T1005_ATTACK_TECHNIQUE_TAG, T1021_ATTACK_TECHNIQUE_TAG, + T1059_ATTACK_TECHNIQUE_TAG, T1098_ATTACK_TECHNIQUE_TAG, T1105_ATTACK_TECHNIQUE_TAG, T1110_ATTACK_TECHNIQUE_TAG, diff --git a/monkey/common/tags/attack.py b/monkey/common/tags/attack.py index e8881dfa7..5c3a8d117 100644 --- a/monkey/common/tags/attack.py +++ b/monkey/common/tags/attack.py @@ -1,6 +1,7 @@ T1003_ATTACK_TECHNIQUE_TAG = "attack-t1003" T1005_ATTACK_TECHNIQUE_TAG = "attack-t1005" T1021_ATTACK_TECHNIQUE_TAG = "attack-t1021" +T1059_ATTACK_TECHNIQUE_TAG = "attack-t1059" T1098_ATTACK_TECHNIQUE_TAG = "attack-t1098" T1105_ATTACK_TECHNIQUE_TAG = "attack-t1105" T1110_ATTACK_TECHNIQUE_TAG = "attack-t1110" From 3bede2f9d19df1b7e3cf4333b56a1ed04b811757 Mon Sep 17 00:00:00 2001 From: Kekoa Kaaikala Date: Wed, 5 Oct 2022 13:59:21 +0000 Subject: [PATCH 2/8] Agent: Publish propagation events --- monkey/infection_monkey/exploit/powershell.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/monkey/infection_monkey/exploit/powershell.py b/monkey/infection_monkey/exploit/powershell.py index ff0f0db4e..de3797a1d 100644 --- a/monkey/infection_monkey/exploit/powershell.py +++ b/monkey/infection_monkey/exploit/powershell.py @@ -3,6 +3,7 @@ from pathlib import Path, PurePath from typing import List, Optional from common import OperatingSystem +from common.tags import T1059_ATTACK_TECHNIQUE_TAG, T1105_ATTACK_TECHNIQUE_TAG from infection_monkey.exploit.HostExploiter import HostExploiter from infection_monkey.exploit.powershell_utils.auth_options import AuthOptions, get_auth_options from infection_monkey.exploit.powershell_utils.credentials import ( @@ -21,6 +22,12 @@ from infection_monkey.utils.environment import is_windows_os from infection_monkey.utils.threading import interruptible_iter logger = logging.getLogger(__name__) +POWERSHELL_EXPLOITER_TAG = "powershell-exploiter" +PROPAGATION_TAGS = ( + POWERSHELL_EXPLOITER_TAG, + T1059_ATTACK_TECHNIQUE_TAG, + T1105_ATTACK_TECHNIQUE_TAG, +) class RemoteAgentCopyError(Exception): @@ -72,8 +79,12 @@ class PowerShellExploiter(HostExploiter): self._execute_monkey_agent_on_victim() self.exploit_result.propagation_success = True except Exception as ex: + self._publish_propagation_event(self.host.ip_addr, False, PROPAGATION_TAGS, str(ex)) logger.error(f"Failed to propagate to the remote host: {ex}") self.exploit_result.error_message = str(ex) + return self.exploit_result + + self._publish_propagation_event(self.host.ip_addr, True, PROPAGATION_TAGS) return self.exploit_result From 7d535c72d9bdfb99d2a157fe29b705cf9c0b4610 Mon Sep 17 00:00:00 2001 From: Kekoa Kaaikala Date: Wed, 5 Oct 2022 14:10:11 +0000 Subject: [PATCH 3/8] Agent: Publish powershell exploitation events --- monkey/infection_monkey/exploit/powershell.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/monkey/infection_monkey/exploit/powershell.py b/monkey/infection_monkey/exploit/powershell.py index de3797a1d..369ca151d 100644 --- a/monkey/infection_monkey/exploit/powershell.py +++ b/monkey/infection_monkey/exploit/powershell.py @@ -3,7 +3,11 @@ from pathlib import Path, PurePath from typing import List, Optional from common import OperatingSystem -from common.tags import T1059_ATTACK_TECHNIQUE_TAG, T1105_ATTACK_TECHNIQUE_TAG +from common.tags import ( + T1059_ATTACK_TECHNIQUE_TAG, + T1105_ATTACK_TECHNIQUE_TAG, + T1110_ATTACK_TECHNIQUE_TAG, +) from infection_monkey.exploit.HostExploiter import HostExploiter from infection_monkey.exploit.powershell_utils.auth_options import AuthOptions, get_auth_options from infection_monkey.exploit.powershell_utils.credentials import ( @@ -23,6 +27,7 @@ from infection_monkey.utils.threading import interruptible_iter logger = logging.getLogger(__name__) POWERSHELL_EXPLOITER_TAG = "powershell-exploiter" +EXPLOITER_TAGS = (POWERSHELL_EXPLOITER_TAG, T1059_ATTACK_TECHNIQUE_TAG, T1110_ATTACK_TECHNIQUE_TAG) PROPAGATION_TAGS = ( POWERSHELL_EXPLOITER_TAG, T1059_ATTACK_TECHNIQUE_TAG, @@ -111,15 +116,20 @@ class PowerShellExploiter(HostExploiter): f"{creds.username}, Secret Type: {creds.secret_type.name}" ) + self._publish_exploitation_event(self.host.ip_addr, True, EXPLOITER_TAGS) self.exploit_result.exploitation_success = True self._report_login_attempt(True, creds) return client except Exception as ex: - logger.debug( + error_message = ( f"Error logging into {self.host.ip_addr} using Powershell. User: " f"{creds.username}, SecretType: {creds.secret_type.name} -- Error: {ex}" ) + logger.debug(error_message) + self._publish_exploitation_event( + self.host.ip_addr, False, EXPLOITER_TAGS, error_message + ) self._report_login_attempt(False, creds) return None From 3bca02af59cc188b64758c828b791af93b89c742 Mon Sep 17 00:00:00 2001 From: Kekoa Kaaikala Date: Wed, 5 Oct 2022 14:25:02 +0000 Subject: [PATCH 4/8] Agent: Fix powershell tests --- .../exploit/test_powershell.py | 35 +++++++++++++++---- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/monkey/tests/unit_tests/infection_monkey/exploit/test_powershell.py b/monkey/tests/unit_tests/infection_monkey/exploit/test_powershell.py index 97096830d..5fb98ea93 100644 --- a/monkey/tests/unit_tests/infection_monkey/exploit/test_powershell.py +++ b/monkey/tests/unit_tests/infection_monkey/exploit/test_powershell.py @@ -16,6 +16,7 @@ LM_HASH_LIST = ["bogo_lm_1"] NT_HASH_LIST = ["bogo_nt_1", "bogo_nt_2"] bogus_servers = ["1.1.1.1:5000", "2.2.2.2:5007"] +VICTIM_IP = "10.10.10.1" mock_agent_binary_repository = MagicMock() @@ -23,7 +24,25 @@ mock_agent_binary_repository.get_agent_binary.return_value = BytesIO(b"BINARY_EX @pytest.fixture -def powershell_arguments(http_and_https_both_enabled_host): +def host_with_ip_address(http_and_https_both_enabled_host): + http_and_https_both_enabled_host.ip_addr = VICTIM_IP + return http_and_https_both_enabled_host + + +@pytest.fixture +def http_host_with_ip_address(http_only_host): + http_only_host.ip_addr = VICTIM_IP + return http_only_host + + +@pytest.fixture +def https_host_with_ip_address(https_only_host): + https_only_host.ip_addr = VICTIM_IP + return https_only_host + + +@pytest.fixture +def powershell_arguments(host_with_ip_address): options = { "credentials": { "exploit_user_list": USER_LIST, @@ -33,7 +52,7 @@ def powershell_arguments(http_and_https_both_enabled_host): }, } arguments = { - "host": http_and_https_both_enabled_host, + "host": host_with_ip_address, "servers": bogus_servers, "options": options, "current_depth": 2, @@ -63,8 +82,10 @@ def test_powershell_disabled(powershell_exploiter, powershell_arguments, powersh assert "disabled" in exploit_result.error_message -def test_powershell_http(monkeypatch, powershell_exploiter, powershell_arguments, http_only_host): - powershell_arguments["host"] = http_only_host +def test_powershell_http( + monkeypatch, powershell_exploiter, powershell_arguments, http_host_with_ip_address +): + powershell_arguments["host"] = http_host_with_ip_address mock_powershell_client = MagicMock() monkeypatch.setattr( @@ -77,7 +98,7 @@ def test_powershell_http(monkeypatch, powershell_exploiter, powershell_arguments assert not call_args[0][2].ssl -def test_powershell_https(monkeypatch, powershell_exploiter, powershell_arguments, https_only_host): +def test_powershell_https(monkeypatch, powershell_exploiter, powershell_arguments): mock_powershell_client = MagicMock() mock_powershell_client.connect = MagicMock(side_effect=Exception("Failed login")) mock_powershell_client_constructor = MagicMock(return_value=mock_powershell_client) @@ -191,11 +212,11 @@ def test_build_monkey_execution_command(): def test_skip_http_only_logins( - monkeypatch, powershell_exploiter, powershell_arguments, https_only_host + monkeypatch, powershell_exploiter, powershell_arguments, https_host_with_ip_address ): # Only HTTPS is enabled on the destination, so we should never try to connect with "" empty # password, since connection with empty password requires SSL == False. - powershell_arguments["host"] = https_only_host + powershell_arguments["host"] = https_host_with_ip_address mock_powershell_client = MagicMock() mock_powershell_client.connect = MagicMock(side_effect=Exception("Failed login")) From 39bada5bb19196bb4f8f56feccf85decfe0cb828 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Wed, 5 Oct 2022 12:17:16 -0400 Subject: [PATCH 5/8] Agent: Move assignment outside of try/except --- monkey/infection_monkey/exploit/powershell.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkey/infection_monkey/exploit/powershell.py b/monkey/infection_monkey/exploit/powershell.py index 369ca151d..a4b2a66a8 100644 --- a/monkey/infection_monkey/exploit/powershell.py +++ b/monkey/infection_monkey/exploit/powershell.py @@ -82,13 +82,13 @@ class PowerShellExploiter(HostExploiter): try: self._execute_monkey_agent_on_victim() - self.exploit_result.propagation_success = True except Exception as ex: self._publish_propagation_event(self.host.ip_addr, False, PROPAGATION_TAGS, str(ex)) logger.error(f"Failed to propagate to the remote host: {ex}") self.exploit_result.error_message = str(ex) return self.exploit_result + self.exploit_result.propagation_success = True self._publish_propagation_event(self.host.ip_addr, True, PROPAGATION_TAGS) return self.exploit_result From ac11d159feb75bc7e2ed9bf9ec3e6c3ab2e00e79 Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Thu, 6 Oct 2022 16:03:15 +0200 Subject: [PATCH 6/8] Agent: Revise Powershell publishing of events --- monkey/infection_monkey/exploit/powershell.py | 37 +++++++++++-------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/monkey/infection_monkey/exploit/powershell.py b/monkey/infection_monkey/exploit/powershell.py index a4b2a66a8..ff1e6d785 100644 --- a/monkey/infection_monkey/exploit/powershell.py +++ b/monkey/infection_monkey/exploit/powershell.py @@ -1,5 +1,6 @@ import logging from pathlib import Path, PurePath +from time import time from typing import List, Optional from common import OperatingSystem @@ -27,12 +28,6 @@ from infection_monkey.utils.threading import interruptible_iter logger = logging.getLogger(__name__) POWERSHELL_EXPLOITER_TAG = "powershell-exploiter" -EXPLOITER_TAGS = (POWERSHELL_EXPLOITER_TAG, T1059_ATTACK_TECHNIQUE_TAG, T1110_ATTACK_TECHNIQUE_TAG) -PROPAGATION_TAGS = ( - POWERSHELL_EXPLOITER_TAG, - T1059_ATTACK_TECHNIQUE_TAG, - T1105_ATTACK_TECHNIQUE_TAG, -) class RemoteAgentCopyError(Exception): @@ -46,6 +41,17 @@ class RemoteAgentExecutionError(Exception): class PowerShellExploiter(HostExploiter): _EXPLOITED_SERVICE = "PowerShell Remoting (WinRM)" + _EXPLOITER_TAGS = ( + POWERSHELL_EXPLOITER_TAG, + T1059_ATTACK_TECHNIQUE_TAG, + T1110_ATTACK_TECHNIQUE_TAG, + ) + _PROPAGATION_TAGS = ( + POWERSHELL_EXPLOITER_TAG, + T1059_ATTACK_TECHNIQUE_TAG, + T1105_ATTACK_TECHNIQUE_TAG, + ) + def __init__(self): super().__init__() self._client = None @@ -80,16 +86,19 @@ class PowerShellExploiter(HostExploiter): ) return self.exploit_result + timestamp = time() try: self._execute_monkey_agent_on_victim() - except Exception as ex: - self._publish_propagation_event(self.host.ip_addr, False, PROPAGATION_TAGS, str(ex)) - logger.error(f"Failed to propagate to the remote host: {ex}") - self.exploit_result.error_message = str(ex) + except Exception as err: + self.exploit_result.error_message = f"Failed to propagate to the remote host: {err}" + self._publish_propagation_event( + time=timestamp, success=False, error_message=self.exploit_result.error_message + ) + logger.error(self.exploit_result.error_message) return self.exploit_result self.exploit_result.propagation_success = True - self._publish_propagation_event(self.host.ip_addr, True, PROPAGATION_TAGS) + self._publish_propagation_event(timestamp, True) return self.exploit_result @@ -116,7 +125,7 @@ class PowerShellExploiter(HostExploiter): f"{creds.username}, Secret Type: {creds.secret_type.name}" ) - self._publish_exploitation_event(self.host.ip_addr, True, EXPLOITER_TAGS) + self._publish_exploitation_event(success=True) self.exploit_result.exploitation_success = True self._report_login_attempt(True, creds) @@ -127,9 +136,7 @@ class PowerShellExploiter(HostExploiter): f"{creds.username}, SecretType: {creds.secret_type.name} -- Error: {ex}" ) logger.debug(error_message) - self._publish_exploitation_event( - self.host.ip_addr, False, EXPLOITER_TAGS, error_message - ) + self._publish_exploitation_event(success=False, error_message=error_message) self._report_login_attempt(False, creds) return None From c4573673ce4819a406794783346385d7e0d10d0d Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Thu, 6 Oct 2022 12:39:11 -0400 Subject: [PATCH 7/8] Agent: Rename timestamp -> execute_agent_timestamp --- monkey/infection_monkey/exploit/powershell.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/monkey/infection_monkey/exploit/powershell.py b/monkey/infection_monkey/exploit/powershell.py index ff1e6d785..d3c9b12f7 100644 --- a/monkey/infection_monkey/exploit/powershell.py +++ b/monkey/infection_monkey/exploit/powershell.py @@ -86,19 +86,21 @@ class PowerShellExploiter(HostExploiter): ) return self.exploit_result - timestamp = time() + execute_agent_timestamp = time() try: self._execute_monkey_agent_on_victim() except Exception as err: self.exploit_result.error_message = f"Failed to propagate to the remote host: {err}" self._publish_propagation_event( - time=timestamp, success=False, error_message=self.exploit_result.error_message + time=execute_agent_timestamp, + success=False, + error_message=self.exploit_result.error_message, ) logger.error(self.exploit_result.error_message) return self.exploit_result self.exploit_result.propagation_success = True - self._publish_propagation_event(timestamp, True) + self._publish_propagation_event(time=execute_agent_timestamp, success=True) return self.exploit_result From 65dd386603ac175b29e53145797f29df1a79f421 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Thu, 6 Oct 2022 12:39:37 -0400 Subject: [PATCH 8/8] Agent: Collect timestamp before powershell connect --- monkey/infection_monkey/exploit/powershell.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/monkey/infection_monkey/exploit/powershell.py b/monkey/infection_monkey/exploit/powershell.py index d3c9b12f7..b8efce04b 100644 --- a/monkey/infection_monkey/exploit/powershell.py +++ b/monkey/infection_monkey/exploit/powershell.py @@ -121,13 +121,14 @@ class PowerShellExploiter(HostExploiter): try: client = PowerShellClient(self.host.ip_addr, creds, opts) + connect_timestamp = time() client.connect() logger.info( f"Successfully logged into {self.host.ip_addr} using Powershell. User: " f"{creds.username}, Secret Type: {creds.secret_type.name}" ) - self._publish_exploitation_event(success=True) + self._publish_exploitation_event(time=connect_timestamp, success=True) self.exploit_result.exploitation_success = True self._report_login_attempt(True, creds) @@ -138,7 +139,9 @@ class PowerShellExploiter(HostExploiter): f"{creds.username}, SecretType: {creds.secret_type.name} -- Error: {ex}" ) logger.debug(error_message) - self._publish_exploitation_event(success=False, error_message=error_message) + self._publish_exploitation_event( + time=connect_timestamp, success=False, error_message=error_message + ) self._report_login_attempt(False, creds) return None