atomicshop 2.11.47__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/addons/process_list/compile.cmd +7 -0
- atomicshop/a_mains/addons/process_list/compiled/Win10x64/process_list.dll +0 -0
- atomicshop/a_mains/addons/process_list/compiled/Win10x64/process_list.exp +0 -0
- atomicshop/a_mains/addons/process_list/compiled/Win10x64/process_list.lib +0 -0
- atomicshop/{addons → a_mains/addons}/process_list/process_list.cpp +8 -1
- 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/{addons/mains → a_mains}/msi_unpacker.py +3 -1
- 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/appointment_management.py +5 -3
- 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/dicts.py +12 -0
- atomicshop/basics/enums.py +2 -2
- atomicshop/basics/exceptions.py +5 -1
- atomicshop/basics/list_of_classes.py +29 -0
- atomicshop/basics/list_of_dicts.py +69 -5
- atomicshop/basics/lists.py +14 -0
- atomicshop/basics/multiprocesses.py +374 -50
- atomicshop/basics/package_module.py +10 -0
- atomicshop/basics/strings.py +160 -7
- atomicshop/basics/threads.py +14 -0
- atomicshop/basics/tracebacks.py +13 -4
- atomicshop/certificates.py +153 -52
- atomicshop/config_init.py +12 -7
- atomicshop/console_user_response.py +7 -14
- atomicshop/consoles.py +9 -0
- atomicshop/datetimes.py +98 -0
- atomicshop/diff_check.py +340 -40
- atomicshop/dns.py +128 -12
- atomicshop/etws/_pywintrace_fix.py +17 -0
- atomicshop/etws/const.py +38 -0
- atomicshop/etws/providers.py +21 -0
- atomicshop/etws/sessions.py +43 -0
- atomicshop/etws/trace.py +168 -0
- atomicshop/etws/traces/trace_dns.py +162 -0
- atomicshop/etws/traces/trace_sysmon_process_creation.py +126 -0
- atomicshop/etws/traces/trace_tcp.py +130 -0
- atomicshop/file_io/csvs.py +222 -24
- atomicshop/file_io/docxs.py +35 -18
- atomicshop/file_io/file_io.py +35 -19
- atomicshop/file_io/jsons.py +49 -0
- atomicshop/file_io/tomls.py +139 -0
- atomicshop/filesystem.py +864 -293
- atomicshop/get_process_list.py +133 -0
- atomicshop/{process_name_cmd.py → get_process_name_cmd_dll.py} +52 -19
- 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 -74
- 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 +257 -166
- atomicshop/mitm/statistic_analyzer_helper/analyzer_helper.py +136 -0
- atomicshop/mitm/statistic_analyzer_helper/moving_average_helper.py +525 -0
- atomicshop/monitor/change_monitor.py +96 -120
- atomicshop/monitor/checks/dns.py +139 -70
- atomicshop/monitor/checks/file.py +77 -0
- atomicshop/monitor/checks/network.py +81 -77
- atomicshop/monitor/checks/process_running.py +33 -34
- atomicshop/monitor/checks/url.py +94 -0
- atomicshop/networks.py +671 -0
- atomicshop/on_exit.py +205 -0
- 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 -41
- atomicshop/process.py +63 -17
- atomicshop/process_poller/__init__.py +0 -0
- atomicshop/process_poller/pollers/__init__.py +0 -0
- atomicshop/process_poller/pollers/psutil_pywin32wmi_dll.py +95 -0
- atomicshop/process_poller/process_pool.py +207 -0
- atomicshop/process_poller/simple_process_pool.py +311 -0
- atomicshop/process_poller/tracer_base.py +45 -0
- atomicshop/process_poller/tracers/__init__.py +0 -0
- atomicshop/process_poller/tracers/event_log.py +46 -0
- atomicshop/process_poller/tracers/sysmon_etw.py +68 -0
- atomicshop/python_file_patcher.py +1 -1
- atomicshop/python_functions.py +27 -75
- atomicshop/question_answer_engine.py +2 -2
- atomicshop/scheduling.py +24 -5
- atomicshop/sound.py +4 -2
- atomicshop/speech_recognize.py +8 -0
- atomicshop/ssh_remote.py +158 -172
- atomicshop/startup/__init__.py +0 -0
- atomicshop/startup/win/__init__.py +0 -0
- atomicshop/startup/win/startup_folder.py +53 -0
- atomicshop/startup/win/task_scheduler.py +119 -0
- atomicshop/system_resource_monitor.py +61 -46
- atomicshop/system_resources.py +8 -8
- atomicshop/tempfiles.py +1 -2
- atomicshop/timer.py +30 -11
- atomicshop/urls.py +41 -0
- atomicshop/venvs.py +28 -0
- atomicshop/versioning.py +27 -0
- atomicshop/web.py +110 -25
- atomicshop/web_apis/__init__.py +0 -0
- 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/__init__.py +0 -0
- atomicshop/wrappers/ctyping/etw_winapi/const.py +335 -0
- atomicshop/wrappers/ctyping/etw_winapi/etw_functions.py +393 -0
- 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 +13 -9
- atomicshop/wrappers/ctyping/msi_windows_installer/tables.py +35 -0
- 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/factw/postgresql/firmware.py +4 -6
- atomicshop/wrappers/githubw.py +583 -51
- atomicshop/wrappers/loggingw/consts.py +49 -0
- atomicshop/wrappers/loggingw/filters.py +102 -0
- atomicshop/wrappers/loggingw/formatters.py +58 -71
- atomicshop/wrappers/loggingw/handlers.py +459 -40
- atomicshop/wrappers/loggingw/loggers.py +19 -0
- atomicshop/wrappers/loggingw/loggingw.py +1010 -178
- atomicshop/wrappers/loggingw/reading.py +344 -19
- atomicshop/wrappers/mongodbw/__init__.py +0 -0
- atomicshop/wrappers/mongodbw/mongo_infra.py +31 -0
- atomicshop/wrappers/mongodbw/mongodbw.py +1432 -0
- 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 +81 -0
- atomicshop/wrappers/psutilw/psutil_networks.py +85 -0
- atomicshop/wrappers/psutilw/psutilw.py +9 -0
- atomicshop/wrappers/pyopensslw.py +9 -2
- atomicshop/wrappers/pywin32w/__init__.py +0 -0
- atomicshop/wrappers/pywin32w/cert_store.py +116 -0
- atomicshop/wrappers/pywin32w/console.py +34 -0
- atomicshop/wrappers/pywin32w/win_event_log/__init__.py +0 -0
- atomicshop/wrappers/pywin32w/win_event_log/fetch.py +174 -0
- atomicshop/wrappers/pywin32w/win_event_log/subscribe.py +212 -0
- atomicshop/wrappers/pywin32w/win_event_log/subscribes/__init__.py +0 -0
- atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_create.py +57 -0
- atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_terminate.py +49 -0
- atomicshop/wrappers/pywin32w/win_event_log/subscribes/schannel_logging.py +97 -0
- atomicshop/wrappers/pywin32w/winshell.py +19 -0
- atomicshop/wrappers/pywin32w/wmis/__init__.py +0 -0
- 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 +500 -173
- 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 +14 -9
- 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 +157 -0
- 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.11.47.dist-info → atomicshop-3.10.5.dist-info}/METADATA +31 -49
- atomicshop-3.10.5.dist-info/RECORD +306 -0
- {atomicshop-2.11.47.dist-info → atomicshop-3.10.5.dist-info}/WHEEL +1 -1
- atomicshop/_basics_temp.py +0 -101
- 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/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/addons/process_list/compile.cmd +0 -2
- atomicshop/addons/process_list/compiled/Win10x64/process_list.dll +0 -0
- atomicshop/addons/process_list/compiled/Win10x64/process_list.exp +0 -0
- atomicshop/addons/process_list/compiled/Win10x64/process_list.lib +0 -0
- 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/etw/dns_trace.py +0 -118
- atomicshop/etw/etw.py +0 -61
- atomicshop/file_types.py +0 -24
- atomicshop/mitm/engines/create_module_template_example.py +0 -13
- atomicshop/mitm/initialize_mitm_server.py +0 -240
- atomicshop/monitor/checks/hash.py +0 -44
- atomicshop/monitor/checks/hash_checks/file.py +0 -55
- atomicshop/monitor/checks/hash_checks/url.py +0 -62
- atomicshop/pbtkmultifile_argparse.py +0 -88
- atomicshop/permissions.py +0 -110
- atomicshop/process_poller.py +0 -237
- 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/loggingw/checks.py +0 -20
- atomicshop/wrappers/nodejsw/install_nodejs.py +0 -139
- atomicshop/wrappers/process_wrapper_pbtk.py +0 -16
- atomicshop/wrappers/socketw/base.py +0 -59
- atomicshop/wrappers/socketw/get_process.py +0 -107
- atomicshop/wrappers/wslw.py +0 -191
- atomicshop-2.11.47.dist-info/RECORD +0 -251
- /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/mains → 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/mains → a_mains}/search_for_hyperlinks_in_docx.py +0 -0
- /atomicshop/{archiver → etws}/__init__.py +0 -0
- /atomicshop/{etw → etws/traces}/__init__.py +0 -0
- /atomicshop/{monitor/checks/hash_checks → mitm/statistic_analyzer_helper}/__init__.py +0 -0
- /atomicshop/{wrappers/nodejsw → permissions}/__init__.py +0 -0
- /atomicshop/wrappers/pywin32w/{wmi_win32process.py → wmis/win32process.py} +0 -0
- {atomicshop-2.11.47.dist-info → atomicshop-3.10.5.dist-info/licenses}/LICENSE.txt +0 -0
- {atomicshop-2.11.47.dist-info → atomicshop-3.10.5.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,21 @@
|
|
|
1
|
-
from
|
|
2
|
-
|
|
3
|
-
from
|
|
1
|
+
from typing import Literal, Union
|
|
2
|
+
|
|
3
|
+
from .checks import dns, network, file, url, process_running
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
DNS__DEFAULT_SETTINGS = {
|
|
7
|
+
'skip_record_list': [], # List of DNS Records to skip emitting. Example: ['PTR', 'SRV']
|
|
8
|
+
'learning_mode_create_unique_entries_list': True,
|
|
9
|
+
'learning_hours': 24, # 0 - the learning will never stop.
|
|
10
|
+
'alert_about_missing_entries_after_learning': False,
|
|
11
|
+
'alert_about_missing_entries_always': True,
|
|
12
|
+
'create_alert_statistics': True,
|
|
13
|
+
'statistics_rotation_hours': 'midnight' # 'midnight' or float of hours
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
FILE__URL__DEFAULT_SETTINGS = {
|
|
17
|
+
'store_original_object': False
|
|
18
|
+
}
|
|
4
19
|
|
|
5
20
|
|
|
6
21
|
class ChangeMonitor:
|
|
@@ -9,32 +24,52 @@ class ChangeMonitor:
|
|
|
9
24
|
"""
|
|
10
25
|
def __init__(
|
|
11
26
|
self,
|
|
12
|
-
|
|
13
|
-
check_object_list: list = None,
|
|
14
|
-
input_file_directory: str = None,
|
|
27
|
+
check_object: any = None,
|
|
15
28
|
input_file_name: str = None,
|
|
16
|
-
|
|
29
|
+
input_statistics_file_name: str = None,
|
|
30
|
+
input_directory: str = None,
|
|
17
31
|
input_file_write_only: bool = True,
|
|
18
|
-
|
|
32
|
+
object_type: Union[
|
|
33
|
+
Literal[
|
|
34
|
+
'file',
|
|
35
|
+
'dns',
|
|
36
|
+
'network',
|
|
37
|
+
'process_running',
|
|
38
|
+
'url_urllib',
|
|
39
|
+
'url_playwright_html',
|
|
40
|
+
'url_playwright_pdf',
|
|
41
|
+
'url_playwright_png',
|
|
42
|
+
'url_playwright_jpeg'],
|
|
43
|
+
None] = None,
|
|
44
|
+
object_type_settings: dict = None,
|
|
45
|
+
etw_session_name: str = None
|
|
19
46
|
):
|
|
20
47
|
"""
|
|
21
48
|
:param object_type: string, type of object to check. The type must be one of the following:
|
|
22
|
-
'
|
|
23
|
-
'
|
|
24
|
-
'
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
49
|
+
'file': 'check_object' must contain string of full path to the file.
|
|
50
|
+
'dns': 'check_object' will be none, since the DNS events will be queried from the system.
|
|
51
|
+
'network': 'check_object' will be none, since the network events will be queried from the system.
|
|
52
|
+
'process_running': 'check_object' must contain list of strings of process names to check if they are
|
|
53
|
+
running.
|
|
54
|
+
Example: ['chrome.exe', 'firefox.exe']
|
|
55
|
+
No file is written.
|
|
56
|
+
'url_*': 'check_object' must contain string of full URL to a web page to download.
|
|
57
|
+
'url_urllib': download using 'urllib' library to HTML file.
|
|
58
|
+
'url_playwright_html': download using 'playwright' library to HTML file.
|
|
59
|
+
'url_playwright_pdf': download using 'playwright' library to PDF file.
|
|
60
|
+
'url_playwright_png': download using 'playwright' library to PNG file.
|
|
61
|
+
'url_playwright_jpeg': download using 'playwright' library to JPEG file.
|
|
62
|
+
:param object_type_settings: dict, specific settings for the object type.
|
|
63
|
+
'dns': Check the default settings example in 'DNS__DEFAULT_SETTINGS'.
|
|
64
|
+
'file': Check the default settings example in 'FILE__URL__DEFAULT_SETTINGS'.
|
|
65
|
+
'url_*': Check the default settings example in 'FILE__URL__DEFAULT_SETTINGS'.
|
|
66
|
+
:param check_object: The object to check if changed.
|
|
67
|
+
'dns': empty.
|
|
68
|
+
'network': empty.
|
|
69
|
+
'process_running': list of strings, process names to check if they are running.
|
|
70
|
+
'file': string, full path to the file.
|
|
71
|
+
'url_*': string, full URL to a web page.
|
|
72
|
+
:param input_directory: string, full directory path for storing input files for current state of objects,
|
|
38
73
|
to check later if this state isn't updated. If this variable is left empty, all the content will be saved
|
|
39
74
|
in memory and input file will not be used.
|
|
40
75
|
If the file is not specified, the update of an object will be checked
|
|
@@ -50,91 +85,54 @@ class ChangeMonitor:
|
|
|
50
85
|
to the input file whether the object was updated.
|
|
51
86
|
False: write to input file each time there is an update, and read each check cycle from the file and not
|
|
52
87
|
from the memory.
|
|
53
|
-
:param
|
|
54
|
-
|
|
88
|
+
:param etw_session_name: string, the name of the ETW session. This should help you manage your ETW sessions
|
|
89
|
+
with logman and other tools: logman query -ets
|
|
90
|
+
If not provided, a default name will be generated.
|
|
91
|
+
'dns': 'AtomicShopDnsTrace'
|
|
55
92
|
|
|
56
|
-
If '
|
|
93
|
+
If 'input_directory' is not specified, the 'input_file_name' is not specified, and
|
|
57
94
|
'generate_input_file_name' is False, then the input file will not be used and the object will be stored
|
|
58
95
|
in memory. This means that the object will be checked only during the time that the script is running.
|
|
59
96
|
"""
|
|
60
97
|
|
|
61
|
-
#
|
|
62
|
-
if not input_file_directory and store_original_object:
|
|
63
|
-
raise ValueError('ERROR: [input_file_directory] must be specified if [store_original_object] is True.')
|
|
98
|
+
# === Initialize Main variables ====================================
|
|
64
99
|
|
|
65
|
-
|
|
66
|
-
|
|
100
|
+
self.check_object: any = check_object
|
|
101
|
+
self.input_file_name: str = input_file_name
|
|
102
|
+
self.input_statistics_file_name: str = input_statistics_file_name
|
|
103
|
+
self.input_directory: str = input_directory
|
|
104
|
+
self.input_file_write_only: bool = input_file_write_only
|
|
105
|
+
self.object_type = object_type
|
|
106
|
+
self.object_type_settings: dict = object_type_settings
|
|
107
|
+
self.etw_session_name: str = etw_session_name
|
|
67
108
|
|
|
68
|
-
|
|
69
|
-
raise ValueError('ERROR: [input_file_directory] must be specified if [input_file_name] is specified.')
|
|
109
|
+
# === Additional variables ========================================
|
|
70
110
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
'ERROR: [input_file_name] and [generate_input_file_name] cannot be both specified and True.')
|
|
111
|
+
self.checks_instance = None
|
|
112
|
+
self._setup_check()
|
|
74
113
|
|
|
75
|
-
|
|
76
|
-
|
|
114
|
+
def _setup_check(self):
|
|
115
|
+
if self.object_type == 'file':
|
|
116
|
+
if not self.object_type_settings:
|
|
117
|
+
self.object_type_settings = FILE__URL__DEFAULT_SETTINGS
|
|
77
118
|
|
|
78
|
-
|
|
79
|
-
|
|
119
|
+
self.checks_instance = file.FileCheck(self)
|
|
120
|
+
elif self.object_type.startswith('url_'):
|
|
121
|
+
if not self.object_type_settings:
|
|
122
|
+
self.object_type_settings = FILE__URL__DEFAULT_SETTINGS
|
|
80
123
|
|
|
81
|
-
|
|
82
|
-
self.
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
self.
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
# The 'diff_check' will store the list of DiffChecker classes.
|
|
93
|
-
self.diff_check_list: list = list()
|
|
94
|
-
|
|
95
|
-
# If 'check_object_list' is a list, loop through it and create a DiffChecker object for each object.
|
|
96
|
-
if self.check_object_list:
|
|
97
|
-
for index in range(len(self.check_object_list)):
|
|
98
|
-
self.diff_check_list.append(
|
|
99
|
-
DiffChecker(
|
|
100
|
-
input_file_write_only=self.input_file_write_only,
|
|
101
|
-
)
|
|
102
|
-
)
|
|
103
|
-
# Else, if 'check_object_list' is None, create a DiffChecker object only once.
|
|
124
|
+
self.checks_instance = url.UrlCheck(self)
|
|
125
|
+
elif self.object_type == 'dns':
|
|
126
|
+
if not self.object_type_settings:
|
|
127
|
+
self.object_type_settings = DNS__DEFAULT_SETTINGS
|
|
128
|
+
|
|
129
|
+
self.checks_instance = dns.DnsCheck(self)
|
|
130
|
+
elif self.object_type == 'network':
|
|
131
|
+
self.checks_instance = network.NetworkCheck(self)
|
|
132
|
+
elif self.object_type == 'process_running':
|
|
133
|
+
self.checks_instance = process_running.ProcessRunningCheck(self)
|
|
104
134
|
else:
|
|
105
|
-
self.
|
|
106
|
-
DiffChecker(
|
|
107
|
-
input_file_write_only=self.input_file_write_only,
|
|
108
|
-
)
|
|
109
|
-
)
|
|
110
|
-
|
|
111
|
-
self.input_file_path = None
|
|
112
|
-
self.original_object_directory = None
|
|
113
|
-
self.original_object_file_path = None
|
|
114
|
-
|
|
115
|
-
# If 'store_original_object' is True, create directory for original object.
|
|
116
|
-
if self.store_original_object:
|
|
117
|
-
# Make path for original object.
|
|
118
|
-
self.original_object_directory = filesystem.add_object_to_path(
|
|
119
|
-
self.input_file_directory, 'Original')
|
|
120
|
-
# Create directory if it doesn't exist.
|
|
121
|
-
filesystem.create_directory(self.original_object_directory)
|
|
122
|
-
|
|
123
|
-
self.first_cycle = True
|
|
124
|
-
|
|
125
|
-
# Initialize objects for DNS and Network monitoring.
|
|
126
|
-
self.fetch_engine = None
|
|
127
|
-
self.thread_looper = scheduling.ThreadLooper()
|
|
128
|
-
|
|
129
|
-
def _set_input_file_path(self, check_object_index: int = 0):
|
|
130
|
-
if self.first_cycle:
|
|
131
|
-
# If 'input_file_directory' and 'input_file_name' are specified, we'll use a filename to store.
|
|
132
|
-
if self.input_file_directory and self.input_file_name:
|
|
133
|
-
self.input_file_path = filesystem.add_object_to_path(
|
|
134
|
-
self.input_file_directory, self.input_file_name)
|
|
135
|
-
|
|
136
|
-
# Set the input file path.
|
|
137
|
-
self.diff_check_list[check_object_index].input_file_path = self.input_file_path
|
|
135
|
+
raise ValueError(f"ERROR: Unknown object type: {self.object_type}")
|
|
138
136
|
|
|
139
137
|
def check_cycle(self, print_kwargs: dict = None):
|
|
140
138
|
"""
|
|
@@ -143,28 +141,6 @@ class ChangeMonitor:
|
|
|
143
141
|
:return: None
|
|
144
142
|
"""
|
|
145
143
|
|
|
146
|
-
return_list =
|
|
147
|
-
|
|
148
|
-
if (
|
|
149
|
-
self.object_type == 'file' or
|
|
150
|
-
'url_' in self.object_type):
|
|
151
|
-
return_list = hash._execute_cycle(self, print_kwargs=print_kwargs)
|
|
152
|
-
if self.object_type == 'dns':
|
|
153
|
-
return_list = dns._execute_cycle(self, print_kwargs=print_kwargs)
|
|
154
|
-
elif self.object_type == 'network':
|
|
155
|
-
return_list = network._execute_cycle(self, print_kwargs=print_kwargs)
|
|
156
|
-
elif self.object_type == 'process_running':
|
|
157
|
-
return_list = process_running._execute_cycle(self, print_kwargs=print_kwargs)
|
|
158
|
-
|
|
159
|
-
# Set 'first_cycle' to False, since the first cycle is finished.
|
|
160
|
-
if self.first_cycle:
|
|
161
|
-
self.first_cycle = False
|
|
144
|
+
return_list = self.checks_instance.execute_cycle(print_kwargs=print_kwargs)
|
|
162
145
|
|
|
163
146
|
return return_list
|
|
164
|
-
|
|
165
|
-
def run_loop(self, interval_seconds=0, print_kwargs: dict = None):
|
|
166
|
-
self.thread_looper.run_loop(
|
|
167
|
-
self.check_cycle, kwargs={'print_kwargs': print_kwargs}, interval_seconds=interval_seconds)
|
|
168
|
-
|
|
169
|
-
def emit_from_loop(self):
|
|
170
|
-
return self.thread_looper.emit_from_loop()
|
atomicshop/monitor/checks/dns.py
CHANGED
|
@@ -1,77 +1,146 @@
|
|
|
1
|
-
from
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from typing import Union
|
|
3
|
+
|
|
4
|
+
from ...etws.traces import trace_dns
|
|
2
5
|
from ...print_api import print_api
|
|
6
|
+
from ...import diff_check
|
|
3
7
|
|
|
4
8
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
This function executes the cycle of the change monitor: dns.
|
|
9
|
+
INPUT_FILE_DEFAULT_NAME: str = 'known_domains.json'
|
|
10
|
+
INPUT_STATISTICS_FILE_DEFAULT_NAME: str = 'dns_statistics.json'
|
|
8
11
|
|
|
9
|
-
:param change_monitor_instance: Instance of the ChangeMonitor class.
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
class DnsCheck:
|
|
12
14
|
"""
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
15
|
+
Class for DNS monitoring.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def __init__(self, change_monitor_instance):
|
|
19
|
+
self.change_monitor_instance = change_monitor_instance
|
|
20
|
+
self.diff_checker_aggregation: Union[diff_check.DiffChecker, None] = None
|
|
21
|
+
self.diff_checker_statistics: Union[diff_check.DiffChecker, None] = None
|
|
22
|
+
self.settings: dict = change_monitor_instance.object_type_settings
|
|
23
|
+
|
|
24
|
+
self.etw_session_name: str = change_monitor_instance.etw_session_name
|
|
25
|
+
|
|
26
|
+
self.fetch_engine: trace_dns.DnsRequestResponseTrace = (
|
|
27
|
+
trace_dns.DnsRequestResponseTrace(
|
|
28
|
+
attrs=['name', 'cmdline', 'query', 'query_type'],
|
|
29
|
+
session_name=self.etw_session_name,
|
|
30
|
+
close_existing_session_name=True,
|
|
31
|
+
skip_record_list=self.settings['skip_record_list'],
|
|
32
|
+
)
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
if self.settings['alert_always'] and self.settings['alert_about_missing_entries_after_learning']:
|
|
36
|
+
raise ValueError(
|
|
37
|
+
"ERROR: [alert_always] and [alert_about_missing_entries_after_learning] "
|
|
38
|
+
"cannot be True at the same time.")
|
|
39
|
+
|
|
40
|
+
if not change_monitor_instance.input_file_name:
|
|
41
|
+
change_monitor_instance.input_file_name = INPUT_FILE_DEFAULT_NAME
|
|
42
|
+
input_file_path = (
|
|
43
|
+
str(Path(change_monitor_instance.input_directory, change_monitor_instance.input_file_name)))
|
|
44
|
+
|
|
45
|
+
if not change_monitor_instance.input_statistics_file_name:
|
|
46
|
+
change_monitor_instance.input_statistics_file_name = INPUT_STATISTICS_FILE_DEFAULT_NAME
|
|
47
|
+
input_statistic_file_path = (
|
|
48
|
+
str(Path(change_monitor_instance.input_directory, change_monitor_instance.input_statistics_file_name)))
|
|
49
|
+
|
|
50
|
+
if self.settings['learning_mode_create_unique_entries_list']:
|
|
51
|
+
aggregation_display_name = \
|
|
52
|
+
f'{change_monitor_instance.input_file_name}|{change_monitor_instance.object_type}'
|
|
53
|
+
self.diff_checker_aggregation = diff_check.DiffChecker(
|
|
54
|
+
check_object=list(), # DNS events will be appended to this list.
|
|
55
|
+
return_first_cycle=True,
|
|
56
|
+
operation_type='new_objects',
|
|
57
|
+
input_file_write_only=change_monitor_instance.input_file_write_only,
|
|
58
|
+
check_object_display_name=aggregation_display_name,
|
|
59
|
+
input_file_path=input_file_path,
|
|
60
|
+
new_objects_hours_then_difference=self.settings['learning_hours']
|
|
61
|
+
)
|
|
62
|
+
self.diff_checker_aggregation.initiate_before_action()
|
|
63
|
+
|
|
64
|
+
if self.settings['create_alert_statistics']:
|
|
65
|
+
statistics_display_name = \
|
|
66
|
+
f'{change_monitor_instance.input_statistics_file_name}|{change_monitor_instance.object_type}'
|
|
67
|
+
|
|
68
|
+
self.diff_checker_statistics = diff_check.DiffChecker(
|
|
69
|
+
check_object=list(), # DNS events will be appended to this list.
|
|
70
|
+
return_first_cycle=True,
|
|
71
|
+
operation_type='hit_statistics',
|
|
72
|
+
hit_statistics_enable_queue=True,
|
|
73
|
+
input_file_write_only=change_monitor_instance.input_file_write_only,
|
|
74
|
+
check_object_display_name=statistics_display_name,
|
|
75
|
+
input_file_path=input_statistic_file_path,
|
|
76
|
+
hit_statistics_input_file_rotation_cycle_hours=self.settings['statistics_rotation_hours']
|
|
77
|
+
)
|
|
78
|
+
self.diff_checker_statistics.initiate_before_action()
|
|
79
|
+
|
|
24
80
|
# Start DNS monitoring.
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
81
|
+
self.fetch_engine.start()
|
|
82
|
+
|
|
83
|
+
def execute_cycle(self, print_kwargs: dict = None) -> list:
|
|
84
|
+
"""
|
|
85
|
+
This function executes the cycle of the change monitor: dns.
|
|
86
|
+
The function is blocking so while using it, the script will wait for the next DNS event.
|
|
87
|
+
No need to use 'time.sleep()'.
|
|
88
|
+
|
|
89
|
+
:param print_kwargs: print_api kwargs.
|
|
90
|
+
:return: List of dictionaries with the results of the cycle.
|
|
91
|
+
"""
|
|
92
|
+
|
|
93
|
+
# 'emit()' method is blocking (it uses 'get' of queue instance)
|
|
94
|
+
# will return a dict with current DNS trace event.
|
|
95
|
+
event_dict = self.fetch_engine.emit()
|
|
96
|
+
|
|
97
|
+
return_list = list()
|
|
98
|
+
if self.settings['learning_mode_create_unique_entries_list']:
|
|
99
|
+
self._aggregation_process(event_dict, return_list, print_kwargs)
|
|
100
|
+
|
|
101
|
+
if self.settings['create_alert_statistics'] and self.settings['alert_always']:
|
|
102
|
+
self._statistics_process(event_dict, return_list, print_kwargs)
|
|
103
|
+
|
|
104
|
+
return return_list
|
|
105
|
+
|
|
106
|
+
def _aggregation_process(self, event_dict: dict, return_list: list, print_kwargs: dict = None):
|
|
107
|
+
self.diff_checker_aggregation.check_object = [event_dict]
|
|
108
|
+
|
|
109
|
+
# Check if 'known_domains' list was updated from previous cycle.
|
|
110
|
+
result, message = self.diff_checker_aggregation.check_list_of_dicts(
|
|
111
|
+
sort_by_keys=['cmdline', 'name'], print_kwargs=print_kwargs)
|
|
112
|
+
|
|
113
|
+
if result:
|
|
114
|
+
# Check if 'updated' key is in the result. This means that this is a regular cycle.
|
|
115
|
+
if 'updated' in result:
|
|
116
|
+
if not result['time_passed']:
|
|
117
|
+
# Get list of new connections only.
|
|
118
|
+
# new_connections_only: list = list_of_dicts.get_difference(result['old'], result['updated'])
|
|
119
|
+
|
|
120
|
+
for connection in result['updated']:
|
|
121
|
+
message = \
|
|
122
|
+
f"[Learning] New Domain Added: {connection['name']} | " \
|
|
123
|
+
f"{connection['domain']} | {connection['query_type']} | " \
|
|
124
|
+
f"{connection['cmdline']}"
|
|
125
|
+
print_api(message, color='yellow', **(print_kwargs or {}))
|
|
126
|
+
|
|
127
|
+
return_list.append(message)
|
|
128
|
+
|
|
129
|
+
# Check if learning time passed, so we can alert the new entries.
|
|
130
|
+
if 'time_passed' in result:
|
|
131
|
+
if result['time_passed']:
|
|
132
|
+
self._statistics_process(result['updated'], return_list, print_kwargs)
|
|
133
|
+
|
|
134
|
+
def _statistics_process(self, event_dict: dict, return_list: list, print_kwargs: dict = None):
|
|
135
|
+
self.diff_checker_statistics.check_object = [event_dict]
|
|
136
|
+
|
|
137
|
+
# Check if 'known_domains' list was updated from previous cycle.
|
|
138
|
+
result, message = self.diff_checker_statistics.check_list_of_dicts(
|
|
139
|
+
sort_by_keys=['cmdline', 'name'], print_kwargs=print_kwargs)
|
|
140
|
+
|
|
141
|
+
if result:
|
|
142
|
+
if 'count' in result:
|
|
143
|
+
message = f"[Alert] DNS Request: {result['entry']} | Times hit: {result['count']}"
|
|
144
|
+
print_api(message, color='yellow', **(print_kwargs or {}))
|
|
145
|
+
|
|
146
|
+
return_list.append(message)
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
from ... import filesystem, hashing
|
|
4
|
+
from ... import diff_check
|
|
5
|
+
from ...print_api import print_api
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class FileCheck:
|
|
9
|
+
"""
|
|
10
|
+
Class for file monitoring.
|
|
11
|
+
"""
|
|
12
|
+
def __init__(self, change_monitor_instance):
|
|
13
|
+
self.diff_checker = None
|
|
14
|
+
self.change_monitor_instance = None
|
|
15
|
+
self.store_original_file_path = None
|
|
16
|
+
|
|
17
|
+
if not change_monitor_instance.input_file_name:
|
|
18
|
+
change_monitor_instance.input_file_name = Path(change_monitor_instance.check_object).name
|
|
19
|
+
change_monitor_instance.input_file_name = change_monitor_instance.input_file_name.lower()
|
|
20
|
+
change_monitor_instance.input_file_name = (
|
|
21
|
+
change_monitor_instance.input_file_name.replace(' ', '_').replace('.', '_'))
|
|
22
|
+
change_monitor_instance.input_file_name = f'{change_monitor_instance.input_file_name}.txt'
|
|
23
|
+
|
|
24
|
+
input_file_path = (
|
|
25
|
+
str(Path(change_monitor_instance.input_directory, change_monitor_instance.input_file_name)))
|
|
26
|
+
|
|
27
|
+
# If 'store_original_object' is True, create filename for the store original object.
|
|
28
|
+
if change_monitor_instance.object_type_settings['store_original_object']:
|
|
29
|
+
store_original_file_name: str = f'ORIGINAL_{Path(change_monitor_instance.check_object).name}'
|
|
30
|
+
self.store_original_file_path = str(Path(change_monitor_instance.input_directory, store_original_file_name))
|
|
31
|
+
|
|
32
|
+
self.diff_checker = diff_check.DiffChecker(
|
|
33
|
+
return_first_cycle=False,
|
|
34
|
+
operation_type='single_object',
|
|
35
|
+
input_file_path=input_file_path,
|
|
36
|
+
check_object_display_name=f'{change_monitor_instance.input_file_name}|{change_monitor_instance.object_type}'
|
|
37
|
+
)
|
|
38
|
+
self.diff_checker.initiate_before_action()
|
|
39
|
+
self.change_monitor_instance = change_monitor_instance
|
|
40
|
+
|
|
41
|
+
def execute_cycle(self, print_kwargs: dict = None):
|
|
42
|
+
"""
|
|
43
|
+
This function executes the cycle of the change monitor: hash.
|
|
44
|
+
|
|
45
|
+
:param print_kwargs: print_api kwargs.
|
|
46
|
+
:return: List of dictionaries with the results of the cycle.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
return_list = list()
|
|
50
|
+
|
|
51
|
+
self._get_hash()
|
|
52
|
+
|
|
53
|
+
# Check if the object was updated.
|
|
54
|
+
result, message = self.diff_checker.check_string(
|
|
55
|
+
print_kwargs=print_kwargs)
|
|
56
|
+
|
|
57
|
+
# If the object was updated, print the message in yellow color, otherwise print in green color.
|
|
58
|
+
if result:
|
|
59
|
+
print_api(message, color='yellow', **print_kwargs)
|
|
60
|
+
# create_message_file(message, self.__class__.__name__, logger=self.logger)
|
|
61
|
+
|
|
62
|
+
return_list.append(message)
|
|
63
|
+
else:
|
|
64
|
+
print_api(message, color='green', **print_kwargs)
|
|
65
|
+
|
|
66
|
+
return return_list
|
|
67
|
+
|
|
68
|
+
def _get_hash(self):
|
|
69
|
+
# Copy the file to the original object directory.
|
|
70
|
+
if self.store_original_file_path:
|
|
71
|
+
filesystem.copy_file(self.change_monitor_instance.check_object, self.store_original_file_path)
|
|
72
|
+
|
|
73
|
+
# Get hash of the file.
|
|
74
|
+
hash_string = hashing.hash_file(self.change_monitor_instance.check_object)
|
|
75
|
+
|
|
76
|
+
# Set the hash string to the 'check_object' variable.
|
|
77
|
+
self.diff_checker.check_object = hash_string
|