Merge branch '2269-publish-events-from-powershell-exploiter' into develop

PR #2402
This commit is contained in:
Mike Salvatore 2022-10-06 12:45:13 -04:00
commit b2c5b22128
4 changed files with 68 additions and 12 deletions

View File

@ -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,

View File

@ -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"

View File

@ -1,8 +1,14 @@
import logging
from pathlib import Path, PurePath
from time import time
from typing import List, Optional
from common import OperatingSystem
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 (
@ -21,6 +27,7 @@ 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"
class RemoteAgentCopyError(Exception):
@ -34,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
@ -68,12 +86,21 @@ class PowerShellExploiter(HostExploiter):
)
return self.exploit_result
execute_agent_timestamp = time()
try:
self._execute_monkey_agent_on_victim()
self.exploit_result.propagation_success = True
except Exception as 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=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(time=execute_agent_timestamp, success=True)
return self.exploit_result
@ -94,21 +121,27 @@ 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(time=connect_timestamp, success=True)
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(
time=connect_timestamp, success=False, error_message=error_message
)
self._report_login_attempt(False, creds)
return None

View File

@ -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"))