Merge branch '2269-publish-events-from-powershell-exploiter' into develop
PR #2402
This commit is contained in:
commit
b2c5b22128
|
@ -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,
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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()
|
||||
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
|
||||
except Exception as ex:
|
||||
logger.error(f"Failed to propagate to the remote host: {ex}")
|
||||
self.exploit_result.error_message = str(ex)
|
||||
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
|
||||
|
|
|
@ -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"))
|
||||
|
|
Loading…
Reference in New Issue