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.
Files changed (221) hide show
  1. atomicshop/__init__.py +1 -1
  2. atomicshop/{addons/mains → a_mains}/FACT/update_extract.py +3 -2
  3. atomicshop/a_mains/dns_gateway_setting.py +11 -0
  4. atomicshop/a_mains/get_local_tcp_ports.py +85 -0
  5. atomicshop/a_mains/github_wrapper.py +11 -0
  6. atomicshop/a_mains/install_ca_certificate.py +172 -0
  7. atomicshop/a_mains/process_from_port.py +119 -0
  8. atomicshop/a_mains/set_default_dns_gateway.py +90 -0
  9. atomicshop/a_mains/update_config_toml.py +38 -0
  10. atomicshop/basics/ansi_escape_codes.py +3 -1
  11. atomicshop/basics/argparse_template.py +2 -0
  12. atomicshop/basics/booleans.py +27 -30
  13. atomicshop/basics/bytes_arrays.py +43 -0
  14. atomicshop/basics/classes.py +149 -1
  15. atomicshop/basics/enums.py +2 -2
  16. atomicshop/basics/exceptions.py +5 -1
  17. atomicshop/basics/list_of_classes.py +29 -0
  18. atomicshop/basics/multiprocesses.py +374 -50
  19. atomicshop/basics/strings.py +72 -3
  20. atomicshop/basics/threads.py +14 -0
  21. atomicshop/basics/tracebacks.py +13 -3
  22. atomicshop/certificates.py +153 -52
  23. atomicshop/config_init.py +11 -6
  24. atomicshop/console_user_response.py +7 -14
  25. atomicshop/consoles.py +9 -0
  26. atomicshop/datetimes.py +1 -1
  27. atomicshop/diff_check.py +3 -3
  28. atomicshop/dns.py +128 -3
  29. atomicshop/etws/_pywintrace_fix.py +17 -0
  30. atomicshop/etws/trace.py +40 -42
  31. atomicshop/etws/traces/trace_dns.py +56 -44
  32. atomicshop/etws/traces/trace_tcp.py +130 -0
  33. atomicshop/file_io/csvs.py +27 -5
  34. atomicshop/file_io/docxs.py +34 -17
  35. atomicshop/file_io/file_io.py +31 -17
  36. atomicshop/file_io/jsons.py +49 -0
  37. atomicshop/file_io/tomls.py +139 -0
  38. atomicshop/filesystem.py +616 -291
  39. atomicshop/get_process_list.py +3 -3
  40. atomicshop/http_parse.py +149 -93
  41. atomicshop/ip_addresses.py +6 -1
  42. atomicshop/mitm/centered_settings.py +132 -0
  43. atomicshop/mitm/config_static.py +207 -0
  44. atomicshop/mitm/config_toml_editor.py +55 -0
  45. atomicshop/mitm/connection_thread_worker.py +875 -357
  46. atomicshop/mitm/engines/__parent/parser___parent.py +4 -17
  47. atomicshop/mitm/engines/__parent/recorder___parent.py +108 -51
  48. atomicshop/mitm/engines/__parent/requester___parent.py +116 -0
  49. atomicshop/mitm/engines/__parent/responder___parent.py +75 -114
  50. atomicshop/mitm/engines/__reference_general/parser___reference_general.py +10 -7
  51. atomicshop/mitm/engines/__reference_general/recorder___reference_general.py +5 -5
  52. atomicshop/mitm/engines/__reference_general/requester___reference_general.py +47 -0
  53. atomicshop/mitm/engines/__reference_general/responder___reference_general.py +95 -13
  54. atomicshop/mitm/engines/create_module_template.py +58 -14
  55. atomicshop/mitm/import_config.py +359 -139
  56. atomicshop/mitm/initialize_engines.py +160 -80
  57. atomicshop/mitm/message.py +64 -23
  58. atomicshop/mitm/mitm_main.py +892 -0
  59. atomicshop/mitm/recs_files.py +183 -0
  60. atomicshop/mitm/shared_functions.py +4 -10
  61. atomicshop/mitm/ssh_tester.py +82 -0
  62. atomicshop/mitm/statistic_analyzer.py +136 -40
  63. atomicshop/mitm/statistic_analyzer_helper/moving_average_helper.py +265 -83
  64. atomicshop/monitor/checks/dns.py +1 -1
  65. atomicshop/networks.py +671 -0
  66. atomicshop/on_exit.py +39 -9
  67. atomicshop/package_mains_processor.py +84 -0
  68. atomicshop/permissions/permissions.py +22 -0
  69. atomicshop/permissions/ubuntu_permissions.py +239 -0
  70. atomicshop/permissions/win_permissions.py +33 -0
  71. atomicshop/print_api.py +24 -42
  72. atomicshop/process.py +24 -6
  73. atomicshop/process_poller/process_pool.py +0 -1
  74. atomicshop/process_poller/simple_process_pool.py +204 -5
  75. atomicshop/python_file_patcher.py +1 -1
  76. atomicshop/python_functions.py +27 -75
  77. atomicshop/speech_recognize.py +8 -0
  78. atomicshop/ssh_remote.py +158 -172
  79. atomicshop/system_resource_monitor.py +61 -47
  80. atomicshop/system_resources.py +8 -8
  81. atomicshop/tempfiles.py +1 -2
  82. atomicshop/urls.py +6 -0
  83. atomicshop/venvs.py +28 -0
  84. atomicshop/versioning.py +27 -0
  85. atomicshop/web.py +98 -27
  86. atomicshop/web_apis/google_custom_search.py +44 -0
  87. atomicshop/web_apis/google_llm.py +188 -0
  88. atomicshop/websocket_parse.py +450 -0
  89. atomicshop/wrappers/certauthw/certauth.py +1 -0
  90. atomicshop/wrappers/cryptographyw.py +29 -8
  91. atomicshop/wrappers/ctyping/etw_winapi/const.py +97 -47
  92. atomicshop/wrappers/ctyping/etw_winapi/etw_functions.py +178 -49
  93. atomicshop/wrappers/ctyping/file_details_winapi.py +67 -0
  94. atomicshop/wrappers/ctyping/msi_windows_installer/cabs.py +2 -1
  95. atomicshop/wrappers/ctyping/msi_windows_installer/extract_msi_main.py +2 -2
  96. atomicshop/wrappers/ctyping/setup_device.py +466 -0
  97. atomicshop/wrappers/ctyping/win_console.py +39 -0
  98. atomicshop/wrappers/dockerw/dockerw.py +113 -2
  99. atomicshop/wrappers/elasticsearchw/config_basic.py +0 -12
  100. atomicshop/wrappers/elasticsearchw/elastic_infra.py +75 -0
  101. atomicshop/wrappers/elasticsearchw/elasticsearchw.py +2 -20
  102. atomicshop/wrappers/factw/get_file_data.py +12 -5
  103. atomicshop/wrappers/factw/install/install_after_restart.py +89 -5
  104. atomicshop/wrappers/factw/install/pre_install_and_install_before_restart.py +20 -14
  105. atomicshop/wrappers/githubw.py +537 -54
  106. atomicshop/wrappers/loggingw/consts.py +1 -1
  107. atomicshop/wrappers/loggingw/filters.py +23 -0
  108. atomicshop/wrappers/loggingw/formatters.py +12 -0
  109. atomicshop/wrappers/loggingw/handlers.py +214 -107
  110. atomicshop/wrappers/loggingw/loggers.py +19 -0
  111. atomicshop/wrappers/loggingw/loggingw.py +860 -22
  112. atomicshop/wrappers/loggingw/reading.py +134 -112
  113. atomicshop/wrappers/mongodbw/mongo_infra.py +31 -0
  114. atomicshop/wrappers/mongodbw/mongodbw.py +1324 -36
  115. atomicshop/wrappers/netshw.py +271 -0
  116. atomicshop/wrappers/playwrightw/engine.py +34 -19
  117. atomicshop/wrappers/playwrightw/infra.py +5 -0
  118. atomicshop/wrappers/playwrightw/javascript.py +7 -3
  119. atomicshop/wrappers/playwrightw/keyboard.py +14 -0
  120. atomicshop/wrappers/playwrightw/scenarios.py +172 -5
  121. atomicshop/wrappers/playwrightw/waits.py +9 -7
  122. atomicshop/wrappers/powershell_networking.py +80 -0
  123. atomicshop/wrappers/psutilw/processes.py +37 -1
  124. atomicshop/wrappers/psutilw/psutil_networks.py +85 -0
  125. atomicshop/wrappers/pyopensslw.py +9 -2
  126. atomicshop/wrappers/pywin32w/cert_store.py +116 -0
  127. atomicshop/wrappers/pywin32w/win_event_log/fetch.py +174 -0
  128. atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_create.py +3 -105
  129. atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_terminate.py +3 -57
  130. atomicshop/wrappers/pywin32w/wmis/msft_netipaddress.py +113 -0
  131. atomicshop/wrappers/pywin32w/wmis/win32_networkadapterconfiguration.py +259 -0
  132. atomicshop/wrappers/pywin32w/wmis/win32networkadapter.py +112 -0
  133. atomicshop/wrappers/pywin32w/wmis/wmi_helpers.py +236 -0
  134. atomicshop/wrappers/socketw/accepter.py +21 -7
  135. atomicshop/wrappers/socketw/certificator.py +216 -150
  136. atomicshop/wrappers/socketw/creator.py +190 -50
  137. atomicshop/wrappers/socketw/dns_server.py +491 -182
  138. atomicshop/wrappers/socketw/exception_wrapper.py +45 -52
  139. atomicshop/wrappers/socketw/process_getter.py +86 -0
  140. atomicshop/wrappers/socketw/receiver.py +144 -102
  141. atomicshop/wrappers/socketw/sender.py +65 -35
  142. atomicshop/wrappers/socketw/sni.py +334 -165
  143. atomicshop/wrappers/socketw/socket_base.py +134 -0
  144. atomicshop/wrappers/socketw/socket_client.py +137 -95
  145. atomicshop/wrappers/socketw/socket_server_tester.py +11 -7
  146. atomicshop/wrappers/socketw/socket_wrapper.py +717 -116
  147. atomicshop/wrappers/socketw/ssl_base.py +15 -14
  148. atomicshop/wrappers/socketw/statistics_csv.py +148 -17
  149. atomicshop/wrappers/sysmonw.py +1 -1
  150. atomicshop/wrappers/ubuntu_terminal.py +65 -26
  151. atomicshop/wrappers/win_auditw.py +189 -0
  152. atomicshop/wrappers/winregw/__init__.py +0 -0
  153. atomicshop/wrappers/winregw/winreg_installed_software.py +58 -0
  154. atomicshop/wrappers/winregw/winreg_network.py +232 -0
  155. {atomicshop-2.15.11.dist-info → atomicshop-3.10.5.dist-info}/METADATA +31 -51
  156. atomicshop-3.10.5.dist-info/RECORD +306 -0
  157. {atomicshop-2.15.11.dist-info → atomicshop-3.10.5.dist-info}/WHEEL +1 -1
  158. atomicshop/_basics_temp.py +0 -101
  159. atomicshop/a_installs/win/fibratus.py +0 -9
  160. atomicshop/a_installs/win/mongodb.py +0 -9
  161. atomicshop/a_installs/win/pycharm.py +0 -9
  162. atomicshop/addons/a_setup_scripts/install_psycopg2_ubuntu.sh +0 -3
  163. atomicshop/addons/a_setup_scripts/install_pywintrace_0.3.cmd +0 -2
  164. atomicshop/addons/mains/__pycache__/install_fibratus_windows.cpython-312.pyc +0 -0
  165. atomicshop/addons/mains/__pycache__/msi_unpacker.cpython-312.pyc +0 -0
  166. atomicshop/addons/mains/install_docker_rootless_ubuntu.py +0 -11
  167. atomicshop/addons/mains/install_docker_ubuntu_main_sudo.py +0 -11
  168. atomicshop/addons/mains/install_elastic_search_and_kibana_ubuntu.py +0 -10
  169. atomicshop/addons/mains/install_wsl_ubuntu_lts_admin.py +0 -9
  170. atomicshop/addons/package_setup/CreateWheel.cmd +0 -7
  171. atomicshop/addons/package_setup/Setup in Edit mode.cmd +0 -6
  172. atomicshop/addons/package_setup/Setup.cmd +0 -7
  173. atomicshop/archiver/_search_in_zip.py +0 -189
  174. atomicshop/archiver/archiver.py +0 -34
  175. atomicshop/archiver/search_in_archive.py +0 -250
  176. atomicshop/archiver/sevenz_app_w.py +0 -86
  177. atomicshop/archiver/sevenzs.py +0 -44
  178. atomicshop/archiver/zips.py +0 -293
  179. atomicshop/file_types.py +0 -24
  180. atomicshop/mitm/config_editor.py +0 -37
  181. atomicshop/mitm/engines/create_module_template_example.py +0 -13
  182. atomicshop/mitm/initialize_mitm_server.py +0 -268
  183. atomicshop/pbtkmultifile_argparse.py +0 -88
  184. atomicshop/permissions.py +0 -151
  185. atomicshop/script_as_string_processor.py +0 -38
  186. atomicshop/ssh_scripts/process_from_ipv4.py +0 -37
  187. atomicshop/ssh_scripts/process_from_port.py +0 -27
  188. atomicshop/wrappers/_process_wrapper_curl.py +0 -27
  189. atomicshop/wrappers/_process_wrapper_tar.py +0 -21
  190. atomicshop/wrappers/dockerw/install_docker.py +0 -209
  191. atomicshop/wrappers/elasticsearchw/infrastructure.py +0 -265
  192. atomicshop/wrappers/elasticsearchw/install_elastic.py +0 -232
  193. atomicshop/wrappers/ffmpegw.py +0 -125
  194. atomicshop/wrappers/fibratusw/install.py +0 -81
  195. atomicshop/wrappers/mongodbw/infrastructure.py +0 -53
  196. atomicshop/wrappers/mongodbw/install_mongodb.py +0 -190
  197. atomicshop/wrappers/msiw.py +0 -149
  198. atomicshop/wrappers/nodejsw/install_nodejs.py +0 -139
  199. atomicshop/wrappers/process_wrapper_pbtk.py +0 -16
  200. atomicshop/wrappers/psutilw/networks.py +0 -45
  201. atomicshop/wrappers/pycharmw.py +0 -81
  202. atomicshop/wrappers/socketw/base.py +0 -59
  203. atomicshop/wrappers/socketw/get_process.py +0 -107
  204. atomicshop/wrappers/wslw.py +0 -191
  205. atomicshop-2.15.11.dist-info/RECORD +0 -302
  206. /atomicshop/{addons/mains → a_mains}/FACT/factw_fact_extractor_docker_image_main_sudo.py +0 -0
  207. /atomicshop/{addons → a_mains/addons}/PlayWrightCodegen.cmd +0 -0
  208. /atomicshop/{addons → a_mains/addons}/ScriptExecution.cmd +0 -0
  209. /atomicshop/{addons → a_mains/addons}/inits/init_to_import_all_modules.py +0 -0
  210. /atomicshop/{addons → a_mains/addons}/process_list/ReadMe.txt +0 -0
  211. /atomicshop/{addons → a_mains/addons}/process_list/compile.cmd +0 -0
  212. /atomicshop/{addons → a_mains/addons}/process_list/compiled/Win10x64/process_list.dll +0 -0
  213. /atomicshop/{addons → a_mains/addons}/process_list/compiled/Win10x64/process_list.exp +0 -0
  214. /atomicshop/{addons → a_mains/addons}/process_list/compiled/Win10x64/process_list.lib +0 -0
  215. /atomicshop/{addons → a_mains/addons}/process_list/process_list.cpp +0 -0
  216. /atomicshop/{archiver → permissions}/__init__.py +0 -0
  217. /atomicshop/{wrappers/fibratusw → web_apis}/__init__.py +0 -0
  218. /atomicshop/wrappers/{nodejsw → pywin32w/wmis}/__init__.py +0 -0
  219. /atomicshop/wrappers/pywin32w/{wmi_win32process.py → wmis/win32process.py} +0 -0
  220. {atomicshop-2.15.11.dist-info → atomicshop-3.10.5.dist-info/licenses}/LICENSE.txt +0 -0
  221. {atomicshop-2.15.11.dist-info → atomicshop-3.10.5.dist-info}/top_level.txt +0 -0
