3
3
import platform
4
4
from pprint import pformat
5
5
from socket import gethostname
6
+ from typing import Mapping , Optional
6
7
7
8
import requests
8
9
from requests .exceptions import ConnectionError
23
24
PBA_FILE_DOWNLOAD = "https://%s/api/pba/download/%s"
24
25
25
26
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
28
32
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 ):
31
38
if parent :
32
39
logger .debug ("parent: %s" % (parent ,))
33
40
@@ -45,67 +52,51 @@ def wakeup(parent=None):
45
52
"launch_time" : agent_process .get_start_time (),
46
53
}
47
54
48
- if ControlClient .proxies :
49
- monkey ["tunnel" ] = ControlClient .proxies .get ("https" )
55
+ if self .proxies :
56
+ monkey ["tunnel" ] = self .proxies .get ("https" )
50
57
51
58
requests .post ( # noqa: DUO123
52
- f"https://{ WormConfiguration . current_server } /api/agent" ,
59
+ f"https://{ self . server_address } /api/agent" ,
53
60
data = json .dumps (monkey ),
54
61
headers = {"content-type" : "application/json" },
55
62
verify = False ,
56
- proxies = ControlClient .proxies ,
63
+ proxies = self .proxies ,
57
64
timeout = MEDIUM_REQUEST_TIMEOUT ,
58
65
)
59
66
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 } " )
66
69
if default_tunnel :
67
70
logger .debug ("default_tunnel: %s" % (default_tunnel ,))
68
71
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
+ )
93
83
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
94
89
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 ()
97
95
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 ):
109
100
"""
110
101
Note: The proxy schema changes between different versions of requests and urllib3,
111
102
which causes the machine to not open a tunnel back.
@@ -120,13 +111,12 @@ def set_proxies(proxy_find):
120
111
proxy_address , proxy_port = proxy_find
121
112
logger .info ("Found tunnel at %s:%s" % (proxy_address , proxy_port ))
122
113
if is_windows_os ():
123
- ControlClient .proxies ["https" ] = f"http://{ proxy_address } :{ proxy_port } "
114
+ self .proxies ["https" ] = f"http://{ proxy_address } :{ proxy_port } "
124
115
else :
125
- ControlClient .proxies ["https" ] = f"{ proxy_address } :{ proxy_port } "
116
+ self .proxies ["https" ] = f"{ proxy_address } :{ proxy_port } "
126
117
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 :
130
120
logger .error (
131
121
"Trying to send %s telemetry before current server is established, aborting."
132
122
% telem_category
@@ -135,53 +125,45 @@ def send_telemetry(telem_category, json_data: str):
135
125
try :
136
126
telemetry = {"monkey_guid" : GUID , "telem_category" : telem_category , "data" : json_data }
137
127
requests .post ( # noqa: DUO123
138
- "https://%s/api/telemetry" % (WormConfiguration . current_server ,),
128
+ "https://%s/api/telemetry" % (self . server_address ,),
139
129
data = json .dumps (telemetry ),
140
130
headers = {"content-type" : "application/json" },
141
131
verify = False ,
142
- proxies = ControlClient .proxies ,
132
+ proxies = self .proxies ,
143
133
timeout = MEDIUM_REQUEST_TIMEOUT ,
144
134
)
145
135
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 } " )
149
137
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 :
153
140
return
154
141
try :
155
142
telemetry = {"monkey_guid" : GUID , "log" : json .dumps (log )}
156
143
requests .post ( # noqa: DUO123
157
- "https://%s/api/log" % (WormConfiguration . current_server ,),
144
+ "https://%s/api/log" % (self . server_address ,),
158
145
data = json .dumps (telemetry ),
159
146
headers = {"content-type" : "application/json" },
160
147
verify = False ,
161
- proxies = ControlClient .proxies ,
148
+ proxies = self .proxies ,
162
149
timeout = MEDIUM_REQUEST_TIMEOUT ,
163
150
)
164
151
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 } " )
168
153
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 :
172
156
return
173
157
try :
174
158
reply = requests .get ( # noqa: DUO123
175
- f"https://{ WormConfiguration . current_server } /api/agent/" ,
159
+ f"https://{ self . server_address } /api/agent/" ,
176
160
verify = False ,
177
- proxies = ControlClient .proxies ,
161
+ proxies = self .proxies ,
178
162
timeout = MEDIUM_REQUEST_TIMEOUT ,
179
163
)
180
164
181
165
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 } " )
185
167
return
186
168
187
169
try :
@@ -194,18 +176,17 @@ def load_control_config():
194
176
# we don't continue with default conf here because it might be dangerous
195
177
logger .error (
196
178
"Error parsing JSON reply from control server %s (%s): %s" ,
197
- WormConfiguration . current_server ,
179
+ self . server_address ,
198
180
reply ._content ,
199
181
exc ,
200
182
)
201
183
raise Exception ("Couldn't load from from server's configuration, aborting. %s" % exc )
202
184
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 :
206
187
return None
207
188
208
- my_proxy = ControlClient .proxies .get ("https" , "" ).replace ("https://" , "" )
189
+ my_proxy = self .proxies .get ("https" , "" ).replace ("https://" , "" )
209
190
if my_proxy :
210
191
proxy_class = TcpProxy
211
192
try :
@@ -224,13 +205,12 @@ def create_control_tunnel():
224
205
target_port = target_port ,
225
206
)
226
207
227
- @staticmethod
228
- def get_pba_file (filename ):
208
+ def get_pba_file (self , filename ):
229
209
try :
230
210
return requests .get ( # noqa: DUO123
231
- PBA_FILE_DOWNLOAD % (WormConfiguration . current_server , filename ),
211
+ PBA_FILE_DOWNLOAD % (self . server_address , filename ),
232
212
verify = False ,
233
- proxies = ControlClient .proxies ,
213
+ proxies = self .proxies ,
234
214
timeout = LONG_REQUEST_TIMEOUT ,
235
215
)
236
216
except requests .exceptions .RequestException :
0 commit comments