forked from p15670423/monkey
parent
453f45e403
commit
765ce858fb
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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]):
|
|
@ -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,
|
||||||
)
|
)
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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())
|
||||||
|
|
||||||
|
|
|
@ -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"])
|
||||||
|
|
||||||
|
|
|
@ -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 = (
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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.")
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue