Merge pull request #1631 from guardicore/1595-new-agent-setup

Implement Agent setup function
This commit is contained in:
Mike Salvatore 2021-12-02 09:20:05 -05:00 committed by GitHub
commit 418b5ce9ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 254 additions and 413 deletions

View File

@ -29,24 +29,6 @@
" victims_max_exploit = 100"
]
},
{
"type": "snippet",
"path": "monkey/infection_monkey/monkey.py",
"comments": [],
"firstLineNumber": 220,
"lines": [
" if not WormConfiguration.alive:",
" logger.info(\"Marked not alive from configuration\")",
" ",
"* machines = self._network.get_victim_machines(",
"* max_find=WormConfiguration.victims_max_find,",
"* stop_callback=ControlClient.check_for_stop,",
"* )",
" for machine in machines:",
" if ControlClient.check_for_stop():",
" break"
]
},
{
"type": "snippet",
"path": "monkey/monkey_island/cc/services/config_schema/internal.py",
@ -79,7 +61,6 @@
"app_version": "0.6.6-2",
"file_blobs": {
"monkey/infection_monkey/config.py": "8f4984ba6563564343282765ab498efca5d89ba8",
"monkey/infection_monkey/monkey.py": "4160a36e0e624404d77526472d51dd07bba49e5a",
"monkey/monkey_island/cc/services/config_schema/internal.py": "86318eaf19b9991a8af5de861a3eb085238e17a4"
}
}

View File

@ -55,7 +55,6 @@ class MonkeyDrops(object):
"destination_path": self.opts.location,
}
def initialize(self):
logger.debug("Dropper is running with config:\n%s", pprint.pformat(self._config))
def start(self):

View File

