atomicshop 3.1.14__py3-none-any.whl → 3.2.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/mitm/connection_thread_worker.py +66 -35
- atomicshop/mitm/engines/create_module_template.py +4 -1
- atomicshop/mitm/initialize_engines.py +67 -0
- atomicshop/mitm/mitm_main.py +12 -2
- atomicshop/wrappers/socketw/socket_wrapper.py +38 -3
- atomicshop/wrappers/socketw/ssl_base.py +9 -12
- {atomicshop-3.1.14.dist-info → atomicshop-3.2.0.dist-info}/METADATA +1 -1
- {atomicshop-3.1.14.dist-info → atomicshop-3.2.0.dist-info}/RECORD +12 -12
- {atomicshop-3.1.14.dist-info → atomicshop-3.2.0.dist-info}/LICENSE.txt +0 -0
- {atomicshop-3.1.14.dist-info → atomicshop-3.2.0.dist-info}/WHEEL +0 -0
- {atomicshop-3.1.14.dist-info → atomicshop-3.2.0.dist-info}/top_level.txt +0 -0
atomicshop/__init__.py
CHANGED
|
@@ -4,14 +4,13 @@ import queue
|
|
|
4
4
|
import socket
|
|
5
5
|
|
|
6
6
|
from ..wrappers.socketw import receiver, sender, socket_client, base
|
|
7
|
-
from .. import websocket_parse
|
|
7
|
+
from .. import websocket_parse, ip_addresses
|
|
8
8
|
from ..http_parse import HTTPRequestParse, HTTPResponseParse
|
|
9
9
|
from ..basics import threads, tracebacks
|
|
10
10
|
from ..print_api import print_api
|
|
11
11
|
|
|
12
12
|
from .message import ClientMessage
|
|
13
|
-
from .
|
|
14
|
-
from . import config_static
|
|
13
|
+
from . import config_static, initialize_engines
|
|
15
14
|
|
|
16
15
|
|
|
17
16
|
def thread_worker_main(
|
|
@@ -218,30 +217,45 @@ def thread_worker_main(
|
|
|
218
217
|
custom_client_pem_certificate_path = pem_file_path
|
|
219
218
|
break
|
|
220
219
|
|
|
221
|
-
#
|
|
222
|
-
|
|
223
|
-
|
|
220
|
+
# Check if the destination service is an ip address or a domain name.
|
|
221
|
+
if ip_addresses.is_ip_address(client_message.server_name, ip_type='ipv4'):
|
|
222
|
+
# If it's an ip address, connect to the ip address directly.
|
|
224
223
|
service_client_instance = socket_client.SocketClient(
|
|
225
224
|
service_name=client_message.server_name,
|
|
225
|
+
connection_ip=client_message.server_name,
|
|
226
226
|
service_port=client_message.destination_port,
|
|
227
227
|
tls=is_tls,
|
|
228
|
-
dns_servers_list=[config_static.DNSServer.forwarding_dns_service_ipv4],
|
|
229
228
|
logger=network_logger,
|
|
230
229
|
custom_pem_client_certificate_file_path=custom_client_pem_certificate_path,
|
|
231
230
|
enable_sslkeylogfile_env_to_client_ssl_context=(
|
|
232
231
|
config_static.Certificates.enable_sslkeylogfile_env_to_client_ssl_context)
|
|
233
232
|
)
|
|
234
|
-
# If
|
|
233
|
+
# If it's a domain name, then we'll use the DNS to resolve it.
|
|
235
234
|
else:
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
config_static.
|
|
244
|
-
|
|
235
|
+
# If we're on localhost, then use external services list in order to resolve the domain:
|
|
236
|
+
# config['tcp']['forwarding_dns_service_ipv4_list___only_for_localhost']
|
|
237
|
+
if client_message.client_ip in base.THIS_DEVICE_IP_LIST:
|
|
238
|
+
service_client_instance = socket_client.SocketClient(
|
|
239
|
+
service_name=client_message.server_name,
|
|
240
|
+
service_port=client_message.destination_port,
|
|
241
|
+
tls=is_tls,
|
|
242
|
+
dns_servers_list=[config_static.DNSServer.forwarding_dns_service_ipv4],
|
|
243
|
+
logger=network_logger,
|
|
244
|
+
custom_pem_client_certificate_file_path=custom_client_pem_certificate_path,
|
|
245
|
+
enable_sslkeylogfile_env_to_client_ssl_context=(
|
|
246
|
+
config_static.Certificates.enable_sslkeylogfile_env_to_client_ssl_context)
|
|
247
|
+
)
|
|
248
|
+
# If we're not on localhost, then connect to domain directly.
|
|
249
|
+
else:
|
|
250
|
+
service_client_instance = socket_client.SocketClient(
|
|
251
|
+
service_name=client_message.server_name,
|
|
252
|
+
service_port=client_message.destination_port,
|
|
253
|
+
tls=is_tls,
|
|
254
|
+
logger=network_logger,
|
|
255
|
+
custom_pem_client_certificate_file_path=custom_client_pem_certificate_path,
|
|
256
|
+
enable_sslkeylogfile_env_to_client_ssl_context=(
|
|
257
|
+
config_static.Certificates.enable_sslkeylogfile_env_to_client_ssl_context)
|
|
258
|
+
)
|
|
245
259
|
|
|
246
260
|
return service_client_instance
|
|
247
261
|
|
|
@@ -336,6 +350,7 @@ def thread_worker_main(
|
|
|
336
350
|
raise ValueError(f"Unknown side of the socket: {receiving_socket}")
|
|
337
351
|
|
|
338
352
|
while True:
|
|
353
|
+
is_socket_closed: bool = False
|
|
339
354
|
# pass the socket connect to responder.
|
|
340
355
|
if side == 'Service' and client_connection_message:
|
|
341
356
|
client_message = client_connection_message
|
|
@@ -343,6 +358,8 @@ def thread_worker_main(
|
|
|
343
358
|
bytes_to_send_list: list[bytes] = create_responder_response(client_message)
|
|
344
359
|
print_api(f"Got responses from connect responder, count: [{len(bytes_to_send_list)}]", logger=network_logger,
|
|
345
360
|
logger_method='info')
|
|
361
|
+
|
|
362
|
+
received_raw_data = None
|
|
346
363
|
else:
|
|
347
364
|
client_message.reinitialize_dynamic_vars()
|
|
348
365
|
|
|
@@ -389,10 +406,10 @@ def thread_worker_main(
|
|
|
389
406
|
# the close on the opposite socket.
|
|
390
407
|
record_and_statistics_write(client_message)
|
|
391
408
|
|
|
392
|
-
if is_socket_closed:
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
409
|
+
# if is_socket_closed:
|
|
410
|
+
# exception_or_close_in_receiving_thread = True
|
|
411
|
+
# finish_thread()
|
|
412
|
+
# return
|
|
396
413
|
|
|
397
414
|
# Now send it to requester/responder.
|
|
398
415
|
if side == 'Client':
|
|
@@ -404,7 +421,6 @@ def thread_worker_main(
|
|
|
404
421
|
print_api("Offline Mode, sending to responder directly.", logger=network_logger,
|
|
405
422
|
logger_method='info')
|
|
406
423
|
process_client_raw_data(bytes_to_send_list[0], error_message, client_message)
|
|
407
|
-
client_message.action = 'client_responder'
|
|
408
424
|
bytes_to_send_list = create_responder_response(client_message)
|
|
409
425
|
elif side == 'Service':
|
|
410
426
|
bytes_to_send_list: list[bytes] = create_responder_response(client_message)
|
|
@@ -420,7 +436,8 @@ def thread_worker_main(
|
|
|
420
436
|
client_connection_message = None
|
|
421
437
|
continue
|
|
422
438
|
|
|
423
|
-
is_socket_closed: bool = False
|
|
439
|
+
# is_socket_closed: bool = False
|
|
440
|
+
error_on_send: str = str()
|
|
424
441
|
for bytes_to_send_single in bytes_to_send_list:
|
|
425
442
|
client_message.reinitialize_dynamic_vars()
|
|
426
443
|
client_message.timestamp = datetime.now()
|
|
@@ -430,7 +447,17 @@ def thread_worker_main(
|
|
|
430
447
|
else:
|
|
431
448
|
client_message.response_raw_bytes = bytes_to_send_single
|
|
432
449
|
|
|
433
|
-
|
|
450
|
+
# This records the requester or responder output, only if it is not the same as the original
|
|
451
|
+
# message.
|
|
452
|
+
if bytes_to_send_single != received_raw_data:
|
|
453
|
+
if side == 'Client':
|
|
454
|
+
client_message.action = 'client_requester'
|
|
455
|
+
|
|
456
|
+
if config_static.MainConfig.offline:
|
|
457
|
+
client_message.action = 'client_responder_offline'
|
|
458
|
+
elif side == 'Service':
|
|
459
|
+
client_message.action = 'service_responder'
|
|
460
|
+
record_and_statistics_write(client_message)
|
|
434
461
|
|
|
435
462
|
# If we're in offline mode, it means we're in the client thread, and we'll send the
|
|
436
463
|
# bytes back to the client socket.
|
|
@@ -454,11 +481,11 @@ def thread_worker_main(
|
|
|
454
481
|
|
|
455
482
|
record_and_statistics_write(client_message)
|
|
456
483
|
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
484
|
+
# If the socket was closed on message receive, then we'll break the loop only after send.
|
|
485
|
+
if is_socket_closed or error_on_send:
|
|
486
|
+
exception_or_close_in_receiving_thread = True
|
|
487
|
+
finish_thread()
|
|
488
|
+
return
|
|
462
489
|
|
|
463
490
|
# For next iteration to start in case this iteration was responsible to process connection message, we need to set it to None.
|
|
464
491
|
client_connection_message = None
|
|
@@ -533,12 +560,9 @@ def thread_worker_main(
|
|
|
533
560
|
# websocket_unmasked_frame_parser = websocket_parse.WebsocketFrameParser()
|
|
534
561
|
websocket_frame_parser = websocket_parse.WebsocketFrameParser()
|
|
535
562
|
|
|
536
|
-
# Offline queue between client and service threads.
|
|
537
|
-
offline_client_service_queue: queue.Queue = queue.Queue()
|
|
538
|
-
|
|
539
563
|
# Loading parser by domain, if there is no parser for current domain - general reference parser is loaded.
|
|
540
564
|
# These should be outside any loop and initialized only once entering the thread.
|
|
541
|
-
found_domain_module = assign_class_by_domain(
|
|
565
|
+
found_domain_module = initialize_engines.assign_class_by_domain(
|
|
542
566
|
engines_list=engines_list,
|
|
543
567
|
message_domain_name=server_name,
|
|
544
568
|
reference_module=reference_module
|
|
@@ -565,8 +589,15 @@ def thread_worker_main(
|
|
|
565
589
|
try:
|
|
566
590
|
engine_name: str = recorder.engine_name
|
|
567
591
|
client_ip, source_port = client_socket.getpeername()
|
|
568
|
-
client_name = socket.gethostbyaddr(client_ip)[0]
|
|
569
|
-
destination_port = client_socket.getsockname()[1]
|
|
592
|
+
client_name: str = socket.gethostbyaddr(client_ip)[0]
|
|
593
|
+
destination_port: int = client_socket.getsockname()[1]
|
|
594
|
+
destination_port_str: str = str(destination_port)
|
|
595
|
+
|
|
596
|
+
# If the destination port is in the on_port_connect dictionary, then we'll get the port from there.
|
|
597
|
+
if destination_port_str in found_domain_module.on_port_connect:
|
|
598
|
+
on_port_connect_value = found_domain_module.on_port_connect[destination_port_str]
|
|
599
|
+
_, destination_port_str = initialize_engines.get_ipv4_from_engine_on_connect_port(on_port_connect_value)
|
|
600
|
+
destination_port: int = int(destination_port_str)
|
|
570
601
|
|
|
571
602
|
if config_static.MainConfig.offline:
|
|
572
603
|
# If in offline mode, then we'll get the TCP server's input address.
|
|
@@ -81,9 +81,12 @@ class CreateModuleTemplate:
|
|
|
81
81
|
config_lines_list.append('[engine]')
|
|
82
82
|
config_lines_list.append(f'domains = [{", ".join(domains_with_quotes)}]')
|
|
83
83
|
config_lines_list.append('localhost = 1\n')
|
|
84
|
-
|
|
84
|
+
config_lines_list.append('[on_port_connect]')
|
|
85
|
+
config_lines_list.append('#5000 = "31.31.31.31"')
|
|
86
|
+
config_lines_list.append('#5000 = "C:\\test\\address.txt"\n')
|
|
85
87
|
config_lines_list.append('[mtls]')
|
|
86
88
|
config_lines_list.append('# "subdomain.domain.com" = "file_name_in_current_dir.pem"\n')
|
|
89
|
+
# config_lines_list.append(f'\n')
|
|
87
90
|
|
|
88
91
|
config_file_path = self.new_engine_directory + os.sep + CONFIG_FILE_NAME
|
|
89
92
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import os
|
|
2
2
|
from pathlib import Path
|
|
3
3
|
|
|
4
|
+
from .. import ip_addresses
|
|
4
5
|
from ..file_io import tomls
|
|
5
6
|
from ..basics.classes import import_first_class_name_from_file_path
|
|
6
7
|
from .engines.__reference_general import parser___reference_general, requester___reference_general, \
|
|
@@ -14,7 +15,10 @@ class ModuleCategory:
|
|
|
14
15
|
|
|
15
16
|
self.domain_list: list = list()
|
|
16
17
|
self.domain_target_dict: dict = dict()
|
|
18
|
+
self.port_target_dict: dict = dict()
|
|
19
|
+
|
|
17
20
|
self.is_localhost: bool = bool()
|
|
21
|
+
self.on_port_connect: dict = dict()
|
|
18
22
|
self.mtls: dict = dict()
|
|
19
23
|
|
|
20
24
|
self.parser_file_path: str = str()
|
|
@@ -48,6 +52,9 @@ class ModuleCategory:
|
|
|
48
52
|
self.domain_list = configuration_data['engine']['domains']
|
|
49
53
|
self.is_localhost = bool(configuration_data['engine']['localhost'])
|
|
50
54
|
|
|
55
|
+
if 'on_port_connect' in configuration_data:
|
|
56
|
+
self.on_port_connect = configuration_data['on_port_connect']
|
|
57
|
+
|
|
51
58
|
if 'mtls' in configuration_data:
|
|
52
59
|
self.mtls = configuration_data['mtls']
|
|
53
60
|
|
|
@@ -75,6 +82,9 @@ class ModuleCategory:
|
|
|
75
82
|
|
|
76
83
|
self.domain_target_dict[domain] = {'ip': None, 'port': port}
|
|
77
84
|
|
|
85
|
+
for port, value in self.on_port_connect.items():
|
|
86
|
+
self.port_target_dict[port] = {'ip': None, 'port': int(port)}
|
|
87
|
+
|
|
78
88
|
for subdomain, file_name in self.mtls.items():
|
|
79
89
|
self.mtls[subdomain] = f'{engine_directory_path}{os.sep}{file_name}'
|
|
80
90
|
|
|
@@ -100,6 +110,47 @@ class ModuleCategory:
|
|
|
100
110
|
return 0, ''
|
|
101
111
|
|
|
102
112
|
|
|
113
|
+
def get_ipv4_from_engine_on_connect_port(
|
|
114
|
+
address_or_file_path: str
|
|
115
|
+
) -> tuple[str, str] | None:
|
|
116
|
+
"""
|
|
117
|
+
Function to get the IPv4 address from the engine on connect port.
|
|
118
|
+
|
|
119
|
+
:param address_or_file_path: string, "ip_address:port" or file path that was set in the engine on_port_connect.
|
|
120
|
+
:return: string, IPv4 address that was parsed from the 'ip_port_address'.
|
|
121
|
+
|
|
122
|
+
"""
|
|
123
|
+
|
|
124
|
+
def get_ip_port_from_address(ip_port_address: str) -> tuple[str, str] | None:
|
|
125
|
+
"""
|
|
126
|
+
Function to get the IP address and port from the address string.
|
|
127
|
+
If the address is a file path, it will return an empty string.
|
|
128
|
+
"""
|
|
129
|
+
if ':' in ip_port_address:
|
|
130
|
+
ipv4_to_connect, port_to_connect = ip_port_address.split(':')
|
|
131
|
+
if ip_addresses.is_ip_address(ipv4_to_connect, ip_type='ipv4'):
|
|
132
|
+
return ipv4_to_connect, port_to_connect
|
|
133
|
+
else:
|
|
134
|
+
return None
|
|
135
|
+
else:
|
|
136
|
+
return None
|
|
137
|
+
|
|
138
|
+
# Try to get it as IP address.
|
|
139
|
+
ip_port_address_from_config = get_ip_port_from_address(address_or_file_path)
|
|
140
|
+
|
|
141
|
+
# If it is not an IP address, try to read it as a text file.
|
|
142
|
+
if not ip_port_address_from_config:
|
|
143
|
+
if os.path.isfile(address_or_file_path):
|
|
144
|
+
with open(address_or_file_path, 'r', encoding='utf-8') as file:
|
|
145
|
+
first_line = file.readline().strip()
|
|
146
|
+
|
|
147
|
+
ip_port_address_from_config = get_ip_port_from_address(first_line)
|
|
148
|
+
else:
|
|
149
|
+
return None
|
|
150
|
+
|
|
151
|
+
return ip_port_address_from_config
|
|
152
|
+
|
|
153
|
+
|
|
103
154
|
def assign_class_by_domain(
|
|
104
155
|
engines_list: list,
|
|
105
156
|
message_domain_name: str,
|
|
@@ -133,6 +184,22 @@ def assign_class_by_domain(
|
|
|
133
184
|
# If the domain was found in the current list of class domains, we can stop the loop
|
|
134
185
|
break
|
|
135
186
|
|
|
187
|
+
# If the module wasn't found by the domain, check it by the port.
|
|
188
|
+
if not module:
|
|
189
|
+
# Get the list of all the ip addresses in the on_port_connect dict.
|
|
190
|
+
list_of_ip_addresses_per_port: list[str] = []
|
|
191
|
+
for port, value in function_module.on_port_connect.items():
|
|
192
|
+
ipv4_to_connect, _ = get_ipv4_from_engine_on_connect_port(value)
|
|
193
|
+
list_of_ip_addresses_per_port.append(ipv4_to_connect)
|
|
194
|
+
|
|
195
|
+
# Checking if the message domain name is in the list of ip addresses per port.
|
|
196
|
+
if any(x in message_domain_name for x in list_of_ip_addresses_per_port):
|
|
197
|
+
# Assigning module by current engine of the port
|
|
198
|
+
module = function_module
|
|
199
|
+
|
|
200
|
+
# If the port was found in the current list of class ports, we can stop the loop
|
|
201
|
+
break
|
|
202
|
+
|
|
136
203
|
# If none of the domains were found in the engine domains list, then we'll assign reference module.
|
|
137
204
|
# It's enough to check only parser, since responder and recorder also will be empty.
|
|
138
205
|
# This section is also relevant if SNI came empty in the request from the client and no domain was passed by the
|
atomicshop/mitm/mitm_main.py
CHANGED
|
@@ -196,6 +196,11 @@ def startup_output(system_logger, script_version: str):
|
|
|
196
196
|
for domain, ip_port in engine.domain_target_dict.items():
|
|
197
197
|
dns_targets.append(ip_port['ip'])
|
|
198
198
|
print_api.print_api(f"[*] DNS Targets: {dns_targets}", logger=system_logger)
|
|
199
|
+
|
|
200
|
+
if engine.on_port_connect:
|
|
201
|
+
print_api.print_api(f"[*] Connect Ports to IPs: {list(engine.on_port_connect.values())}", logger=system_logger)
|
|
202
|
+
print_api.print_api(f"[*] Connect Ports to IPs Targets: {list(engine.port_target_dict.values())}", logger=system_logger)
|
|
203
|
+
|
|
199
204
|
# print_api.print_api(f"[*] TCP Listening Interfaces: {engine.tcp_listening_address_list}", logger=system_logger)
|
|
200
205
|
|
|
201
206
|
if config_static.DNSServer.enable:
|
|
@@ -235,13 +240,15 @@ def get_ipv4s_for_tcp_server():
|
|
|
235
240
|
|
|
236
241
|
# Create a list of all the domains in all the engines.
|
|
237
242
|
domains_to_create_ips_for: list[str] = list()
|
|
243
|
+
ports_to_create_ips_for: list[str] = list()
|
|
238
244
|
for engine in config_static.ENGINES_LIST:
|
|
239
245
|
domains_to_create_ips_for += list(engine.domain_target_dict.keys())
|
|
246
|
+
ports_to_create_ips_for += list(engine.on_port_connect.keys())
|
|
240
247
|
|
|
241
248
|
engine_ips: list[str] = list()
|
|
242
249
|
# Check if we need the localhost ips (12.0.0.1) or external local ips (192.168.0.100).
|
|
243
250
|
if config_static.ENGINES_LIST[0].is_localhost:
|
|
244
|
-
create_ips: int = len(domains_to_create_ips_for)
|
|
251
|
+
create_ips: int = len(domains_to_create_ips_for) + len(ports_to_create_ips_for)
|
|
245
252
|
|
|
246
253
|
# Generate the list of localhost ips.
|
|
247
254
|
for i in range(create_ips):
|
|
@@ -288,7 +295,10 @@ def get_ipv4s_for_tcp_server():
|
|
|
288
295
|
# If the domain is in the list of domains to create IPs for, add the IP to the engine.
|
|
289
296
|
if domain in domains_to_create_ips_for:
|
|
290
297
|
engine.domain_target_dict[domain]['ip'] = engine_ips.pop(0)
|
|
291
|
-
|
|
298
|
+
for port in engine.on_port_connect.keys():
|
|
299
|
+
# If the port is in the list of ports to create IPs for, add the IP to the engine.
|
|
300
|
+
if port in ports_to_create_ips_for:
|
|
301
|
+
engine.port_target_dict[port]['ip'] = engine_ips.pop(0)
|
|
292
302
|
|
|
293
303
|
def mitm_server(config_file_path: str, script_version: str):
|
|
294
304
|
on_exit.register_exit_handler(exit_cleanup, at_exit=False, kill_signal=False)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import os.path
|
|
1
2
|
import threading
|
|
2
3
|
import select
|
|
3
4
|
from typing import Literal, Union
|
|
@@ -427,8 +428,11 @@ class SocketWrapper:
|
|
|
427
428
|
# If engines were passed, we will use the listening addresses from the engines.
|
|
428
429
|
if not self.no_engine_usage_enable:
|
|
429
430
|
for engine in self.engines_list:
|
|
431
|
+
# Combine the domain and port dicts.
|
|
432
|
+
connection_dict: dict = {**engine.domain_target_dict, **engine.port_target_dict}
|
|
433
|
+
|
|
430
434
|
# Start all the regular listening interfaces.
|
|
431
|
-
for
|
|
435
|
+
for domain_or_port, ip_port_dict in connection_dict.items():
|
|
432
436
|
ip_address: str = ip_port_dict['ip']
|
|
433
437
|
port = int(ip_port_dict['port'])
|
|
434
438
|
socket_by_port = self.create_socket_ipv4_tcp(ip_address, port)
|
|
@@ -511,10 +515,28 @@ class SocketWrapper:
|
|
|
511
515
|
|
|
512
516
|
domain_from_engine = None
|
|
513
517
|
for engine in self.engines_list:
|
|
518
|
+
# Get the domain to connect on this process in case on no SNI provided.
|
|
514
519
|
for domain, ip_port_dict in engine.domain_target_dict.items():
|
|
515
520
|
if ip_port_dict['ip'] == listening_ip:
|
|
516
521
|
domain_from_engine = domain
|
|
517
522
|
break
|
|
523
|
+
# If there was no domain found, try to find the IP address for port.
|
|
524
|
+
if not domain_from_engine:
|
|
525
|
+
for port, file_or_ip in engine.port_target_dict.items():
|
|
526
|
+
if file_or_ip['ip'] == listening_ip:
|
|
527
|
+
# Get the value from the 'on_port_connect' dictionary.
|
|
528
|
+
address_or_file_path: str = engine.on_port_connect[str(listening_port)]
|
|
529
|
+
ip_port_address_from_config: tuple = initialize_engines.get_ipv4_from_engine_on_connect_port(
|
|
530
|
+
address_or_file_path)
|
|
531
|
+
if not ip_port_address_from_config:
|
|
532
|
+
raise ValueError(
|
|
533
|
+
f"Invalid IP address or file path in 'on_port_connect' for port "
|
|
534
|
+
f"{listening_port}: {address_or_file_path}"
|
|
535
|
+
)
|
|
536
|
+
|
|
537
|
+
domain_from_engine = ip_port_address_from_config[0]
|
|
538
|
+
|
|
539
|
+
break
|
|
518
540
|
|
|
519
541
|
self.logger.info(f"Requested domain setting: {domain_from_engine}")
|
|
520
542
|
|
|
@@ -598,6 +620,9 @@ class SocketWrapper:
|
|
|
598
620
|
print_kwargs={'logger': self.logger}
|
|
599
621
|
)
|
|
600
622
|
|
|
623
|
+
# Get the real tls version after connection is wrapped.
|
|
624
|
+
tls_version = ssl_client_socket.version()
|
|
625
|
+
|
|
601
626
|
# If the 'domain_from_dns_server' is empty, it means that the 'engine_name' is not set.
|
|
602
627
|
# In this case we will set the 'engine_name' to from the SNI.
|
|
603
628
|
if engine_name == '':
|
|
@@ -697,8 +722,18 @@ def get_engine_name(domain: str, engine_list: list):
|
|
|
697
722
|
:return: string, engine name.
|
|
698
723
|
"""
|
|
699
724
|
|
|
725
|
+
engine_name: str = ''
|
|
700
726
|
for engine in engine_list:
|
|
727
|
+
# Get engine name by domain.
|
|
701
728
|
if domain in engine.domain_target_dict:
|
|
702
|
-
|
|
729
|
+
engine_name = engine.engine_name
|
|
730
|
+
|
|
731
|
+
# If didn't find by domain, try to find by port.
|
|
732
|
+
if engine_name == '':
|
|
733
|
+
for port, ip_port_to_connect_value in engine.on_port_connect.items():
|
|
734
|
+
ipv4_to_connect, _ = initialize_engines.get_ipv4_from_engine_on_connect_port(ip_port_to_connect_value)
|
|
735
|
+
if ipv4_to_connect == domain:
|
|
736
|
+
engine_name = engine.engine_name
|
|
737
|
+
break
|
|
703
738
|
|
|
704
|
-
return
|
|
739
|
+
return engine_name
|
|
@@ -34,12 +34,9 @@ def is_tls(client_socket) -> Optional[Tuple[str, str]]:
|
|
|
34
34
|
|
|
35
35
|
first_bytes = receiver.peek_first_bytes(client_socket, bytes_amount=3)
|
|
36
36
|
|
|
37
|
-
#
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
# Extract the content type and version
|
|
42
|
-
content_type, version_major, version_minor = first_bytes
|
|
37
|
+
# Sometimes only one byte is available, so we need to handle that case.
|
|
38
|
+
# convert to a tuple of ints, add three Nones, and keep only the first 3 items.
|
|
39
|
+
content_type, version_major, version_minor = (tuple(first_bytes) + (None, None, None))[:3]
|
|
43
40
|
|
|
44
41
|
# Map TLS content types to their string representation.
|
|
45
42
|
content_type_map = {
|
|
@@ -52,19 +49,19 @@ def is_tls(client_socket) -> Optional[Tuple[str, str]]:
|
|
|
52
49
|
|
|
53
50
|
# Map TLS version bytes to their string representation.
|
|
54
51
|
version_map = {
|
|
55
|
-
(0x03, 0x00): "
|
|
56
|
-
(0x03, 0x01): "
|
|
57
|
-
(0x03, 0x02): "
|
|
58
|
-
(0x03, 0x03): "
|
|
52
|
+
(0x03, 0x00): "SSLv3.0",
|
|
53
|
+
(0x03, 0x01): "TLSv1.0",
|
|
54
|
+
(0x03, 0x02): "TLSv1.1",
|
|
55
|
+
(0x03, 0x03): "TLSv1.2/1.3"
|
|
59
56
|
# Remember, you can't definitively differentiate 1.2 and 1.3 just from these bytes
|
|
60
57
|
}
|
|
61
58
|
|
|
62
59
|
# Get the tuple of the type and version as strings.
|
|
63
|
-
tls_content_and_version_tuple: tuple = \
|
|
60
|
+
tls_content_and_version_tuple: tuple[str, str] = \
|
|
64
61
|
content_type_map.get(content_type), version_map.get((version_major, version_minor))
|
|
65
62
|
|
|
66
63
|
# If both parts of the tuple are not None, return the protocol type.
|
|
67
|
-
if tls_content_and_version_tuple[0]
|
|
64
|
+
if tls_content_and_version_tuple[0]:
|
|
68
65
|
return tls_content_and_version_tuple
|
|
69
66
|
else:
|
|
70
67
|
return None
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
atomicshop/__init__.py,sha256=
|
|
1
|
+
atomicshop/__init__.py,sha256=ia_QL-nkKuszLHN2XwNJas4i3cauADZSyyLAKJGWcD0,122
|
|
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
|
|
@@ -136,16 +136,16 @@ atomicshop/file_io/xmls.py,sha256=zh3SuK-dNaFq2NDNhx6ivcf4GYCfGM8M10PcEwDSpxk,21
|
|
|
136
136
|
atomicshop/mitm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
137
137
|
atomicshop/mitm/config_static.py,sha256=N3D06C_wUytwm80PQCL90ZGHLMHeQlCcI2XQQU2FZ1I,8145
|
|
138
138
|
atomicshop/mitm/config_toml_editor.py,sha256=2p1CMcktWRR_NW-SmyDwylu63ad5e0-w1QPMa8ZLDBw,1635
|
|
139
|
-
atomicshop/mitm/connection_thread_worker.py,sha256=
|
|
139
|
+
atomicshop/mitm/connection_thread_worker.py,sha256=E_DNvP4lbbcoeFziiG10Aa7bg7Ka09wdwV_uqaRm5rU,32554
|
|
140
140
|
atomicshop/mitm/import_config.py,sha256=gCH1hV-CxBAdwjeFJu1I5ntbm5hqzcB0y0vzRPkzra0,16936
|
|
141
|
-
atomicshop/mitm/initialize_engines.py,sha256=
|
|
141
|
+
atomicshop/mitm/initialize_engines.py,sha256=N4JVoC7PXN8GxUBXvNCXS-ZA5ag6rXqYXyZ3EyHOcLM,10318
|
|
142
142
|
atomicshop/mitm/message.py,sha256=CDhhm4BTuZE7oNZCjvIZ4BuPOW4MuIzQLOg91hJaxDI,3065
|
|
143
|
-
atomicshop/mitm/mitm_main.py,sha256=
|
|
143
|
+
atomicshop/mitm/mitm_main.py,sha256=at9uxnXF_4b273HRXt9UGkERkHantRTOAvRtlYYI68E,30774
|
|
144
144
|
atomicshop/mitm/recs_files.py,sha256=ZAAD0twun-FtmbSniXe3XQhIlawvANNB_HxwbHj7kwI,3151
|
|
145
145
|
atomicshop/mitm/shared_functions.py,sha256=0lzeyINd44sVEfFbahJxQmz6KAMWbYrW5ou3UYfItvw,1777
|
|
146
146
|
atomicshop/mitm/statistic_analyzer.py,sha256=5_sAYGX2Xunzo_pS2W5WijNCwr_BlGJbbOO462y_wN4,27533
|
|
147
147
|
atomicshop/mitm/engines/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
148
|
-
atomicshop/mitm/engines/create_module_template.py,sha256=
|
|
148
|
+
atomicshop/mitm/engines/create_module_template.py,sha256=_1aoB-ety98szV__2jnn6cohxmrClU5mOnf6u-nq_Zc,5762
|
|
149
149
|
atomicshop/mitm/engines/create_module_template_main_example.py,sha256=LeQ44Rp2Gi_KbIDY_4OMS0odkSK3zFZWra_oAka5eJY,243
|
|
150
150
|
atomicshop/mitm/engines/__parent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
151
151
|
atomicshop/mitm/engines/__parent/parser___parent.py,sha256=HHaCXhScl3OlPjz6eUxsDpJaZyk6BNuDMc9xCkeo2Ws,661
|
|
@@ -331,14 +331,14 @@ atomicshop/wrappers/socketw/sender.py,sha256=aX_K8l_rHjd5AWb8bi5mt8-YTkMYVRDB6Dn
|
|
|
331
331
|
atomicshop/wrappers/socketw/sni.py,sha256=q-F-R1KtE94g8WGrR3QHgi-otXZJUPBprEwQqnY80_A,17639
|
|
332
332
|
atomicshop/wrappers/socketw/socket_client.py,sha256=AQKjm_GZLH2PO7gkFbwzIbXzUXxRFvBTc6onrgapFqs,22048
|
|
333
333
|
atomicshop/wrappers/socketw/socket_server_tester.py,sha256=Qobmh4XV8ZxLUaw-eW4ESKAbeSLecCKn2OWFzMhadk0,6420
|
|
334
|
-
atomicshop/wrappers/socketw/socket_wrapper.py,sha256=
|
|
335
|
-
atomicshop/wrappers/socketw/ssl_base.py,sha256=
|
|
334
|
+
atomicshop/wrappers/socketw/socket_wrapper.py,sha256=_q_QDdyQjSmc0Q0WbMDQDajqDx0_AO3IqlL78Pk4nkE,43179
|
|
335
|
+
atomicshop/wrappers/socketw/ssl_base.py,sha256=62-hPm7zla1rh3m_WvDnXqKH-sDUTdiRptD8STCkgdk,2313
|
|
336
336
|
atomicshop/wrappers/socketw/statistics_csv.py,sha256=WcNyaqEZ82S5-f3kzqi1nllNT2Nd2P_zg8HqCc7vW4s,4120
|
|
337
337
|
atomicshop/wrappers/winregw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
338
338
|
atomicshop/wrappers/winregw/winreg_installed_software.py,sha256=Qzmyktvob1qp6Tjk2DjLfAqr_yXV0sgWzdMW_9kwNjY,2345
|
|
339
339
|
atomicshop/wrappers/winregw/winreg_network.py,sha256=ih0BVNwByLvf9F_Lac4EdmDYYJA3PzMvmG0PieDZrsE,9905
|
|
340
|
-
atomicshop-3.
|
|
341
|
-
atomicshop-3.
|
|
342
|
-
atomicshop-3.
|
|
343
|
-
atomicshop-3.
|
|
344
|
-
atomicshop-3.
|
|
340
|
+
atomicshop-3.2.0.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
|
|
341
|
+
atomicshop-3.2.0.dist-info/METADATA,sha256=VKefd8URMpY8zVcDX7iiRnpIcssdPlobeUlqhIyA7HQ,10670
|
|
342
|
+
atomicshop-3.2.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
343
|
+
atomicshop-3.2.0.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
|
|
344
|
+
atomicshop-3.2.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|