atomicshop 2.16.46__py3-none-any.whl → 2.17.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of atomicshop might be problematic. Click here for more details.
- atomicshop/__init__.py +1 -1
- atomicshop/diff_check.py +3 -3
- atomicshop/mitm/connection_thread_worker.py +147 -100
- atomicshop/mitm/engines/create_module_template.py +18 -7
- atomicshop/mitm/initialize_engines.py +13 -11
- atomicshop/mitm/recs_files.py +0 -1
- atomicshop/mitm/shared_functions.py +0 -2
- atomicshop/web_apis/__init__.py +0 -0
- atomicshop/web_apis/google_custom_search.py +0 -0
- atomicshop/web_apis/google_llm.py +42 -0
- atomicshop/wrappers/fibratusw/install.py +1 -2
- atomicshop/wrappers/socketw/certificator.py +5 -2
- atomicshop/wrappers/socketw/creator.py +38 -7
- atomicshop/wrappers/socketw/receiver.py +19 -0
- atomicshop/wrappers/socketw/sender.py +1 -1
- atomicshop/wrappers/socketw/sni.py +6 -8
- atomicshop/wrappers/socketw/socket_client.py +41 -20
- atomicshop/wrappers/sysmonw.py +1 -1
- {atomicshop-2.16.46.dist-info → atomicshop-2.17.0.dist-info}/METADATA +1 -1
- {atomicshop-2.16.46.dist-info → atomicshop-2.17.0.dist-info}/RECORD +23 -20
- {atomicshop-2.16.46.dist-info → atomicshop-2.17.0.dist-info}/LICENSE.txt +0 -0
- {atomicshop-2.16.46.dist-info → atomicshop-2.17.0.dist-info}/WHEEL +0 -0
- {atomicshop-2.16.46.dist-info → atomicshop-2.17.0.dist-info}/top_level.txt +0 -0
atomicshop/__init__.py
CHANGED
atomicshop/diff_check.py
CHANGED
|
@@ -54,9 +54,9 @@ class DiffChecker:
|
|
|
54
54
|
function input for that object. So, not always you know what your object type during class initialization.
|
|
55
55
|
:param check_object_display_name: string, name of the object to display in the message.
|
|
56
56
|
If not specified, the provided 'check_object' will be displayed.
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
#:param aggregation: boolean, if True, the object will be aggregated with other objects in the list of objects.
|
|
58
|
+
# Meaning, that the object will be checked against the existing objects in the list, and if it is not
|
|
59
|
+
# in the list, it will be added to the list. If it is in the list, it will be ignored.
|
|
60
60
|
:param input_file_path: string, full file path for storing input file for current state of objects,
|
|
61
61
|
to check later if this state isn't updated. If this variable is left empty, all the content will be saved
|
|
62
62
|
in memory and input file will not be used.
|
|
@@ -143,6 +143,124 @@ def thread_worker_main(
|
|
|
143
143
|
|
|
144
144
|
network_logger.info("Thread Finished. Will continue listening on the Main thread")
|
|
145
145
|
|
|
146
|
+
def process_client_raw_data_request() -> bool:
|
|
147
|
+
"""
|
|
148
|
+
Process the client raw data request.
|
|
149
|
+
|
|
150
|
+
:return: True if the socket should be closed, False if not.
|
|
151
|
+
"""
|
|
152
|
+
|
|
153
|
+
# If the message is empty, then the connection was closed already by the other side,
|
|
154
|
+
# so we can close the socket as well.
|
|
155
|
+
# If the received message from the client is not empty, then continue.
|
|
156
|
+
if not client_received_raw_data:
|
|
157
|
+
return True
|
|
158
|
+
|
|
159
|
+
# Putting the received message to the aggregating message class.
|
|
160
|
+
client_message.request_raw_bytes = client_received_raw_data
|
|
161
|
+
|
|
162
|
+
parse_http()
|
|
163
|
+
if protocol != '':
|
|
164
|
+
client_message.protocol = protocol
|
|
165
|
+
|
|
166
|
+
# Parse websocket frames only if it is not the first protocol upgrade request.
|
|
167
|
+
if protocol == 'Websocket' and cycle_count != 0:
|
|
168
|
+
client_message.request_raw_decoded = parse_websocket(client_message.request_raw_bytes)
|
|
169
|
+
|
|
170
|
+
# Custom parser, should parse HTTP body or the whole message if not HTTP.
|
|
171
|
+
parser_instance = parser(client_message)
|
|
172
|
+
parser_instance.parse()
|
|
173
|
+
|
|
174
|
+
# Converting body parsed to string on logging, since there is no strict rule for the parameter
|
|
175
|
+
# to be string.
|
|
176
|
+
parser_instance.logger.info(f"{str(client_message.request_body_parsed)[0: 100]}...")
|
|
177
|
+
|
|
178
|
+
return False
|
|
179
|
+
|
|
180
|
+
def create_responder_response():
|
|
181
|
+
# Since we're in response mode, we'll record the request anyway, after the responder did its job.
|
|
182
|
+
client_message.info = "In Server Response Mode"
|
|
183
|
+
|
|
184
|
+
# Re-initiate the 'client_message.response_list_of_raw_bytes' list, since we'll be appending
|
|
185
|
+
# new entries for empty list.
|
|
186
|
+
client_message.response_list_of_raw_bytes = list()
|
|
187
|
+
|
|
188
|
+
# If it's the first cycle and the protocol is Websocket, then we'll create the HTTP Handshake
|
|
189
|
+
# response automatically.
|
|
190
|
+
if protocol == 'Websocket' and cycle_count == 0:
|
|
191
|
+
client_message.response_list_of_raw_bytes.append(
|
|
192
|
+
websocket_parse.create_byte_http_response(client_message.request_raw_bytes))
|
|
193
|
+
# Creating response for parsed message and printing
|
|
194
|
+
responder.create_response(client_message)
|
|
195
|
+
|
|
196
|
+
# Output first 100 characters of all the responses in the list.
|
|
197
|
+
for response_raw_bytes_single in client_message.response_list_of_raw_bytes:
|
|
198
|
+
responder.logger.info(f"{response_raw_bytes_single[0: 100]}...")
|
|
199
|
+
|
|
200
|
+
def create_client_socket():
|
|
201
|
+
# If there is a custom certificate for the client for this domain, then we'll use it.
|
|
202
|
+
# noinspection PyTypeChecker
|
|
203
|
+
custom_client_pem_certificate_path: str = None
|
|
204
|
+
for subdomain, pem_file_path in mtls_dict.items():
|
|
205
|
+
if subdomain == client_message.server_name:
|
|
206
|
+
custom_client_pem_certificate_path = pem_file_path
|
|
207
|
+
break
|
|
208
|
+
|
|
209
|
+
# If we're on localhost, then use external services list in order to resolve the domain:
|
|
210
|
+
# config['tcp']['forwarding_dns_service_ipv4_list___only_for_localhost']
|
|
211
|
+
if client_message.client_ip in base.THIS_DEVICE_IP_LIST:
|
|
212
|
+
service_client_instance = socket_client.SocketClient(
|
|
213
|
+
service_name=client_message.server_name, service_port=client_message.destination_port,
|
|
214
|
+
tls=is_tls,
|
|
215
|
+
dns_servers_list=(
|
|
216
|
+
config_static.TCPServer.forwarding_dns_service_ipv4_list___only_for_localhost),
|
|
217
|
+
logger=network_logger,
|
|
218
|
+
custom_pem_client_certificate_file_path=custom_client_pem_certificate_path
|
|
219
|
+
)
|
|
220
|
+
# If we're not on localhost, then connect to domain directly.
|
|
221
|
+
else:
|
|
222
|
+
service_client_instance = socket_client.SocketClient(
|
|
223
|
+
service_name=client_message.server_name,
|
|
224
|
+
service_port=client_message.destination_port,
|
|
225
|
+
tls=is_tls,
|
|
226
|
+
logger=network_logger,
|
|
227
|
+
custom_pem_client_certificate_file_path=custom_client_pem_certificate_path
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
return service_client_instance
|
|
231
|
+
|
|
232
|
+
def process_received_response_from_service_client():
|
|
233
|
+
if client_message.error is not None:
|
|
234
|
+
statistics_error_list.append(client_message.error)
|
|
235
|
+
|
|
236
|
+
# Since we need a list for raw bytes, we'll add the 'response_raw_bytes' to our list object.
|
|
237
|
+
# But we need to re-initiate it first.
|
|
238
|
+
client_message.response_list_of_raw_bytes = list()
|
|
239
|
+
# If there was error during send or receive from the service and response was None,
|
|
240
|
+
# It means that there was no response at all because of the error.
|
|
241
|
+
if client_message.error and response_raw_bytes is None:
|
|
242
|
+
client_message.response_list_of_raw_bytes.append(None)
|
|
243
|
+
# If there was no error, but response came empty, it means that the service has closed the
|
|
244
|
+
# socket after it received the request, without sending any data.
|
|
245
|
+
elif client_message.error is None and response_raw_bytes is None:
|
|
246
|
+
client_message.response_list_of_raw_bytes.append("")
|
|
247
|
+
else:
|
|
248
|
+
client_message.response_list_of_raw_bytes.append(response_raw_bytes)
|
|
249
|
+
|
|
250
|
+
client_message.response_list_of_raw_decoded = list()
|
|
251
|
+
# Make HTTP Response parsing only if there was response at all.
|
|
252
|
+
if response_raw_bytes:
|
|
253
|
+
response_raw_decoded, is_http_response, response_parsing_error = (
|
|
254
|
+
HTTPResponseParse(response_raw_bytes).parse())
|
|
255
|
+
|
|
256
|
+
if is_http_response:
|
|
257
|
+
client_message.response_list_of_raw_decoded.append(response_raw_decoded)
|
|
258
|
+
elif protocol == 'Websocket' and cycle_count != 0:
|
|
259
|
+
response_decoded = parse_websocket(response_raw_bytes)
|
|
260
|
+
client_message.response_list_of_raw_decoded.append(response_decoded)
|
|
261
|
+
else:
|
|
262
|
+
client_message.response_list_of_raw_decoded.append(None)
|
|
263
|
+
|
|
146
264
|
# Building client message object before the loop only for any exception to occurs, since we write it to
|
|
147
265
|
# recording file in its current state.
|
|
148
266
|
client_message: ClientMessage = ClientMessage()
|
|
@@ -172,7 +290,7 @@ def thread_worker_main(
|
|
|
172
290
|
|
|
173
291
|
# Loading parser by domain, if there is no parser for current domain - general reference parser is loaded.
|
|
174
292
|
# These should be outside any loop and initialized only once entering the thread.
|
|
175
|
-
parser, responder, recorder = assign_class_by_domain(
|
|
293
|
+
parser, responder, recorder, mtls_dict = assign_class_by_domain(
|
|
176
294
|
engines_usage=config_static.TCPServer.engines_usage,
|
|
177
295
|
engines_list=engines_list,
|
|
178
296
|
message_domain_name=server_name,
|
|
@@ -191,6 +309,7 @@ def thread_worker_main(
|
|
|
191
309
|
network_logger.info(f"Thread Created - Client [{client_ip}:{source_port}] | "
|
|
192
310
|
f"Destination service: [{server_name}:{destination_port}]")
|
|
193
311
|
|
|
312
|
+
end_socket: bool = False
|
|
194
313
|
service_client = None
|
|
195
314
|
# Loop while received message is not empty, if so, close socket, since other side already closed.
|
|
196
315
|
# noinspection PyTypeChecker
|
|
@@ -217,79 +336,34 @@ def thread_worker_main(
|
|
|
217
336
|
# Getting current time of message received from client.
|
|
218
337
|
client_message.request_time_received = datetime.now()
|
|
219
338
|
|
|
220
|
-
|
|
221
|
-
#
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
if client_received_raw_data:
|
|
229
|
-
# Putting the received message to the aggregating message class.
|
|
230
|
-
client_message.request_raw_bytes = client_received_raw_data
|
|
339
|
+
# Peek if there is some data in the socket.
|
|
340
|
+
# This is needed to check if the client just connects without sending data, if so we need to try and
|
|
341
|
+
# receive data from the server and send it to the client.
|
|
342
|
+
# We will do it only on the first cycle, after that the connection should work as usual.
|
|
343
|
+
# Sometimes the client will execute connection without sending data, just for the server to send response.
|
|
344
|
+
is_socket_ready: bool = True
|
|
345
|
+
if cycle_count == 0:
|
|
346
|
+
is_socket_ready = receiver.is_socket_ready_for_read(client_socket)
|
|
231
347
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
348
|
+
if is_socket_ready:
|
|
349
|
+
network_logger.info(f"Initializing Receiver on cycle: {str(cycle_count+1)}")
|
|
350
|
+
# Getting message from the client over the socket using specific class.
|
|
351
|
+
client_received_raw_data = receiver.Receiver(
|
|
352
|
+
ssl_socket=client_socket, logger=network_logger).receive()
|
|
235
353
|
|
|
236
|
-
|
|
237
|
-
if protocol == 'Websocket' and cycle_count != 0:
|
|
238
|
-
client_message.request_raw_decoded = parse_websocket(client_message.request_raw_bytes)
|
|
239
|
-
|
|
240
|
-
# Custom parser, should parse HTTP body or the whole message if not HTTP.
|
|
241
|
-
parser_instance = parser(client_message)
|
|
242
|
-
parser_instance.parse()
|
|
243
|
-
|
|
244
|
-
# Converting body parsed to string on logging, since there is no strict rule for the parameter
|
|
245
|
-
# to be string.
|
|
246
|
-
parser_instance.logger.info(f"{str(client_message.request_body_parsed)[0: 100]}...")
|
|
354
|
+
end_socket = process_client_raw_data_request()
|
|
247
355
|
|
|
356
|
+
if not end_socket:
|
|
248
357
|
# If we're in response mode, execute responder.
|
|
249
358
|
response_raw_bytes = None
|
|
250
359
|
if config_static.TCPServer.server_response_mode:
|
|
251
|
-
|
|
252
|
-
client_message.info = "In Server Response Mode"
|
|
253
|
-
|
|
254
|
-
# Re-initiate the 'client_message.response_list_of_raw_bytes' list, since we'll be appending
|
|
255
|
-
# new entries for empty list.
|
|
256
|
-
client_message.response_list_of_raw_bytes = list()
|
|
257
|
-
|
|
258
|
-
# If it's the first cycle and the protocol is Websocket, then we'll create the HTTP Handshake
|
|
259
|
-
# response automatically.
|
|
260
|
-
if protocol == 'Websocket' and cycle_count == 0:
|
|
261
|
-
client_message.response_list_of_raw_bytes.append(
|
|
262
|
-
websocket_parse.create_byte_http_response(client_message.request_raw_bytes))
|
|
263
|
-
# Creating response for parsed message and printing
|
|
264
|
-
responder.create_response(client_message)
|
|
265
|
-
|
|
266
|
-
# Output first 100 characters of all the responses in the list.
|
|
267
|
-
for response_raw_bytes in client_message.response_list_of_raw_bytes:
|
|
268
|
-
if response_raw_bytes:
|
|
269
|
-
responder.logger.info(f"{response_raw_bytes[0: 100]}...")
|
|
270
|
-
else:
|
|
271
|
-
responder.logger.info(f"Response empty...")
|
|
360
|
+
create_responder_response()
|
|
272
361
|
# Else, we're not in response mode, then execute client connect and record section.
|
|
273
362
|
else:
|
|
274
363
|
# If "service_client" object is not defined, we'll define it.
|
|
275
|
-
# If it's defined, then
|
|
276
|
-
# domain.
|
|
364
|
+
# If it's defined, then there's still active "ssl_socket" with connection to the service domain.
|
|
277
365
|
if not service_client:
|
|
278
|
-
|
|
279
|
-
# config['tcp']['forwarding_dns_service_ipv4_list___only_for_localhost']
|
|
280
|
-
if client_message.client_ip in base.THIS_DEVICE_IP_LIST:
|
|
281
|
-
service_client = socket_client.SocketClient(
|
|
282
|
-
service_name=client_message.server_name, service_port=client_message.destination_port,
|
|
283
|
-
tls=is_tls,
|
|
284
|
-
dns_servers_list=(
|
|
285
|
-
config_static.TCPServer.forwarding_dns_service_ipv4_list___only_for_localhost),
|
|
286
|
-
logger=network_logger
|
|
287
|
-
)
|
|
288
|
-
# If we're not on localhost, then connect to domain directly.
|
|
289
|
-
else:
|
|
290
|
-
service_client = socket_client.SocketClient(
|
|
291
|
-
service_name=client_message.server_name, service_port=client_message.destination_port,
|
|
292
|
-
tls=is_tls, logger=network_logger)
|
|
366
|
+
service_client = create_client_socket()
|
|
293
367
|
|
|
294
368
|
# Sending current client message and receiving a response.
|
|
295
369
|
# If there was an error it will be passed to "client_message" object class and if not, "None" will
|
|
@@ -297,40 +371,9 @@ def thread_worker_main(
|
|
|
297
371
|
# If there was connection error or socket close, then "ssl_socket" of the "service_client"
|
|
298
372
|
# will be empty.
|
|
299
373
|
response_raw_bytes, client_message.error, client_message.server_ip, service_ssl_socket = (
|
|
300
|
-
service_client.send_receive_to_service(client_message.request_raw_bytes))
|
|
301
|
-
|
|
302
|
-
if client_message.error is not None:
|
|
303
|
-
statistics_error_list.append(client_message.error)
|
|
304
|
-
|
|
305
|
-
# Since we need a list for raw bytes, we'll add the 'response_raw_bytes' to our list object.
|
|
306
|
-
# But we need to re-initiate it first.
|
|
307
|
-
client_message.response_list_of_raw_bytes = list()
|
|
308
|
-
# If there was error during send or receive from the service and response was None,
|
|
309
|
-
# It means that there was no response at all because of the error.
|
|
310
|
-
if client_message.error and response_raw_bytes is None:
|
|
311
|
-
client_message.response_list_of_raw_bytes.append(None)
|
|
312
|
-
# If there was no error, but response came empty, it means that the service has closed the
|
|
313
|
-
# socket after it received the request, without sending any data.
|
|
314
|
-
elif client_message.error is None and response_raw_bytes is None:
|
|
315
|
-
client_message.response_list_of_raw_bytes.append("")
|
|
316
|
-
else:
|
|
317
|
-
client_message.response_list_of_raw_bytes.append(response_raw_bytes)
|
|
318
|
-
|
|
319
|
-
client_message.response_list_of_raw_decoded = list()
|
|
320
|
-
# Make HTTP Response parsing only if there was response at all.
|
|
321
|
-
if response_raw_bytes:
|
|
322
|
-
response_raw_decoded, is_http_response, response_parsing_error = (
|
|
323
|
-
HTTPResponseParse(response_raw_bytes).parse())
|
|
324
|
-
|
|
325
|
-
if is_http_response:
|
|
326
|
-
client_message.response_list_of_raw_decoded.append(response_raw_decoded)
|
|
327
|
-
elif protocol == 'Websocket' and cycle_count != 0:
|
|
328
|
-
response_decoded = parse_websocket(response_raw_bytes)
|
|
329
|
-
client_message.response_list_of_raw_decoded.append(response_decoded)
|
|
330
|
-
else:
|
|
331
|
-
client_message.response_list_of_raw_decoded.append(None)
|
|
332
|
-
|
|
374
|
+
service_client.send_receive_to_service(client_message.request_raw_bytes, (not is_socket_ready)))
|
|
333
375
|
|
|
376
|
+
process_received_response_from_service_client()
|
|
334
377
|
|
|
335
378
|
# So if the socket was closed and there was an error we can break the loop
|
|
336
379
|
if not service_ssl_socket:
|
|
@@ -338,8 +381,8 @@ def thread_worker_main(
|
|
|
338
381
|
recorded = True
|
|
339
382
|
break
|
|
340
383
|
|
|
341
|
-
# If there is a response, then send it.
|
|
342
|
-
if
|
|
384
|
+
# If there is a response(s), then send it.
|
|
385
|
+
if client_message.response_list_of_raw_bytes:
|
|
343
386
|
# Sending response/s to client no matter if in record mode or not.
|
|
344
387
|
network_logger.info(
|
|
345
388
|
f"Sending messages to client: {len(client_message.response_list_of_raw_bytes)}")
|
|
@@ -362,7 +405,10 @@ def thread_worker_main(
|
|
|
362
405
|
|
|
363
406
|
record_and_statistics_write()
|
|
364
407
|
recorded = True
|
|
365
|
-
|
|
408
|
+
|
|
409
|
+
# If the message is empty, then the connection was closed already by the other side, also if there will
|
|
410
|
+
# be empty response from the server, so we can close the socket as well and exceptions will be raised.
|
|
411
|
+
if end_socket:
|
|
366
412
|
# If it's the first cycle we will record the message from the client if it came empty.
|
|
367
413
|
if cycle_count == 0:
|
|
368
414
|
record_and_statistics_write()
|
|
@@ -370,6 +416,7 @@ def thread_worker_main(
|
|
|
370
416
|
# In other cases, we'll just break the loop, since empty message means that the other side closed the
|
|
371
417
|
# connection.
|
|
372
418
|
recorded = True
|
|
419
|
+
|
|
373
420
|
break
|
|
374
421
|
|
|
375
422
|
finish_thread()
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import os
|
|
2
|
+
import argparse
|
|
2
3
|
from typing import Literal
|
|
3
4
|
|
|
4
5
|
from ... import filesystem
|
|
@@ -19,11 +20,17 @@ SCRIPT_DIRECTORY: str = filesystem.get_file_directory(__file__)
|
|
|
19
20
|
ENGINES_DIRECTORY_PATH: str = filesystem.get_working_directory() + os.sep + ENGINES_DIRECTORY_NAME
|
|
20
21
|
|
|
21
22
|
|
|
23
|
+
def parse_arguments():
|
|
24
|
+
parser = argparse.ArgumentParser(description='Create a new engine module template.')
|
|
25
|
+
parser.add_argument('engine_name', type=str, help='The name of the new engine.')
|
|
26
|
+
return parser.parse_args()
|
|
27
|
+
|
|
28
|
+
|
|
22
29
|
class CreateModuleTemplate:
|
|
23
|
-
def __init__(self
|
|
30
|
+
def __init__(self):
|
|
24
31
|
# === Get input variables. ===
|
|
25
|
-
self.engine_name: str = engine_name
|
|
26
|
-
self.domains: list =
|
|
32
|
+
self.engine_name: str = parse_arguments().engine_name
|
|
33
|
+
self.domains: list = ['example.com']
|
|
27
34
|
|
|
28
35
|
# New engine's directory.
|
|
29
36
|
self.new_engine_directory: str = ENGINES_DIRECTORY_PATH + os.sep + self.engine_name
|
|
@@ -66,10 +73,14 @@ class CreateModuleTemplate:
|
|
|
66
73
|
|
|
67
74
|
# Add "" to each domain.
|
|
68
75
|
domains_with_quotes: list = [f'"{domain}"' for domain in self.domains]
|
|
69
|
-
config_lines_list.append(f'domains = [{", ".join(domains_with_quotes)}]\n')
|
|
70
|
-
config_lines_list.append(f'
|
|
71
|
-
config_lines_list.append(f'
|
|
72
|
-
config_lines_list.append(f'
|
|
76
|
+
config_lines_list.append(f'"domains" = [{", ".join(domains_with_quotes)}]\n')
|
|
77
|
+
# config_lines_list.append(f'\n')
|
|
78
|
+
config_lines_list.append(f'"parser_file" = "{self.parser_file_name}"')
|
|
79
|
+
config_lines_list.append(f'"responder_file" = "{self.responder_file_name}"')
|
|
80
|
+
config_lines_list.append(f'"recorder_file" = "{self.recorder_file_name}"\n')
|
|
81
|
+
# config_lines_list.append(f'\n')
|
|
82
|
+
config_lines_list.append(f'[mtls]')
|
|
83
|
+
config_lines_list.append(f'# "subdomain.domain.com" = "file_name_in_current_dir.pem"')
|
|
73
84
|
|
|
74
85
|
config_file_path = self.new_engine_directory + os.sep + CONFIG_FILE_NAME
|
|
75
86
|
|
|
@@ -2,15 +2,11 @@ import os
|
|
|
2
2
|
import sys
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
|
|
5
|
-
from .. import filesystem
|
|
6
5
|
from ..file_io import tomls
|
|
7
6
|
from ..basics.classes import import_first_class_name_from_file_path
|
|
8
|
-
from ..wrappers.loggingw import loggingw
|
|
9
7
|
from .engines.__reference_general import parser___reference_general, responder___reference_general, \
|
|
10
8
|
recorder___reference_general
|
|
11
9
|
|
|
12
|
-
from . import config_static
|
|
13
|
-
|
|
14
10
|
|
|
15
11
|
class ModuleCategory:
|
|
16
12
|
def __init__(self, script_directory: str):
|
|
@@ -29,6 +25,8 @@ class ModuleCategory:
|
|
|
29
25
|
# The instance of the recorder class that will be initiated once in the script start
|
|
30
26
|
self.responder_instance = None
|
|
31
27
|
|
|
28
|
+
self.mtls: dict = dict()
|
|
29
|
+
|
|
32
30
|
def fill_engine_fields_from_general_reference(self, engines_fullpath: str):
|
|
33
31
|
# Reference module variables.
|
|
34
32
|
self.engine_name = '__reference_general'
|
|
@@ -47,6 +45,7 @@ class ModuleCategory:
|
|
|
47
45
|
|
|
48
46
|
# Getting the parameters from engine config file
|
|
49
47
|
self.domain_list = configuration_data['domains']
|
|
48
|
+
self.mtls = configuration_data['mtls']
|
|
50
49
|
|
|
51
50
|
# If there's module configuration file, but no domains in it, there's no point to continue.
|
|
52
51
|
# Since, each engine is based on domains.
|
|
@@ -54,12 +53,12 @@ class ModuleCategory:
|
|
|
54
53
|
raise ValueError(f"Engine Configuration file doesn't contain any domains: {engine_config_file_path}")
|
|
55
54
|
|
|
56
55
|
# Full path to file
|
|
57
|
-
self.parser_file_path =
|
|
58
|
-
|
|
59
|
-
self.
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
56
|
+
self.parser_file_path = f'{engine_directory_path}{os.sep}{configuration_data['parser_file']}'
|
|
57
|
+
self.responder_file_path = f'{engine_directory_path}{os.sep}{configuration_data['responder_file']}'
|
|
58
|
+
self.recorder_file_path = f'{engine_directory_path}{os.sep}{configuration_data['recorder_file']}'
|
|
59
|
+
|
|
60
|
+
for subdomain, file_name in self.mtls.items():
|
|
61
|
+
self.mtls[subdomain] = f'{engine_directory_path}{os.sep}{file_name}'
|
|
63
62
|
|
|
64
63
|
def initialize_engine(self, logs_path: str, logger=None, reference_general: bool = False, **kwargs):
|
|
65
64
|
# Initiating logger for each engine by its name
|
|
@@ -108,6 +107,7 @@ def assign_class_by_domain(
|
|
|
108
107
|
function_parser = None
|
|
109
108
|
function_responder = None
|
|
110
109
|
function_recorder = None
|
|
110
|
+
mtls_data: dict = dict()
|
|
111
111
|
|
|
112
112
|
# In case SNI came empty in the request from client, then there's no point in iterating through engine domains.
|
|
113
113
|
if message_domain_name:
|
|
@@ -130,6 +130,8 @@ def assign_class_by_domain(
|
|
|
130
130
|
function_recorder = function_module.recorder_class_object
|
|
131
131
|
# Since the responder is being initiated only once, we're assigning only the instance
|
|
132
132
|
function_responder = function_module.responder_instance
|
|
133
|
+
mtls_data = function_module.mtls
|
|
134
|
+
|
|
133
135
|
|
|
134
136
|
logger.info(f"Assigned Modules for [{message_domain_name}]: "
|
|
135
137
|
f"{function_module.parser_class_object.__name__}, "
|
|
@@ -151,4 +153,4 @@ def assign_class_by_domain(
|
|
|
151
153
|
function_responder = reference_module.responder_instance
|
|
152
154
|
|
|
153
155
|
# Return all the initiated modules
|
|
154
|
-
return function_parser, function_responder, function_recorder
|
|
156
|
+
return function_parser, function_responder, function_recorder, mtls_data
|
atomicshop/mitm/recs_files.py
CHANGED
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
import google.generativeai as genai
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class GoogleLLM:
|
|
7
|
+
def __init__(
|
|
8
|
+
self,
|
|
9
|
+
llm_api_key: str
|
|
10
|
+
) -> None:
|
|
11
|
+
self.genai = genai
|
|
12
|
+
|
|
13
|
+
os.environ["API_KEY"] = llm_api_key
|
|
14
|
+
genai.configure(api_key=os.environ["API_KEY"])
|
|
15
|
+
|
|
16
|
+
def get_current_models(self) -> list[str]:
|
|
17
|
+
""" Function to get the current models available in the Gemini API """
|
|
18
|
+
result_list: list[str] = []
|
|
19
|
+
for model in self.genai.list_models():
|
|
20
|
+
result_list.append(model.name)
|
|
21
|
+
|
|
22
|
+
return result_list
|
|
23
|
+
|
|
24
|
+
def get_answer_online(
|
|
25
|
+
self,
|
|
26
|
+
search_query: str,
|
|
27
|
+
additional_llm_instructions: str,
|
|
28
|
+
number_of_top_links: int = 2,
|
|
29
|
+
number_of_characters_per_link: int = 15000,
|
|
30
|
+
temperature: float = 0,
|
|
31
|
+
max_output_tokens: int = 4096
|
|
32
|
+
):
|
|
33
|
+
"""
|
|
34
|
+
Function to get the answer to a question by searching Google Custom Console API and processing the content using Gemini API.
|
|
35
|
+
:param search_query:
|
|
36
|
+
:param additional_llm_instructions:
|
|
37
|
+
:param number_of_top_links:
|
|
38
|
+
:param number_of_characters_per_link:
|
|
39
|
+
:param temperature:
|
|
40
|
+
:param max_output_tokens:
|
|
41
|
+
:return:
|
|
42
|
+
"""
|
|
@@ -40,8 +40,7 @@ def install_fibratus(
|
|
|
40
40
|
exclude_string='slim')
|
|
41
41
|
|
|
42
42
|
# Install the MSI file
|
|
43
|
-
msiw.install_msi(
|
|
44
|
-
msi_path=fibratus_setup_file_path, exit_on_error=True, as_admin=True)
|
|
43
|
+
msiw.install_msi(msi_path=fibratus_setup_file_path)
|
|
45
44
|
|
|
46
45
|
count = 0
|
|
47
46
|
while count != WAIT_SECONDS_FOR_EXECUTABLE_TO_APPEAR_AFTER_INSTALLATION:
|
|
@@ -154,13 +154,16 @@ class Certificator:
|
|
|
154
154
|
service_name=sni_received_parameters.destination_name,
|
|
155
155
|
service_port=base.get_destination_address_from_socket(sni_received_parameters.ssl_socket)[1],
|
|
156
156
|
tls=self.tls,
|
|
157
|
-
dns_servers_list=self.forwarding_dns_service_ipv4_list___only_for_localhost
|
|
157
|
+
dns_servers_list=self.forwarding_dns_service_ipv4_list___only_for_localhost,
|
|
158
|
+
logger=print_kwargs.get('logger') if print_kwargs else None
|
|
159
|
+
)
|
|
158
160
|
# If we're not on localhost, then connect to domain directly.
|
|
159
161
|
else:
|
|
160
162
|
service_client = socket_client.SocketClient(
|
|
161
163
|
service_name=sni_received_parameters.destination_name,
|
|
162
164
|
service_port=base.get_destination_address_from_socket(sni_received_parameters.ssl_socket)[1],
|
|
163
|
-
tls=self.tls
|
|
165
|
+
tls=self.tls,
|
|
166
|
+
logger=print_kwargs.get('logger') if print_kwargs else None
|
|
164
167
|
)
|
|
165
168
|
|
|
166
169
|
# If certificate from socket exists, then we don't need to get it from the socket and write to file.
|
|
@@ -37,11 +37,26 @@ def create_ssl_context_for_client():
|
|
|
37
37
|
return ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
|
|
38
38
|
|
|
39
39
|
|
|
40
|
-
def
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
def set_client_ssl_context_ca_default_certs(ssl_context):
|
|
41
|
+
"""
|
|
42
|
+
"load_default_certs" method is telling the client to check the local certificate storage on the system for the
|
|
43
|
+
needed certificate of the server. Without this line you will get an error from the server that the client
|
|
44
|
+
is using self-signed certificate. Which is partly true, since you used the SLL wrapper,
|
|
45
|
+
but didn't specify the certificate at all.
|
|
46
|
+
-----------------------------------------
|
|
47
|
+
https://docs.python.org/3/library/ssl.html#ssl.SSLContext.load_default_certs
|
|
48
|
+
Load a set of default “certification authority” (CA) certificates from default locations.
|
|
49
|
+
On Windows it loads CA certs from the CA and ROOT system stores.
|
|
50
|
+
On all systems it calls SSLContext.set_default_verify_paths().
|
|
51
|
+
In the future the method may load CA certificates from other locations, too.
|
|
52
|
+
|
|
53
|
+
The purpose flag specifies what kind of CA certificates are loaded.
|
|
54
|
+
The default settings Purpose.SERVER_AUTH loads certificates, that are flagged and trusted for
|
|
55
|
+
TLS web server authentication (client side sockets). Purpose.CLIENT_AUTH loads CA certificates for
|
|
56
|
+
client certificate verification on the server side.
|
|
57
|
+
-----------------------------------------
|
|
58
|
+
"""
|
|
59
|
+
|
|
45
60
|
# The purpose of the certificate is to authenticate on the server
|
|
46
61
|
# context.load_default_certs(Purpose.SERVER_AUTH)
|
|
47
62
|
# You don't have to specify the purpose to connect, but if you get a purpose error, you know where to find it
|
|
@@ -187,10 +202,26 @@ def set_listen_on_socket(socket_object, **kwargs):
|
|
|
187
202
|
# Socket Creator Presets
|
|
188
203
|
|
|
189
204
|
def wrap_socket_with_ssl_context_client___default_certs___ignore_verification(
|
|
190
|
-
socket_object,
|
|
205
|
+
socket_object,
|
|
206
|
+
server_hostname: str = None,
|
|
207
|
+
custom_pem_client_certificate_file_path: str = None
|
|
208
|
+
):
|
|
209
|
+
"""
|
|
210
|
+
This function is a preset for wrapping the socket with SSL context for the client.
|
|
211
|
+
It sets the CA default certificates, and ignores the server's certificate verification.
|
|
212
|
+
|
|
213
|
+
:param socket_object: socket.socket object
|
|
214
|
+
:param server_hostname: string, hostname of the server. Default is None.
|
|
215
|
+
:param custom_pem_client_certificate_file_path: string, full file path for the client certificate PWM file.
|
|
216
|
+
Default is None.
|
|
217
|
+
"""
|
|
191
218
|
ssl_context: ssl.SSLContext = create_ssl_context_for_client()
|
|
192
|
-
|
|
219
|
+
set_client_ssl_context_ca_default_certs(ssl_context)
|
|
193
220
|
set_client_ssl_context_certificate_verification_ignore(ssl_context)
|
|
221
|
+
|
|
222
|
+
if custom_pem_client_certificate_file_path:
|
|
223
|
+
ssl_context.load_cert_chain(certfile=custom_pem_client_certificate_file_path, keyfile=None)
|
|
224
|
+
|
|
194
225
|
ssl_socket: ssl.SSLSocket = wrap_socket_with_ssl_context_client(
|
|
195
226
|
socket_object, ssl_context, server_hostname=server_hostname)
|
|
196
227
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import socket
|
|
3
3
|
import ssl
|
|
4
|
+
import select
|
|
4
5
|
from pathlib import Path
|
|
5
6
|
|
|
6
7
|
from ...print_api import print_api
|
|
@@ -20,6 +21,24 @@ def peek_first_bytes(client_socket, bytes_amount: int = 1) -> bytes:
|
|
|
20
21
|
return client_socket.recv(bytes_amount, socket.MSG_PEEK)
|
|
21
22
|
|
|
22
23
|
|
|
24
|
+
def is_socket_ready_for_read(client_socket, timeout: int = 0) -> bool:
|
|
25
|
+
"""
|
|
26
|
+
Check if socket is ready for read.
|
|
27
|
+
|
|
28
|
+
:param client_socket: Socket object.
|
|
29
|
+
:param timeout: Timeout in seconds. The default is no timeout.
|
|
30
|
+
|
|
31
|
+
:return: True if socket is ready for read, False otherwise.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
# Use select to check if the socket is ready for reading.
|
|
35
|
+
# 'readable' returns a list of sockets that are ready for reading.
|
|
36
|
+
# Since we use only one socket, it will return a list with one element if the socket is ready for reading,
|
|
37
|
+
# or an empty list if the socket is not ready for reading.
|
|
38
|
+
readable, _, _ = select.select([client_socket], [], [], timeout)
|
|
39
|
+
return bool(readable)
|
|
40
|
+
|
|
41
|
+
|
|
23
42
|
class Receiver:
|
|
24
43
|
""" Receiver Class is responsible for receiving the message from socket and populate the message class """
|
|
25
44
|
def __init__(
|
|
@@ -254,15 +254,13 @@ class SNIHandler:
|
|
|
254
254
|
|
|
255
255
|
# Try on general settings in the SNI function.
|
|
256
256
|
try:
|
|
257
|
-
# Check if SNI was passed.
|
|
258
|
-
if self.sni_received_parameters.destination_name:
|
|
259
|
-
service_name_from_sni = self.sni_received_parameters.destination_name
|
|
260
|
-
# If no SNI was passed.
|
|
261
|
-
else:
|
|
257
|
+
# Check if SNI was passed. If no SNI was passed.
|
|
258
|
+
if not self.sni_received_parameters.destination_name:
|
|
262
259
|
# If DNS server is enabled we'll get the domain from dns server.
|
|
263
260
|
if self.domain_from_dns_server:
|
|
264
|
-
|
|
265
|
-
message =
|
|
261
|
+
self.sni_received_parameters.destination_name = self.domain_from_dns_server
|
|
262
|
+
message = \
|
|
263
|
+
f"SNI Handler: No SNI was passed, using domain from DNS Server: {self.domain_from_dns_server}"
|
|
266
264
|
print_api(message, **(print_kwargs or {}))
|
|
267
265
|
# If DNS server is disabled, the domain from dns server will be empty.
|
|
268
266
|
else:
|
|
@@ -271,7 +269,7 @@ class SNIHandler:
|
|
|
271
269
|
print_api(message, **(print_kwargs or {}))
|
|
272
270
|
|
|
273
271
|
# Setting "server_hostname" as a domain.
|
|
274
|
-
self.sni_received_parameters.ssl_socket.server_hostname =
|
|
272
|
+
self.sni_received_parameters.ssl_socket.server_hostname = self.sni_received_parameters.destination_name
|
|
275
273
|
message = \
|
|
276
274
|
f"SNI Handler: port {self.sni_received_parameters.ssl_socket.getsockname()[1]}: " \
|
|
277
275
|
f"Incoming connection for [{self.sni_received_parameters.ssl_socket.server_hostname}]"
|
|
@@ -16,7 +16,7 @@ from .sender import Sender
|
|
|
16
16
|
from . import ssl_base
|
|
17
17
|
from .. import cryptographyw
|
|
18
18
|
from ..loggingw import loggingw
|
|
19
|
-
from ...
|
|
19
|
+
from ... import print_api
|
|
20
20
|
from ...file_io import file_io
|
|
21
21
|
from ...basics import tracebacks
|
|
22
22
|
|
|
@@ -29,7 +29,8 @@ class SocketClient:
|
|
|
29
29
|
tls: bool = False,
|
|
30
30
|
connection_ip=None,
|
|
31
31
|
dns_servers_list=None,
|
|
32
|
-
logger: logging.Logger = None
|
|
32
|
+
logger: logging.Logger = None,
|
|
33
|
+
custom_pem_client_certificate_file_path: str = None
|
|
33
34
|
):
|
|
34
35
|
"""
|
|
35
36
|
If you have a certificate for domain, but not for the IPv4 address, the SSL Socket context can be created for
|
|
@@ -47,6 +48,8 @@ class SocketClient:
|
|
|
47
48
|
:param dns_servers_list: (Optional) List object with dns IPv4 addresses that 'service_name' will be resolved
|
|
48
49
|
with, using 'dnspython' module. 'connection_ip' will be populated with first resolved IP.
|
|
49
50
|
:param logger: (Optional) Logger object. If not provided, the default logger will be used.
|
|
51
|
+
:param custom_pem_client_certificate_file_path: (Optional) If specified, the SSL Socket will be created with
|
|
52
|
+
custom client certificate. The path to the file with the certificate should be provided.
|
|
50
53
|
|
|
51
54
|
If both 'connection_ip' and 'dns_servers_list' specified, ValueException with raise.
|
|
52
55
|
"""
|
|
@@ -55,6 +58,7 @@ class SocketClient:
|
|
|
55
58
|
self.tls: bool = tls
|
|
56
59
|
self.connection_ip = connection_ip
|
|
57
60
|
self.dns_servers_list = dns_servers_list
|
|
61
|
+
self.custom_pem_client_certificate_file_path: str = custom_pem_client_certificate_file_path
|
|
58
62
|
|
|
59
63
|
if logger:
|
|
60
64
|
# Create child logger for the provided logger with the module's name.
|
|
@@ -79,13 +83,15 @@ class SocketClient:
|
|
|
79
83
|
def create_service_socket(self):
|
|
80
84
|
# If TLS is enabled.
|
|
81
85
|
if not self.tls:
|
|
82
|
-
|
|
86
|
+
log_message: str = f"Creating non-SSL socket to [{self.service_name}:{self.service_port}]"
|
|
87
|
+
print_api.print_api(log_message, logger=self.logger, logger_method='info')
|
|
83
88
|
return creator.create_socket_ipv4_tcp()
|
|
84
89
|
else:
|
|
85
|
-
|
|
90
|
+
log_message: str = f"Creating SSL socket to [{self.service_name}:{self.service_port}]"
|
|
91
|
+
print_api.print_api(log_message, logger=self.logger, logger_method='info')
|
|
86
92
|
socket_object = creator.create_socket_ipv4_tcp()
|
|
87
93
|
return creator.wrap_socket_with_ssl_context_client___default_certs___ignore_verification(
|
|
88
|
-
socket_object, self.service_name)
|
|
94
|
+
socket_object, self.service_name, self.custom_pem_client_certificate_file_path)
|
|
89
95
|
|
|
90
96
|
def service_connection(
|
|
91
97
|
self
|
|
@@ -141,7 +147,7 @@ class SocketClient:
|
|
|
141
147
|
error_string = (
|
|
142
148
|
f"Socket Client Connect: {exception_type}: "
|
|
143
149
|
f"Domain {self.service_name} doesn't exist - Couldn't resolve with {self.dns_servers_list}.")
|
|
144
|
-
print_api(error_string, logger=self.logger, logger_method='error')
|
|
150
|
+
print_api.print_api(error_string, logger=self.logger, logger_method='error')
|
|
145
151
|
return None, error_string
|
|
146
152
|
|
|
147
153
|
# If DNS was resolved correctly or DNS servers weren't specified - we can try connecting.
|
|
@@ -163,16 +169,16 @@ class SocketClient:
|
|
|
163
169
|
error_string: str = f"Socket Client Connect: {destination}: {exception_type}"
|
|
164
170
|
|
|
165
171
|
if exception_type in ['ConnectionRefusedError', 'ConnectionAbortedError', 'ConnectionResetError',
|
|
166
|
-
'
|
|
172
|
+
'TimeoutError'] or 'ssl' in exception_type.lower():
|
|
167
173
|
error_message: str = f"{error_string}: {exception_error}"
|
|
168
|
-
print_api(error_message, logger=self.logger, logger_method='error')
|
|
174
|
+
print_api.print_api(error_message, logger=self.logger, logger_method='error')
|
|
169
175
|
return None, error_message
|
|
170
176
|
elif exception_type == 'socket.gaierror':
|
|
171
177
|
custom_error_message: str = (
|
|
172
178
|
f"Couldn't resolve [{self.service_name}] to IP using default methods. "
|
|
173
179
|
f"Domain doesn't exist or there's no IP assigned to it.")
|
|
174
180
|
error_message: str = f"{error_string}: {custom_error_message}"
|
|
175
|
-
print_api(error_message, logger=self.logger, logger_method='error')
|
|
181
|
+
print_api.print_api(error_message, logger=self.logger, logger_method='error')
|
|
176
182
|
return None, error_message
|
|
177
183
|
else:
|
|
178
184
|
raise e
|
|
@@ -192,7 +198,18 @@ class SocketClient:
|
|
|
192
198
|
self.logger.info(f"Closed socket to service server [{self.service_name}:{self.service_port}]")
|
|
193
199
|
|
|
194
200
|
# noinspection PyUnusedLocal
|
|
195
|
-
def send_receive_to_service(
|
|
201
|
+
def send_receive_to_service(
|
|
202
|
+
self,
|
|
203
|
+
request_bytes: Union[bytearray, bytes],
|
|
204
|
+
skip_send: bool = False
|
|
205
|
+
):
|
|
206
|
+
"""
|
|
207
|
+
Function to send data to service server and receive response.
|
|
208
|
+
|
|
209
|
+
:param request_bytes: The data that will be sent to the service server.
|
|
210
|
+
:param skip_send: If True, the data will not be sent to the service server. After the connection is established,
|
|
211
|
+
the function will wait for the response only.
|
|
212
|
+
"""
|
|
196
213
|
# Define variables
|
|
197
214
|
function_service_data = None
|
|
198
215
|
error_message = None
|
|
@@ -214,18 +231,22 @@ class SocketClient:
|
|
|
214
231
|
self.logger.info(
|
|
215
232
|
f"[{self.service_name}] resolves to ip: [{self.connection_ip}]. Pulled IP from the socket.")
|
|
216
233
|
|
|
217
|
-
#
|
|
218
|
-
error_on_send: str =
|
|
219
|
-
|
|
234
|
+
# noinspection PyTypeChecker
|
|
235
|
+
error_on_send: str = None
|
|
236
|
+
if not skip_send:
|
|
237
|
+
# Send the data received from the client to the service over socket
|
|
238
|
+
error_on_send = Sender(
|
|
239
|
+
ssl_socket=self.socket_instance, class_message=request_bytes, logger=self.logger).send()
|
|
220
240
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
241
|
+
# If the socket disconnected on data send
|
|
242
|
+
if error_on_send:
|
|
243
|
+
error_message = f"Service socket closed on data send: {error_on_send}"
|
|
244
|
+
|
|
245
|
+
# We'll close the socket and nullify the object
|
|
246
|
+
self.close_socket()
|
|
224
247
|
|
|
225
|
-
# We'll close the socket and nullify the object
|
|
226
|
-
self.close_socket()
|
|
227
248
|
# Else if send was successful
|
|
228
|
-
|
|
249
|
+
if not error_on_send:
|
|
229
250
|
function_service_data = Receiver(
|
|
230
251
|
ssl_socket=self.socket_instance, logger=self.logger).receive()
|
|
231
252
|
|
|
@@ -355,7 +376,7 @@ class SocketClient:
|
|
|
355
376
|
server_socket_for_certificate, error_message = self.service_connection()
|
|
356
377
|
# Get the DER byte certificate from the socket.
|
|
357
378
|
certificate_from_socket_der_bytes = ssl_base.get_certificate_from_socket(server_socket_for_certificate)
|
|
358
|
-
print_api('Fetched certificate from socket.', logger=self.logger, **kwargs)
|
|
379
|
+
print_api.print_api('Fetched certificate from socket.', logger=self.logger, **kwargs)
|
|
359
380
|
# Close the socket.
|
|
360
381
|
self.close_socket()
|
|
361
382
|
|
atomicshop/wrappers/sysmonw.py
CHANGED
|
@@ -49,7 +49,7 @@ def is_sysmon_running():
|
|
|
49
49
|
"""
|
|
50
50
|
|
|
51
51
|
process_list: list = process.get_running_processes_by_cmdline_pattern(
|
|
52
|
-
pattern=SYSMON_FILE_NAME, first=True,
|
|
52
|
+
pattern=SYSMON_FILE_NAME, first=True, cmdline_case_insensitive=True)
|
|
53
53
|
|
|
54
54
|
if process_list:
|
|
55
55
|
return True
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
atomicshop/__init__.py,sha256=
|
|
1
|
+
atomicshop/__init__.py,sha256=JaX16ugkhtjjNo6Te9NZk6rsS2IsN9ETiFc6wSyNBes,123
|
|
2
2
|
atomicshop/_basics_temp.py,sha256=6cu2dd6r2dLrd1BRNcVDKTHlsHs_26Gpw8QS6v32lQ0,3699
|
|
3
3
|
atomicshop/_create_pdf_demo.py,sha256=Yi-PGZuMg0RKvQmLqVeLIZYadqEZwUm-4A9JxBl_vYA,3713
|
|
4
4
|
atomicshop/_patch_import.py,sha256=ENp55sKVJ0e6-4lBvZnpz9PQCt3Otbur7F6aXDlyje4,6334
|
|
@@ -9,7 +9,7 @@ atomicshop/config_init.py,sha256=50kD2lXP8sgwPekcmAbfADcY46YvXkF-6XIdA7W_638,250
|
|
|
9
9
|
atomicshop/console_output.py,sha256=AOSJjrRryE97PAGtgDL03IBtWSi02aNol8noDnW3k6M,4667
|
|
10
10
|
atomicshop/console_user_response.py,sha256=31HIy9QGXa7f-GVR8MzJauQ79E_ZqAeagF3Ks4GGdDU,3234
|
|
11
11
|
atomicshop/datetimes.py,sha256=IQZ66lmta-ZqxYbyHzm_9eugbJFSilXK1e0kfMgoXGg,18371
|
|
12
|
-
atomicshop/diff_check.py,sha256=
|
|
12
|
+
atomicshop/diff_check.py,sha256=vxTDccVbGZHEge6Ja9_ArLWwslOUgIoJAdYPylh4cZg,27176
|
|
13
13
|
atomicshop/dns.py,sha256=5Gimq_WY2arqg7BeGmR7P--fGfnH0Dsh8lrOt_H0jRY,6817
|
|
14
14
|
atomicshop/domains.py,sha256=Rxu6JhhMqFZRcoFs69IoEd1PtYca0lMCG6F1AomP7z4,3197
|
|
15
15
|
atomicshop/emails.py,sha256=I0KyODQpIMEsNRi9YWSOL8EUPBiWyon3HRdIuSj3AEU,1410
|
|
@@ -126,16 +126,16 @@ atomicshop/file_io/xmls.py,sha256=zh3SuK-dNaFq2NDNhx6ivcf4GYCfGM8M10PcEwDSpxk,21
|
|
|
126
126
|
atomicshop/mitm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
127
127
|
atomicshop/mitm/config_static.py,sha256=ROAtbibSWSsF3BraUbhu-QO3MPIFqYY5KUKgsQbiSkk,7813
|
|
128
128
|
atomicshop/mitm/config_toml_editor.py,sha256=2p1CMcktWRR_NW-SmyDwylu63ad5e0-w1QPMa8ZLDBw,1635
|
|
129
|
-
atomicshop/mitm/connection_thread_worker.py,sha256=
|
|
129
|
+
atomicshop/mitm/connection_thread_worker.py,sha256=EtEp6aymfQ-btZzeZDmxLJdIortB4Gf5MOaHwEFSShI,21095
|
|
130
130
|
atomicshop/mitm/import_config.py,sha256=0Ij14aISTllTOiWYJpIUMOWobQqGofD6uafui5uWllE,9272
|
|
131
|
-
atomicshop/mitm/initialize_engines.py,sha256=
|
|
131
|
+
atomicshop/mitm/initialize_engines.py,sha256=NWz0yBErSrYBn0xWkJDBcHStBJ-kcsv9VtorcSP9x5M,8258
|
|
132
132
|
atomicshop/mitm/message.py,sha256=URR5JKSuAT8XmGIkyprEjlPW2GW4ef_gfUz_GgcFseE,2184
|
|
133
133
|
atomicshop/mitm/mitm_main.py,sha256=5c-9oxBiLueTbZr4Dyd4EEOorEUix5vSWxX9p5O1fBs,23375
|
|
134
|
-
atomicshop/mitm/recs_files.py,sha256=
|
|
135
|
-
atomicshop/mitm/shared_functions.py,sha256=
|
|
134
|
+
atomicshop/mitm/recs_files.py,sha256=gzFuTonqcXkMvhpOj1Nwse3E8umFGrKN2H5AleMjJ3w,3051
|
|
135
|
+
atomicshop/mitm/shared_functions.py,sha256=0lzeyINd44sVEfFbahJxQmz6KAMWbYrW5ou3UYfItvw,1777
|
|
136
136
|
atomicshop/mitm/statistic_analyzer.py,sha256=5_sAYGX2Xunzo_pS2W5WijNCwr_BlGJbbOO462y_wN4,27533
|
|
137
137
|
atomicshop/mitm/engines/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
138
|
-
atomicshop/mitm/engines/create_module_template.py,sha256=
|
|
138
|
+
atomicshop/mitm/engines/create_module_template.py,sha256=TAzsA4eLD2wYr7auuL4Nf_71iXqn-BOBXlSkNVrnYD4,5336
|
|
139
139
|
atomicshop/mitm/engines/create_module_template_example.py,sha256=X5xhvbV6-g9jU_bQVhf_crZmaH50LRWz3bS-faQ18ds,489
|
|
140
140
|
atomicshop/mitm/engines/__parent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
141
141
|
atomicshop/mitm/engines/__parent/parser___parent.py,sha256=RK2wviepP0oeq7zuLpgkvqvTJtc0r0a7hDGWdV0dGc4,657
|
|
@@ -175,6 +175,9 @@ atomicshop/startup/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuF
|
|
|
175
175
|
atomicshop/startup/win/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
176
176
|
atomicshop/startup/win/startup_folder.py,sha256=2RZEyF-Mf8eWPlt_-OaoGKKnMs6YhELEzJZ376EI0E0,1891
|
|
177
177
|
atomicshop/startup/win/task_scheduler.py,sha256=qALe-8sfthYxsdCViH2r8OsH3x-WauDqteg5RzElPdk,4348
|
|
178
|
+
atomicshop/web_apis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
179
|
+
atomicshop/web_apis/google_custom_search.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
180
|
+
atomicshop/web_apis/google_llm.py,sha256=WVLqyfZHFIGEncxdBvrHCv2FbvQw40z75uMGzq9lxB4,1291
|
|
178
181
|
atomicshop/wrappers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
179
182
|
atomicshop/wrappers/_process_wrapper_curl.py,sha256=XkZZXYl7D0Q6UfdWqy-18AvpU0yVp9i2BVD2qRcXlkk,841
|
|
180
183
|
atomicshop/wrappers/_process_wrapper_tar.py,sha256=WUMZFKNrlG4nJP9tWZ51W7BR1j_pIjsjgyAStmWjRGs,655
|
|
@@ -189,7 +192,7 @@ atomicshop/wrappers/olefilew.py,sha256=biD5m58rogifCYmYhJBrAFb9O_Bn_spLek_9HofLe
|
|
|
189
192
|
atomicshop/wrappers/pipw.py,sha256=mu4jnHkSaYNfpBiLZKMZxEX_E2LqW5BVthMZkblPB_c,1317
|
|
190
193
|
atomicshop/wrappers/process_wrapper_pbtk.py,sha256=ycPmBRnv627RWks6N8OhxJQe8Gu3h3Vwj-4HswPOw0k,599
|
|
191
194
|
atomicshop/wrappers/pyopensslw.py,sha256=OBWxA6EJ2vU_Qlf4M8m6ilcG3hyYB4yB0EsXUf7NhEU,6804
|
|
192
|
-
atomicshop/wrappers/sysmonw.py,sha256=
|
|
195
|
+
atomicshop/wrappers/sysmonw.py,sha256=CdawuWuy_uUi3ALCm6lKP7pSyKeTk1MXyzOaTMbBSO8,5346
|
|
193
196
|
atomicshop/wrappers/ubuntu_terminal.py,sha256=3UJaje_Ke5G9xEyj3b37XZ_KjR_FSSnb4gupdCyI-jE,11965
|
|
194
197
|
atomicshop/wrappers/wslw.py,sha256=2Z7X0j5M2hoRZjbHfm_vqwNXZeptsdkNCdhdcM_S9vo,6998
|
|
195
198
|
atomicshop/wrappers/certauthw/certauth.py,sha256=hKedW0DOWlEigSNm8wu4SqHkCQsGJ1tJfH7s4nr3Bk0,12223
|
|
@@ -246,7 +249,7 @@ atomicshop/wrappers/factw/rest/router.py,sha256=fdGok5ESBxcZHIBgM93l4yTPRGoeooQN
|
|
|
246
249
|
atomicshop/wrappers/factw/rest/statistics.py,sha256=vznwzKP1gEF7uXz3HsuV66BU9wrp73N_eFqpFpye9Qw,653
|
|
247
250
|
atomicshop/wrappers/factw/rest/status.py,sha256=4O3xS1poafwyUiLDkhyx4oMMe4PBwABuRPpOMnMKgIU,641
|
|
248
251
|
atomicshop/wrappers/fibratusw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
249
|
-
atomicshop/wrappers/fibratusw/install.py,sha256=
|
|
252
|
+
atomicshop/wrappers/fibratusw/install.py,sha256=GnaAAqcXRhovxZ3x5uB9RAXTMCh5xd5k1niCKTzh4Z0,3242
|
|
250
253
|
atomicshop/wrappers/loggingw/consts.py,sha256=JWiUJEydjhwatBxtIJsGTmDUSTLbmIRidtR6qRLMaIY,1608
|
|
251
254
|
atomicshop/wrappers/loggingw/filters.py,sha256=48UVhJHemCS0agXmQP8dHvAHM8r9DFphJ1TNEBP3Dlg,3545
|
|
252
255
|
atomicshop/wrappers/loggingw/formatters.py,sha256=ZY12IokVY1G_Wzn2Zlv9qjK-e8CtIK6yUgUfPHvH2BU,5802
|
|
@@ -300,23 +303,23 @@ atomicshop/wrappers/pywin32w/wmis/win32process.py,sha256=qMzXtJ5hBZ5ydAyqpDbSx0n
|
|
|
300
303
|
atomicshop/wrappers/socketw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
301
304
|
atomicshop/wrappers/socketw/accepter.py,sha256=hZZKVYlF3LOHQJsSIEKXZUf6QXXWm-AtqXZevvaYigE,1732
|
|
302
305
|
atomicshop/wrappers/socketw/base.py,sha256=DV6BWao9kiLAWimhVDKGEi3ISVaWk5iPHXtBHrO3uwc,2264
|
|
303
|
-
atomicshop/wrappers/socketw/certificator.py,sha256=
|
|
304
|
-
atomicshop/wrappers/socketw/creator.py,sha256=
|
|
306
|
+
atomicshop/wrappers/socketw/certificator.py,sha256=mtWPJ_ew3OSwt0-1W4jaoco1VIY4NRCrMv3mDUxb_Cc,12418
|
|
307
|
+
atomicshop/wrappers/socketw/creator.py,sha256=OLcd7FyUk_k8iyoL-xYnCnNmolPSgio6OeQXth7NdLg,11414
|
|
305
308
|
atomicshop/wrappers/socketw/dns_server.py,sha256=RklzINNuoMQn4PGGQEI5hiAldprbVwwvikY6u9X-jTY,49067
|
|
306
309
|
atomicshop/wrappers/socketw/exception_wrapper.py,sha256=B-X5SHLSUIWToihH2MKnOB1F4A81_X0DpLLfnYKYbEc,7067
|
|
307
310
|
atomicshop/wrappers/socketw/get_process.py,sha256=aJC-_qFUv3NgWCSUzDI72E4z8_-VTZE9NVZ0CwUoNlM,5698
|
|
308
|
-
atomicshop/wrappers/socketw/receiver.py,sha256
|
|
309
|
-
atomicshop/wrappers/socketw/sender.py,sha256=
|
|
310
|
-
atomicshop/wrappers/socketw/sni.py,sha256=
|
|
311
|
-
atomicshop/wrappers/socketw/socket_client.py,sha256=
|
|
311
|
+
atomicshop/wrappers/socketw/receiver.py,sha256=-QtKK0T_lmoAIypTYaIKOD3pgB1npWGPxcVEN37y_gk,10060
|
|
312
|
+
atomicshop/wrappers/socketw/sender.py,sha256=gwSzF51QD5paeeFav6fpbQpO8KgBO5lNztHYQyN5id0,4959
|
|
313
|
+
atomicshop/wrappers/socketw/sni.py,sha256=Nc8WMZZR21o5GXILQLVWbf7OzNPXAfE8trJY153e9Qk,17591
|
|
314
|
+
atomicshop/wrappers/socketw/socket_client.py,sha256=YUlwbasxYQqz1xUlPWxwEnSDSCYKGdxWb2CFAogefr8,21131
|
|
312
315
|
atomicshop/wrappers/socketw/socket_server_tester.py,sha256=Qobmh4XV8ZxLUaw-eW4ESKAbeSLecCKn2OWFzMhadk0,6420
|
|
313
316
|
atomicshop/wrappers/socketw/socket_wrapper.py,sha256=WtylpezgIIBuz-A6PfM0hO1sm9Exd4j3qhDXcFc74-E,35567
|
|
314
317
|
atomicshop/wrappers/socketw/ssl_base.py,sha256=kmiif84kMhBr5yjQW17p935sfjR5JKG0LxIwBA4iVvU,2275
|
|
315
318
|
atomicshop/wrappers/socketw/statistics_csv.py,sha256=SDYI1cN0oaapvPeLxSXiJrelTy6xbZl-bopR0jAjVGE,3149
|
|
316
319
|
atomicshop/wrappers/winregw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
317
320
|
atomicshop/wrappers/winregw/winreg_network.py,sha256=zZQfps-CdODQaTUADbHAwKHr5RUg7BLafnKWBbKaLN4,8728
|
|
318
|
-
atomicshop-2.
|
|
319
|
-
atomicshop-2.
|
|
320
|
-
atomicshop-2.
|
|
321
|
-
atomicshop-2.
|
|
322
|
-
atomicshop-2.
|
|
321
|
+
atomicshop-2.17.0.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
|
|
322
|
+
atomicshop-2.17.0.dist-info/METADATA,sha256=MG763mizxXrtHLWqgLymqhAomm0BYskwwRsHU-mvJpY,10499
|
|
323
|
+
atomicshop-2.17.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
324
|
+
atomicshop-2.17.0.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
|
|
325
|
+
atomicshop-2.17.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|