Skip to content

Commit ad1928d

Browse files
authoredJun 15, 2022
Merge pull request #2016 from guardicore/1996-agent-worm-config-decouple
1996 agent worm config decouple
2 parents 133f7f5 + 5ff617b commit ad1928d

File tree

11 files changed

+126
-155
lines changed

11 files changed

+126
-155
lines changed
 

‎monkey/infection_monkey/config.py

+1-5
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"exploit_user_list",
99
"exploit_ssh_keys",
1010
]
11-
LOCAL_CONFIG_VARS = ["name", "id", "current_server", "max_depth"]
11+
LOCAL_CONFIG_VARS = ["name", "id", "max_depth"]
1212
HIDDEN_FIELD_REPLACEMENT_CONTENT = "hidden"
1313

1414

@@ -62,10 +62,6 @@ def as_dict(self):
6262
# depth of propagation
6363
depth = 2
6464
max_depth = None
65-
current_server = ""
66-
67-
# Configuration servers to try to connect to, in this order.
68-
command_servers = []
6965

7066
keep_tunnel_open_time = 30
7167

‎monkey/infection_monkey/control.py

+66-86
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import platform
44
from pprint import pformat
55
from socket import gethostname
6+
from typing import Mapping, Optional
67

78
import requests
89
from requests.exceptions import ConnectionError
@@ -23,11 +24,17 @@
2324
PBA_FILE_DOWNLOAD = "https://%s/api/pba/download/%s"
2425

2526

26-
class ControlClient(object):
27-
proxies = {}
27+
class ControlClient:
28+
# TODO When we have mechanism that support telemetry messenger
29+
# with control clients, then this needs to be removed
30+
# https://github.com/guardicore/monkey/blob/133f7f5da131b481561141171827d1f9943f6aec/monkey/infection_monkey/telemetry/base_telem.py
31+
control_client_object = None
2832

29-
@staticmethod
30-
def wakeup(parent=None):
33+
def __init__(self, server_address: str, proxies: Optional[Mapping[str, str]] = None):
34+
self.proxies = {} if not proxies else proxies
35+
self.server_address = server_address
36+
37+
def wakeup(self, parent=None):
3138
if parent:
3239
logger.debug("parent: %s" % (parent,))
3340

@@ -45,67 +52,51 @@ def wakeup(parent=None):
4552
"launch_time": agent_process.get_start_time(),
4653
}
4754

48-
if ControlClient.proxies:
49-
monkey["tunnel"] = ControlClient.proxies.get("https")
55+
if self.proxies:
56+
monkey["tunnel"] = self.proxies.get("https")
5057

5158
requests.post( # noqa: DUO123
52-
f"https://{WormConfiguration.current_server}/api/agent",
59+
f"https://{self.server_address}/api/agent",
5360
data=json.dumps(monkey),
5461
headers={"content-type": "application/json"},
5562
verify=False,
56-
proxies=ControlClient.proxies,
63+
proxies=self.proxies,
5764
timeout=MEDIUM_REQUEST_TIMEOUT,
5865
)
5966

60-
@staticmethod
61-
def find_server(default_tunnel=None):
62-
logger.debug(
63-
"Trying to wake up with Monkey Island servers list: %r"
64-
% WormConfiguration.command_servers
65-
)
67+
def find_server(self, default_tunnel=None):
68+
logger.debug(f"Trying to wake up with Monkey Island server: {self.server_address}")
6669
if default_tunnel:
6770
logger.debug("default_tunnel: %s" % (default_tunnel,))
6871

