atomicshop 2.15.11__py3-none-any.whl → 3.10.5__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.
- atomicshop/__init__.py +1 -1
- atomicshop/{addons/mains → a_mains}/FACT/update_extract.py +3 -2
- atomicshop/a_mains/dns_gateway_setting.py +11 -0
- atomicshop/a_mains/get_local_tcp_ports.py +85 -0
- atomicshop/a_mains/github_wrapper.py +11 -0
- atomicshop/a_mains/install_ca_certificate.py +172 -0
- atomicshop/a_mains/process_from_port.py +119 -0
- atomicshop/a_mains/set_default_dns_gateway.py +90 -0
- atomicshop/a_mains/update_config_toml.py +38 -0
- atomicshop/basics/ansi_escape_codes.py +3 -1
- atomicshop/basics/argparse_template.py +2 -0
- atomicshop/basics/booleans.py +27 -30
- atomicshop/basics/bytes_arrays.py +43 -0
- atomicshop/basics/classes.py +149 -1
- atomicshop/basics/enums.py +2 -2
- atomicshop/basics/exceptions.py +5 -1
- atomicshop/basics/list_of_classes.py +29 -0
- atomicshop/basics/multiprocesses.py +374 -50
- atomicshop/basics/strings.py +72 -3
- atomicshop/basics/threads.py +14 -0
- atomicshop/basics/tracebacks.py +13 -3
- atomicshop/certificates.py +153 -52
- atomicshop/config_init.py +11 -6
- atomicshop/console_user_response.py +7 -14
- atomicshop/consoles.py +9 -0
- atomicshop/datetimes.py +1 -1
- atomicshop/diff_check.py +3 -3
- atomicshop/dns.py +128 -3
- atomicshop/etws/_pywintrace_fix.py +17 -0
- atomicshop/etws/trace.py +40 -42
- atomicshop/etws/traces/trace_dns.py +56 -44
- atomicshop/etws/traces/trace_tcp.py +130 -0
- atomicshop/file_io/csvs.py +27 -5
- atomicshop/file_io/docxs.py +34 -17
- atomicshop/file_io/file_io.py +31 -17
- atomicshop/file_io/jsons.py +49 -0
- atomicshop/file_io/tomls.py +139 -0
- atomicshop/filesystem.py +616 -291
- atomicshop/get_process_list.py +3 -3
- atomicshop/http_parse.py +149 -93
- atomicshop/ip_addresses.py +6 -1
- atomicshop/mitm/centered_settings.py +132 -0
- atomicshop/mitm/config_static.py +207 -0
- atomicshop/mitm/config_toml_editor.py +55 -0
- atomicshop/mitm/connection_thread_worker.py +875 -357
- atomicshop/mitm/engines/__parent/parser___parent.py +4 -17
- atomicshop/mitm/engines/__parent/recorder___parent.py +108 -51
- atomicshop/mitm/engines/__parent/requester___parent.py +116 -0
- atomicshop/mitm/engines/__parent/responder___parent.py +75 -114
- atomicshop/mitm/engines/__reference_general/parser___reference_general.py +10 -7
- atomicshop/mitm/engines/__reference_general/recorder___reference_general.py +5 -5
- atomicshop/mitm/engines/__reference_general/requester___reference_general.py +47 -0
- atomicshop/mitm/engines/__reference_general/responder___reference_general.py +95 -13
- atomicshop/mitm/engines/create_module_template.py +58 -14
- atomicshop/mitm/import_config.py +359 -139
- atomicshop/mitm/initialize_engines.py +160 -80
- atomicshop/mitm/message.py +64 -23
- atomicshop/mitm/mitm_main.py +892 -0
- atomicshop/mitm/recs_files.py +183 -0
- atomicshop/mitm/shared_functions.py +4 -10
- atomicshop/mitm/ssh_tester.py +82 -0
- atomicshop/mitm/statistic_analyzer.py +136 -40
- atomicshop/mitm/statistic_analyzer_helper/moving_average_helper.py +265 -83
- atomicshop/monitor/checks/dns.py +1 -1
- atomicshop/networks.py +671 -0
- atomicshop/on_exit.py +39 -9
- atomicshop/package_mains_processor.py +84 -0
- atomicshop/permissions/permissions.py +22 -0
- atomicshop/permissions/ubuntu_permissions.py +239 -0
- atomicshop/permissions/win_permissions.py +33 -0
- atomicshop/print_api.py +24 -42
- atomicshop/process.py +24 -6
- atomicshop/process_poller/process_pool.py +0 -1
- atomicshop/process_poller/simple_process_pool.py +204 -5
- atomicshop/python_file_patcher.py +1 -1
- atomicshop/python_functions.py +27 -75
- atomicshop/speech_recognize.py +8 -0
- atomicshop/ssh_remote.py +158 -172
- atomicshop/system_resource_monitor.py +61 -47
- atomicshop/system_resources.py +8 -8
- atomicshop/tempfiles.py +1 -2
- atomicshop/urls.py +6 -0
- atomicshop/venvs.py +28 -0
- atomicshop/versioning.py +27 -0
- atomicshop/web.py +98 -27
- atomicshop/web_apis/google_custom_search.py +44 -0
- atomicshop/web_apis/google_llm.py +188 -0
- atomicshop/websocket_parse.py +450 -0
- atomicshop/wrappers/certauthw/certauth.py +1 -0
- atomicshop/wrappers/cryptographyw.py +29 -8
- atomicshop/wrappers/ctyping/etw_winapi/const.py +97 -47
- atomicshop/wrappers/ctyping/etw_winapi/etw_functions.py +178 -49
- atomicshop/wrappers/ctyping/file_details_winapi.py +67 -0
- atomicshop/wrappers/ctyping/msi_windows_installer/cabs.py +2 -1
- atomicshop/wrappers/ctyping/msi_windows_installer/extract_msi_main.py +2 -2
- atomicshop/wrappers/ctyping/setup_device.py +466 -0
- atomicshop/wrappers/ctyping/win_console.py +39 -0
- atomicshop/wrappers/dockerw/dockerw.py +113 -2
- atomicshop/wrappers/elasticsearchw/config_basic.py +0 -12
- atomicshop/wrappers/elasticsearchw/elastic_infra.py +75 -0
- atomicshop/wrappers/elasticsearchw/elasticsearchw.py +2 -20
- atomicshop/wrappers/factw/get_file_data.py +12 -5
- atomicshop/wrappers/factw/install/install_after_restart.py +89 -5
- atomicshop/wrappers/factw/install/pre_install_and_install_before_restart.py +20 -14
- atomicshop/wrappers/githubw.py +537 -54
- atomicshop/wrappers/loggingw/consts.py +1 -1
- atomicshop/wrappers/loggingw/filters.py +23 -0
- atomicshop/wrappers/loggingw/formatters.py +12 -0
- atomicshop/wrappers/loggingw/handlers.py +214 -107
- atomicshop/wrappers/loggingw/loggers.py +19 -0
- atomicshop/wrappers/loggingw/loggingw.py +860 -22
- atomicshop/wrappers/loggingw/reading.py +134 -112
- atomicshop/wrappers/mongodbw/mongo_infra.py +31 -0
- atomicshop/wrappers/mongodbw/mongodbw.py +1324 -36
- atomicshop/wrappers/netshw.py +271 -0
- atomicshop/wrappers/playwrightw/engine.py +34 -19
- atomicshop/wrappers/playwrightw/infra.py +5 -0
- atomicshop/wrappers/playwrightw/javascript.py +7 -3
- atomicshop/wrappers/playwrightw/keyboard.py +14 -0
- atomicshop/wrappers/playwrightw/scenarios.py +172 -5
- atomicshop/wrappers/playwrightw/waits.py +9 -7
- atomicshop/wrappers/powershell_networking.py +80 -0
- atomicshop/wrappers/psutilw/processes.py +37 -1
- atomicshop/wrappers/psutilw/psutil_networks.py +85 -0
- atomicshop/wrappers/pyopensslw.py +9 -2
- atomicshop/wrappers/pywin32w/cert_store.py +116 -0
- atomicshop/wrappers/pywin32w/win_event_log/fetch.py +174 -0
- atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_create.py +3 -105
- atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_terminate.py +3 -57
- atomicshop/wrappers/pywin32w/wmis/msft_netipaddress.py +113 -0
- atomicshop/wrappers/pywin32w/wmis/win32_networkadapterconfiguration.py +259 -0
- atomicshop/wrappers/pywin32w/wmis/win32networkadapter.py +112 -0
- atomicshop/wrappers/pywin32w/wmis/wmi_helpers.py +236 -0
- atomicshop/wrappers/socketw/accepter.py +21 -7
- atomicshop/wrappers/socketw/certificator.py +216 -150
- atomicshop/wrappers/socketw/creator.py +190 -50
- atomicshop/wrappers/socketw/dns_server.py +491 -182
- atomicshop/wrappers/socketw/exception_wrapper.py +45 -52
- atomicshop/wrappers/socketw/process_getter.py +86 -0
- atomicshop/wrappers/socketw/receiver.py +144 -102
- atomicshop/wrappers/socketw/sender.py +65 -35
- atomicshop/wrappers/socketw/sni.py +334 -165
- atomicshop/wrappers/socketw/socket_base.py +134 -0
- atomicshop/wrappers/socketw/socket_client.py +137 -95
- atomicshop/wrappers/socketw/socket_server_tester.py +11 -7
- atomicshop/wrappers/socketw/socket_wrapper.py +717 -116
- atomicshop/wrappers/socketw/ssl_base.py +15 -14
- atomicshop/wrappers/socketw/statistics_csv.py +148 -17
- atomicshop/wrappers/sysmonw.py +1 -1
- atomicshop/wrappers/ubuntu_terminal.py +65 -26
- atomicshop/wrappers/win_auditw.py +189 -0
- atomicshop/wrappers/winregw/__init__.py +0 -0
- atomicshop/wrappers/winregw/winreg_installed_software.py +58 -0
- atomicshop/wrappers/winregw/winreg_network.py +232 -0
- {atomicshop-2.15.11.dist-info → atomicshop-3.10.5.dist-info}/METADATA +31 -51
- atomicshop-3.10.5.dist-info/RECORD +306 -0
- {atomicshop-2.15.11.dist-info → atomicshop-3.10.5.dist-info}/WHEEL +1 -1
- atomicshop/_basics_temp.py +0 -101
- atomicshop/a_installs/win/fibratus.py +0 -9
- atomicshop/a_installs/win/mongodb.py +0 -9
- atomicshop/a_installs/win/pycharm.py +0 -9
- atomicshop/addons/a_setup_scripts/install_psycopg2_ubuntu.sh +0 -3
- atomicshop/addons/a_setup_scripts/install_pywintrace_0.3.cmd +0 -2
- atomicshop/addons/mains/__pycache__/install_fibratus_windows.cpython-312.pyc +0 -0
- atomicshop/addons/mains/__pycache__/msi_unpacker.cpython-312.pyc +0 -0
- atomicshop/addons/mains/install_docker_rootless_ubuntu.py +0 -11
- atomicshop/addons/mains/install_docker_ubuntu_main_sudo.py +0 -11
- atomicshop/addons/mains/install_elastic_search_and_kibana_ubuntu.py +0 -10
- atomicshop/addons/mains/install_wsl_ubuntu_lts_admin.py +0 -9
- atomicshop/addons/package_setup/CreateWheel.cmd +0 -7
- atomicshop/addons/package_setup/Setup in Edit mode.cmd +0 -6
- atomicshop/addons/package_setup/Setup.cmd +0 -7
- atomicshop/archiver/_search_in_zip.py +0 -189
- atomicshop/archiver/archiver.py +0 -34
- atomicshop/archiver/search_in_archive.py +0 -250
- atomicshop/archiver/sevenz_app_w.py +0 -86
- atomicshop/archiver/sevenzs.py +0 -44
- atomicshop/archiver/zips.py +0 -293
- atomicshop/file_types.py +0 -24
- atomicshop/mitm/config_editor.py +0 -37
- atomicshop/mitm/engines/create_module_template_example.py +0 -13
- atomicshop/mitm/initialize_mitm_server.py +0 -268
- atomicshop/pbtkmultifile_argparse.py +0 -88
- atomicshop/permissions.py +0 -151
- atomicshop/script_as_string_processor.py +0 -38
- atomicshop/ssh_scripts/process_from_ipv4.py +0 -37
- atomicshop/ssh_scripts/process_from_port.py +0 -27
- atomicshop/wrappers/_process_wrapper_curl.py +0 -27
- atomicshop/wrappers/_process_wrapper_tar.py +0 -21
- atomicshop/wrappers/dockerw/install_docker.py +0 -209
- atomicshop/wrappers/elasticsearchw/infrastructure.py +0 -265
- atomicshop/wrappers/elasticsearchw/install_elastic.py +0 -232
- atomicshop/wrappers/ffmpegw.py +0 -125
- atomicshop/wrappers/fibratusw/install.py +0 -81
- atomicshop/wrappers/mongodbw/infrastructure.py +0 -53
- atomicshop/wrappers/mongodbw/install_mongodb.py +0 -190
- atomicshop/wrappers/msiw.py +0 -149
- atomicshop/wrappers/nodejsw/install_nodejs.py +0 -139
- atomicshop/wrappers/process_wrapper_pbtk.py +0 -16
- atomicshop/wrappers/psutilw/networks.py +0 -45
- atomicshop/wrappers/pycharmw.py +0 -81
- atomicshop/wrappers/socketw/base.py +0 -59
- atomicshop/wrappers/socketw/get_process.py +0 -107
- atomicshop/wrappers/wslw.py +0 -191
- atomicshop-2.15.11.dist-info/RECORD +0 -302
- /atomicshop/{addons/mains → a_mains}/FACT/factw_fact_extractor_docker_image_main_sudo.py +0 -0
- /atomicshop/{addons → a_mains/addons}/PlayWrightCodegen.cmd +0 -0
- /atomicshop/{addons → a_mains/addons}/ScriptExecution.cmd +0 -0
- /atomicshop/{addons → a_mains/addons}/inits/init_to_import_all_modules.py +0 -0
- /atomicshop/{addons → a_mains/addons}/process_list/ReadMe.txt +0 -0
- /atomicshop/{addons → a_mains/addons}/process_list/compile.cmd +0 -0
- /atomicshop/{addons → a_mains/addons}/process_list/compiled/Win10x64/process_list.dll +0 -0
- /atomicshop/{addons → a_mains/addons}/process_list/compiled/Win10x64/process_list.exp +0 -0
- /atomicshop/{addons → a_mains/addons}/process_list/compiled/Win10x64/process_list.lib +0 -0
- /atomicshop/{addons → a_mains/addons}/process_list/process_list.cpp +0 -0
- /atomicshop/{archiver → permissions}/__init__.py +0 -0
- /atomicshop/{wrappers/fibratusw → web_apis}/__init__.py +0 -0
- /atomicshop/wrappers/{nodejsw → pywin32w/wmis}/__init__.py +0 -0
- /atomicshop/wrappers/pywin32w/{wmi_win32process.py → wmis/win32process.py} +0 -0
- {atomicshop-2.15.11.dist-info → atomicshop-3.10.5.dist-info/licenses}/LICENSE.txt +0 -0
- {atomicshop-2.15.11.dist-info → atomicshop-3.10.5.dist-info}/top_level.txt +0 -0
|
@@ -1,112 +1,189 @@
|
|
|
1
1
|
import os
|
|
2
|
-
import sys
|
|
3
2
|
from pathlib import Path
|
|
4
3
|
|
|
5
|
-
from .. import
|
|
4
|
+
from .. import ip_addresses
|
|
6
5
|
from ..file_io import tomls
|
|
7
6
|
from ..basics.classes import import_first_class_name_from_file_path
|
|
8
|
-
from
|
|
9
|
-
|
|
10
|
-
recorder___reference_general
|
|
7
|
+
from .engines.__reference_general import parser___reference_general, requester___reference_general, \
|
|
8
|
+
responder___reference_general, recorder___reference_general
|
|
11
9
|
|
|
12
10
|
|
|
13
11
|
class ModuleCategory:
|
|
14
12
|
def __init__(self, script_directory: str):
|
|
15
|
-
self.domain_list: list = list()
|
|
16
13
|
self.engine_name: str = str()
|
|
17
14
|
self.script_directory: str = script_directory
|
|
18
15
|
|
|
16
|
+
self.domain_list: list = list()
|
|
17
|
+
self.domain_target_dict: dict = dict()
|
|
18
|
+
self.port_target_dict: dict = dict()
|
|
19
|
+
|
|
20
|
+
self.is_localhost: bool = bool()
|
|
21
|
+
self.on_port_connect: dict = dict()
|
|
22
|
+
self.mtls: dict = dict()
|
|
23
|
+
|
|
19
24
|
self.parser_file_path: str = str()
|
|
25
|
+
self.requester_file_path: str = str()
|
|
20
26
|
self.responder_file_path: str = str()
|
|
21
27
|
self.recorder_file_path: str = str()
|
|
22
28
|
|
|
23
29
|
self.parser_class_object: str = str()
|
|
30
|
+
self.requester_class_object: str = str()
|
|
24
31
|
self.responder_class_object: str = str()
|
|
25
32
|
self.recorder_class_object: str = str()
|
|
26
33
|
|
|
27
|
-
# The instance of the recorder class that will be initiated once in the script start
|
|
28
|
-
self.responder_instance = None
|
|
29
|
-
|
|
30
34
|
def fill_engine_fields_from_general_reference(self, engines_fullpath: str):
|
|
31
35
|
# Reference module variables.
|
|
32
36
|
self.engine_name = '__reference_general'
|
|
33
37
|
reference_folder_path: str = engines_fullpath + os.sep + self.engine_name
|
|
34
38
|
# Full path to file.
|
|
35
39
|
self.parser_file_path = reference_folder_path + os.sep + "parser___reference_general.py"
|
|
40
|
+
self.requester_file_path = reference_folder_path + os.sep + "requester___reference_general.py"
|
|
36
41
|
self.responder_file_path = reference_folder_path + os.sep + "responder___reference_general.py"
|
|
37
42
|
self.recorder_file_path = reference_folder_path + os.sep + "recorder___reference_general.py"
|
|
38
43
|
|
|
39
|
-
def fill_engine_fields_from_config(
|
|
44
|
+
def fill_engine_fields_from_config(
|
|
45
|
+
self,
|
|
46
|
+
engine_config_file_path: str,
|
|
47
|
+
print_kwargs: dict = None
|
|
48
|
+
) -> tuple[int, str]:
|
|
40
49
|
# Read the configuration file of the engine.
|
|
41
|
-
configuration_data = tomls.read_toml_file(engine_config_file_path)
|
|
50
|
+
configuration_data = tomls.read_toml_file(engine_config_file_path, **(print_kwargs or {}))
|
|
42
51
|
|
|
43
52
|
engine_directory_path: str = str(Path(engine_config_file_path).parent)
|
|
44
53
|
self.engine_name = Path(engine_directory_path).name
|
|
45
54
|
|
|
46
55
|
# Getting the parameters from engine config file
|
|
47
|
-
self.domain_list = configuration_data['domains']
|
|
56
|
+
self.domain_list = configuration_data['engine']['domains']
|
|
57
|
+
|
|
58
|
+
if 'on_port_connect' in configuration_data:
|
|
59
|
+
self.on_port_connect = configuration_data['on_port_connect']
|
|
60
|
+
|
|
61
|
+
if 'mtls' in configuration_data:
|
|
62
|
+
self.mtls = configuration_data['mtls']
|
|
48
63
|
|
|
49
64
|
# If there's module configuration file, but no domains in it, there's no point to continue.
|
|
50
65
|
# Since, each engine is based on domains.
|
|
51
66
|
if not self.domain_list or self.domain_list[0] == '':
|
|
52
67
|
raise ValueError(f"Engine Configuration file doesn't contain any domains: {engine_config_file_path}")
|
|
53
68
|
|
|
54
|
-
#
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
engine_directory_path, file_name_check_pattern=configuration_data['responder_file'])[0]
|
|
59
|
-
self.recorder_file_path = filesystem.get_file_paths_from_directory(
|
|
60
|
-
engine_directory_path, file_name_check_pattern=configuration_data['recorder_file'])[0]
|
|
61
|
-
|
|
62
|
-
def initialize_engine(self, logs_path: str, logger=None, reference_general: bool = False, **kwargs):
|
|
63
|
-
if not reference_general:
|
|
64
|
-
self.parser_class_object = import_first_class_name_from_file_path(
|
|
65
|
-
self.script_directory, self.parser_file_path, logger=logger, stdout=False)
|
|
66
|
-
self.responder_class_object = import_first_class_name_from_file_path(
|
|
67
|
-
self.script_directory, self.responder_file_path, logger=logger, stdout=False)
|
|
68
|
-
self.recorder_class_object = import_first_class_name_from_file_path(
|
|
69
|
-
self.script_directory, self.recorder_file_path, logger=logger, stdout=False)
|
|
69
|
+
# This is needed for backwards compatibility before glass 1.8.2, atomicshop 2.20.6
|
|
70
|
+
# When the name of each file was following the pattern: parser_<EngineName>.py, responder_<EngineName>.py, recorder_<EngineName>.py
|
|
71
|
+
if os.path.isfile(f"{engine_directory_path}{os.sep}parser.py"):
|
|
72
|
+
file_name_suffix: str = ''
|
|
70
73
|
else:
|
|
71
|
-
|
|
72
|
-
self.responder_class_object = responder___reference_general.ResponderGeneral
|
|
73
|
-
self.recorder_class_object = recorder___reference_general.RecorderGeneral
|
|
74
|
+
file_name_suffix: str = f"_{self.engine_name}"
|
|
74
75
|
|
|
76
|
+
# Full path to file
|
|
77
|
+
self.parser_file_path = f"{engine_directory_path}{os.sep}parser{file_name_suffix}.py"
|
|
78
|
+
self.requester_file_path = f"{engine_directory_path}{os.sep}requester{file_name_suffix}.py"
|
|
79
|
+
self.responder_file_path = f"{engine_directory_path}{os.sep}responder{file_name_suffix}.py"
|
|
80
|
+
self.recorder_file_path = f"{engine_directory_path}{os.sep}recorder{file_name_suffix}.py"
|
|
81
|
+
|
|
82
|
+
for domain_index, domain_port_string in enumerate(self.domain_list):
|
|
83
|
+
# Splitting the domain and port
|
|
84
|
+
if ':' in domain_port_string:
|
|
85
|
+
domain, port = domain_port_string.split(':')
|
|
86
|
+
else:
|
|
87
|
+
error_string: str = f"No [domain:port] pair found in: {domain_port_string}"
|
|
88
|
+
return 1, error_string
|
|
89
|
+
|
|
90
|
+
self.domain_target_dict[domain] = {'ip': None, 'port': int(port)}
|
|
91
|
+
|
|
92
|
+
for port, value in self.on_port_connect.items():
|
|
93
|
+
self.port_target_dict[port] = {'ip': None, 'port': int(port)}
|
|
94
|
+
|
|
95
|
+
# If it is not an IP address (e.g. <IP:PORT>) it will be treated as file path.
|
|
96
|
+
if ':' not in value:
|
|
97
|
+
self.on_port_connect[port] = f'{engine_directory_path}{os.sep}{value}'
|
|
98
|
+
|
|
99
|
+
for subdomain, file_name in self.mtls.items():
|
|
100
|
+
self.mtls[subdomain] = f'{engine_directory_path}{os.sep}{file_name}'
|
|
101
|
+
|
|
102
|
+
return 0, ''
|
|
103
|
+
|
|
104
|
+
def initialize_engine(
|
|
105
|
+
self,
|
|
106
|
+
reference_general: bool = False,
|
|
107
|
+
print_kwargs: dict = None
|
|
108
|
+
) -> tuple[int, str]:
|
|
75
109
|
try:
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
110
|
+
if not reference_general:
|
|
111
|
+
self.parser_class_object = import_first_class_name_from_file_path(
|
|
112
|
+
self.script_directory, self.parser_file_path, **(print_kwargs or {}))
|
|
113
|
+
self.requester_class_object = import_first_class_name_from_file_path(
|
|
114
|
+
self.script_directory, self.requester_file_path, **(print_kwargs or {}))
|
|
115
|
+
self.responder_class_object = import_first_class_name_from_file_path(
|
|
116
|
+
self.script_directory, self.responder_file_path, **(print_kwargs or {}))
|
|
117
|
+
self.recorder_class_object = import_first_class_name_from_file_path(
|
|
118
|
+
self.script_directory, self.recorder_file_path, **(print_kwargs or {}))
|
|
119
|
+
else:
|
|
120
|
+
self.parser_class_object = parser___reference_general.ParserGeneral
|
|
121
|
+
self.requester_class_object = requester___reference_general.RequesterGeneral
|
|
122
|
+
self.responder_class_object = responder___reference_general.ResponderGeneral
|
|
123
|
+
self.recorder_class_object = recorder___reference_general.RecorderGeneral
|
|
124
|
+
except ModuleNotFoundError as e:
|
|
125
|
+
return 1, str(e)
|
|
126
|
+
|
|
127
|
+
return 0, ''
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def get_ipv4_from_engine_on_connect_port(
|
|
131
|
+
address_or_file_path: str
|
|
132
|
+
) -> tuple[str, str] | None:
|
|
133
|
+
"""
|
|
134
|
+
Function to get the IPv4 address from the engine on connect port.
|
|
135
|
+
|
|
136
|
+
:param address_or_file_path: string, "ip_address:port" or file path that was set in the engine on_port_connect.
|
|
137
|
+
:return: string, IPv4 address that was parsed from the 'ip_port_address'.
|
|
138
|
+
|
|
139
|
+
"""
|
|
140
|
+
|
|
141
|
+
def get_ip_port_from_address(ip_port_address: str) -> tuple[str, str] | None:
|
|
142
|
+
"""
|
|
143
|
+
Function to get the IP address and port from the address string.
|
|
144
|
+
If the address is a file path, it will return an empty string.
|
|
145
|
+
"""
|
|
146
|
+
if ':' in ip_port_address:
|
|
147
|
+
ipv4_to_connect, port_to_connect = ip_port_address.split(':')
|
|
148
|
+
if ip_addresses.is_ip_address(ipv4_to_connect, ip_type='ipv4'):
|
|
149
|
+
return ipv4_to_connect, port_to_connect
|
|
150
|
+
else:
|
|
151
|
+
return None
|
|
152
|
+
else:
|
|
153
|
+
return None
|
|
154
|
+
|
|
155
|
+
# Try to get it as IP address.
|
|
156
|
+
ip_port_address_from_config = get_ip_port_from_address(address_or_file_path)
|
|
157
|
+
|
|
158
|
+
# If it is not an IP address, try to read it as a text file.
|
|
159
|
+
if not ip_port_address_from_config:
|
|
160
|
+
if os.path.isfile(address_or_file_path):
|
|
161
|
+
with open(address_or_file_path, 'r', encoding='utf-8') as file:
|
|
162
|
+
first_line = file.readline().strip()
|
|
163
|
+
|
|
164
|
+
ip_port_address_from_config = get_ip_port_from_address(first_line)
|
|
165
|
+
else:
|
|
166
|
+
return None
|
|
167
|
+
|
|
168
|
+
return ip_port_address_from_config
|
|
169
|
+
|
|
170
|
+
|
|
98
171
|
def assign_class_by_domain(
|
|
99
|
-
engines_list: list,
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
172
|
+
engines_list: list,
|
|
173
|
+
message_domain_name: str,
|
|
174
|
+
reference_module
|
|
175
|
+
):
|
|
176
|
+
"""
|
|
177
|
+
Assigning external class object by message domain received from client. If the domain is not in the list,
|
|
178
|
+
the reference general module will be assigned.
|
|
179
|
+
"""
|
|
104
180
|
|
|
105
181
|
# In case SNI came empty in the request from client, then there's no point in iterating through engine domains.
|
|
182
|
+
module = None
|
|
106
183
|
if message_domain_name:
|
|
107
|
-
# If
|
|
184
|
+
# If engine/s exit, the engines_list will not be empty, then we'll iterate through the list of engines
|
|
108
185
|
# to find the domain in the list of domains of the engine.
|
|
109
|
-
if
|
|
186
|
+
if engines_list:
|
|
110
187
|
# Checking if current domain is in engines' domain list to activate domain specific engine
|
|
111
188
|
for function_module in engines_list:
|
|
112
189
|
# The list: matches_list = ["domain1.com", "domain2.com", "domain3.com"]
|
|
@@ -117,31 +194,34 @@ def assign_class_by_domain(
|
|
|
117
194
|
# On the other hand if you want to find if partial string is
|
|
118
195
|
# in the list of strings: if any(a_string in x for x in matches_list):
|
|
119
196
|
# In this case list is the same and string: a_string = domain
|
|
120
|
-
if any(x in message_domain_name for x in function_module.
|
|
121
|
-
# Assigning
|
|
122
|
-
|
|
123
|
-
function_recorder = function_module.recorder_class_object
|
|
124
|
-
# Since the responder is being initiated only once, we're assigning only the instance
|
|
125
|
-
function_responder = function_module.responder_instance
|
|
126
|
-
|
|
127
|
-
logger.info(f"Assigned Modules for [{message_domain_name}]: "
|
|
128
|
-
f"{function_module.parser_class_object.__name__}, "
|
|
129
|
-
f"{function_module.responder_class_object.__name__}, "
|
|
130
|
-
f"{function_module.recorder_class_object.__name__}")
|
|
197
|
+
if any(x in message_domain_name for x in function_module.domain_target_dict.keys()):
|
|
198
|
+
# Assigning module by current engine of the domain
|
|
199
|
+
module = function_module
|
|
131
200
|
|
|
132
201
|
# If the domain was found in the current list of class domains, we can stop the loop
|
|
133
202
|
break
|
|
134
203
|
|
|
204
|
+
# If the module wasn't found by the domain, check it by the port.
|
|
205
|
+
if not module:
|
|
206
|
+
# Get the list of all the ip addresses in the on_port_connect dict.
|
|
207
|
+
list_of_ip_addresses_per_port: list[str] = []
|
|
208
|
+
for port, value in function_module.on_port_connect.items():
|
|
209
|
+
ipv4_to_connect, _ = get_ipv4_from_engine_on_connect_port(value)
|
|
210
|
+
list_of_ip_addresses_per_port.append(ipv4_to_connect)
|
|
211
|
+
|
|
212
|
+
# Checking if the message domain name is in the list of ip addresses per port.
|
|
213
|
+
if any(x in message_domain_name for x in list_of_ip_addresses_per_port):
|
|
214
|
+
# Assigning module by current engine of the port
|
|
215
|
+
module = function_module
|
|
216
|
+
|
|
217
|
+
# If the port was found in the current list of class ports, we can stop the loop
|
|
218
|
+
break
|
|
219
|
+
|
|
135
220
|
# If none of the domains were found in the engine domains list, then we'll assign reference module.
|
|
136
221
|
# It's enough to check only parser, since responder and recorder also will be empty.
|
|
137
222
|
# This section is also relevant if SNI came empty in the request from the client and no domain was passed by the
|
|
138
223
|
# DNS Server.
|
|
139
|
-
if not
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
# Since the responder is being initiated only once, we're assigning only the instance
|
|
144
|
-
function_responder = reference_module.responder_instance
|
|
145
|
-
|
|
146
|
-
# Return all the initiated modules
|
|
147
|
-
return function_parser, function_responder, function_recorder
|
|
224
|
+
if not module:
|
|
225
|
+
module = reference_module
|
|
226
|
+
|
|
227
|
+
return module
|
atomicshop/mitm/message.py
CHANGED
|
@@ -1,39 +1,80 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from typing import Union, Any
|
|
3
|
+
|
|
4
|
+
from .. import http_parse
|
|
5
|
+
from ..basics import dicts
|
|
6
|
+
|
|
7
|
+
|
|
1
8
|
class ClientMessage:
|
|
2
9
|
""" A class that will store all the message details from the client """
|
|
3
10
|
def __init__(self):
|
|
4
|
-
|
|
5
|
-
self.
|
|
6
|
-
self.
|
|
7
|
-
|
|
11
|
+
# noinspection PyTypeChecker
|
|
12
|
+
self.timestamp: datetime = None
|
|
13
|
+
self.engine_name: str = str()
|
|
14
|
+
# noinspection PyTypeChecker
|
|
15
|
+
self.request_raw_bytes: bytes = None
|
|
16
|
+
self.request_auto_parsed: Union[http_parse.HTTPRequestParse, any] = None
|
|
17
|
+
self.request_custom_parsed: Any = None
|
|
8
18
|
self.request_raw_hex: hex = None
|
|
9
|
-
#
|
|
10
|
-
self.
|
|
11
|
-
self.
|
|
12
|
-
|
|
13
|
-
self.
|
|
19
|
+
# noinspection PyTypeChecker
|
|
20
|
+
self.response_raw_bytes: bytes = None
|
|
21
|
+
self.response_auto_parsed: Any = None
|
|
22
|
+
self.response_custom_parsed: Any = None
|
|
23
|
+
self.response_raw_hex: hex = None
|
|
14
24
|
self.server_name: str = str()
|
|
15
25
|
self.server_ip: str = str()
|
|
26
|
+
self.client_name: str = str()
|
|
16
27
|
self.client_ip: str = str()
|
|
17
28
|
self.source_port: int = int()
|
|
18
29
|
self.destination_port: int = int()
|
|
19
30
|
self.process_name: str = str()
|
|
20
31
|
self.thread_id = None
|
|
32
|
+
self.thread_process: str = str()
|
|
21
33
|
self.info: str = str()
|
|
22
|
-
self.
|
|
34
|
+
self.errors: list = list()
|
|
35
|
+
self.protocol: str = str()
|
|
36
|
+
self.protocol2: str = str()
|
|
37
|
+
self.protocol3: str = str()
|
|
38
|
+
self.recorded_file_path: str = str()
|
|
39
|
+
self.action: str = str()
|
|
23
40
|
|
|
24
|
-
def
|
|
41
|
+
def reinitialize_dynamic_vars(self):
|
|
25
42
|
"""
|
|
26
|
-
|
|
27
|
-
are being processed on the same socket, so we need to reinitialize variables that are being updated, like
|
|
28
|
-
lists and dictionaries. Added the rest pf the variables that are repopulated to be on the safe side.
|
|
29
|
-
:return:
|
|
43
|
+
Reinitialize the dynamic variables of the class for the new cycle.
|
|
30
44
|
"""
|
|
31
|
-
|
|
32
|
-
self.
|
|
33
|
-
self.
|
|
34
|
-
self.
|
|
35
|
-
self.request_body_parsed = None
|
|
36
|
-
self.response_list_of_raw_bytes = list()
|
|
45
|
+
self.request_raw_bytes = None
|
|
46
|
+
self.timestamp = None
|
|
47
|
+
self.request_auto_parsed = None
|
|
48
|
+
self.request_custom_parsed = None
|
|
37
49
|
self.request_raw_hex = None
|
|
38
|
-
self.
|
|
39
|
-
self.
|
|
50
|
+
self.response_raw_bytes = None
|
|
51
|
+
self.response_auto_parsed = None
|
|
52
|
+
self.response_custom_parsed = None
|
|
53
|
+
self.response_raw_hex = None
|
|
54
|
+
self.action = None
|
|
55
|
+
self.info = str()
|
|
56
|
+
self.errors = list()
|
|
57
|
+
self.protocol = str()
|
|
58
|
+
self.protocol2 = str()
|
|
59
|
+
self.protocol3 = str()
|
|
60
|
+
self.recorded_file_path = str()
|
|
61
|
+
|
|
62
|
+
def __iter__(self):
|
|
63
|
+
# __dict__ returns a dictionary containing the instance's attributes
|
|
64
|
+
for key, value in self.__dict__.items():
|
|
65
|
+
if key == 'request_raw_bytes':
|
|
66
|
+
value = str(value)
|
|
67
|
+
elif key == 'timestamp':
|
|
68
|
+
value = value.strftime('%Y-%m-%d-%H:%M:%S.%f')
|
|
69
|
+
elif key == 'request_auto_parsed':
|
|
70
|
+
if isinstance(value, http_parse.HTTPRequestParse):
|
|
71
|
+
value = dicts.convert_complex_object_to_dict(value)
|
|
72
|
+
else:
|
|
73
|
+
value = str(value)
|
|
74
|
+
elif key == 'request_custom_parsed':
|
|
75
|
+
value = dicts.convert_complex_object_to_dict(value)
|
|
76
|
+
elif key == 'response_raw_bytes':
|
|
77
|
+
value = str(value)
|
|
78
|
+
elif key == 'response_auto_parsed':
|
|
79
|
+
value = dicts.convert_complex_object_to_dict(value)
|
|
80
|
+
yield key, value
|