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
atomicshop/dns.py
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
|
+
import socket
|
|
2
|
+
import argparse
|
|
3
|
+
|
|
4
|
+
# noinspection PyPackageRequirements
|
|
1
5
|
import dns.resolver
|
|
2
6
|
|
|
3
|
-
from .
|
|
7
|
+
from . import print_api
|
|
8
|
+
from . import networks
|
|
9
|
+
from .permissions import permissions
|
|
10
|
+
from .wrappers.pywin32w.wmis import win32networkadapter
|
|
11
|
+
from .wrappers import netshw
|
|
4
12
|
|
|
5
13
|
|
|
6
14
|
# Defining Dictionary of Numeric to String DNS Query Types.
|
|
@@ -18,15 +26,6 @@ TYPES_DICT = {
|
|
|
18
26
|
'255': 'ANY'
|
|
19
27
|
}
|
|
20
28
|
|
|
21
|
-
# Event Tracing DNS info.
|
|
22
|
-
ETW_DNS_INFO = {
|
|
23
|
-
'provider_name': 'Microsoft-Windows-DNS-Client',
|
|
24
|
-
'provider_guid': '{1C95126E-7EEA-49A9-A3FE-A378B03DDB4D}',
|
|
25
|
-
# Event ID 3008 got DNS Queries and DNS Answers. Meaning, that information in ETW will arrive after DNS Response
|
|
26
|
-
# is received and not After DNS Query is sent.
|
|
27
|
-
'event_id': 3008
|
|
28
|
-
}
|
|
29
|
-
|
|
30
29
|
|
|
31
30
|
def resolve_dns_localhost(domain_name: str, dns_servers_list: list = None, print_kwargs: dict = None) -> str:
|
|
32
31
|
"""
|
|
@@ -61,10 +60,127 @@ def resolve_dns_localhost(domain_name: str, dns_servers_list: list = None, print
|
|
|
61
60
|
# Get only the first entry of the list of IPs [0]
|
|
62
61
|
connection_ip = function_server_address[0].to_text()
|
|
63
62
|
message = f"Resolved to [{connection_ip}]"
|
|
64
|
-
print_api(message, **print_kwargs)
|
|
63
|
+
print_api.print_api(message, **print_kwargs)
|
|
65
64
|
except dns.resolver.NXDOMAIN:
|
|
66
65
|
message = f"Domain {domain_name} doesn't exist - Couldn't resolve with {dns_servers_list}."
|
|
67
|
-
print_api(message, **print_kwargs, error_type=True, logger_method='error')
|
|
66
|
+
print_api.print_api(message, **print_kwargs, error_type=True, logger_method='error')
|
|
68
67
|
pass
|
|
69
68
|
|
|
70
69
|
return connection_ip
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def get_default_dns_gateway() -> tuple[bool, list[str]]:
|
|
73
|
+
"""
|
|
74
|
+
Get the default DNS gateway from the system.
|
|
75
|
+
:return: tuple(is dynamic boolean, list of DNS server IPv4s).
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
interfaces_with_dns_settings: list[dict] = netshw.get_netsh_ipv4()
|
|
79
|
+
|
|
80
|
+
default_interface_ipv4 = socket.gethostbyname(socket.gethostname())
|
|
81
|
+
is_dynamic, dns_servers = None, None
|
|
82
|
+
for interface in interfaces_with_dns_settings:
|
|
83
|
+
if default_interface_ipv4 in interface['ip_addresses']:
|
|
84
|
+
is_dynamic = interface['dns_mode']
|
|
85
|
+
dns_servers = interface['dns_servers']
|
|
86
|
+
break
|
|
87
|
+
|
|
88
|
+
return is_dynamic, dns_servers
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def get_default_dns_gateway_with_dns_resolver() -> list[str]:
|
|
92
|
+
"""
|
|
93
|
+
Get the default DNS gateway from the system using dns.resolver.
|
|
94
|
+
:return: tuple(is dynamic boolean, list of DNS server IPv4s).
|
|
95
|
+
"""
|
|
96
|
+
|
|
97
|
+
resolver = dns.resolver.Resolver()
|
|
98
|
+
dns_servers = list(resolver.nameservers)
|
|
99
|
+
return dns_servers
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def set_interface_dns_gateway_static(
|
|
103
|
+
interface_name: str,
|
|
104
|
+
dns_servers: list[str]
|
|
105
|
+
) -> None:
|
|
106
|
+
"""
|
|
107
|
+
Set the DNS servers for a network adapter.
|
|
108
|
+
:param interface_name: string, adapter name as shown in the network settings.
|
|
109
|
+
:param dns_servers: list of strings, DNS server IPv4 addresses.
|
|
110
|
+
:return: None
|
|
111
|
+
"""
|
|
112
|
+
|
|
113
|
+
win32networkadapter.set_dns_server(interface_name=interface_name, dns_servers=dns_servers)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def set_interface_dns_gateway_dynamic(
|
|
117
|
+
interface_name: str = None
|
|
118
|
+
) -> None:
|
|
119
|
+
"""
|
|
120
|
+
Set the DNS servers for a network adapter to obtain them automatically from DHCP.
|
|
121
|
+
:param interface_name: string, adapter name as shown in the network settings.
|
|
122
|
+
:return: None
|
|
123
|
+
"""
|
|
124
|
+
|
|
125
|
+
win32networkadapter.set_dns_server(
|
|
126
|
+
interface_name=interface_name, dns_servers=None)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def default_dns_gateway_main() -> int:
|
|
130
|
+
"""
|
|
131
|
+
Main function for the default DNS gateway manipulations.
|
|
132
|
+
:return: None
|
|
133
|
+
"""
|
|
134
|
+
|
|
135
|
+
argparse_obj = argparse.ArgumentParser(description="Get/Set the DNS gateway for the network adapter.")
|
|
136
|
+
arg_action_group = argparse_obj.add_mutually_exclusive_group(required=True)
|
|
137
|
+
arg_action_group.add_argument(
|
|
138
|
+
'-g', '--get', action='store_true', help='Get the default DNS gateway for the system.')
|
|
139
|
+
arg_action_group.add_argument(
|
|
140
|
+
'-s', '--set', type=str, nargs='+',
|
|
141
|
+
help='Set static DNS gateway for the system, provide values with spaces between each value.\n'
|
|
142
|
+
' Example: -s 8.8.8.8 1.1.1.1.')
|
|
143
|
+
arg_action_group.add_argument(
|
|
144
|
+
'-d', '--dynamic', action='store_true',
|
|
145
|
+
help='Set the DNS gateway to obtain automatically from DHCP.')
|
|
146
|
+
|
|
147
|
+
arg_interface_group = argparse_obj.add_mutually_exclusive_group()
|
|
148
|
+
arg_interface_group.add_argument(
|
|
149
|
+
'-in', '--interface_name', type=str, help='Network Interface name as shown in the network settings.')
|
|
150
|
+
arg_interface_group.add_argument(
|
|
151
|
+
'-id', '--interface_default', action='store_true', help='Use the default network interface.')
|
|
152
|
+
|
|
153
|
+
args = argparse_obj.parse_args()
|
|
154
|
+
|
|
155
|
+
if (args.set or args.dynamic) and not (args.interface_name or args.interface_default):
|
|
156
|
+
print_api.print_api(
|
|
157
|
+
"Please provide the interface name [-in] or use the default interface [-id].", color='red')
|
|
158
|
+
return 1
|
|
159
|
+
|
|
160
|
+
if args.set or args.dynamic:
|
|
161
|
+
if not permissions.is_admin():
|
|
162
|
+
print_api.print_api("You need to run this script as an administrator", color='red')
|
|
163
|
+
return 1
|
|
164
|
+
|
|
165
|
+
def get_interface_name() -> str:
|
|
166
|
+
if args.interface_default:
|
|
167
|
+
return networks.get_default_interface_name()
|
|
168
|
+
else:
|
|
169
|
+
return args.interface_name
|
|
170
|
+
|
|
171
|
+
if args.get:
|
|
172
|
+
is_dynamic, dns_servers = get_default_dns_gateway()
|
|
173
|
+
|
|
174
|
+
if is_dynamic:
|
|
175
|
+
is_dynamic_string = 'Dynamic'
|
|
176
|
+
else:
|
|
177
|
+
is_dynamic_string = 'Static'
|
|
178
|
+
print_api.print_api(f'DNS Gateway: {is_dynamic_string} - {dns_servers}', color='blue')
|
|
179
|
+
elif args.set:
|
|
180
|
+
# dns_servers_list: list = args.dns_servers.split(',')
|
|
181
|
+
set_interface_dns_gateway_static(
|
|
182
|
+
dns_servers=args.set, interface_name=get_interface_name())
|
|
183
|
+
elif args.dynamic:
|
|
184
|
+
set_interface_dns_gateway_dynamic(interface_name=get_interface_name())
|
|
185
|
+
|
|
186
|
+
return 0
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Need to fix the
|
|
3
|
+
etw.etw
|
|
4
|
+
file, in the
|
|
5
|
+
EventConsumer._unpackSimpleType
|
|
6
|
+
function.
|
|
7
|
+
"""
|
|
8
|
+
"""
|
|
9
|
+
data = formatted_data.value
|
|
10
|
+
# Convert the formatted data if necessary
|
|
11
|
+
if isinstance(data, str):
|
|
12
|
+
if data.endswith(' '):
|
|
13
|
+
data = data[:-1]
|
|
14
|
+
else:
|
|
15
|
+
if out_type in tdh.TDH_CONVERTER_LOOKUP and type(data) != tdh.TDH_CONVERTER_LOOKUP[out_type]:
|
|
16
|
+
data = tdh.TDH_CONVERTER_LOOKUP[out_type](data)
|
|
17
|
+
"""
|
atomicshop/etws/const.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
ETW_DNS = {
|
|
2
|
+
'provider_name': 'Microsoft-Windows-DNS-Client',
|
|
3
|
+
'provider_guid': '{1C95126E-7EEA-49A9-A3FE-A378B03DDB4D}',
|
|
4
|
+
'event_ids': {
|
|
5
|
+
# Event ID 3008 got DNS Queries and DNS Answers. Meaning, that information in ETW will arrive after DNS Response
|
|
6
|
+
# is received and not after DNS Query Request is sent.
|
|
7
|
+
'dns_request_response': 3008
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# Event Tracing Kernel-Process.
|
|
13
|
+
ETW_KERNEL_PROCESS = {
|
|
14
|
+
'provider_name': 'Microsoft-Windows-Kernel-Process',
|
|
15
|
+
'provider_guid': '{22FB2CD6-0E7B-422B-A0C7-2FAD1FD0E716}',
|
|
16
|
+
'event_ids': {
|
|
17
|
+
'process_create': 1 # Emits all the processes that are started.
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# You need SYSTEM privileges to execute this one. Try with psexec -s -i
|
|
23
|
+
ETW_SECURITY_AUDITING = {
|
|
24
|
+
'provider_name': 'Microsoft-Windows-Security-Auditing',
|
|
25
|
+
'provider_guid': '{54849625-5478-4994-A5BA-3E3B0328C30D}',
|
|
26
|
+
'event_ids': {
|
|
27
|
+
'process_create': 4688 # Emits all the processes that are started.
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
ETW_SYSMON = {
|
|
33
|
+
'provider_name': 'Microsoft-Windows-Sysmon',
|
|
34
|
+
'provider_guid': '{5770385F-C22A-43E0-BF4C-06F5698FFBD9}',
|
|
35
|
+
'event_ids': {
|
|
36
|
+
'process_create': 1 # Emits all the processes that are started.
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from typing import Literal
|
|
2
|
+
|
|
3
|
+
from ..wrappers.ctyping.etw_winapi import etw_functions
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def get_providers(key_as: Literal['name', 'guid'] = 'name'):
|
|
7
|
+
return etw_functions.get_all_providers(key_as=key_as)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def get_provider_guid_by_name(provider_name):
|
|
11
|
+
providers = get_providers(key_as='name')
|
|
12
|
+
|
|
13
|
+
try:
|
|
14
|
+
provider_guid = providers[provider_name]
|
|
15
|
+
except KeyError:
|
|
16
|
+
provider_guid = None
|
|
17
|
+
|
|
18
|
+
if not provider_guid:
|
|
19
|
+
raise ValueError(f"Provider '{provider_name}' not found")
|
|
20
|
+
|
|
21
|
+
return provider_guid
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from ..wrappers.ctyping.etw_winapi import etw_functions
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def stop_and_delete(session_name: str) -> tuple[bool, int]:
|
|
5
|
+
"""
|
|
6
|
+
Stop and delete ETW session.
|
|
7
|
+
|
|
8
|
+
:param session_name: The name of the session to stop and delete.
|
|
9
|
+
:return: A tuple containing a boolean indicating success and an integer status code.
|
|
10
|
+
True, 0: If the session was stopped and deleted successfully.
|
|
11
|
+
False, <status>: If the session could not be stopped and deleted and the status code, why it failed.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
return etw_functions.stop_and_delete_etw_session(session_name)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def get_running_list() -> list[dict]:
|
|
18
|
+
"""
|
|
19
|
+
List all running ETW sessions.
|
|
20
|
+
|
|
21
|
+
:return: A list of strings containing the names of all running ETW sessions.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
return etw_functions.list_etw_sessions()
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def is_session_running(session_name: str) -> bool:
|
|
28
|
+
"""
|
|
29
|
+
Check if an ETW session is running.
|
|
30
|
+
|
|
31
|
+
:param session_name: The name of the session to check.
|
|
32
|
+
:return: A boolean indicating if the session is running.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
# Get all running sessions.
|
|
36
|
+
running_sessions = get_running_list()
|
|
37
|
+
|
|
38
|
+
# Check if the session is in the list of running sessions.
|
|
39
|
+
for session in running_sessions:
|
|
40
|
+
if session['session_name'] == session_name:
|
|
41
|
+
return True
|
|
42
|
+
|
|
43
|
+
return False
|
atomicshop/etws/trace.py
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import queue
|
|
2
|
+
import sys
|
|
3
|
+
import multiprocessing.managers
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
|
|
6
|
+
# Import FireEye Event Tracing library.
|
|
7
|
+
import etw
|
|
8
|
+
|
|
9
|
+
from ..print_api import print_api
|
|
10
|
+
from . import sessions
|
|
11
|
+
from ..process_poller import simple_process_pool
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class EventTrace(etw.ETW):
|
|
15
|
+
def __init__(
|
|
16
|
+
self,
|
|
17
|
+
providers: list,
|
|
18
|
+
event_callback: callable = None,
|
|
19
|
+
event_id_filters: list = None,
|
|
20
|
+
session_name: str = None,
|
|
21
|
+
close_existing_session_name: bool = True,
|
|
22
|
+
enable_process_poller: bool = False,
|
|
23
|
+
process_pool_shared_dict_proxy: multiprocessing.managers.DictProxy = None
|
|
24
|
+
):
|
|
25
|
+
"""
|
|
26
|
+
:param providers: List of tuples with provider name and provider GUID.
|
|
27
|
+
tuple[0] = provider name
|
|
28
|
+
tuple[1] = provider GUID
|
|
29
|
+
|
|
30
|
+
Example: [('Microsoft-Windows-DNS-Client', '{1c95126e-7ee8-4e23-86b2-6e7e4a5a8e9b}')]
|
|
31
|
+
:param event_callback: Reference to the callable callback function that will be called for each occurring event.
|
|
32
|
+
:param event_id_filters: List of event IDs that we want to filter. If not provided, all events will be returned.
|
|
33
|
+
The default in the 'etw.ETW' method is 'None'.
|
|
34
|
+
:param session_name: The name of the session to create. If not provided, a UUID will be generated.
|
|
35
|
+
:param close_existing_session_name: Boolean to close existing session names.
|
|
36
|
+
:param enable_process_poller: Boolean to enable process poller. Gets the process PID, Name and CommandLine.
|
|
37
|
+
Since the DNS events doesn't contain the process name and command line, only PID.
|
|
38
|
+
Then DNS events will be enriched with the process name and command line from the process poller.
|
|
39
|
+
:param process_pool_shared_dict_proxy: multiprocessing.managers.DictProxy,
|
|
40
|
+
multiprocessing shared dict proxy that contains current processes.
|
|
41
|
+
Check the 'atomicshop\process_poller\simple_process_pool.py' SimpleProcessPool class for more information.
|
|
42
|
+
|
|
43
|
+
If None, the process poller will create a new shared dict proxy.
|
|
44
|
+
If provided, then the provided shared dict proxy will be used.
|
|
45
|
+
Off course valid only if 'enable_process_poller' is True.
|
|
46
|
+
|
|
47
|
+
------------------------------------------
|
|
48
|
+
|
|
49
|
+
You should stop the ETW tracing when you are done with it.
|
|
50
|
+
'pywintrace' module starts a new session for ETW tracing, and it will not stop the session when the script
|
|
51
|
+
exits or exception is raised.
|
|
52
|
+
This can cause problems when you want to start the script again, and the session is already running.
|
|
53
|
+
If the session is already running, and you start a new session with the same session name, you will get
|
|
54
|
+
the buffer from when you stopped getting the events from the buffer.
|
|
55
|
+
If you give different session name for new session, the previous session will still continue to run,
|
|
56
|
+
filling the buffer with events, until you will stop getting new events on all sessions or get an
|
|
57
|
+
exception that the buffer is full (WinError 1450).
|
|
58
|
+
|
|
59
|
+
Example to stop the ETW tracing at the end of the script:
|
|
60
|
+
from atomicshop.basics import atexits
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
event_tracing = EventTrace(<Your parameters>)
|
|
64
|
+
atexits.run_callable_on_exit_and_signals(EventTrace.stop)
|
|
65
|
+
"""
|
|
66
|
+
self.event_queue = queue.Queue()
|
|
67
|
+
self.close_existing_session_name: bool = close_existing_session_name
|
|
68
|
+
self.enable_process_poller: bool = enable_process_poller
|
|
69
|
+
self.process_pool_shared_dict_proxy: multiprocessing.managers.DictProxy = process_pool_shared_dict_proxy
|
|
70
|
+
|
|
71
|
+
# If no callback function is provided, we will use the default one, which will put the event in the queue.
|
|
72
|
+
if not event_callback:
|
|
73
|
+
function_callable = lambda x: self.event_queue.put(x)
|
|
74
|
+
# If a callback function is provided, we will use it.
|
|
75
|
+
else:
|
|
76
|
+
function_callable = lambda x: event_callback(x)
|
|
77
|
+
|
|
78
|
+
# Defining the list of specified ETW providers in 'etw' library format.
|
|
79
|
+
etw_format_providers: list = list()
|
|
80
|
+
for provider in providers:
|
|
81
|
+
etw_format_providers.append(etw.ProviderInfo(provider[0], etw.GUID(provider[1])))
|
|
82
|
+
|
|
83
|
+
self.self_hosted_poller: bool = False
|
|
84
|
+
if self.enable_process_poller:
|
|
85
|
+
if self.process_pool_shared_dict_proxy is None:
|
|
86
|
+
self.self_hosted_poller = True
|
|
87
|
+
self.process_poller = simple_process_pool.SimpleProcessPool()
|
|
88
|
+
self.multiprocessing_manager: multiprocessing.managers.SyncManager = multiprocessing.Manager()
|
|
89
|
+
self.process_pool_shared_dict_proxy = self.multiprocessing_manager.dict()
|
|
90
|
+
|
|
91
|
+
self.pid_process_converter = simple_process_pool.PidProcessConverter(
|
|
92
|
+
process_pool_shared_dict_proxy=self.process_pool_shared_dict_proxy)
|
|
93
|
+
|
|
94
|
+
super().__init__(
|
|
95
|
+
providers=etw_format_providers, event_callback=function_callable, event_id_filters=event_id_filters,
|
|
96
|
+
session_name=session_name
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
def start(self):
|
|
100
|
+
if self.enable_process_poller and self.self_hosted_poller:
|
|
101
|
+
self.process_poller.start()
|
|
102
|
+
|
|
103
|
+
# Check if the session name already exists.
|
|
104
|
+
if sessions.is_session_running(self.session_name):
|
|
105
|
+
print_api(f'ETW Session already running: {self.session_name}', color='yellow')
|
|
106
|
+
|
|
107
|
+
# Close the existing session name.
|
|
108
|
+
if self.close_existing_session_name:
|
|
109
|
+
print_api(f'Closing existing session: {self.session_name}', color='blue')
|
|
110
|
+
sessions.stop_and_delete(self.session_name)
|
|
111
|
+
else:
|
|
112
|
+
print_api(f'Using existing session: {self.session_name}', color='yellow')
|
|
113
|
+
|
|
114
|
+
try:
|
|
115
|
+
super().start()
|
|
116
|
+
except OSError as e:
|
|
117
|
+
message = f"PyWinTrace Error: {e}\n" \
|
|
118
|
+
f"PyWinTrace crashed, didn't find solution to this, RESTART computer."
|
|
119
|
+
print_api(message, error_type=True, logger_method='critical')
|
|
120
|
+
sys.exit(1)
|
|
121
|
+
|
|
122
|
+
def stop(self):
|
|
123
|
+
super().stop()
|
|
124
|
+
|
|
125
|
+
if self.self_hosted_poller:
|
|
126
|
+
self.process_poller.stop()
|
|
127
|
+
|
|
128
|
+
self.multiprocessing_manager.shutdown()
|
|
129
|
+
|
|
130
|
+
def emit(self):
|
|
131
|
+
"""
|
|
132
|
+
The Function will return the next event from the queue.
|
|
133
|
+
The queue is blocking, so if there is no event in the queue, the function will wait until there is one.
|
|
134
|
+
|
|
135
|
+
Usage Example:
|
|
136
|
+
while True:
|
|
137
|
+
dns_dict = dns_trace.emit()
|
|
138
|
+
print(dns_dict)
|
|
139
|
+
|
|
140
|
+
event object:
|
|
141
|
+
event[0]: is the event ID. Example: for DNS Tracing, it is event id 3008.
|
|
142
|
+
event[1]: contains a dictionary with all the event's parameters.
|
|
143
|
+
|
|
144
|
+
:return: etw event object.
|
|
145
|
+
"""
|
|
146
|
+
|
|
147
|
+
event: tuple = self.event_queue.get()
|
|
148
|
+
|
|
149
|
+
current_datetime = datetime.now()
|
|
150
|
+
readable_time = current_datetime.strftime('%Y-%m-%d %H:%M:%S.%f')
|
|
151
|
+
|
|
152
|
+
event_dict: dict = {
|
|
153
|
+
'EventId': event[0],
|
|
154
|
+
'EventHeader': event[1],
|
|
155
|
+
'timestamp': readable_time
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if 'ProcessId' not in event[1]:
|
|
159
|
+
event_dict['pid'] = event[1]['EventHeader']['ProcessId']
|
|
160
|
+
else:
|
|
161
|
+
event_dict['pid'] = event[1]['ProcessId']
|
|
162
|
+
|
|
163
|
+
if self.enable_process_poller:
|
|
164
|
+
process_info: dict = self.pid_process_converter.get_process_by_pid(event_dict['pid'])
|
|
165
|
+
event_dict['name'] = process_info['name']
|
|
166
|
+
event_dict['cmdline'] = process_info['cmdline']
|
|
167
|
+
|
|
168
|
+
return event_dict
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import multiprocessing.managers
|
|
2
|
+
|
|
3
|
+
from .. import trace, const
|
|
4
|
+
from ...basics import dicts
|
|
5
|
+
from ... import dns, ip_addresses
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
ETW_DEFAULT_SESSION_NAME: str = 'AtomicShopDnsTrace'
|
|
9
|
+
|
|
10
|
+
PROVIDER_NAME: str = const.ETW_DNS['provider_name']
|
|
11
|
+
PROVIDER_GUID: str = const.ETW_DNS['provider_guid']
|
|
12
|
+
REQUEST_RESP_EVENT_ID: int = const.ETW_DNS['event_ids']['dns_request_response']
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class DnsRequestResponseTrace:
|
|
16
|
+
"""DnsTrace class use to trace DNS events from Windows Event Tracing for EventId 3008."""
|
|
17
|
+
def __init__(
|
|
18
|
+
self,
|
|
19
|
+
attrs: list = None,
|
|
20
|
+
session_name: str = None,
|
|
21
|
+
close_existing_session_name: bool = True,
|
|
22
|
+
skip_record_list: list = None,
|
|
23
|
+
process_pool_shared_dict_proxy: multiprocessing.managers.DictProxy = None
|
|
24
|
+
):
|
|
25
|
+
"""
|
|
26
|
+
:param attrs: List of attributes to return. If None, all attributes will be returned.
|
|
27
|
+
:param session_name: The name of the session to create. If not provided, a UUID will be generated.
|
|
28
|
+
:param close_existing_session_name: Boolean to close existing session names.
|
|
29
|
+
True: if ETW session with 'session_name' exists, you will be notified and the session will be closed.
|
|
30
|
+
Then the new session with this name will be created.
|
|
31
|
+
False: if ETW session with 'session_name' exists, you will be notified and the new session will not be
|
|
32
|
+
created. Instead, the existing session will be used. If there is a buffer from the previous session,
|
|
33
|
+
you will get the events from the buffer.
|
|
34
|
+
:param skip_record_list: List of DNS Records to skip emitting. Example: ['PTR', 'SRV']
|
|
35
|
+
:param process_pool_shared_dict_proxy: multiprocessing.managers.DictProxy, multiprocessing shared dict proxy
|
|
36
|
+
that contains current processes.
|
|
37
|
+
Check the 'atomicshop\process_poller\simple_process_pool.py' SimpleProcessPool class for more information.
|
|
38
|
+
|
|
39
|
+
For this specific class it means that you can run the process poller outside of this class and pass the
|
|
40
|
+
'process_pool_shared_dict_proxy' to this class. Then you can get the process name and command line for
|
|
41
|
+
the DNS events from the 'process_pool_shared_dict_proxy' and use it also in other classes.
|
|
42
|
+
|
|
43
|
+
-------------------------------------------------
|
|
44
|
+
|
|
45
|
+
Usage Example:
|
|
46
|
+
from atomicshop.etw import dns_trace
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
dns_trace_w = dns_trace.DnsTrace(
|
|
50
|
+
attrs=['pid', 'name', 'cmdline', 'query', 'query_type'],
|
|
51
|
+
session_name='MyDnsTrace',
|
|
52
|
+
close_existing_session_name=True,
|
|
53
|
+
enable_process_poller=True
|
|
54
|
+
)
|
|
55
|
+
dns_trace_w.start()
|
|
56
|
+
while True:
|
|
57
|
+
dns_dict = dns_trace_w.emit()
|
|
58
|
+
print(dns_dict)
|
|
59
|
+
dns_trace_w.stop()
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
self.attrs = attrs
|
|
63
|
+
self.process_pool_shared_dict_proxy: multiprocessing.managers.DictProxy = process_pool_shared_dict_proxy
|
|
64
|
+
|
|
65
|
+
if skip_record_list:
|
|
66
|
+
self.skip_record_list: list = skip_record_list
|
|
67
|
+
else:
|
|
68
|
+
self.skip_record_list: list = list()
|
|
69
|
+
|
|
70
|
+
if not session_name:
|
|
71
|
+
session_name = ETW_DEFAULT_SESSION_NAME
|
|
72
|
+
|
|
73
|
+
self.event_trace = trace.EventTrace(
|
|
74
|
+
providers=[(PROVIDER_NAME, PROVIDER_GUID)],
|
|
75
|
+
# lambda x: self.event_queue.put(x),
|
|
76
|
+
event_id_filters=[REQUEST_RESP_EVENT_ID],
|
|
77
|
+
session_name=session_name,
|
|
78
|
+
close_existing_session_name=close_existing_session_name,
|
|
79
|
+
enable_process_poller=True,
|
|
80
|
+
process_pool_shared_dict_proxy=self.process_pool_shared_dict_proxy
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
def start(self):
|
|
84
|
+
self.event_trace.start()
|
|
85
|
+
|
|
86
|
+
def stop(self):
|
|
87
|
+
self.event_trace.stop()
|
|
88
|
+
|
|
89
|
+
def emit(self):
|
|
90
|
+
"""
|
|
91
|
+
Function that will return the next event from the queue.
|
|
92
|
+
The queue is blocking, so if there is no event in the queue, the function will wait until there is one.
|
|
93
|
+
|
|
94
|
+
Usage Example:
|
|
95
|
+
while True:
|
|
96
|
+
dns_dict = dns_trace.emit()
|
|
97
|
+
print(dns_dict)
|
|
98
|
+
|
|
99
|
+
:return: Dictionary with the event data.
|
|
100
|
+
"""
|
|
101
|
+
|
|
102
|
+
# Get the event from ETW as is.
|
|
103
|
+
event = self.event_trace.emit()
|
|
104
|
+
|
|
105
|
+
# Get the raw query results string from the event.
|
|
106
|
+
query_results: str = event['EventHeader']['QueryResults']
|
|
107
|
+
|
|
108
|
+
if query_results != '':
|
|
109
|
+
query_results_list: list = query_results.split(';')
|
|
110
|
+
|
|
111
|
+
addresses_ips: list = list()
|
|
112
|
+
addresses_cnames: list = list()
|
|
113
|
+
for query_result in query_results_list:
|
|
114
|
+
# If there is a type in the query result, it means it is a cname (domain).
|
|
115
|
+
if 'type' in query_result:
|
|
116
|
+
query_result = query_result.split(' ')[-1]
|
|
117
|
+
|
|
118
|
+
# But we'll still make sure that the query result is an IP address or not.
|
|
119
|
+
if ip_addresses.is_ip_address(query_result):
|
|
120
|
+
addresses_ips.append(query_result)
|
|
121
|
+
# If it is not empty, then it is a cname.
|
|
122
|
+
elif query_result != '':
|
|
123
|
+
addresses_cnames.append(query_result)
|
|
124
|
+
# if the query results are empty, then we'll just set the addresses to empty lists.
|
|
125
|
+
else:
|
|
126
|
+
addresses_ips: list = list()
|
|
127
|
+
addresses_cnames: list = list()
|
|
128
|
+
|
|
129
|
+
status_id: str = str(event['EventHeader']['QueryStatus'])
|
|
130
|
+
|
|
131
|
+
# Getting the 'QueryStatus' key. If DNS Query Status is '0' then it was executed successfully.
|
|
132
|
+
# And if not, it means there was an error. The 'QueryStatus' indicate what number of an error it is.
|
|
133
|
+
if status_id == '0':
|
|
134
|
+
status = 'Success'
|
|
135
|
+
else:
|
|
136
|
+
status = 'Error'
|
|
137
|
+
|
|
138
|
+
event_dict: dict = {
|
|
139
|
+
'timestamp': event['timestamp'],
|
|
140
|
+
'event_id': event['EventId'],
|
|
141
|
+
'query': event['EventHeader']['QueryName'],
|
|
142
|
+
'query_type_id': str(event['EventHeader']['QueryType']),
|
|
143
|
+
'query_type': dns.TYPES_DICT[str(event['EventHeader']['QueryType'])],
|
|
144
|
+
'result_ips': ','.join(addresses_ips),
|
|
145
|
+
'result_cnames': ','.join(addresses_cnames),
|
|
146
|
+
'status_id': status_id,
|
|
147
|
+
'status': status,
|
|
148
|
+
'pid': event['pid'],
|
|
149
|
+
'name': event['name'],
|
|
150
|
+
'cmdline': event['cmdline']
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
# Skip emitting the record if it is in the 'skip_record_list'.
|
|
154
|
+
# Just recall the function to get the next event and return it.
|
|
155
|
+
if event_dict['query_type'] in self.skip_record_list:
|
|
156
|
+
return self.emit()
|
|
157
|
+
|
|
158
|
+
if self.attrs:
|
|
159
|
+
event_dict = dicts.reorder_keys(
|
|
160
|
+
event_dict, self.attrs, skip_keys_not_in_list=True)
|
|
161
|
+
|
|
162
|
+
return event_dict
|