Agent: Rename IAgentRepository -> IAgentBinaryRepository

PR #2239
This commit is contained in:
Mike Salvatore 2022-09-01 14:08:11 -04:00
parent 453f45e403
commit 765ce858fb
17 changed files with 59 additions and 47 deletions

View File

@ -9,7 +9,7 @@ from common.utils.exceptions import FailedExploitationError
from infection_monkey.i_puppet import ExploiterResultData from infection_monkey.i_puppet import ExploiterResultData
from infection_monkey.telemetry.messengers.i_telemetry_messenger import ITelemetryMessenger from infection_monkey.telemetry.messengers.i_telemetry_messenger import ITelemetryMessenger
from . import IAgentRepository from . import IAgentBinaryRepository
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -61,7 +61,7 @@ class HostExploiter:
current_depth: int, current_depth: int,
telemetry_messenger: ITelemetryMessenger, telemetry_messenger: ITelemetryMessenger,
event_queue: IEventQueue, event_queue: IEventQueue,
agent_repository: IAgentRepository, agent_binary_repository: IAgentBinaryRepository,
options: Dict, options: Dict,
interrupt: threading.Event, interrupt: threading.Event,
): ):
@ -69,7 +69,7 @@ class HostExploiter:
self.current_depth = current_depth self.current_depth = current_depth
self.telemetry_messenger = telemetry_messenger self.telemetry_messenger = telemetry_messenger
self.event_queue = event_queue self.event_queue = event_queue
self.agent_repository = agent_repository self.agent_binary_repository = agent_binary_repository
self.options = options self.options = options
self.interrupt = interrupt self.interrupt = interrupt

View File

@ -1,3 +1,3 @@
from .i_agent_repository import IAgentRepository from .i_agent_binary_repository import IAgentBinaryRepository
from .caching_agent_repository import CachingAgentRepository from .caching_agent_binary_repository import CachingAgentBinaryRepository
from .exploiter_wrapper import ExploiterWrapper from .exploiter_wrapper import ExploiterWrapper

View File

@ -8,14 +8,14 @@ import requests
from common import OperatingSystem from common import OperatingSystem
from common.common_consts.timeouts import MEDIUM_REQUEST_TIMEOUT from common.common_consts.timeouts import MEDIUM_REQUEST_TIMEOUT
from . import IAgentRepository from . import IAgentBinaryRepository
class CachingAgentRepository(IAgentRepository): class CachingAgentBinaryRepository(IAgentBinaryRepository):
""" """
CachingAgentRepository implements the IAgentRepository interface and downloads the requested CachingAgentBinaryRepository implements the IAgentBinaryRepository interface and downloads the
agent binary from the island on request. The agent binary is cached so that only one request is requested agent binary from the island on request. The agent binary is cached so that only one
actually sent to the island for each requested binary. request is actually sent to the island for each requested binary.
""" """
def __init__(self, island_url: str, proxies: Mapping[str, str]): def __init__(self, island_url: str, proxies: Mapping[str, str]):

View File

@ -5,7 +5,7 @@ from common.event_queue import IEventQueue
from infection_monkey.model import VictimHost from infection_monkey.model import VictimHost
from infection_monkey.telemetry.messengers.i_telemetry_messenger import ITelemetryMessenger from infection_monkey.telemetry.messengers.i_telemetry_messenger import ITelemetryMessenger
from . import IAgentRepository from . import IAgentBinaryRepository
from .HostExploiter import HostExploiter from .HostExploiter import HostExploiter
@ -23,12 +23,12 @@ class ExploiterWrapper:
exploit_class: Type[HostExploiter], exploit_class: Type[HostExploiter],
telemetry_messenger: ITelemetryMessenger, telemetry_messenger: ITelemetryMessenger,
event_queue: IEventQueue, event_queue: IEventQueue,
agent_repository: IAgentRepository, agent_binary_repository: IAgentBinaryRepository,
): ):
self._exploit_class = exploit_class self._exploit_class = exploit_class
self._telemetry_messenger = telemetry_messenger self._telemetry_messenger = telemetry_messenger
self._event_queue = event_queue self._event_queue = event_queue
self._agent_repository = agent_repository self._agent_binary_repository = agent_binary_repository
def exploit_host( def exploit_host(
self, host: VictimHost, current_depth: int, options: Dict, interrupt: threading.Event self, host: VictimHost, current_depth: int, options: Dict, interrupt: threading.Event
@ -39,7 +39,7 @@ class ExploiterWrapper:
current_depth, current_depth,
self._telemetry_messenger, self._telemetry_messenger,
self._event_queue, self._event_queue,
self._agent_repository, self._agent_binary_repository,
options, options,
interrupt, interrupt,
) )
@ -48,13 +48,16 @@ class ExploiterWrapper:
self, self,
telemetry_messenger: ITelemetryMessenger, telemetry_messenger: ITelemetryMessenger,
event_queue: IEventQueue, event_queue: IEventQueue,
agent_repository: IAgentRepository, agent_binary_repository: IAgentBinaryRepository,
): ):
self._telemetry_messenger = telemetry_messenger self._telemetry_messenger = telemetry_messenger
self._event_queue = event_queue self._event_queue = event_queue
self._agent_repository = agent_repository self._agent_binary_repository = agent_binary_repository
def wrap(self, exploit_class: Type[HostExploiter]): def wrap(self, exploit_class: Type[HostExploiter]):
return ExploiterWrapper.Inner( return ExploiterWrapper.Inner(
exploit_class, self._telemetry_messenger, self._event_queue, self._agent_repository exploit_class,
self._telemetry_messenger,
self._event_queue,
self._agent_binary_repository,
) )