@ -66,10 +66,16 @@ class HostExploiter(Plugin):
def is_os_supported(self):
return self.host.os.get("type") in self._TARGET_OS_TYPE
def send_exploit_telemetry(self, result):
def send_exploit_telemetry(self, name: str, result: bool):
from infection_monkey.telemetry.exploit_telem import ExploitTelem
ExploitTelem(self, result).send()
ExploitTelem(
name=name,
host=self.host,
result=result,
info=self.exploit_info,
attempts=self.exploit_attempts,
).send()
def report_login_attempt(self, result, user, password="", lm_hash="", ntlm_hash="", ssh_key=""):
self.exploit_attempts.append(

View File

@ -118,11 +118,9 @@ def main():
logger.info(f"version: {get_version()}")
monkey = monkey_cls(monkey_args)
monkey.initialize()
try:
monkey.start()
return True
except Exception as e:
logger.exception("Exception thrown from monkey's start function. More info: {}".format(e))

View File

@ -33,7 +33,7 @@ class MockMaster(IMaster):
self._run_payload()
def _run_sys_info_collectors(self):
logging.info("Running system info collectors")
logger.info("Running system info collectors")
system_info_telemetry = {}
system_info_telemetry["ProcessListCollector"] = self._puppet.run_sys_info_collector(
"ProcessListCollector"
@ -43,10 +43,13 @@ class MockMaster(IMaster):
)
system_info = self._puppet.run_sys_info_collector("LinuxInfoCollector")
self._telemetry_messenger.send_telemetry(SystemInfoTelem(system_info))
logging.info("Finished running system info collectors")
logger.info("Finished running system info collectors")
def _run_pbas(self):
logging.info("Running post breach actions")
# TODO: Create monkey_dir and revise setup in monkey.py
logger.info("Running post breach actions")
name = "AccountDiscovery"
command, result = self._puppet.run_pba(name, {})
self._telemetry_messenger.send_telemetry(PostBreachTelem(name, command, result))
@ -54,10 +57,10 @@ class MockMaster(IMaster):
name = "CommunicateAsBackdoorUser"
command, result = self._puppet.run_pba(name, {})
self._telemetry_messenger.send_telemetry(PostBreachTelem(name, command, result))
logging.info("Finished running post breach actions")
logger.info("Finished running post breach actions")
def _scan_victims(self):
logging.info("Scanning network for potential victims")
logger.info("Scanning network for potential victims")
ips = ["10.0.0.1", "10.0.0.2", "10.0.0.3"]
ports = [22, 445, 3389, 8008]
for ip in ips:
@ -78,10 +81,10 @@ class MockMaster(IMaster):
h.services[port_scan_data.service]["banner"] = port_scan_data.banner
self._telemetry_messenger.send_telemetry(ScanTelem(h))
logging.info("Finished scanning network for potential victims")
logger.info("Finished scanning network for potential victims")
def _fingerprint(self):
logging.info("Running fingerprinters on potential victims")
logger.info("Running fingerprinters on potential victims")
machine_1 = self._hosts["10.0.0.1"]
machine_3 = self._hosts["10.0.0.3"]
@ -93,32 +96,35 @@ class MockMaster(IMaster):
self._puppet.fingerprint("HTTPFinger", machine_3)
self._telemetry_messenger.send_telemetry(ScanTelem(machine_3))
logging.info("Finished running fingerprinters on potential victims")
logger.info("Finished running fingerprinters on potential victims")
def _exploit(self):
logging.info("Exploiting victims")
logger.info("Exploiting victims")
result, info, attempts = self._puppet.exploit_host(
"PowerShellExploiter", "10.0.0.1", {}, None
)
logger.info(f"Attempts for exploiting {attempts}")
self._telemetry_messenger.send_telemetry(
ExploitTelem("PowerShellExploiter", self._hosts["10.0.0.1"], result, info, attempts)
)
result, info, attempts = self._puppet.exploit_host("SSHExploiter", "10.0.0.3", {}, None)
logger.info(f"Attempts for exploiting {attempts}")
self._telemetry_messenger.send_telemetry(
ExploitTelem("SSHExploiter", self._hosts["10.0.0.3"], result, info, attempts)
)
logging.info("Finished exploiting victims")
logger.info("Finished exploiting victims")
def _run_payload(self):
logging.info("Running payloads")
logger.info("Running payloads")
# TODO: modify what FileEncryptionTelem gets
path, success, error = self._puppet.run_payload("RansomwarePayload", {}, None)
self._telemetry_messenger.send_telemetry(FileEncryptionTelem(path, success, error))
logging.info("Finished running payloads")
logger.info("Finished running payloads")
def terminate(self) -> None:
logger.info("Terminating MockMaster")
def cleanup(self) -> None:
# TODO: Cleanup monkey_dir and send telemetry
pass

View File

@ -4,316 +4,239 @@ import os
import subprocess
import sys
import time
from threading import Thread
import infection_monkey.tunnel as tunnel
from common.utils.attack_utils import ScanStatus, UsageEnum
from common.utils.exceptions import ExploitingVulnerableMachineError, FailedExploitationError
from common.version import get_version
from infection_monkey.config import WormConfiguration
from infection_monkey.control import ControlClient
from infection_monkey.exploit.HostExploiter import HostExploiter
from infection_monkey.master.mock_master import MockMaster
from infection_monkey.model import DELAY_DELETE_CMD
from infection_monkey.network.firewall import app as firewall
from infection_monkey.network.HostFinger import HostFinger
from infection_monkey.network.network_scanner import NetworkScanner
from infection_monkey.network.tools import get_interface_to_target, is_running_on_island
from infection_monkey.post_breach.post_breach_handler import PostBreach
from infection_monkey.ransomware.ransomware_payload_builder import build_ransomware_payload
from infection_monkey.system_info import SystemInfoCollector
from infection_monkey.network.tools import is_running_on_island
from infection_monkey.puppet.mock_puppet import MockPuppet
from infection_monkey.system_singleton import SystemSingleton
from infection_monkey.telemetry.attack.t1106_telem import T1106Telem
from infection_monkey.telemetry.attack.t1107_telem import T1107Telem
from infection_monkey.telemetry.attack.victim_host_telem import VictimHostTelem
from infection_monkey.telemetry.scan_telem import ScanTelem
from infection_monkey.telemetry.messengers.legacy_telemetry_messenger_adapter import (
LegacyTelemetryMessengerAdapter,
)
from infection_monkey.telemetry.state_telem import StateTelem
from infection_monkey.telemetry.system_info_telem import SystemInfoTelem
from infection_monkey.telemetry.trace_telem import TraceTelem
from infection_monkey.telemetry.tunnel_telem import TunnelTelem
from infection_monkey.utils.environment import is_windows_os
from infection_monkey.utils.exceptions.planned_shutdown_exception import PlannedShutdownException
from infection_monkey.utils.monkey_dir import (
create_monkey_dir,
get_monkey_dir_path,
remove_monkey_dir,
)
from infection_monkey.utils.monkey_dir import get_monkey_dir_path, remove_monkey_dir
from infection_monkey.utils.monkey_log_path import get_monkey_log_path
from infection_monkey.utils.signal_handler import register_signal_handlers
from infection_monkey.windows_upgrader import WindowsUpgrader
MAX_DEPTH_REACHED_MESSAGE = "Reached max depth, skipping propagation phase."
logger = logging.getLogger(__name__)
class InfectionMonkey(object):
class InfectionMonkey:
def __init__(self, args):
self._keep_running = False
self._exploited_machines = set()
self._fail_exploitation_machines = set()
self._singleton = SystemSingleton()
self._parent = None
self._default_tunnel = None
self._args = args
self._network = None
self._exploiters = None
self._fingerprint = None
self._default_server = None
self._default_server_port = None
self._opts = None
self._upgrading_to_64 = False
self._monkey_tunnel = None
self._post_breach_phase = None
def initialize(self):
logger.info("Monkey is initializing...")
self._master = MockMaster(MockPuppet(), LegacyTelemetryMessengerAdapter())
self._singleton = SystemSingleton()
self._opts = self._get_arguments(args)
# TODO Used in propagation phase to set the default server for the victim
self._default_server_port = None
# TODO used in propogation phase
self._monkey_inbound_tunnel = None
if not self._singleton.try_lock():
raise Exception("Another instance of the monkey is already running")
@staticmethod
def _get_arguments(args):
arg_parser = argparse.ArgumentParser()
arg_parser.add_argument("-p", "--parent")
arg_parser.add_argument("-t", "--tunnel")
arg_parser.add_argument("-s", "--server")
arg_parser.add_argument("-d", "--depth", type=int)
arg_parser.add_argument("-vp", "--vulnerable-port")
self._opts, self._args = arg_parser.parse_known_args(self._args)
self.log_arguments()
opts, _ = arg_parser.parse_known_args(args)
InfectionMonkey._log_arguments(opts)
return opts
self._parent = self._opts.parent
self._default_tunnel = self._opts.tunnel
self._default_server = self._opts.server
@staticmethod
def _log_arguments(args):
arg_string = " ".join([f"{key}: {value}" for key, value in vars(args).items()])
logger.info(f"Monkey started with arguments: {arg_string}")
if self._opts.depth is not None:
def start(self):
if self._is_another_monkey_running():
logger.info("Another instance of the monkey is already running")
return
logger.info("Monkey is starting...")
self._set_propagation_depth(self._opts)
self._add_default_server_to_config(self._opts.server)
self._connect_to_island()
# TODO: Reevaluate who is responsible to send this information
if is_windows_os():
T1106Telem(ScanStatus.USED, UsageEnum.SINGLETON_WINAPI).send()
if InfectionMonkey._is_monkey_alive_by_config():
logger.info("Monkey marked 'not alive' from configuration.")
return
if InfectionMonkey._is_upgrade_to_64_needed():
self._upgrade_to_64()
logger.info("32 bit Agent can't run on 64 bit system.")
return
self._setup()
self._master.start()
@staticmethod
def _set_propagation_depth(options):
if options.depth is not None:
WormConfiguration._depth_from_commandline = True
WormConfiguration.depth = self._opts.depth
WormConfiguration.depth = options.depth
logger.debug("Setting propagation depth from command line")
logger.debug(f"Set propagation depth to {WormConfiguration.depth}")
self._keep_running = True
self._network = NetworkScanner()
if self._default_server:
if self._default_server not in WormConfiguration.command_servers:
logger.debug("Added default server: %s" % self._default_server)
WormConfiguration.command_servers.insert(0, self._default_server)
@staticmethod
def _add_default_server_to_config(default_server: str):
if default_server:
if default_server not in WormConfiguration.command_servers:
logger.debug("Added default server: %s" % default_server)
WormConfiguration.command_servers.insert(0, default_server)
else:
logger.debug(
"Default server: %s is already in command servers list" % self._default_server
"Default server: %s is already in command servers list" % default_server
)
def start(self):
try:
logger.info("Monkey is starting...")
logger.debug("Starting the setup phase.")
# Sets island's IP and port for monkey to communicate to
self.set_default_server()
self.set_default_port()
# Create a dir for monkey files if there isn't one
create_monkey_dir()
self.upgrade_to_64_if_needed()
ControlClient.wakeup(parent=self._parent)
ControlClient.load_control_config()
if is_windows_os():
T1106Telem(ScanStatus.USED, UsageEnum.SINGLETON_WINAPI).send()
self.shutdown_by_not_alive_config()
if is_running_on_island():
WormConfiguration.started_on_island = True
ControlClient.report_start_on_island()
if not ControlClient.should_monkey_run(self._opts.vulnerable_port):
raise PlannedShutdownException(
"Monkey shouldn't run on current machine "
"(it will be exploited later with more depth)."
)
if firewall.is_enabled():
firewall.add_firewall_rule()
self._monkey_tunnel = ControlClient.create_control_tunnel()
if self._monkey_tunnel:
self._monkey_tunnel.start()
StateTelem(is_done=False, version=get_version()).send()
TunnelTelem().send()
logger.debug("Starting the post-breach phase asynchronously.")
self._post_breach_phase = Thread(target=self.start_post_breach_phase)
self._post_breach_phase.start()
if not InfectionMonkey.max_propagation_depth_reached():
logger.info("Starting the propagation phase.")
logger.debug("Running with depth: %d" % WormConfiguration.depth)
self.propagate()
else:
logger.info(
"Maximum propagation depth has been reached; monkey will not propagate."
)
TraceTelem(MAX_DEPTH_REACHED_MESSAGE).send()
if self._keep_running and WormConfiguration.alive:
InfectionMonkey.run_ransomware()
# if host was exploited, before continue to closing the tunnel ensure the exploited
# host had its chance to
# connect to the tunnel
if len(self._exploited_machines) > 0:
time_to_sleep = WormConfiguration.keep_tunnel_open_time
logger.info(
"Sleeping %d seconds for exploited machines to connect to tunnel", time_to_sleep
)
time.sleep(time_to_sleep)
except PlannedShutdownException:
logger.info(
"A planned shutdown of the Monkey occurred. Logging the reason and finishing "
"execution."
def _connect_to_island(self):
# Sets island's IP and port for monkey to communicate to
if not self._is_default_server_set():
raise Exception(
"Monkey couldn't find server with {} default tunnel.".format(self._opts.tunnel)
)
logger.exception("Planned shutdown, reason:")
self._set_default_port()
finally:
if self._monkey_tunnel:
self._monkey_tunnel.stop()
self._monkey_tunnel.join()
if self._post_breach_phase:
self._post_breach_phase.join()
def start_post_breach_phase(self):
self.collect_system_info_if_configured()
PostBreach().execute_all_configured()
@staticmethod
def max_propagation_depth_reached():
return 0 == WormConfiguration.depth
def collect_system_info_if_configured(self):
logger.debug("Calling for system info collection")
try:
system_info_collector = SystemInfoCollector()
system_info = system_info_collector.get_info()
SystemInfoTelem(system_info).send()
except Exception as e:
logger.exception(f"Exception encountered during system info collection: {str(e)}")
def shutdown_by_not_alive_config(self):
if not WormConfiguration.alive:
raise PlannedShutdownException("Marked 'not alive' from configuration.")
def propagate(self):
ControlClient.keepalive()
ControlClient.wakeup(parent=self._opts.parent)
ControlClient.load_control_config()
self._network.initialize()
def _is_default_server_set(self) -> bool:
"""
Sets the default server for the Monkey to communicate back to.
:return
"""
if not ControlClient.find_server(default_tunnel=self._opts.tunnel):
return False
self._opts.server = WormConfiguration.current_server
logger.debug("default server set to: %s" % self._opts.server)
return True
self._fingerprint = HostFinger.get_instances()
@staticmethod
def _is_monkey_alive_by_config():
return not WormConfiguration.alive
self._exploiters = HostExploiter.get_classes()
@staticmethod
def _is_upgrade_to_64_needed():
return WindowsUpgrader.should_upgrade()
if not WormConfiguration.alive:
logger.info("Marked not alive from configuration")
def _upgrade_to_64(self):
self._singleton.unlock()
logger.info("32bit monkey running on 64bit Windows. Upgrading.")
WindowsUpgrader.upgrade(self._opts)
logger.info("Finished upgrading from 32bit to 64bit.")
machines = self._network.get_victim_machines(
max_find=WormConfiguration.victims_max_find,
stop_callback=ControlClient.check_for_stop,
)
for machine in machines:
if ControlClient.check_for_stop():
break
def _setup(self):
logger.debug("Starting the setup phase.")
for finger in self._fingerprint:
logger.info(
"Trying to get OS fingerprint from %r with module %s",
machine,
finger.__class__.__name__,
)
try:
finger.get_host_fingerprint(machine)
except BaseException as exc:
logger.error(
"Failed to run fingerprinter %s, exception %s" % finger.__class__.__name__,
str(exc),
)
ScanTelem(machine).send()
# skip machines that we've already exploited
if machine in self._exploited_machines:
logger.debug("Skipping %r - already exploited", machine)
continue
if self._monkey_tunnel:
self._monkey_tunnel.set_tunnel_for_host(machine)
if self._default_server:
if self._network.on_island(self._default_server):
machine.set_default_server(
get_interface_to_target(machine.ip_addr)
+ (":" + self._default_server_port if self._default_server_port else "")
)
else:
machine.set_default_server(self._default_server)
logger.debug(
"Default server for machine: %r set to %s" % (machine, machine.default_server)
)
# Order exploits according to their type
self._exploiters = sorted(
self._exploiters, key=lambda exploiter_: exploiter_.EXPLOIT_TYPE.value
if self._should_exit_for_performance():
logger.info(
"Monkey shouldn't run on current machine to improve perfomance"
"(it will be exploited later with more depth)."
)
host_exploited = False
for exploiter in [exploiter(machine) for exploiter in self._exploiters]:
if self.try_exploiting(machine, exploiter):
host_exploited = True
VictimHostTelem("T1210", ScanStatus.USED, machine=machine).send()
if exploiter.RUNS_AGENT_ON_SUCCESS:
break # if adding machine to exploited, won't try other exploits
# on it
if not host_exploited:
self._fail_exploitation_machines.add(machine)
VictimHostTelem("T1210", ScanStatus.SCANNED, machine=machine).send()
if not self._keep_running:
break
return
if not WormConfiguration.alive:
logger.info("Marked not alive from configuration")
if firewall.is_enabled():
firewall.add_firewall_rule()
def upgrade_to_64_if_needed(self):
if WindowsUpgrader.should_upgrade():
self._upgrading_to_64 = True
self._singleton.unlock()
logger.info("32bit monkey running on 64bit Windows. Upgrading.")
WindowsUpgrader.upgrade(self._opts)
raise PlannedShutdownException("Finished upgrading from 32bit to 64bit.")
self._monkey_inbound_tunnel = ControlClient.create_control_tunnel()
if self._monkey_inbound_tunnel:
self._monkey_inbound_tunnel.start()
StateTelem(is_done=False, version=get_version()).send()
TunnelTelem().send()
register_signal_handlers(self._master)
def _should_exit_for_performance(self):
"""
This method implements propagation performance enhancing algorithm that
kicks in if the run was started from the Island.
Should get replaced by other, better performance enhancement solutions
"""
if is_running_on_island():
WormConfiguration.started_on_island = True
ControlClient.report_start_on_island()
return not ControlClient.should_monkey_run(self._opts.vulnerable_port)
def _is_another_monkey_running(self):
return not self._singleton.try_lock()
def _set_default_port(self):
try:
self._default_server_port = self._opts.server.split(":")[1]
except KeyError:
self._default_server_port = ""
def cleanup(self):
logger.info("Monkey cleanup started")
self._keep_running = False
self._wait_for_exploited_machine_connection()
try:
if self._is_upgrade_to_64_needed():
logger.debug("Cleanup not needed for 32 bit agent on 64 bit system(it didn't run)")
return
if self._master:
self._master.cleanup()
if self._monkey_inbound_tunnel:
self._monkey_inbound_tunnel.stop()
self._monkey_inbound_tunnel.join()
if firewall.is_enabled():
firewall.remove_firewall_rule()
firewall.close()
InfectionMonkey._self_delete()
InfectionMonkey._send_log()
if self._upgrading_to_64:
InfectionMonkey.close_tunnel()
firewall.close()
else:
StateTelem(
is_done=True, version=get_version()
).send() # Signal the server (before closing the tunnel)
InfectionMonkey.close_tunnel()
firewall.close()
self.send_log()
self._singleton.unlock()
InfectionMonkey.self_delete()
# TODO: Determine how long between when we
# send telemetry and the monkey actually exits
InfectionMonkey._close_tunnel()
self._singleton.unlock()
except Exception as e:
logger.error(f"An error occurred while cleaning up the monkey agent: {e}")
InfectionMonkey._self_delete()
logger.info("Monkey is shutting down")
def _wait_for_exploited_machine_connection(self):
# TODO check for actual exploitation
machines_exploited = False
# if host was exploited, before continue to closing the tunnel ensure the exploited
# host had its chance to
# connect to the tunnel
if machines_exploited:
time_to_sleep = WormConfiguration.keep_tunnel_open_time
logger.info(
"Sleeping %d seconds for exploited machines to connect to tunnel", time_to_sleep
)
time.sleep(time_to_sleep)
@staticmethod
def close_tunnel():
def _close_tunnel():
tunnel_address = (
ControlClient.proxies.get("https", "").replace("https://", "").split(":")[0]
)
@ -322,7 +245,18 @@ class InfectionMonkey(object):
tunnel.quit_tunnel(tunnel_address)
@staticmethod
def self_delete():
def _send_log():
monkey_log_path = get_monkey_log_path()
if os.path.exists(monkey_log_path):
with open(monkey_log_path, "r") as f:
log = f.read()
else:
log = ""
ControlClient.send_log(log)
@staticmethod
def _self_delete():
status = ScanStatus.USED if remove_monkey_dir() else ScanStatus.SCANNED
T1107Telem(status, get_monkey_dir_path()).send()
@ -351,117 +285,3 @@ class InfectionMonkey(object):
status = ScanStatus.SCANNED
if status:
T1107Telem(status, sys.executable).send()
def send_log(self):
monkey_log_path = get_monkey_log_path()
if os.path.exists(monkey_log_path):
with open(monkey_log_path, "r") as f:
log = f.read()
else:
log = ""
ControlClient.send_log(log)
def try_exploiting(self, machine, exploiter):
"""
Workflow of exploiting one machine with one exploiter
:param machine: Machine monkey tries to exploit
:param exploiter: Exploiter to use on that machine
:return: True if successfully exploited, False otherwise
"""
if not exploiter.is_os_supported():
logger.info(
"Skipping exploiter %s host:%r, os %s is not supported",
exploiter.__class__.__name__,
machine,
machine.os,
)
return False
logger.info(
"Trying to exploit %r with exploiter %s...", machine, exploiter.__class__.__name__
)
result = False
try:
result = exploiter.exploit_host()
if result:
self.successfully_exploited(machine, exploiter, exploiter.RUNS_AGENT_ON_SUCCESS)
return True
else:
logger.info(
"Failed exploiting %r with exploiter %s", machine, exploiter.__class__.__name__
)
except ExploitingVulnerableMachineError as exc:
logger.error(
"Exception while attacking %s using %s: %s",
machine,
exploiter.__class__.__name__,
exc,
)
self.successfully_exploited(machine, exploiter, exploiter.RUNS_AGENT_ON_SUCCESS)
return True
except FailedExploitationError as e:
logger.info(
"Failed exploiting %r with exploiter %s, %s",
machine,
exploiter.__class__.__name__,
e,
)
except Exception as exc:
logger.exception(
"Exception while attacking %s using %s: %s",
machine,
exploiter.__class__.__name__,
exc,
)
finally:
exploiter.send_exploit_telemetry(result)
return False
def successfully_exploited(self, machine, exploiter, RUNS_AGENT_ON_SUCCESS=True):
"""
Workflow of registering successfully exploited machine
:param machine: machine that was exploited
:param exploiter: exploiter that succeeded
"""
if RUNS_AGENT_ON_SUCCESS:
self._exploited_machines.add(machine)
logger.info("Successfully propagated to %s using %s", machine, exploiter.__class__.__name__)
# check if max-exploitation limit is reached
if WormConfiguration.victims_max_exploit <= len(self._exploited_machines):
self._keep_running = False
logger.info("Max exploited victims reached (%d)", WormConfiguration.victims_max_exploit)
def set_default_port(self):
try:
self._default_server_port = self._default_server.split(":")[1]
except KeyError:
self._default_server_port = ""
def set_default_server(self):
"""
Sets the default server for the Monkey to communicate back to.
:raises PlannedShutdownException if couldn't find the server.
"""
if not ControlClient.find_server(default_tunnel=self._default_tunnel):
raise PlannedShutdownException(
"Monkey couldn't find server with {} default tunnel.".format(self._default_tunnel)
)
self._default_server = WormConfiguration.current_server
logger.debug("default server set to: %s" % self._default_server)
def log_arguments(self):
arg_string = " ".join([f"{key}: {value}" for key, value in vars(self._opts).items()])
logger.info(f"Monkey started with arguments: {arg_string}")
@staticmethod
def run_ransomware():
try:
ransomware_payload = build_ransomware_payload(WormConfiguration.ransomware)
ransomware_payload.run_payload()
except Exception as ex:
logger.error(f"An unexpected error occurred while running the ransomware payload: {ex}")

View File

@ -220,17 +220,48 @@ class MockPuppet(IPuppet):
self, name: str, host: str, options: Dict, interrupt: threading.Event
) -> ExploiterResultData:
logger.debug(f"exploit_hosts({name}, {host}, {options})")
attempts = [
{
"result": False,
"user": "Administrator",
"password": "",
"lm_hash": "",
"ntlm_hash": "",
"ssh_key": host,
},
{
"result": False,
"user": "root",
"password": "",
"lm_hash": "",
"ntlm_hash": "",
"ssh_key": host,
},
]
info_powershell = {
"display_name": "PowerShell",
"started": "2021-11-25T15:57:06.307696",
"finished": "2021-11-25T15:58:33.788238",
"vulnerable_urls": [],
"vulnerable_ports": [],
"executed_cmds": [
{
"cmd": "/tmp/monkey m0nk3y -s 10.10.10.10:5000 -d 1 >git s /dev/null 2>&1 &",
"powershell": True,
}
],
}
info_ssh = {
"display_name": "SSH",
"started": "2021-11-25T15:57:06.307696",
"finished": "2021-11-25T15:58:33.788238",
"vulnerable_urls": [],
"vulnerable_ports": [22],
"executed_cmds": [],
}
successful_exploiters = {
DOT_1: {
"PowerShellExploiter": ExploiterResultData(
True, {"info": "important success stuff"}, ["attempt 1"]
)
},
DOT_3: {
"SSHExploiter": ExploiterResultData(
False, {"info": "important failure stuff"}, ["attempt 2"]
)
},
DOT_1: {"PowerShellExploiter": ExploiterResultData(True, info_powershell, attempts)},
DOT_3: {"SSHExploiter": ExploiterResultData(False, info_ssh, attempts)},
}
return successful_exploiters[host][name]

View File

@ -0,0 +1,2 @@
class PlannedShutdownError(Exception):
pass

View File

@ -1,2 +0,0 @@
class PlannedShutdownException(Exception):
pass

View File

@ -3,7 +3,7 @@ import signal
from infection_monkey.i_master import IMaster
from infection_monkey.utils.environment import is_windows_os
from infection_monkey.utils.exceptions.planned_shutdown_exception import PlannedShutdownException
from infection_monkey.utils.exceptions.planned_shutdown_error import PlannedShutdownError
logger = logging.getLogger(__name__)
@ -16,7 +16,7 @@ class StopSignalHandler:
self._handle_signal(signum)
# Windows signal handlers must return boolean. Only raising this exception for POSIX
# signals.
raise PlannedShutdownException("Monkey Agent got an interrupt signal")
raise PlannedShutdownError("Monkey Agent got an interrupt signal")
def handle_windows_signals(self, signum):
import win32con