Agent: Query for updated credentials in Exploiter

Allows exploiters to be run with the most up-to-date configured and
stolen credentials from the Island.
This commit is contained in:
Mike Salvatore 2022-02-17 12:36:17 -05:00
parent 095572f919
commit 7551f254fc
4 changed files with 49 additions and 7 deletions

View File

@ -41,7 +41,9 @@ class AutomatedMaster(IMaster):
self._control_channel = control_channel self._control_channel = control_channel
ip_scanner = IPScanner(self._puppet, NUM_SCAN_THREADS) ip_scanner = IPScanner(self._puppet, NUM_SCAN_THREADS)
exploiter = Exploiter(self._puppet, NUM_EXPLOIT_THREADS) exploiter = Exploiter(
self._puppet, NUM_EXPLOIT_THREADS, self._control_channel.get_credentials_for_propagation
)
self._propagator = Propagator( self._propagator = Propagator(
self._telemetry_messenger, self._telemetry_messenger,
ip_scanner, ip_scanner,

View File

@ -3,7 +3,7 @@ import queue
import threading import threading
from queue import Queue from queue import Queue
from threading import Event from threading import Event
from typing import Callable, Dict, List from typing import Callable, Dict, List, Mapping
from infection_monkey.i_puppet import ExploiterResultData, IPuppet from infection_monkey.i_puppet import ExploiterResultData, IPuppet
from infection_monkey.model import VictimHost from infection_monkey.model import VictimHost
@ -18,9 +18,15 @@ Callback = Callable[[ExploiterName, VictimHost, ExploiterResultData], None]
class Exploiter: class Exploiter:
def __init__(self, puppet: IPuppet, num_workers: int): def __init__(
self,
puppet: IPuppet,
num_workers: int,
get_updated_credentials_for_propagation: Callable[[], Mapping],
):
self._puppet = puppet self._puppet = puppet
self._num_workers = num_workers self._num_workers = num_workers
self._get_updated_credentials_for_propagation = get_updated_credentials_for_propagation
def exploit_hosts( def exploit_hosts(
self, self,
@ -74,6 +80,7 @@ class Exploiter:
results_callback: Callback, results_callback: Callback,
stop: Event, stop: Event,
): ):
for exploiter in interruptable_iter(exploiters_to_run, stop): for exploiter in interruptable_iter(exploiters_to_run, stop):
exploiter_name = exploiter["name"] exploiter_name = exploiter["name"]
exploiter_results = self._run_exploiter(exploiter_name, victim_host, stop) exploiter_results = self._run_exploiter(exploiter_name, victim_host, stop)
@ -86,7 +93,19 @@ class Exploiter:
self, exploiter_name: str, victim_host: VictimHost, stop: Event self, exploiter_name: str, victim_host: VictimHost, stop: Event
) -> ExploiterResultData: ) -> ExploiterResultData:
logger.debug(f"Attempting to use {exploiter_name} on {victim_host}") logger.debug(f"Attempting to use {exploiter_name} on {victim_host}")
return self._puppet.exploit_host(exploiter_name, victim_host.ip_addr, {}, stop)
credentials = self._get_credentials_for_propagation()
options = {"credentials": credentials}
return self._puppet.exploit_host(exploiter_name, victim_host.ip_addr, options, stop)
def _get_credentials_for_propagation(self) -> Mapping:
try:
return self._get_updated_credentials_for_propagation()
except Exception as ex:
logger.error(f"Error while attempting to retrieve credentials for propagation: {ex}")
return {}
def _all_hosts_have_been_processed(scan_completed: Event, hosts_to_exploit: Queue): def _all_hosts_have_been_processed(scan_completed: Event, hosts_to_exploit: Queue):

View File

@ -14,7 +14,7 @@ INTERVAL = 0.001
def test_terminate_without_start(): def test_terminate_without_start():
m = AutomatedMaster(None, None, None, None, []) m = AutomatedMaster(None, None, None, MagicMock(), [])
# Test that call to terminate does not raise exception # Test that call to terminate does not raise exception
m.terminate() m.terminate()

View File

@ -59,11 +59,18 @@ def hosts_to_exploit(hosts):
return q return q
CREDENTIALS_FOR_PROPAGATION = {"usernames": ["m0nk3y", "user"], "passwords": ["1234", "pword"]}
def get_credentials_for_propagation():
return CREDENTIALS_FOR_PROPAGATION
def test_exploiter(exploiter_config, callback, scan_completed, stop, hosts, hosts_to_exploit): def test_exploiter(exploiter_config, callback, scan_completed, stop, hosts, hosts_to_exploit):
# Set this so that Exploiter() exits once it has processed all victims # Set this so that Exploiter() exits once it has processed all victims
scan_completed.set() scan_completed.set()
e = Exploiter(MockPuppet(), 2) e = Exploiter(MockPuppet(), 2, get_credentials_for_propagation)
e.exploit_hosts(exploiter_config, hosts_to_exploit, callback, scan_completed, stop) e.exploit_hosts(exploiter_config, hosts_to_exploit, callback, scan_completed, stop)
assert callback.call_count == 5 assert callback.call_count == 5
@ -81,6 +88,20 @@ def test_exploiter(exploiter_config, callback, scan_completed, stop, hosts, host
assert ("SSHExploiter", hosts[1]) in host_exploit_combos assert ("SSHExploiter", hosts[1]) in host_exploit_combos
def test_credentials_passed_to_exploiter(
exploiter_config, callback, scan_completed, stop, hosts, hosts_to_exploit
):
mock_puppet = MagicMock()
# Set this so that Exploiter() exits once it has processed all victims
scan_completed.set()
e = Exploiter(mock_puppet, 2, get_credentials_for_propagation)
e.exploit_hosts(exploiter_config, hosts_to_exploit, callback, scan_completed, stop)
for call_args in mock_puppet.exploit_host.call_args_list:
assert call_args[0][2].get("credentials") == CREDENTIALS_FOR_PROPAGATION
def test_stop_after_callback(exploiter_config, callback, scan_completed, stop, hosts_to_exploit): def test_stop_after_callback(exploiter_config, callback, scan_completed, stop, hosts_to_exploit):
callback_barrier_count = 2 callback_barrier_count = 2
@ -96,7 +117,7 @@ def test_stop_after_callback(exploiter_config, callback, scan_completed, stop, h
# Intentionally NOT setting scan_completed.set(); _callback() will set stop # Intentionally NOT setting scan_completed.set(); _callback() will set stop
e = Exploiter(MockPuppet(), callback_barrier_count + 2) e = Exploiter(MockPuppet(), callback_barrier_count + 2, get_credentials_for_propagation)
e.exploit_hosts(exploiter_config, hosts_to_exploit, stoppable_callback, scan_completed, stop) e.exploit_hosts(exploiter_config, hosts_to_exploit, stoppable_callback, scan_completed, stop)
assert stoppable_callback.call_count == 2 assert stoppable_callback.call_count == 2