69-
current_server = ""
70-
71-
for server in WormConfiguration.command_servers:
72-
try:
73-
current_server = server
74-
75-
debug_message = "Trying to connect to server: %s" % server
76-
if ControlClient.proxies:
77-
debug_message += " through proxies: %s" % ControlClient.proxies
78-
logger.debug(debug_message)
79-
requests.get( # noqa: DUO123
80-
f"https://{server}/api?action=is-up",
81-
verify=False,
82-
proxies=ControlClient.proxies,
83-
timeout=MEDIUM_REQUEST_TIMEOUT,
84-
)
85-
WormConfiguration.current_server = current_server
86-
break
87-
88-
except ConnectionError as exc:
89-
current_server = ""
90-
logger.warning("Error connecting to control server %s: %s", server, exc)
91-
92-
if current_server:
72+
try:
73+
debug_message = "Trying to connect to server: %s" % self.server_address
74+
if self.proxies:
75+
debug_message += " through proxies: %s" % self.proxies
76+
logger.debug(debug_message)
77+
requests.get( # noqa: DUO123
78+
f"https://{self.server_address}/api?action=is-up",
79+
verify=False,
80+
proxies=self.proxies,
81+
timeout=MEDIUM_REQUEST_TIMEOUT,
82+
)
9383
return True
84+
except ConnectionError as exc:
85+
logger.warning("Error connecting to control server %s: %s", self.server_address, exc)
86+
87+
if self.proxies:
88+
return False
9489
else:
95-
if ControlClient.proxies:
96-
return False
90+
logger.info("Starting tunnel lookup...")
91+
proxy_find = tunnel.find_tunnel(default=default_tunnel)
92+
if proxy_find:
93+
self.set_proxies(proxy_find)
94+
return self.find_server()
9795
else:
98-
logger.info("Starting tunnel lookup...")
99-
proxy_find = tunnel.find_tunnel(default=default_tunnel)
100-
if proxy_find:
101-
ControlClient.set_proxies(proxy_find)
102-
return ControlClient.find_server()
103-
else:
104-
logger.info("No tunnel found")
105-
return False
106-
107-
@staticmethod
108-
def set_proxies(proxy_find):
96+
logger.info("No tunnel found")
97+
return False
98+
99+
def set_proxies(self, proxy_find):
109100
"""
110101
Note: The proxy schema changes between different versions of requests and urllib3,
111102
which causes the machine to not open a tunnel back.
@@ -120,13 +111,12 @@ def set_proxies(proxy_find):
120111
proxy_address, proxy_port = proxy_find
121112
logger.info("Found tunnel at %s:%s" % (proxy_address, proxy_port))
122113
if is_windows_os():
123-
ControlClient.proxies["https"] = f"http://{proxy_address}:{proxy_port}"
114+
self.proxies["https"] = f"http://{proxy_address}:{proxy_port}"
124115
else:
125-
ControlClient.proxies["https"] = f"{proxy_address}:{proxy_port}"
116+
self.proxies["https"] = f"{proxy_address}:{proxy_port}"
126117

127-
@staticmethod
128-
def send_telemetry(telem_category, json_data: str):
129-
if not WormConfiguration.current_server:
118+
def send_telemetry(self, telem_category, json_data: str):
119+
if not self.server_address:
130120
logger.error(
131121
"Trying to send %s telemetry before current server is established, aborting."
132122
% telem_category
@@ -135,53 +125,45 @@ def send_telemetry(telem_category, json_data: str):
135125
try:
136126
telemetry = {"monkey_guid": GUID, "telem_category": telem_category, "data": json_data}
137127
requests.post( # noqa: DUO123
138-
"https://%s/api/telemetry" % (WormConfiguration.current_server,),
128+
"https://%s/api/telemetry" % (self.server_address,),
139129
data=json.dumps(telemetry),
140130
headers={"content-type": "application/json"},
141131
verify=False,
142-
proxies=ControlClient.proxies,
132+
proxies=self.proxies,
143133
timeout=MEDIUM_REQUEST_TIMEOUT,
144134
)
145135
except Exception as exc:
146-
logger.warning(
147-
"Error connecting to control server %s: %s", WormConfiguration.current_server, exc
148-
)
136+
logger.warning(f"Error connecting to control server {self.server_address}: {exc}")
149137

150-
@staticmethod
151-
def send_log(log):
152-
if not WormConfiguration.current_server:
138+
def send_log(self, log):
139+
if not self.server_address:
153140
return
154141
try:
155142
telemetry = {"monkey_guid": GUID, "log": json.dumps(log)}
156143
requests.post( # noqa: DUO123
157-
"https://%s/api/log" % (WormConfiguration.current_server,),
144+
"https://%s/api/log" % (self.server_address,),
158145
data=json.dumps(telemetry),
159146
headers={"content-type": "application/json"},
160147
verify=False,
161-
proxies=ControlClient.proxies,
148+
proxies=self.proxies,
162149
timeout=MEDIUM_REQUEST_TIMEOUT,
163150
)
164151
except Exception as exc:
165-
logger.warning(
166-
"Error connecting to control server %s: %s", WormConfiguration.current_server, exc
167-
)
152+
logger.warning(f"Error connecting to control server {self.server_address}: {exc}")
168153

169-
@staticmethod
170-
def load_control_config():
171-
if not WormConfiguration.current_server:
154+
def load_control_config(self):
155+
if not self.server_address:
172156
return
173157
try:
174158
reply = requests.get( # noqa: DUO123
175-
f"https://{WormConfiguration.current_server}/api/agent/",
159+
f"https://{self.server_address}/api/agent/",
176160
verify=False,
177-
proxies=ControlClient.proxies,
161+
proxies=self.proxies,
178162
timeout=MEDIUM_REQUEST_TIMEOUT,
179163
)
180164

181165
except Exception as exc:
182-
logger.warning(
183-
"Error connecting to control server %s: %s", WormConfiguration.current_server, exc
184-
)
166+
logger.warning(f"Error connecting to control server {self.server_address}: {exc}")
185167
return
186168

187169
try:
@@ -194,18 +176,17 @@ def load_control_config():
194176
# we don't continue with default conf here because it might be dangerous
195177
logger.error(
196178
"Error parsing JSON reply from control server %s (%s): %s",
197-
WormConfiguration.current_server,
179+
self.server_address,
198180
reply._content,
199181
exc,
200182
)
201183
raise Exception("Couldn't load from from server's configuration, aborting. %s" % exc)
202184

203-
@staticmethod
204-
def create_control_tunnel():
205-
if not WormConfiguration.current_server:
185+
def create_control_tunnel(self):
186+
if not self.server_address:
206187
return None
207188

208-
my_proxy = ControlClient.proxies.get("https", "").replace("https://", "")
189+
my_proxy = self.proxies.get("https", "").replace("https://", "")
209190
if my_proxy:
210191
proxy_class = TcpProxy
211192
try:
@@ -224,13 +205,12 @@ def create_control_tunnel():
224205
target_port=target_port,
225206
)
226207

227-
@staticmethod
228-
def get_pba_file(filename):
208+
def get_pba_file(self, filename):
229209
try:
230210
return requests.get( # noqa: DUO123
231-
PBA_FILE_DOWNLOAD % (WormConfiguration.current_server, filename),
211+
PBA_FILE_DOWNLOAD % (self.server_address, filename),
232212
verify=False,
233-
proxies=ControlClient.proxies,
213+
proxies=self.proxies,
234214
timeout=LONG_REQUEST_TIMEOUT,
235215
)
236216
except requests.exceptions.RequestException:

‎monkey/infection_monkey/master/control_channel.py

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import json
22
import logging
3+
from typing import Mapping
34

45
import requests
56

67
from common.common_consts.timeouts import SHORT_REQUEST_TIMEOUT
7-
from infection_monkey.control import ControlClient
88
from infection_monkey.custom_types import PropagationCredentials
99
from infection_monkey.i_control_channel import IControlChannel, IslandCommunicationError
1010

@@ -14,9 +14,10 @@
1414

1515

1616
class ControlChannel(IControlChannel):
17-
def __init__(self, server: str, agent_id: str):
17+
def __init__(self, server: str, agent_id: str, proxies: Mapping[str, str]):
1818
self._agent_id = agent_id
1919
self._control_channel_server = server
20+
self._proxies = proxies
2021

2122
def should_agent_stop(self) -> bool:
2223
if not self._control_channel_server:
@@ -30,7 +31,7 @@ def should_agent_stop(self) -> bool:
3031
response = requests.get( # noqa: DUO123
3132
url,
3233
verify=False,
33-
proxies=ControlClient.proxies,
34+
proxies=self._proxies,
3435
timeout=SHORT_REQUEST_TIMEOUT,
3536
)
3637
response.raise_for_status()
@@ -51,7 +52,7 @@ def get_config(self) -> dict:
5152
response = requests.get( # noqa: DUO123
5253
f"https://{self._control_channel_server}/api/agent",
5354
verify=False,
54-
proxies=ControlClient.proxies,
55+
proxies=self._proxies,
5556
timeout=SHORT_REQUEST_TIMEOUT,
5657
)
5758
response.raise_for_status()
@@ -74,7 +75,7 @@ def get_credentials_for_propagation(self) -> PropagationCredentials:
7475
response = requests.get( # noqa: DUO123
7576
propagation_credentials_url,
7677
verify=False,
77-
proxies=ControlClient.proxies,
78+
proxies=self._proxies,
7879
timeout=SHORT_REQUEST_TIMEOUT,
7980
)
8081
response.raise_for_status()

0 commit comments

Comments
 (0)