@@ -24,22 +24,23 @@ def convert_der_x509_bytes_to_pem_string(certificate) -> str:
24
24
  return ssl.DER_cert_to_PEM_cert(certificate)
25
25
 
26
26
 
27
- def is_tls(client_socket) -> Optional[Tuple[str, str]]:
27
+ def is_tls(
28
+ client_socket,
29
+ timeout: float = None
30
+ ) -> Optional[Tuple[str, str]]:
28
31
  """
29
32
  Return protocol type of the incoming socket after 'accept()'.
30
33
  :param client_socket: incoming socket after 'accept()'.
34
+ :param timeout: optional timeout for receiving/peeking the first bytes.
31
35
  :return: tuple with content type, protocol type + version.
32
36
  If the length of the first bytes is less than 3, return None.
33
37
  """
34
38
 
35
- first_bytes = receiver.peek_first_bytes(client_socket, bytes_amount=3)
39
+ first_bytes = receiver.peek_first_bytes(client_socket, bytes_amount=3, timeout=timeout)
36
40
 
37
- # Ensure we got enough data.
38
- if len(first_bytes) < 3:
39
- return None
40
-
41
- # Extract the content type and version
42
- content_type, version_major, version_minor = first_bytes
41
+ # Sometimes only one byte is available, so we need to handle that case.
42
+ # convert to a tuple of ints, add three Nones, and keep only the first 3 items.
43
+ content_type, version_major, version_minor = (tuple(first_bytes) + (None, None, None))[:3]
43
44
 