View File

@ -48,7 +48,7 @@ class HadoopExploiter(WebRCE):
return self.exploit_result return self.exploit_result
http_path, http_thread = HTTPTools.create_locked_transfer( http_path, http_thread = HTTPTools.create_locked_transfer(
self.host, str(monkey_path_on_victim), self.agent_repository self.host, str(monkey_path_on_victim), self.agent_binary_repository
) )
try: try:

View File

@ -3,15 +3,15 @@ import io
from common import OperatingSystem from common import OperatingSystem
# TODO: The Island also has an IAgentRepository with a totally different interface. At the moment, # TODO: The Island also has an IAgentBinaryRepository with a totally different interface. At the
# the Island and Agent have different needs, but at some point we should unify these. # moment, the Island and Agent have different needs, but at some point we should unify these.
class IAgentRepository(metaclass=abc.ABCMeta): class IAgentBinaryRepository(metaclass=abc.ABCMeta):
""" """
IAgentRepository provides an interface for other components to access agent binaries. Notably, IAgentBinaryRepository provides an interface for other components to access agent binaries.
this is used by exploiters during propagation to retrieve the appropriate agent binary so that Notably, this is used by exploiters during propagation to retrieve the appropriate agent binary
it can be uploaded to a victim and executed. so that it can be uploaded to a victim and executed.
""" """
@abc.abstractmethod @abc.abstractmethod

View File

@ -79,7 +79,7 @@ class Log4ShellExploiter(WebRCE):
def _start_agent_http_server(self, dropper_target_path) -> str: def _start_agent_http_server(self, dropper_target_path) -> str:
# Create server for http download and wait for it's startup. # Create server for http download and wait for it's startup.
http_path, http_thread = HTTPTools.try_create_locked_transfer( http_path, http_thread = HTTPTools.try_create_locked_transfer(
self.host, dropper_target_path, self.agent_repository self.host, dropper_target_path, self.agent_binary_repository
) )
self._agent_http_server_thread = http_thread self._agent_http_server_thread = http_thread
return http_path return http_path

View File

@ -147,7 +147,7 @@ class MSSQLExploiter(HostExploiter):
def _start_agent_server(self, agent_path_on_victim: PureWindowsPath) -> LockedHTTPServer: def _start_agent_server(self, agent_path_on_victim: PureWindowsPath) -> LockedHTTPServer:
self.agent_http_path, http_thread = HTTPTools.create_locked_transfer( self.agent_http_path, http_thread = HTTPTools.create_locked_transfer(
self.host, str(agent_path_on_victim), self.agent_repository self.host, str(agent_path_on_victim), self.agent_binary_repository
) )
return http_thread return http_thread

View File

@ -163,7 +163,7 @@ class PowerShellExploiter(HostExploiter):
temp_monkey_binary_filepath.unlink() temp_monkey_binary_filepath.unlink()
def _create_local_agent_file(self, binary_path): def _create_local_agent_file(self, binary_path):
agent_binary_bytes = self.agent_repository.get_agent_binary(OperatingSystem.WINDOWS) agent_binary_bytes = self.agent_binary_repository.get_agent_binary(OperatingSystem.WINDOWS)
with open(binary_path, "wb") as f: with open(binary_path, "wb") as f:
f.write(agent_binary_bytes.getvalue()) f.write(agent_binary_bytes.getvalue())

View File

@ -30,7 +30,7 @@ class SMBExploiter(HostExploiter):
SMB_SERVICE_NAME = "InfectionMonkey" SMB_SERVICE_NAME = "InfectionMonkey"
def _exploit_host(self): def _exploit_host(self):
agent_binary = self.agent_repository.get_agent_binary(self.host.os["type"]) agent_binary = self.agent_binary_repository.get_agent_binary(self.host.os["type"])
dest_path = get_agent_dst_path(self.host) dest_path = get_agent_dst_path(self.host)
creds = generate_brute_force_combinations(self.options["credentials"]) creds = generate_brute_force_combinations(self.options["credentials"])

