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,
|
T1003_ATTACK_TECHNIQUE_TAG,
|
||||||
T1005_ATTACK_TECHNIQUE_TAG,
|
T1005_ATTACK_TECHNIQUE_TAG,
|
||||||
T1021_ATTACK_TECHNIQUE_TAG,
|
T1021_ATTACK_TECHNIQUE_TAG,
|
||||||
|
T1059_ATTACK_TECHNIQUE_TAG,
|
||||||
T1098_ATTACK_TECHNIQUE_TAG,
|
T1098_ATTACK_TECHNIQUE_TAG,
|
||||||
T1105_ATTACK_TECHNIQUE_TAG,
|
T1105_ATTACK_TECHNIQUE_TAG,
|
||||||
T1110_ATTACK_TECHNIQUE_TAG,
|
T1110_ATTACK_TECHNIQUE_TAG,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
T1003_ATTACK_TECHNIQUE_TAG = "attack-t1003"
|
T1003_ATTACK_TECHNIQUE_TAG = "attack-t1003"
|
||||||
T1005_ATTACK_TECHNIQUE_TAG = "attack-t1005"
|
T1005_ATTACK_TECHNIQUE_TAG = "attack-t1005"
|
||||||
T1021_ATTACK_TECHNIQUE_TAG = "attack-t1021"
|
T1021_ATTACK_TECHNIQUE_TAG = "attack-t1021"
|
||||||
|
T1059_ATTACK_TECHNIQUE_TAG = "attack-t1059"
|
||||||
T1098_ATTACK_TECHNIQUE_TAG = "attack-t1098"
|
T1098_ATTACK_TECHNIQUE_TAG = "attack-t1098"
|
||||||
T1105_ATTACK_TECHNIQUE_TAG = "attack-t1105"
|
T1105_ATTACK_TECHNIQUE_TAG = "attack-t1105"
|
||||||
T1110_ATTACK_TECHNIQUE_TAG = "attack-t1110"
|
T1110_ATTACK_TECHNIQUE_TAG = "attack-t1110"
|
||||||
|
|
|
@ -1,8 +1,14 @@
|
||||||
import logging
|
import logging
|
||||||
from pathlib import Path, PurePath
|
from pathlib import Path, PurePath
|
||||||
|
from time import time
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
from common import OperatingSystem
|
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.HostExploiter import HostExploiter
|
||||||
from infection_monkey.exploit.powershell_utils.auth_options import AuthOptions, get_auth_options
|
from infection_monkey.exploit.powershell_utils.auth_options import AuthOptions, get_auth_options
|
||||||
from infection_monkey.exploit.powershell_utils.credentials import (
|
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
|
from infection_monkey.utils.threading import interruptible_iter
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
POWERSHELL_EXPLOITER_TAG = "powershell-exploiter"
|
||||||
|
|
||||||
|
|
||||||
class RemoteAgentCopyError(Exception):
|
class RemoteAgentCopyError(Exception):
|
||||||
|
@ -34,6 +41,17 @@ class RemoteAgentExecutionError(Exception):
|
||||||
class PowerShellExploiter(HostExploiter):
|
class PowerShellExploiter(HostExploiter):
|
||||||
_EXPLOITED_SERVICE = "PowerShell Remoting (WinRM)"
|
_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):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self._client = None
|
self._client = None
|
||||||
|
@ -68,12 +86,21 @@ class PowerShellExploiter(HostExploiter):
|
||||||
)
|
)
|
||||||
return self.exploit_result
|
return self.exploit_result
|
||||||
|
|
||||||
|
execute_agent_timestamp = time()
|
||||||
try:
|
try:
|
||||||
self._execute_monkey_agent_on_victim()
|
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
|
self.exploit_result.propagation_success = True
|
||||||
except Exception as ex:
|
self._publish_propagation_event(time=execute_agent_timestamp, success=True)
|
||||||
logger.error(f"Failed to propagate to the remote host: {ex}")
|
|
||||||
self.exploit_result.error_message = str(ex)
|
|
||||||
|
|
||||||
return self.exploit_result
|
return self.exploit_result
|
||||||
|
|
||||||
|
@ -94,21 +121,27 @@ class PowerShellExploiter(HostExploiter):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
client = PowerShellClient(self.host.ip_addr, creds, opts)
|
client = PowerShellClient(self.host.ip_addr, creds, opts)
|
||||||
|
connect_timestamp = time()
|
||||||
client.connect()
|
client.connect()
|
||||||
logger.info(
|
logger.info(
|
||||||
f"Successfully logged into {self.host.ip_addr} using Powershell. User: "
|
f"Successfully logged into {self.host.ip_addr} using Powershell. User: "
|
||||||
f"{creds.username}, Secret Type: {creds.secret_type.name}"
|
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.exploit_result.exploitation_success = True
|
||||||
self._report_login_attempt(True, creds)
|
self._report_login_attempt(True, creds)
|
||||||
|
|
||||||
return client
|
return client
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
logger.debug(
|
error_message = (
|
||||||
f"Error logging into {self.host.ip_addr} using Powershell. User: "
|
f"Error logging into {self.host.ip_addr} using Powershell. User: "
|
||||||
f"{creds.username}, SecretType: {creds.secret_type.name} -- Error: {ex}"
|
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)
|
self._report_login_attempt(False, creds)
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
|
@ -16,6 +16,7 @@ LM_HASH_LIST = ["bogo_lm_1"]
|
||||||
NT_HASH_LIST = ["bogo_nt_1", "bogo_nt_2"]
|
NT_HASH_LIST = ["bogo_nt_1", "bogo_nt_2"]
|
||||||
|
|
||||||
bogus_servers = ["1.1.1.1:5000", "2.2.2.2:5007"]
|
bogus_servers = ["1.1.1.1:5000", "2.2.2.2:5007"]
|
||||||
|
VICTIM_IP = "10.10.10.1"
|
||||||
|
|
||||||
|
|
||||||
mock_agent_binary_repository = MagicMock()
|
mock_agent_binary_repository = MagicMock()
|
||||||
|
@ -23,7 +24,25 @@ mock_agent_binary_repository.get_agent_binary.return_value = BytesIO(b"BINARY_EX
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@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 = {
|
options = {
|
||||||
"credentials": {
|
"credentials": {
|
||||||
"exploit_user_list": USER_LIST,
|
"exploit_user_list": USER_LIST,
|
||||||
|
@ -33,7 +52,7 @@ def powershell_arguments(http_and_https_both_enabled_host):
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
arguments = {
|
arguments = {
|
||||||
"host": http_and_https_both_enabled_host,
|
"host": host_with_ip_address,
|
||||||
"servers": bogus_servers,
|
"servers": bogus_servers,
|
||||||
"options": options,
|
"options": options,
|
||||||
"current_depth": 2,
|
"current_depth": 2,
|
||||||
|
@ -63,8 +82,10 @@ def test_powershell_disabled(powershell_exploiter, powershell_arguments, powersh
|
||||||
assert "disabled" in exploit_result.error_message
|
assert "disabled" in exploit_result.error_message
|
||||||
|
|
||||||
|
|
||||||
def test_powershell_http(monkeypatch, powershell_exploiter, powershell_arguments, http_only_host):
|
def test_powershell_http(
|
||||||
powershell_arguments["host"] = http_only_host
|
monkeypatch, powershell_exploiter, powershell_arguments, http_host_with_ip_address
|
||||||
|
):
|
||||||
|
powershell_arguments["host"] = http_host_with_ip_address
|
||||||
|
|
||||||
mock_powershell_client = MagicMock()
|
mock_powershell_client = MagicMock()
|
||||||
monkeypatch.setattr(
|
monkeypatch.setattr(
|
||||||
|
@ -77,7 +98,7 @@ def test_powershell_http(monkeypatch, powershell_exploiter, powershell_arguments
|
||||||
assert not call_args[0][2].ssl
|
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 = MagicMock()
|
||||||
mock_powershell_client.connect = MagicMock(side_effect=Exception("Failed login"))
|
mock_powershell_client.connect = MagicMock(side_effect=Exception("Failed login"))
|
||||||
mock_powershell_client_constructor = MagicMock(return_value=mock_powershell_client)
|
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(
|
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
|
# 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.
|
# 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 = MagicMock()
|
||||||
mock_powershell_client.connect = MagicMock(side_effect=Exception("Failed login"))
|
mock_powershell_client.connect = MagicMock(side_effect=Exception("Failed login"))
|
||||||
|
|
Loading…
Reference in New Issue