44
45
  # Map TLS content types to their string representation.
45
46
  content_type_map = {
@@ -52,19 +53,19 @@ def is_tls(client_socket) -> Optional[Tuple[str, str]]:
52
53
 
53
54
  # Map TLS version bytes to their string representation.
54
55
  version_map = {
55
- (0x03, 0x00): "SSL 3.0",
56
- (0x03, 0x01): "TLS 1.0",
57
- (0x03, 0x02): "TLS 1.1",
58
- (0x03, 0x03): "TLS 1.2/1.3"
56
+ (0x03, 0x00): "SSLv3.0",
57
+ (0x03, 0x01): "TLSv1.0",
58
+ (0x03, 0x02): "TLSv1.1",
59
+ (0x03, 0x03): "TLSv1.2/1.3"
59
60
  # Remember, you can't definitively differentiate 1.2 and 1.3 just from these bytes
60
61
  }
61
62
 
62
63
  # Get the tuple of the type and version as strings.
63
- tls_content_and_version_tuple: tuple =\
64
+ tls_content_and_version_tuple: tuple[str, str] = \
64
65
  content_type_map.get(content_type), version_map.get((version_major, version_minor))
65
66
 
66
67
  # If both parts of the tuple are not None, return the protocol type.
67
- if tls_content_and_version_tuple[0] and tls_content_and_version_tuple[1]:
68
+ if tls_content_and_version_tuple[0]:
68
69
  return tls_content_and_version_tuple
69
70
  else:
70
71
  return None
@@ -1,23 +1,154 @@
1
1
  import datetime
2
+ import multiprocessing
2
3
 
3
- from ...print_api import print_api
4
+ from ..loggingw import loggingw
4
5
 
5
6
 
6
- def write_accept_error(error_message: str, host: str, process_name: str, statistics_logger, print_kwargs: dict = None):
7
- request_time_sent = datetime.datetime.now()
7
+ LOGGER_NAME: str = 'statistics'
8
+ STATISTICS_HEADER: str = (
9
+ 'request_time_sent,thread_id,engine,source_host,source_ip,tls,protocol,protocol2,protocol3,dest_port,host,path,command,status_code,request_size_bytes,'
10
+ 'response_size_bytes,file_path,process_cmd,action,error')
8
11
 
9
- # If 'message' is not defined, it means there was no execution and there is no need for statistics.
10
- try:
11
- statistics_logger.info(
12
- f"{request_time_sent},"
13
- f"{host},"
14
- f",,,,,,"
15
- f"\"{process_name}\","
16
- f"{error_message}"
12
+
13
+ class StatisticsCSVWriter(loggingw.CsvLogger):
14
+ """
15
+ Class to write statistics to CSV file.
16
+ This can be initiated at the main, and then passed to the thread worker function.
17
+ """
18
+ def __init__(
19
+ self,
20
+ logger_name: str = LOGGER_NAME,
21
+ directory_path: str = None,
22
+ log_queue: multiprocessing.Queue = None,
23
+ add_queue_handler_start_listener_multiprocessing: bool = False,
24
+ add_queue_handler_no_listener_multiprocessing: bool = False
25
+ ):
26
+ """
27
+ Initialize the StatisticsCSVWriter with the directory path for the statistics CSV file.
28
+ :param directory_path: str, the directory path where the statistics CSV file will be created.
29
+ :param log_queue: multiprocessing.Queue, the queue to use for logging in multiprocessing.
30
+ :param add_queue_handler_start_listener_multiprocessing: bool, whether to add a queue handler that will use
31
+ the 'logger_queue' and start the queue listener with the same 'logger_queue' for multiprocessing.
32
+ :param add_queue_handler_no_listener_multiprocessing: bool, whether to add a queue handler that will use
33
+ the 'logger_queue' but will not start the queue listener for multiprocessing. This is useful when you
34
+ already started the queue listener and want to add more handlers to the logger without
35
+ starting a new listener.
36
+
37
+ If you don't set any of 'add_queue_handler_start_listener_multiprocessing' or
38
+ 'add_queue_handler_no_listener_multiprocessing', the logger will be created without a queue handler.
39
+ """
40
+
41
+ super().__init__(
42
+ logger_name=logger_name,
43
+ directory_path=directory_path,
44
+ log_queue=log_queue,
45
+ add_queue_handler_start_listener_multiprocessing=add_queue_handler_start_listener_multiprocessing,
46
+ add_queue_handler_no_listener_multiprocessing=add_queue_handler_no_listener_multiprocessing,
47
+ custom_header=STATISTICS_HEADER
48
+ )
49
+
50
+ def write_row(
51
+ self,
52
+ thread_id: str,
53
+ engine: str,
54
+ source_host: str,
55
+ source_ip: str,
56
+ host: str,
57
+ tls_type: str,
58
+ tls_version: str,
59
+ protocol: str,
60
+ protocol2: str,
61
+ protocol3: str,
62
+ dest_port: str,
63
+ path: str,
64
+ status_code: str,
65
+ command: str,
66
+ request_size_bytes: str,
67
+ response_size_bytes: str,
68
+ recorded_file_path: str = None,
69
+ process_cmd: str = None,
70
+ error: str = None,
71
+ action: str = None,
72
+ timestamp=None,
73
+ ):
74
+ if not timestamp:
75
+ timestamp = datetime.datetime.now()
76
+
77
+ if not tls_type and not tls_version:
78
+ tls_info = ''
79
+ else:
80
+ tls_info = f'{tls_type}|{tls_version}'
81
+
82
+ row_of_cols: list = [
83
+ timestamp,
84
+ thread_id,
85
+ engine,
86
+ source_host,
87
+ source_ip,
88
+ tls_info,
89
+ protocol,
90
+ protocol2,
91
+ protocol3,
92
+ dest_port,
93
+ host,
94
+ path,
95
+ command,
96
+ status_code,
97
+ request_size_bytes,
98
+ response_size_bytes,
99
+ recorded_file_path,
100
+ process_cmd,
101
+ action,
102
+ error
103
+ ]
104
+
105
+ super().write(row_of_cols)
106
+
107
+ def write_accept_error(
108
+ self,
109
+ engine: str,
110
+ source_ip: str,
111
+ source_host: str,
112
+ error_message: str,
113
+ dest_port: str,
114
+ host: str,
115
+ process_name: str,
116
+ thread_id: str = str()
117
+ ):
118
+ """
119
+ Write the error message to the statistics CSV file.
120
+ This is used for easier execution, since most of the parameters will be empty on accept.
121
+
122
+ :param engine: string, engine name.
123
+ :param source_ip: string, source IP address.
124
+ :param source_host: string, source host name.
125
+ :param error_message: string, error message.
126
+ :param dest_port: string, destination port.
127
+ :param host: string, host, the domain or IP address.
128
+ :param process_name: process name, the command line of the process.
129
+ :param thread_id: integer, the id of the thread.
130
+ :return:
131
+ """
132
+
133
+ self.write_row(
134
+ thread_id=thread_id,
135
+ engine=engine,
136
+ source_host=source_host,
137
+ source_ip=source_ip,
138
+ tls_type='',
139
+ tls_version='',
140
+ protocol='',
141
+ protocol2='',
142
+ protocol3='',
143
+ dest_port=dest_port,
144
+ host=host,
145
+ path='',
146
+ status_code='',
147
+ command='',
148
+ request_size_bytes='',
149
+ response_size_bytes='',
150
+ recorded_file_path='',
151
+ process_cmd=process_name,
152
+ action='client_accept',
153
+ error=error_message
17
154
  )
18
- except UnboundLocalError:
19
- pass
20
- except Exception:
21
- message = "Undocumented exception after accept on building statistics."
22
- print_api(message, error_type=True, logger_method='error', traceback_string=True, oneline=True, **print_kwargs)
23
- pass
@@ -49,7 +49,7 @@ def is_sysmon_running():
49
49
  """
50
50
 
51
51
  process_list: list = process.get_running_processes_by_cmdline_pattern(
52
- pattern=SYSMON_FILE_NAME, first=True, process_name_case_insensitive=True)
52
+ pattern=SYSMON_FILE_NAME, first=True, cmdline_case_insensitive=True)
53
53
 
54
54
  if process_list:
55
55
  return True
@@ -4,23 +4,64 @@ import subprocess
4
4
  import shutil
5
5
  import time
6
6
 
7
+ from rich.console import Console
8
+
7
9
  from ..print_api import print_api
8
- from .. import permissions
10
+ from ..permissions import ubuntu_permissions
11
+
12
+
13
+ console = Console()
9
14
 
10
15
 
11
- def install_packages(package_list: list[str]):
16
+ def install_packages(
17
+ package_list: list[str],
18
+ timeout_seconds: int = 0,
19
+ ):
12
20
  """
13
21
  Function installs a package using apt-get.
14
22
  :param package_list: list of strings, package names to install.
23
+ :param timeout_seconds: int, if the 'apt-get' command is busy at the moment, the function will wait for
24
+ 'timeout_seconds' seconds before raising an error.
25
+ '-1' means wait indefinitely.
15
26
  :return:
16
27
  """
17
28
 
18
29
  # Construct the command with the package list
19
- command = ["sudo", "apt-get", "install", "-y"] + package_list
30
+ command = ["sudo", "apt", "install", "-y"] + package_list
31
+
32
+ if timeout_seconds != 0:
33
+ command.extend(["-o", f"DPkg::Lock::Timeout={str(timeout_seconds)}"])
20
34
 
21
35
  subprocess.check_call(command)
22
36
 
23
37
 
38
+ def remove_packages(
39
+ package_list: list[str],
40
+ remove_config_files: bool = False,
41
+ remove_dependencies: bool = False,
42
+ ):
43
+ """
44
+ Function removes a list of packages.
45
+ :param package_list: list of strings, package names to remove. Regular removal is through 'apt remove'.
46
+ :param remove_config_files: bool, if True, the config files will be removed also through 'apt purge'.
47
+ :param remove_dependencies: bool, if True, the dependencies will be removed also through 'apt autoremove'.
48
+ :return:
49
+ """
50
+
51
+ # Construct the command with the package list
52
+ command = ["sudo", "apt", "remove", "-y"] + package_list
53
+
54
+ # If remove_config_files is True, add 'purge' to the command
55
+ if remove_config_files:
56
+ command.insert(2, "purge")
57
+
58
+ subprocess.check_call(command)
59
+
60
+ # If remove_dependencies is True, remove the dependencies
61
+ if remove_dependencies:
62
+ subprocess.check_call(["sudo", "apt", "autoremove", "-y"])
63
+
64
+
24
65
  def is_package_installed(package: str) -> bool:
25
66
  """
26
67
  Function checks if a package is installed.
@@ -74,7 +115,7 @@ def update_system_packages():
74
115
  Function updates the system packages.
75
116
  :return:
76
117
  """
77
- subprocess.check_call(['sudo', 'apt-get', 'update'])
118
+ subprocess.check_call(['sudo', 'apt', 'update'])
78
119
 
79
120
 
80
121
  def upgrade_system_packages(apt_update: bool = True):
@@ -88,7 +129,7 @@ def upgrade_system_packages(apt_update: bool = True):
88
129
  if apt_update:
89
130
  update_system_packages()
90
131
 
91
- subprocess.check_call(['sudo', 'apt-get', 'upgrade', '-y'])
132
+ subprocess.check_call(['sudo', 'apt', 'upgrade', '-y'])
92
133
 
93
134
 
94
135
  def is_service_running(service_name: str, user_mode: bool = False, return_false_on_error: bool = False) -> bool:
@@ -175,28 +216,25 @@ def start_service(service_name: str, sudo: bool = False, user_mode: bool = False
175
216
  def start_enable_service_check_availability(
176
217
  service_name: str,
177
218
  wait_time_seconds: float = 30,
178
- exit_on_error: bool = True,
179
219
  start_service_bool: bool = True,
180
220
  enable_service_bool: bool = True,
181
221
  check_service_running: bool = True,
182
222
  user_mode: bool = False,
183
- sudo: bool = True,
184
- print_kwargs: dict = None
185
- ):
223
+ sudo: bool = True
224
+ ) -> int:
186
225
  """
187
226
  Function starts and enables a service and checks its availability.
188
227
 
189
228
  :param service_name: str, the service name.
190
229
  :param wait_time_seconds: float, the time to wait after starting the service before checking the service
191
230
  availability.
192
- :param exit_on_error: bool, if True, the function will exit the program if the service is not available.
193
231
  :param start_service_bool: bool, if True, the service will be started.
194
232
  :param enable_service_bool: bool, if True, the service will be enabled.
195
233
  :param check_service_running: bool, if True, the function will check if the service is running.
196
234
  :param user_mode: bool, if True, the service will be started and enabled in user mode.
197
235
  :param sudo: bool, if True, the command will be executed with sudo.
198
- :param print_kwargs: dict, the print arguments.
199
- :return:
236
+
237
+ :return: int, 0 if the service is running, 1 if the service is not running.
200
238
  """
201
239
 
202
240
  if not start_service_bool and not enable_service_bool:
@@ -209,18 +247,19 @@ def start_enable_service_check_availability(
209
247
  enable_service(service_name, user_mode=user_mode,sudo=sudo)
210
248
 
211
249
  if check_service_running:
212
- print_api(
213
- f"Waiting {str(wait_time_seconds)} seconds for the program to start before availability check...",
214
- **(print_kwargs or {}))
215
- time.sleep(wait_time_seconds)
250
+ print(f"Waiting up to {str(wait_time_seconds)} seconds for the program to start.")
251
+ count: int = 0
252
+ while not is_service_running(service_name, user_mode=user_mode) and count < wait_time_seconds:
253
+ count += 1
254
+ time.sleep(1)
216
255
 
217
256
  if not is_service_running(service_name, user_mode=user_mode):
218
- print_api(
219
- f"[{service_name}] service failed to start.", color='red', error_type=True, **(print_kwargs or {}))
220
- if exit_on_error:
221
- sys.exit(1)
257
+ console.print(f"[{service_name}] service failed to start.", style='red', markup=False)
258
+ return 1
222
259
  else:
223
- print_api(f"[{service_name}] service is running.", color='green', **(print_kwargs or {}))
260
+ console.print(f"[{service_name}] service is running.", style='green', markup=False)
261
+
262
+ return 0
224
263
 
225
264
 
226
265
  def add_path_to_bashrc(as_regular_user: bool = False):
@@ -231,11 +270,11 @@ def add_path_to_bashrc(as_regular_user: bool = False):
231
270
 
232
271
  if as_regular_user:
233
272
  # Get the current non-sudo user
234
- with permissions.temporary_regular_permissions():
273
+ with ubuntu_permissions.temporary_regular_permissions():
235
274
  current_non_sudo_user = os.getlogin()
236
275
 
237
276
  # Get the home path of the current non-sudo user
238
- user_bashrc_path = permissions.expand_user_path(current_non_sudo_user, home_path_bashrc)
277
+ user_bashrc_path = ubuntu_permissions.expand_user_path(current_non_sudo_user, home_path_bashrc)
239
278
  else:
240
279
  user_bashrc_path = os.path.expanduser(home_path_bashrc)
241
280
 
@@ -258,11 +297,11 @@ def add_line_to_bashrc(line: str, as_regular_user: bool = False):
258
297
 
259
298
  if as_regular_user:
260
299
  # Get the current non-sudo user
261
- with permissions.temporary_regular_permissions():
300
+ with ubuntu_permissions.temporary_regular_permissions():
262
301
  current_non_sudo_user = os.getlogin()
263
302
 
264
303
  # Get the home path of the current non-sudo user
265
- user_bashrc_path = permissions.expand_user_path(current_non_sudo_user, home_path_bashrc)
304
+ user_bashrc_path = ubuntu_permissions.expand_user_path(current_non_sudo_user, home_path_bashrc)
266
305
  else:
267
306
  user_bashrc_path = os.path.expanduser(home_path_bashrc)
268
307
 
@@ -293,7 +332,7 @@ def get_command_execution_as_sudo_executer(command: str, add_bash_exec: bool = F
293
332
 
294
333
  command = command.replace('sudo ', '').strip()
295
334
 
296
- sudo_executer_username: str = permissions.get_ubuntu_sudo_executer_username()
335
+ sudo_executer_username: str = ubuntu_permissions.get_sudo_executer_username()
297
336
 
298
337
  if sudo_executer_username:
299
338
  if add_bash_exec:
@@ -0,0 +1,189 @@
1
+ import subprocess
2
+ import winreg
3
+
4
+ from ..print_api import print_api
5
+
6
+
7
+ AUDITING_REG_PATH: str = r"Software\Microsoft\Windows\CurrentVersion\Policies\System\Audit"
8
+ PROCESS_CREATION_INCLUDE_CMDLINE_VALUE: str = "ProcessCreationIncludeCmdLine_Enabled"
9
+
10
+
11
+ def enable_command_line_auditing(print_kwargs: dict = None):
12
+ """
13
+ Enable the 'Include command line in process creation events' policy.
14
+
15
+ reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\Audit" /v ProcessCreationIncludeCmdLine_Enabled /t REG_DWORD /d 1 /f
16
+
17
+ :param print_kwargs: Optional keyword arguments for the print function.
18
+ """
19
+
20
+ if is_command_line_auditing_enabled():
21
+ print_api(
22
+ "[Include command line in process creation events] is already enabled.", color='blue',
23
+ **(print_kwargs or {}))
24
+ return
25
+
26
+ try:
27
+ # Open the registry key
28
+ with winreg.CreateKey(winreg.HKEY_LOCAL_MACHINE, AUDITING_REG_PATH) as reg_key:
29
+ # Set the value
30
+ winreg.SetValueEx(reg_key, PROCESS_CREATION_INCLUDE_CMDLINE_VALUE, 0, winreg.REG_DWORD, 1)
31
+
32
+ print_api(
33
+ "Successfully enabled [Include command line in process creation events].",
34
+ color='green', **(print_kwargs or {}))
35
+ except WindowsError as e:
36
+ print_api(
37
+ f"Failed to enable [Include command line in process creation events]: {e}", error_type=True,
38
+ color='red', **(print_kwargs or {}))
39
+
40
+
41
+ def is_command_line_auditing_enabled():
42
+ try:
43
+ # Open the registry key
44
+ with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, AUDITING_REG_PATH, 0, winreg.KEY_READ) as reg_key:
45
+ # Query the value
46
+ value, reg_type = winreg.QueryValueEx(reg_key, PROCESS_CREATION_INCLUDE_CMDLINE_VALUE)
47
+ # Check if the value is 1 (enabled)
48
+ return value == 1
49
+ except FileNotFoundError:
50
+ # Key or value not found, assume it's not enabled
51
+ return False
52
+ except WindowsError as e:
53
+ print(f"Failed to read the 'Include command line in process creation events' setting: {e}")
54
+ return False
55
+
56
+
57
+ def enable_audit_process_creation(print_kwargs: dict = None):
58
+ """
59
+ Enable the 'Audit Process Creation' policy.
60
+ Log: Security
61
+ Event ID: 4688 - A new process has been created.
62
+
63
+ auditpol /set /subcategory:"Process Creation" /success:enable /failure:enable
64
+
65
+ :param print_kwargs: Optional keyword arguments for the print function.
66
+ """
67
+ if is_audit_process_creation_enabled():
68
+ print_api("Audit Process Creation is already enabled.", color='blue', **(print_kwargs or {}))
69
+ return
70
+
71
+ # Enable "Audit Process Creation" policy
72
+ audit_policy_command = [
73
+ "auditpol", "/set", "/subcategory:Process Creation", "/success:enable", "/failure:enable"
74
+ ]
75
+ try:
76
+ subprocess.run(audit_policy_command, check=True)
77
+ print_api("Successfully enabled 'Audit Process Creation'.", color='green', **(print_kwargs or {}))
78
+ except subprocess.CalledProcessError as e:
79
+ print_api(f"Failed to enable 'Audit Process Creation': {e}", error_type=True, color='red', **(print_kwargs or {}))
80
+ raise e
81
+
82
+
83
+ def is_audit_process_creation_enabled(print_kwargs: dict = None) -> bool:
84
+ """
85
+ Check if the 'Audit Process Creation' policy is enabled.
86
+
87
+ :param print_kwargs: Optional keyword arguments for the print function.
88
+ """
89
+ # Command to check the "Audit Process Creation" policy
90
+ audit_policy_check_command = [
91
+ "auditpol", "/get", "/subcategory:Process Creation"
92
+ ]
93
+ try:
94
+ result = subprocess.run(audit_policy_check_command, check=True, capture_output=True, text=True)
95
+ output = result.stdout
96
+ # print_api(output) # Print the output for inspection
97
+
98
+ if "Process Creation" in output and "Success and Failure" in output:
99
+ # print_api(
100
+ # "'Audit Process Creation' is enabled for both success and failure.",
101
+ # color='green', **(print_kwargs or {}))
102
+ return True
103
+ else:
104
+ # print_api(output, **(print_kwargs or {}))
105
+ # print_api(
106
+ # "'Audit Process Creation' is not fully enabled. Check the output above for details.",
107
+ # color='yellow', **(print_kwargs or {}))
108
+ return False
109
+ except subprocess.CalledProcessError as e:
110
+ print_api(f"Failed to check 'Audit Process Creation': {e}", color='red', error_type=True, **(print_kwargs or {}))
111
+ return False
112
+
113
+
114
+ def enable_audit_process_termination(print_kwargs: dict = None):
115
+ """
116
+ Enable the 'Audit Process Termination' policy.
117
+
118
+ :param print_kwargs: Optional keyword arguments for the print function.
119
+ """
120
+ if is_audit_process_termination_enabled():
121
+ print_api("Audit Process Termination is already enabled.", color='blue', **(print_kwargs or {}))
122
+ return
123
+
124
+ audit_policy_command = [
125
+ "auditpol", "/set", "/subcategory:Process Termination", "/success:enable", "/failure:enable"
126
+ ]
127
+ try:
128
+ subprocess.run(audit_policy_command, check=True)
129
+ print_api("Successfully enabled 'Audit Process Termination'.", color='green', **(print_kwargs or {}))
130
+ except subprocess.CalledProcessError as e:
131
+ print_api(f"Failed to enable 'Audit Process Termination': {e}", error_type=True, color='red', **(print_kwargs or {}))
132
+ raise e
133
+
134
+
135
+ def is_audit_process_termination_enabled(print_kwargs: dict = None) -> bool:
136
+ """
137
+ Check if the 'Audit Process Termination' policy is enabled.
138
+
139
+ :param print_kwargs: Optional keyword arguments for the print function.
140
+ """
141
+ # Command to check the "Audit Process Creation" policy
142
+ audit_policy_check_command = [
143
+ "auditpol", "/get", "/subcategory:Process Termination"
144
+ ]
145
+ try:
146
+ result = subprocess.run(audit_policy_check_command, check=True, capture_output=True, text=True)
147
+ output = result.stdout
148
+ # print_api(output) # Print the output for inspection
149
+
150
+ if "Process Termination" in output and "Success and Failure" in output:
151
+ # print_api(
152
+ # "'Audit Process Termination' is enabled for both success and failure.",
153
+ # color='green', **(print_kwargs or {}))
154
+ return True
155
+ else:
156
+ # print_api(output, **(print_kwargs or {}))
157
+ # print_api(
158
+ # "'Audit Process Termination' is not fully enabled. Check the output above for details.",
159
+ # color='yellow', **(print_kwargs or {}))
160
+ return False
161
+ except subprocess.CalledProcessError as e:
162
+ print_api(f"Failed to check 'Audit Process Termination': {e}", color='red', error_type=True, **(print_kwargs or {}))
163
+ return False
164
+
165
+
166
+ def enable_audit_filtering_platform_connection(print_kwargs: dict = None):
167
+ """
168
+ Enable the 'Filtering Platform Connection' policy.
169
+ This enables you to fetch connection creations and deletions from the Windows Security Event Log.
170
+ Log: Security
171
+ Event IDs:
172
+ 5156 - The Windows Filtering Platform has permitted a connection.
173
+ 5158 - The Windows Filtering Platform has blocked a connection.
174
+ Events include information about source and destination IP addresses and ports.
175
+
176
+ auditpol /set /subcategory:"Filtering Platform Connection" /success:enable /failure:enable
177
+
178
+ :param print_kwargs: Optional keyword arguments for the print function.
179
+ """
180
+
181
+ audit_policy_command = [
182
+ "auditpol", "/set", '/subcategory:"Filtering Platform Connection"', "/success:enable", "/failure:enable"
183
+ ]
184
+ try:
185
+ subprocess.run(audit_policy_command, check=True)
186
+ print_api("Successfully enabled 'Audit Filtering Platform Connection'.", color='green', **(print_kwargs or {}))
187
+ except subprocess.CalledProcessError as e:
188
+ print_api(f"Failed to enable 'Audit Filtering Platform Connection': {e}", error_type=True, color='red', **(print_kwargs or {}))
189
+ raise e
File without changes
@@ -0,0 +1,58 @@
1
+ import os
2
+ import winreg
3
+
4
+
5
+ def get_installed_software() -> list[dict]:
6
+ registry_path: str = r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"
7
+ data: list[dict] = []
8
+
9
+ # Open the specified registry path
10
+ with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, registry_path) as reg_key:
11
+ i = 0
12
+ while True:
13
+ try:
14
+ # Enumerate all sub-keys
15
+ subkey_name = winreg.EnumKey(reg_key, i)
16
+ subkey_path = os.path.join(registry_path, subkey_name)
17
+ with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, subkey_path) as subkey:
18
+ try:
19
+ # Fetch DisplayName and DisplayVersion if they exist
20
+ display_name, _ = winreg.QueryValueEx(subkey, "DisplayName")
21
+ except FileNotFoundError:
22
+ display_name = "N/A"
23
+
24
+ try:
25
+ display_version, _ = winreg.QueryValueEx(subkey, "DisplayVersion")
26
+ except FileNotFoundError:
27
+ display_version = "N/A"
28
+
29
+ try:
30
+ install_date, _ = winreg.QueryValueEx(subkey, "InstallDate")
31
+ except FileNotFoundError:
32
+ install_date = "N/A"
33
+
34
+ try:
35
+ install_location, _ = winreg.QueryValueEx(subkey, "InstallLocation")
36
+ except FileNotFoundError:
37
+ install_location = "N/A"
38
+
39
+ try:
40
+ install_source, _ = winreg.QueryValueEx(subkey, "InstallSource")
41
+ except FileNotFoundError:
42
+ install_source = "N/A"
43
+
44
+ if display_name != "N/A":
45
+ data.append({
46
+ "DisplayName": display_name,
47
+ "DisplayVersion": display_version,
48
+ "InstallDate": install_date,
49
+ "SubkeyName": subkey_name,
50
+ "InstallLocation": install_location,
51
+ "InstallSource": install_source
52
+ })
53
+ except OSError:
54
+ break # No more subkeys
55
+
56
+ i += 1
57
+
58
+ return data