View File

@ -195,7 +195,9 @@ class SSHExploiter(HostExploiter):
logger.error(self.exploit_result.error_message) logger.error(self.exploit_result.error_message)
return self.exploit_result return self.exploit_result
agent_binary_file_object = self.agent_repository.get_agent_binary(self.exploit_result.os) agent_binary_file_object = self.agent_binary_repository.get_agent_binary(
self.exploit_result.os
)
if not agent_binary_file_object: if not agent_binary_file_object:
self.exploit_result.error_message = ( self.exploit_result.error_message = (

View File

@ -15,10 +15,10 @@ logger = logging.getLogger(__name__)
class HTTPTools(object): class HTTPTools(object):
@staticmethod @staticmethod
def try_create_locked_transfer( def try_create_locked_transfer(
host, src_path, agent_repository, local_ip=None, local_port=None host, src_path, agent_binary_repository, local_ip=None, local_port=None
): ):
http_path, http_thread = HTTPTools.create_locked_transfer( http_path, http_thread = HTTPTools.create_locked_transfer(
host, src_path, agent_repository, local_ip, local_port host, src_path, agent_binary_repository, local_ip, local_port
) )
if not http_path: if not http_path:
raise Exception("Http transfer creation failed.") raise Exception("Http transfer creation failed.")
@ -27,13 +27,13 @@ class HTTPTools(object):
@staticmethod @staticmethod
def create_locked_transfer( def create_locked_transfer(
host, dropper_target_path, agent_repository, local_ip=None, local_port=None host, dropper_target_path, agent_binary_repository, local_ip=None, local_port=None
) -> LockedHTTPServer: ) -> LockedHTTPServer:
""" """
Create http server for file transfer with a lock Create http server for file transfer with a lock
:param host: Variable with target's information :param host: Variable with target's information
:param src_path: Monkey's path on current system :param src_path: Monkey's path on current system
:param agent_repository: Repository to download Monkey agents :param agent_binary_repository: Repository to download Monkey agents
:param local_ip: IP where to host server :param local_ip: IP where to host server
:param local_port: Port at which to host monkey's download :param local_port: Port at which to host monkey's download
:return: Server address in http://%s:%s/%s format and LockedHTTPServer handler :return: Server address in http://%s:%s/%s format and LockedHTTPServer handler
@ -52,7 +52,12 @@ class HTTPTools(object):
return None, None return None, None
httpd = LockedHTTPServer( httpd = LockedHTTPServer(
local_ip, local_port, host.os["type"], dropper_target_path, agent_repository, lock local_ip,
local_port,
host.os["type"],
dropper_target_path,
agent_binary_repository,
lock,
) )
httpd.start() httpd.start()
lock.acquire() lock.acquire()

View File

@ -295,7 +295,7 @@ class WebRCE(HostExploiter):
dropper_target_path = self.monkey_target_paths[self.host.os["type"]] dropper_target_path = self.monkey_target_paths[self.host.os["type"]]
# Create server for http download and wait for it's startup. # Create server for http download and wait for it's startup.
http_path, http_thread = HTTPTools.create_locked_transfer( http_path, http_thread = HTTPTools.create_locked_transfer(
self.host, dropper_target_path, self.agent_repository self.host, dropper_target_path, self.agent_binary_repository
) )
if not http_path: if not http_path:
logger.debug("Exploiter failed, http transfer creation failed.") logger.debug("Exploiter failed, http transfer creation failed.")

View File

@ -68,7 +68,7 @@ class WmiExploiter(HostExploiter):
self.report_login_attempt(True, user, password, lm_hash, ntlm_hash) self.report_login_attempt(True, user, password, lm_hash, ntlm_hash)
self.exploit_result.exploitation_success = True self.exploit_result.exploitation_success = True
downloaded_agent = self.agent_repository.get_agent_binary(self.host.os["type"]) downloaded_agent = self.agent_binary_repository.get_agent_binary(self.host.os["type"])
if self._is_interrupted(): if self._is_interrupted():
self._set_interrupted() self._set_interrupted()

View File

@ -27,7 +27,7 @@ from infection_monkey.credential_repository import (
IPropagationCredentialsRepository, IPropagationCredentialsRepository,
add_credentials_from_event_to_propagation_credentials_repository, add_credentials_from_event_to_propagation_credentials_repository,
) )
from infection_monkey.exploit import CachingAgentRepository, ExploiterWrapper from infection_monkey.exploit import CachingAgentBinaryRepository, ExploiterWrapper
from infection_monkey.exploit.hadoop import HadoopExploiter from infection_monkey.exploit.hadoop import HadoopExploiter
from infection_monkey.exploit.log4shell import Log4ShellExploiter from infection_monkey.exploit.log4shell import Log4ShellExploiter
from infection_monkey.exploit.mssqlexec import MSSQLExploiter from infection_monkey.exploit.mssqlexec import MSSQLExploiter
@ -270,10 +270,12 @@ 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)
agent_repository = CachingAgentRepository( agent_binary_repository = CachingAgentBinaryRepository(
f"https://{self._control_client.server_address}", self._control_client.proxies f"https://{self._control_client.server_address}", self._control_client.proxies
) )
exploit_wrapper = ExploiterWrapper(self._telemetry_messenger, event_queue, agent_repository) exploit_wrapper = ExploiterWrapper(
self._telemetry_messenger, event_queue, agent_binary_repository
)
puppet.load_plugin( puppet.load_plugin(
"HadoopExploiter", exploit_wrapper.wrap(HadoopExploiter), PluginType.EXPLOITER "HadoopExploiter", exploit_wrapper.wrap(HadoopExploiter), PluginType.EXPLOITER

View File

@ -19,7 +19,7 @@ logger = getLogger(__name__)
class FileServHTTPRequestHandler(http.server.BaseHTTPRequestHandler): class FileServHTTPRequestHandler(http.server.BaseHTTPRequestHandler):
protocol_version = "HTTP/1.1" protocol_version = "HTTP/1.1"
victim_os = "" victim_os = ""
agent_repository = None agent_binary_repository = None
def version_string(self): def version_string(self):
return "Microsoft-IIS/7.5." return "Microsoft-IIS/7.5."
@ -66,7 +66,7 @@ class FileServHTTPRequestHandler(http.server.BaseHTTPRequestHandler):
self.send_error(500, "") self.send_error(500, "")
return None, 0, 0 return None, 0, 0
try: try:
f = self.agent_repository.get_agent_binary(self.victim_os) f = self.agent_binary_repository.get_agent_binary(self.victim_os)
except IOError: except IOError:
self.send_error(404, "File not found") self.send_error(404, "File not found")
return None, 0, 0 return None, 0, 0
@ -178,7 +178,7 @@ class LockedHTTPServer(threading.Thread):
local_port, local_port,
victim_os, victim_os,
dropper_target_path, dropper_target_path,
agent_repository, agent_binary_repository,
lock, lock,
max_downloads=1, max_downloads=1,
): ):
@ -186,7 +186,7 @@ class LockedHTTPServer(threading.Thread):
self._local_port = local_port self._local_port = local_port
self._victim_os = victim_os self._victim_os = victim_os
self._dropper_target_path = dropper_target_path self._dropper_target_path = dropper_target_path
self._agent_repository = agent_repository self._agent_binary_repository = agent_binary_repository
self.max_downloads = max_downloads self.max_downloads = max_downloads
self.downloads = 0 self.downloads = 0
self._stopped = False self._stopped = False
@ -200,7 +200,7 @@ class LockedHTTPServer(threading.Thread):
from infection_monkey.telemetry.attack.t1105_telem import T1105Telem from infection_monkey.telemetry.attack.t1105_telem import T1105Telem
victim_os = self._victim_os victim_os = self._victim_os
agent_repository = self._agent_repository agent_binary_repository = self._agent_binary_repository
@staticmethod @staticmethod
def report_download(dest=None): def report_download(dest=None):

View File

@ -17,8 +17,8 @@ LM_HASH_LIST = ["bogo_lm_1"]
NT_HASH_LIST = ["bogo_nt_1", "bogo_nt_2"] NT_HASH_LIST = ["bogo_nt_1", "bogo_nt_2"]
mock_agent_repository = MagicMock() mock_agent_binary_repository = MagicMock()
mock_agent_repository.get_agent_binary.return_value = BytesIO(b"BINARY_EXECUTABLE") mock_agent_binary_repository.get_agent_binary.return_value = BytesIO(b"BINARY_EXECUTABLE")
@pytest.fixture @pytest.fixture
@ -37,7 +37,7 @@ def powershell_arguments(http_and_https_both_enabled_host):
"current_depth": 2, "current_depth": 2,
"telemetry_messenger": MagicMock(), "telemetry_messenger": MagicMock(),
"event_queue": MagicMock(), "event_queue": MagicMock(),
"agent_repository": mock_agent_repository, "agent_binary_repository": mock_agent_binary_repository,
"interrupt": threading.Event(), "interrupt": threading.Event(),
} }
return arguments return arguments