dissect.target 3.20.dev64__py3-none-any.whl → 3.20.1__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- dissect/target/helpers/configutil.py +2 -2
- dissect/target/helpers/record.py +12 -6
- dissect/target/helpers/regutil.py +28 -11
- dissect/target/helpers/utils.py +20 -1
- dissect/target/plugins/general/network.py +1 -1
- dissect/target/plugins/os/unix/bsd/osx/network.py +2 -1
- dissect/target/plugins/os/unix/etc/etc.py +12 -6
- dissect/target/plugins/os/unix/linux/fortios/_keys.py +832 -0
- dissect/target/plugins/os/unix/linux/network.py +338 -0
- dissect/target/plugins/os/unix/trash.py +13 -2
- dissect/target/plugins/os/windows/network.py +9 -5
- {dissect.target-3.20.dev64.dist-info → dissect.target-3.20.1.dist-info}/METADATA +73 -73
- {dissect.target-3.20.dev64.dist-info → dissect.target-3.20.1.dist-info}/RECORD +18 -17
- {dissect.target-3.20.dev64.dist-info → dissect.target-3.20.1.dist-info}/WHEEL +1 -1
- {dissect.target-3.20.dev64.dist-info → dissect.target-3.20.1.dist-info}/COPYRIGHT +0 -0
- {dissect.target-3.20.dev64.dist-info → dissect.target-3.20.1.dist-info}/LICENSE +0 -0
- {dissect.target-3.20.dev64.dist-info → dissect.target-3.20.1.dist-info}/entry_points.txt +0 -0
- {dissect.target-3.20.dev64.dist-info → dissect.target-3.20.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,338 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import re
|
4
|
+
from dataclasses import dataclass, field
|
5
|
+
from datetime import datetime, timezone
|
6
|
+
from ipaddress import ip_address, ip_interface
|
7
|
+
from typing import TYPE_CHECKING, Any, Iterator, Literal, NamedTuple
|
8
|
+
|
9
|
+
from dissect.target.helpers import configutil
|
10
|
+
from dissect.target.helpers.record import UnixInterfaceRecord
|
11
|
+
from dissect.target.helpers.utils import to_list
|
12
|
+
from dissect.target.plugins.general.network import NetworkPlugin
|
13
|
+
|
14
|
+
if TYPE_CHECKING:
|
15
|
+
from ipaddress import IPv4Address, IPv4Interface, IPv6Address, IPv6Interface
|
16
|
+
|
17
|
+
from dissect.target import Target
|
18
|
+
from dissect.target.target import TargetPath
|
19
|
+
|
20
|
+
NetAddress = IPv4Address | IPv6Address
|
21
|
+
NetInterface = IPv4Interface | IPv6Interface
|
22
|
+
|
23
|
+
|
24
|
+
class LinuxNetworkPlugin(NetworkPlugin):
|
25
|
+
"""Linux network interface plugin."""
|
26
|
+
|
27
|
+
def _interfaces(self) -> Iterator[UnixInterfaceRecord]:
|
28
|
+
"""Try all available network configuration managers and aggregate the results."""
|
29
|
+
for manager_cls in MANAGERS:
|
30
|
+
manager: LinuxNetworkConfigParser = manager_cls(self.target)
|
31
|
+
yield from manager.interfaces()
|
32
|
+
|
33
|
+
|
34
|
+
VlanIdByInterface = dict[str, set[int]]
|
35
|
+
|
36
|
+
|
37
|
+
class LinuxNetworkConfigParser:
|
38
|
+
def __init__(self, target: Target):
|
39
|
+
self._target = target
|
40
|
+
|
41
|
+
def _config_files(self, config_paths: list[str], glob: str) -> list[TargetPath]:
|
42
|
+
"""Returns all configuration files in config_paths matching the given extension."""
|
43
|
+
all_files = []
|
44
|
+
for config_path in config_paths:
|
45
|
+
paths = self._target.fs.path(config_path).glob(glob)
|
46
|
+
all_files.extend(config_file for config_file in paths if config_file.is_file())
|
47
|
+
|
48
|
+
return sorted(all_files, key=lambda p: p.stem)
|
49
|
+
|
50
|
+
def interfaces(self) -> Iterator[UnixInterfaceRecord]:
|
51
|
+
"""Parse network interfaces from configuration files."""
|
52
|
+
yield from ()
|
53
|
+
|
54
|
+
|
55
|
+
class NetworkManagerConfigParser(LinuxNetworkConfigParser):
|
56
|
+
"""NetworkManager configuration parser.
|
57
|
+
|
58
|
+
NetworkManager configuration files are generally in an INI-like format.
|
59
|
+
Note that Red Hat and Fedora deprecated ifcfg files.
|
60
|
+
Documentation: https://networkmanager.dev/docs/api/latest/nm-settings-keyfile.html
|
61
|
+
"""
|
62
|
+
|
63
|
+
config_paths: list[str] = [
|
64
|
+
"/etc/NetworkManager/system-connections/",
|
65
|
+
"/usr/lib/NetworkManager/system-connections/",
|
66
|
+
"/run/NetworkManager/system-connections/",
|
67
|
+
]
|
68
|
+
|
69
|
+
@dataclass
|
70
|
+
class ParserContext:
|
71
|
+
source: str
|
72
|
+
uuid: str | None = None
|
73
|
+
last_connected: datetime | None = None
|
74
|
+
name: str | None = None
|
75
|
+
mac_address: str | None = None
|
76
|
+
type: str = ""
|
77
|
+
dns: set[NetAddress] = field(default_factory=set)
|
78
|
+
ip_interfaces: set[NetInterface] = field(default_factory=set)
|
79
|
+
gateways: set[NetAddress] = field(default_factory=set)
|
80
|
+
dhcp_ipv4: bool = False
|
81
|
+
dhcp_ipv6: bool = False
|
82
|
+
vlan: set[int] = field(default_factory=set)
|
83
|
+
|
84
|
+
def to_record(self) -> UnixInterfaceRecord:
|
85
|
+
return UnixInterfaceRecord(
|
86
|
+
source=self.source,
|
87
|
+
last_connected=self.last_connected,
|
88
|
+
name=self.name,
|
89
|
+
mac=[self.mac_address] if self.mac_address else [],
|
90
|
+
type=self.type,
|
91
|
+
dhcp_ipv4=self.dhcp_ipv4,
|
92
|
+
dhcp_ipv6=self.dhcp_ipv6,
|
93
|
+
dns=list(self.dns),
|
94
|
+
ip=[interface.ip for interface in self.ip_interfaces],
|
95
|
+
network=[interface.network for interface in self.ip_interfaces],
|
96
|
+
gateway=list(self.gateways),
|
97
|
+
vlan=list(self.vlan),
|
98
|
+
configurator="NetworkManager",
|
99
|
+
)
|
100
|
+
|
101
|
+
def interfaces(self) -> Iterator[UnixInterfaceRecord]:
|
102
|
+
connections: list[NetworkManagerConfigParser.ParserContext] = []
|
103
|
+
vlan_id_by_interface: VlanIdByInterface = {}
|
104
|
+
|
105
|
+
for connection_file_path in self._config_files(self.config_paths, "*"):
|
106
|
+
try:
|
107
|
+
config = configutil.parse(connection_file_path, hint="ini")
|
108
|
+
context = self.ParserContext(source=connection_file_path)
|
109
|
+
common_section: dict[str, str] = config.get("connection", {})
|
110
|
+
context.type = common_section.get("type", "")
|
111
|
+
sub_type: dict[str, str] = config.get(context.type, {})
|
112
|
+
|
113
|
+
if context.type == "vlan":
|
114
|
+
self._parse_vlan(sub_type, vlan_id_by_interface)
|
115
|
+
continue
|
116
|
+
|
117
|
+
for ip_version in ["ipv4", "ipv6"]:
|
118
|
+
ip_section: dict[str, str] = config.get(ip_version, {})
|
119
|
+
for key, value in ip_section.items():
|
120
|
+
self._parse_ip_section_key(key, value, context, ip_version)
|
121
|
+
|
122
|
+
context.name = common_section.get("interface-name")
|
123
|
+
context.mac_address = sub_type.get("mac-address")
|
124
|
+
context.uuid = common_section.get("uuid")
|
125
|
+
context.source = str(connection_file_path)
|
126
|
+
context.last_connected = self._parse_lastconnected(common_section.get("timestamp", ""))
|
127
|
+
|
128
|
+
connections.append(context)
|
129
|
+
|
130
|
+
except Exception as e:
|
131
|
+
self._target.log.warning("Error parsing network config file %s", connection_file_path)
|
132
|
+
self._target.log.debug("", exc_info=e)
|
133
|
+
|
134
|
+
for connection in connections:
|
135
|
+
vlan_ids_from_interface = vlan_id_by_interface.get(connection.name, set())
|
136
|
+
connection.vlan.update(vlan_ids_from_interface)
|
137
|
+
|
138
|
+
vlan_ids_from_uuid = vlan_id_by_interface.get(connection.uuid, set())
|
139
|
+
connection.vlan.update(vlan_ids_from_uuid)
|
140
|
+
|
141
|
+
yield connection.to_record()
|
142
|
+
|
143
|
+
def _parse_route(self, route: str) -> NetAddress | None:
|
144
|
+
"""Parse a route and return gateway IP address."""
|
145
|
+
if (elements := route.split(",")) and len(elements) > 1:
|
146
|
+
return ip_address(elements[1])
|
147
|
+
|
148
|
+
return None
|
149
|
+
|
150
|
+
def _parse_lastconnected(self, last_connected: str) -> datetime | None:
|
151
|
+
"""Parse last connected timestamp."""
|
152
|
+
if not last_connected:
|
153
|
+
return None
|
154
|
+
|
155
|
+
return datetime.fromtimestamp(int(last_connected), timezone.utc)
|
156
|
+
|
157
|
+
def _parse_ip_section_key(
|
158
|
+
self, key: str, value: str, context: ParserContext, ip_version: Literal["ipv4", "ipv6"]
|
159
|
+
) -> None:
|
160
|
+
if not (trimmed := value.strip()):
|
161
|
+
return
|
162
|
+
|
163
|
+
if key == "dns":
|
164
|
+
context.dns.update(ip_address(addr) for addr in trimmed.split(";") if addr)
|
165
|
+
elif key.startswith("address"):
|
166
|
+
# Undocumented: single gateway on address line. Observed when running:
|
167
|
+
# nmcli connection add type ethernet ... ip4 192.168.2.138/24 gw4 192.168.2.1
|
168
|
+
ip, *gateway = trimmed.split(",", 1)
|
169
|
+
context.ip_interfaces.add(ip_interface(ip))
|
170
|
+
if gateway:
|
171
|
+
context.gateways.add(ip_address(gateway[0]))
|
172
|
+
elif key.startswith("gateway"):
|
173
|
+
context.gateways.add(ip_address(trimmed))
|
174
|
+
elif key == "method":
|
175
|
+
if ip_version == "ipv4":
|
176
|
+
context.dhcp_ipv4 = trimmed == "auto"
|
177
|
+
elif ip_version == "ipv6":
|
178
|
+
context.dhcp_ipv6 = trimmed == "auto"
|
179
|
+
elif key.startswith("route"):
|
180
|
+
if gateway := self._parse_route(value):
|
181
|
+
context.gateways.add(gateway)
|
182
|
+
|
183
|
+
def _parse_vlan(self, sub_type: dict[str, Any], vlan_id_by_interface: VlanIdByInterface) -> None:
|
184
|
+
parent_interface = sub_type.get("parent")
|
185
|
+
vlan_id = sub_type.get("id")
|
186
|
+
if not parent_interface or not vlan_id:
|
187
|
+
return
|
188
|
+
|
189
|
+
ids = vlan_id_by_interface.setdefault(parent_interface, set())
|
190
|
+
ids.add(int(vlan_id))
|
191
|
+
|
192
|
+
|
193
|
+
class SystemdNetworkConfigParser(LinuxNetworkConfigParser):
|
194
|
+
"""Systemd network configuration parser.
|
195
|
+
|
196
|
+
Systemd network configuration files are generally in an INI-like format with some quirks.
|
197
|
+
Note that drop-in directories are not yet supported.
|
198
|
+
|
199
|
+
Documentation: https://www.freedesktop.org/software/systemd/man/latest/systemd.network.html
|
200
|
+
"""
|
201
|
+
|
202
|
+
config_paths: list[str] = [
|
203
|
+
"/etc/systemd/network/",
|
204
|
+
"/run/systemd/network/",
|
205
|
+
"/usr/lib/systemd/network/",
|
206
|
+
"/usr/local/lib/systemd/network/",
|
207
|
+
]
|
208
|
+
|
209
|
+
class DhcpConfig(NamedTuple):
|
210
|
+
ipv4: bool
|
211
|
+
ipv6: bool
|
212
|
+
|
213
|
+
# Can be enclosed in brackets for IPv6. Can also have port, iface name, and SNI, which we ignore.
|
214
|
+
# Example: [1111:2222::3333]:9953%ifname#example.com
|
215
|
+
dns_ip_patttern = re.compile(
|
216
|
+
r"(?P<withoutBrackets>(?:\d{1,3}\.){3}\d{1,3})|\[(?P<withBrackets>\[?[0-9a-fA-F:]+\]?)\]"
|
217
|
+
)
|
218
|
+
|
219
|
+
def interfaces(self) -> Iterator:
|
220
|
+
virtual_networks = self._parse_virtual_networks()
|
221
|
+
yield from self._parse_networks(virtual_networks)
|
222
|
+
|
223
|
+
def _parse_virtual_networks(self) -> VlanIdByInterface:
|
224
|
+
"""Parse virtual network configurations from systemd network configuration files."""
|
225
|
+
|
226
|
+
virtual_networks: VlanIdByInterface = {}
|
227
|
+
for config_file in self._config_files(self.config_paths, "*.netdev"):
|
228
|
+
try:
|
229
|
+
virtual_network_config = configutil.parse(config_file, hint="systemd")
|
230
|
+
net_dev_section: dict[str, str] = virtual_network_config.get("NetDev", {})
|
231
|
+
if net_dev_section.get("Kind") != "vlan":
|
232
|
+
continue
|
233
|
+
|
234
|
+
vlan_id = virtual_network_config.get("VLAN", {}).get("Id")
|
235
|
+
if (name := net_dev_section.get("Name")) and vlan_id:
|
236
|
+
vlan_ids = virtual_networks.setdefault(name, set())
|
237
|
+
vlan_ids.add(int(vlan_id))
|
238
|
+
except Exception as e:
|
239
|
+
self._target.log.warning("Error parsing virtual network config file %s", config_file)
|
240
|
+
self._target.log.debug("", exc_info=e)
|
241
|
+
|
242
|
+
return virtual_networks
|
243
|
+
|
244
|
+
def _parse_networks(self, virtual_networks: VlanIdByInterface) -> Iterator[UnixInterfaceRecord]:
|
245
|
+
"""Parse network configurations from systemd network configuration files."""
|
246
|
+
for config_file in self._config_files(self.config_paths, "*.network"):
|
247
|
+
try:
|
248
|
+
config = configutil.parse(config_file, hint="systemd")
|
249
|
+
|
250
|
+
match_section: dict[str, str] = config.get("Match", {})
|
251
|
+
network_section: dict[str, str] = config.get("Network", {})
|
252
|
+
link_section: dict[str, str] = config.get("Link", {})
|
253
|
+
|
254
|
+
ip_interfaces: set[NetInterface] = set()
|
255
|
+
gateways: set[NetAddress] = set()
|
256
|
+
dns: set[NetAddress] = set()
|
257
|
+
mac_addresses: set[str] = set()
|
258
|
+
|
259
|
+
if link_mac := link_section.get("MACAddress"):
|
260
|
+
mac_addresses.add(link_mac)
|
261
|
+
mac_addresses.update(match_section.get("MACAddress", "").split())
|
262
|
+
mac_addresses.update(match_section.get("PermanentMACAddress", "").split())
|
263
|
+
|
264
|
+
dns_value = to_list(network_section.get("DNS", []))
|
265
|
+
dns.update(self._parse_dns_ip(dns_ip) for dns_ip in dns_value)
|
266
|
+
|
267
|
+
address_value = to_list(network_section.get("Address", []))
|
268
|
+
ip_interfaces.update(ip_interface(addr) for addr in address_value)
|
269
|
+
|
270
|
+
gateway_value = to_list(network_section.get("Gateway", []))
|
271
|
+
gateways.update(ip_address(gateway) for gateway in gateway_value)
|
272
|
+
|
273
|
+
vlan_ids: set[int] = set()
|
274
|
+
vlan_names = to_list(network_section.get("VLAN", []))
|
275
|
+
for vlan_name in vlan_names:
|
276
|
+
if ids := virtual_networks.get(vlan_name):
|
277
|
+
vlan_ids.update(ids)
|
278
|
+
|
279
|
+
# There are possibly multiple route sections, but they are collapsed into one by the parser.
|
280
|
+
route_section: dict[str, Any] = config.get("Route", {})
|
281
|
+
gateway_values = to_list(route_section.get("Gateway", []))
|
282
|
+
gateways.update(filter(None, map(self._parse_gateway, gateway_values)))
|
283
|
+
|
284
|
+
dhcp_ipv4, dhcp_ipv6 = self._parse_dhcp(network_section.get("DHCP"))
|
285
|
+
|
286
|
+
yield UnixInterfaceRecord(
|
287
|
+
source=str(config_file),
|
288
|
+
type=match_section.get("Type"),
|
289
|
+
enabled=None, # Unknown, dependent on run-time state
|
290
|
+
dhcp_ipv4=dhcp_ipv4,
|
291
|
+
dhcp_ipv6=dhcp_ipv6,
|
292
|
+
name=match_section.get("Name"),
|
293
|
+
dns=list(dns),
|
294
|
+
mac=list(mac_addresses),
|
295
|
+
ip=[interface.ip for interface in ip_interfaces],
|
296
|
+
network=[interface.network for interface in ip_interfaces],
|
297
|
+
gateway=list(gateways),
|
298
|
+
vlan=list(vlan_ids),
|
299
|
+
configurator="systemd-networkd",
|
300
|
+
)
|
301
|
+
except Exception as e:
|
302
|
+
self._target.log.warning("Error parsing network config file %s", config_file)
|
303
|
+
self._target.log.debug("", exc_info=e)
|
304
|
+
|
305
|
+
def _parse_dns_ip(self, address: str) -> NetAddress:
|
306
|
+
"""Parse DNS address from systemd network configuration file.
|
307
|
+
|
308
|
+
The optional brackets and port number make this hard to parse.
|
309
|
+
See https://www.freedesktop.org/software/systemd/man/latest/systemd.network.html and search for DNS.
|
310
|
+
"""
|
311
|
+
|
312
|
+
if match := self.dns_ip_patttern.search(address):
|
313
|
+
return ip_address(match.group("withoutBrackets") or match.group("withBrackets"))
|
314
|
+
|
315
|
+
raise ValueError(f"Invalid DNS address format: {address}")
|
316
|
+
|
317
|
+
def _parse_dhcp(self, value: str | None) -> DhcpConfig:
|
318
|
+
"""Parse DHCP value from systemd network configuration file to a named tuple (ipv4, ipv6)."""
|
319
|
+
|
320
|
+
if value is None or value == "no":
|
321
|
+
return self.DhcpConfig(ipv4=False, ipv6=False)
|
322
|
+
elif value == "yes":
|
323
|
+
return self.DhcpConfig(ipv4=True, ipv6=True)
|
324
|
+
elif value == "ipv4":
|
325
|
+
return self.DhcpConfig(ipv4=True, ipv6=False)
|
326
|
+
elif value == "ipv6":
|
327
|
+
return self.DhcpConfig(ipv4=False, ipv6=True)
|
328
|
+
|
329
|
+
raise ValueError(f"Invalid DHCP value: {value}")
|
330
|
+
|
331
|
+
def _parse_gateway(self, value: str | None) -> NetAddress | None:
|
332
|
+
if (not value) or (value in {"_dhcp4", "_ipv6ra"}):
|
333
|
+
return None
|
334
|
+
|
335
|
+
return ip_address(value)
|
336
|
+
|
337
|
+
|
338
|
+
MANAGERS = [NetworkManagerConfigParser, SystemdNetworkConfigParser]
|
@@ -31,15 +31,25 @@ class GnomeTrashPlugin(Plugin):
|
|
31
31
|
|
32
32
|
def __init__(self, target: Target):
|
33
33
|
super().__init__(target)
|
34
|
-
self.trashes =
|
34
|
+
self.trashes = set(self._garbage_collector())
|
35
35
|
|
36
36
|
def _garbage_collector(self) -> Iterator[tuple[UserDetails, TargetPath]]:
|
37
37
|
"""it aint much, but its honest work"""
|
38
|
+
|
39
|
+
# home trash folders
|
38
40
|
for user_details in self.target.user_details.all_with_home():
|
39
41
|
for trash_path in self.PATHS:
|
40
42
|
if (path := user_details.home_path.joinpath(trash_path)).exists():
|
41
43
|
yield user_details, path
|
42
44
|
|
45
|
+
# mounted devices trash folders
|
46
|
+
for mount_path in list(self.target.fs.mounts) + ["/mnt", "/media"]:
|
47
|
+
if mount_path == "/":
|
48
|
+
continue
|
49
|
+
|
50
|
+
for mount_trash in self.target.fs.path(mount_path).rglob(".Trash-*"):
|
51
|
+
yield UserDetails(None, None), mount_trash
|
52
|
+
|
43
53
|
def check_compatible(self) -> None:
|
44
54
|
if not self.trashes:
|
45
55
|
raise UnsupportedPluginError("No Trash folder(s) found")
|
@@ -52,7 +62,8 @@ class GnomeTrashPlugin(Plugin):
|
|
52
62
|
Recovers deleted files and artifacts from ``$HOME/.local/share/Trash``.
|
53
63
|
Probably also works with other desktop interfaces as long as they follow the Trash specification from FreeDesktop.
|
54
64
|
|
55
|
-
|
65
|
+
Also parses media trash locations such as ``/media/$USER/$Label/.Trash-*``, ``/mnt/$Label/.Trash-*`` and other
|
66
|
+
locations as defined in ``/etc/fstab``.
|
56
67
|
|
57
68
|
Resources:
|
58
69
|
- https://specifications.freedesktop.org/trash-spec/latest/
|
@@ -1,5 +1,6 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
+
import re
|
3
4
|
from enum import IntEnum
|
4
5
|
from functools import lru_cache
|
5
6
|
from typing import Iterator
|
@@ -224,11 +225,13 @@ def _try_value(subkey: RegistryKey, value: str) -> str | list | None:
|
|
224
225
|
return None
|
225
226
|
|
226
227
|
|
227
|
-
def _get_config_value(key: RegistryKey, name: str) -> set:
|
228
|
+
def _get_config_value(key: RegistryKey, name: str, sep: str | None = None) -> set:
|
228
229
|
value = _try_value(key, name)
|
229
230
|
if not value or value in ("", "0.0.0.0", None, [], ["0.0.0.0"]):
|
230
231
|
return set()
|
231
|
-
|
232
|
+
if sep and isinstance(value, str):
|
233
|
+
re_sep = "|".join(map(re.escape, sep))
|
234
|
+
value = re.split(re_sep, value)
|
232
235
|
if isinstance(value, list):
|
233
236
|
return set(value)
|
234
237
|
|
@@ -281,7 +284,8 @@ class WindowsNetworkPlugin(NetworkPlugin):
|
|
281
284
|
pass
|
282
285
|
|
283
286
|
# Extract the rest of the device information
|
284
|
-
|
287
|
+
if mac_address := _try_value(subkey, "NetworkAddress"):
|
288
|
+
device_info["mac"] = [mac_address]
|
285
289
|
device_info["vlan"] = _try_value(subkey, "VlanID")
|
286
290
|
|
287
291
|
if timestamp := _try_value(subkey, "NetworkInterfaceInstallTimestamp"):
|
@@ -354,11 +358,11 @@ class WindowsNetworkPlugin(NetworkPlugin):
|
|
354
358
|
dhcp_config["ip"].update(_get_config_value(key, "DhcpIPAddress"))
|
355
359
|
dhcp_config["subnetmask"].update(_get_config_value(key, "DhcpSubnetMask"))
|
356
360
|
dhcp_config["search_domain"].update(_get_config_value(key, "DhcpDomain"))
|
357
|
-
dhcp_config["dns"].update(_get_config_value(key, "DhcpNameServer"))
|
361
|
+
dhcp_config["dns"].update(_get_config_value(key, "DhcpNameServer", " ,"))
|
358
362
|
|
359
363
|
# Extract static configuration from the registry
|
360
364
|
static_config["gateway"].update(_get_config_value(key, "DefaultGateway"))
|
361
|
-
static_config["dns"].update(_get_config_value(key, "NameServer"))
|
365
|
+
static_config["dns"].update(_get_config_value(key, "NameServer", " ,"))
|
362
366
|
static_config["search_domain"].update(_get_config_value(key, "Domain"))
|
363
367
|
static_config["ip"].update(_get_config_value(key, "IPAddress"))
|
364
368
|
static_config["subnetmask"].update(_get_config_value(key, "SubnetMask"))
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: dissect.target
|
3
|
-
Version: 3.20.
|
3
|
+
Version: 3.20.1
|
4
4
|
Summary: This module ties all other Dissect modules together, it provides a programming API and command line tools which allow easy access to various data sources inside disk images or file collections (a.k.a. targets)
|
5
5
|
Author-email: Dissect Team <dissect@fox-it.com>
|
6
6
|
License: Affero General Public License v3
|
@@ -23,81 +23,81 @@ Description-Content-Type: text/markdown
|
|
23
23
|
License-File: LICENSE
|
24
24
|
License-File: COPYRIGHT
|
25
25
|
Requires-Dist: defusedxml
|
26
|
-
Requires-Dist: dissect.cstruct
|
27
|
-
Requires-Dist: dissect.eventlog
|
28
|
-
Requires-Dist: dissect.evidence
|
29
|
-
Requires-Dist: dissect.hypervisor
|
30
|
-
Requires-Dist: dissect.ntfs
|
31
|
-
Requires-Dist: dissect.regf
|
32
|
-
Requires-Dist: dissect.util
|
33
|
-
Requires-Dist: dissect.volume
|
34
|
-
Requires-Dist: flow.record
|
26
|
+
Requires-Dist: dissect.cstruct<5,>=4
|
27
|
+
Requires-Dist: dissect.eventlog<4,>=3
|
28
|
+
Requires-Dist: dissect.evidence<4,>=3
|
29
|
+
Requires-Dist: dissect.hypervisor<4,>=3
|
30
|
+
Requires-Dist: dissect.ntfs<4,>=3.4
|
31
|
+
Requires-Dist: dissect.regf<4,>=3.3
|
32
|
+
Requires-Dist: dissect.util<4,>=3
|
33
|
+
Requires-Dist: dissect.volume<4,>=2
|
34
|
+
Requires-Dist: flow.record~=3.18.0
|
35
35
|
Requires-Dist: structlog
|
36
|
-
Provides-Extra: cb
|
37
|
-
Requires-Dist: dissect.target[full] ; extra == 'cb'
|
38
|
-
Requires-Dist: carbon-black-cloud-sdk ~=1.4.3 ; extra == 'cb'
|
39
|
-
Provides-Extra: dev
|
40
|
-
Requires-Dist: dissect.target[full,mqtt,yara] ; extra == 'dev'
|
41
|
-
Requires-Dist: dissect.archive[dev] <2.0.dev,>=1.0.dev ; extra == 'dev'
|
42
|
-
Requires-Dist: dissect.btrfs[dev] <2.0.dev,>=1.0.dev ; extra == 'dev'
|
43
|
-
Requires-Dist: dissect.cim[dev] <4.0.dev,>=3.0.dev ; extra == 'dev'
|
44
|
-
Requires-Dist: dissect.clfs[dev] <2.0.dev,>=1.0.dev ; extra == 'dev'
|
45
|
-
Requires-Dist: dissect.cstruct <5.0.dev,>=4.0.dev ; extra == 'dev'
|
46
|
-
Requires-Dist: dissect.esedb[dev] <4.0.dev,>=3.0.dev ; extra == 'dev'
|
47
|
-
Requires-Dist: dissect.etl[dev] <4.0.dev,>=3.0.dev ; extra == 'dev'
|
48
|
-
Requires-Dist: dissect.eventlog[dev] <4.0.dev,>=3.0.dev ; extra == 'dev'
|
49
|
-
Requires-Dist: dissect.evidence[dev] <4.0.dev,>=3.0.dev ; extra == 'dev'
|
50
|
-
Requires-Dist: dissect.extfs[dev] <4.0.dev,>=3.0.dev ; extra == 'dev'
|
51
|
-
Requires-Dist: dissect.fat[dev] <4.0.dev,>=3.0.dev ; extra == 'dev'
|
52
|
-
Requires-Dist: dissect.ffs[dev] <4.0.dev,>=3.0.dev ; extra == 'dev'
|
53
|
-
Requires-Dist: dissect.hypervisor[dev] <4.0.dev,>=3.0.dev ; extra == 'dev'
|
54
|
-
Requires-Dist: dissect.jffs[dev] <2.0.dev,>=1.0.dev ; extra == 'dev'
|
55
|
-
Requires-Dist: dissect.ntfs[dev] <4.0.dev,>=3.4.dev ; extra == 'dev'
|
56
|
-
Requires-Dist: dissect.regf[dev] <4.0.dev,>=3.3.dev ; extra == 'dev'
|
57
|
-
Requires-Dist: dissect.shellitem[dev] <4.0.dev,>=3.0.dev ; extra == 'dev'
|
58
|
-
Requires-Dist: dissect.sql[dev] <4.0.dev,>=3.0.dev ; extra == 'dev'
|
59
|
-
Requires-Dist: dissect.squashfs[dev] <2.0.dev,>=1.0.dev ; extra == 'dev'
|
60
|
-
Requires-Dist: dissect.thumbcache[dev] <2.0.dev,>=1.0.dev ; extra == 'dev'
|
61
|
-
Requires-Dist: dissect.util <4.0.dev,>=3.0.dev ; extra == 'dev'
|
62
|
-
Requires-Dist: dissect.vmfs[dev] <4.0.dev,>=3.0.dev ; extra == 'dev'
|
63
|
-
Requires-Dist: dissect.volume[dev] <4.0.dev,>=3.0.dev ; extra == 'dev'
|
64
|
-
Requires-Dist: dissect.xfs[dev] <4.0.dev,>=3.0.dev ; extra == 'dev'
|
65
|
-
Requires-Dist: dissect.fve[dev] <5.0.dev,>=4.0.dev ; (platform_system != "Windows" or platform_python_implementation != "PyPy") and extra == 'dev'
|
66
36
|
Provides-Extra: full
|
67
|
-
Requires-Dist: asn1crypto
|
68
|
-
Requires-Dist: dissect.archive
|
69
|
-
Requires-Dist: dissect.btrfs
|
70
|
-
Requires-Dist: dissect.cim
|
71
|
-
Requires-Dist: dissect.clfs
|
72
|
-
Requires-Dist: dissect.esedb
|
73
|
-
Requires-Dist: dissect.etl
|
74
|
-
Requires-Dist: dissect.extfs
|
75
|
-
Requires-Dist: dissect.fat
|
76
|
-
Requires-Dist: dissect.ffs
|
77
|
-
Requires-Dist: dissect.
|
78
|
-
Requires-Dist: dissect.
|
79
|
-
Requires-Dist: dissect.
|
80
|
-
Requires-Dist: dissect.
|
81
|
-
Requires-Dist: dissect.
|
82
|
-
Requires-Dist: dissect.
|
83
|
-
Requires-Dist: dissect.
|
84
|
-
Requires-Dist: dissect.
|
85
|
-
Requires-Dist:
|
86
|
-
Requires-Dist:
|
87
|
-
Requires-Dist:
|
88
|
-
Requires-Dist:
|
89
|
-
Requires-Dist:
|
90
|
-
Requires-Dist:
|
91
|
-
Requires-Dist:
|
92
|
-
Provides-Extra:
|
93
|
-
Requires-Dist: dissect.target[full]
|
94
|
-
Requires-Dist:
|
95
|
-
|
96
|
-
Requires-Dist: dissect.
|
97
|
-
Requires-Dist:
|
37
|
+
Requires-Dist: asn1crypto; extra == "full"
|
38
|
+
Requires-Dist: dissect.archive<2,>=1; extra == "full"
|
39
|
+
Requires-Dist: dissect.btrfs<2,>=1; extra == "full"
|
40
|
+
Requires-Dist: dissect.cim<4,>=3; extra == "full"
|
41
|
+
Requires-Dist: dissect.clfs<2,>=1; extra == "full"
|
42
|
+
Requires-Dist: dissect.esedb<4,>=3; extra == "full"
|
43
|
+
Requires-Dist: dissect.etl<4,>=3; extra == "full"
|
44
|
+
Requires-Dist: dissect.extfs<4,>=3; extra == "full"
|
45
|
+
Requires-Dist: dissect.fat<4,>=3; extra == "full"
|
46
|
+
Requires-Dist: dissect.ffs<4,>=3; extra == "full"
|
47
|
+
Requires-Dist: dissect.fve<5,>=4; (platform_system != "Windows" or platform_python_implementation != "PyPy") and extra == "full"
|
48
|
+
Requires-Dist: dissect.jffs<2,>=1; extra == "full"
|
49
|
+
Requires-Dist: dissect.ole<4,>=3; extra == "full"
|
50
|
+
Requires-Dist: dissect.shellitem<4,>=3; extra == "full"
|
51
|
+
Requires-Dist: dissect.squashfs<2,>=1; extra == "full"
|
52
|
+
Requires-Dist: dissect.sql<4,>=3; extra == "full"
|
53
|
+
Requires-Dist: dissect.thumbcache<2,>=1; extra == "full"
|
54
|
+
Requires-Dist: dissect.vmfs<4,>=3; extra == "full"
|
55
|
+
Requires-Dist: dissect.xfs<4,>=3; extra == "full"
|
56
|
+
Requires-Dist: ipython; extra == "full"
|
57
|
+
Requires-Dist: fusepy; extra == "full"
|
58
|
+
Requires-Dist: pycryptodome; extra == "full"
|
59
|
+
Requires-Dist: ruamel.yaml; extra == "full"
|
60
|
+
Requires-Dist: tomli; python_version < "3.11" and extra == "full"
|
61
|
+
Requires-Dist: zstandard; extra == "full"
|
62
|
+
Provides-Extra: dev
|
63
|
+
Requires-Dist: dissect.target[full,mqtt,yara]; extra == "dev"
|
64
|
+
Requires-Dist: dissect.archive[dev]<2.0.dev,>=1.0.dev; extra == "dev"
|
65
|
+
Requires-Dist: dissect.btrfs[dev]<2.0.dev,>=1.0.dev; extra == "dev"
|
66
|
+
Requires-Dist: dissect.cim[dev]<4.0.dev,>=3.0.dev; extra == "dev"
|
67
|
+
Requires-Dist: dissect.clfs[dev]<2.0.dev,>=1.0.dev; extra == "dev"
|
68
|
+
Requires-Dist: dissect.cstruct<5.0.dev,>=4.0.dev; extra == "dev"
|
69
|
+
Requires-Dist: dissect.esedb[dev]<4.0.dev,>=3.0.dev; extra == "dev"
|
70
|
+
Requires-Dist: dissect.etl[dev]<4.0.dev,>=3.0.dev; extra == "dev"
|
71
|
+
Requires-Dist: dissect.eventlog[dev]<4.0.dev,>=3.0.dev; extra == "dev"
|
72
|
+
Requires-Dist: dissect.evidence[dev]<4.0.dev,>=3.0.dev; extra == "dev"
|
73
|
+
Requires-Dist: dissect.extfs[dev]<4.0.dev,>=3.0.dev; extra == "dev"
|
74
|
+
Requires-Dist: dissect.fat[dev]<4.0.dev,>=3.0.dev; extra == "dev"
|
75
|
+
Requires-Dist: dissect.ffs[dev]<4.0.dev,>=3.0.dev; extra == "dev"
|
76
|
+
Requires-Dist: dissect.fve[dev]<5.0.dev,>=4.0.dev; (platform_system != "Windows" or platform_python_implementation != "PyPy") and extra == "dev"
|
77
|
+
Requires-Dist: dissect.hypervisor[dev]<4.0.dev,>=3.0.dev; extra == "dev"
|
78
|
+
Requires-Dist: dissect.jffs[dev]<2.0.dev,>=1.0.dev; extra == "dev"
|
79
|
+
Requires-Dist: dissect.ntfs[dev]<4.0.dev,>=3.4.dev; extra == "dev"
|
80
|
+
Requires-Dist: dissect.regf[dev]<4.0.dev,>=3.3.dev; extra == "dev"
|
81
|
+
Requires-Dist: dissect.shellitem[dev]<4.0.dev,>=3.0.dev; extra == "dev"
|
82
|
+
Requires-Dist: dissect.sql[dev]<4.0.dev,>=3.0.dev; extra == "dev"
|
83
|
+
Requires-Dist: dissect.squashfs[dev]<2.0.dev,>=1.0.dev; extra == "dev"
|
84
|
+
Requires-Dist: dissect.thumbcache[dev]<2.0.dev,>=1.0.dev; extra == "dev"
|
85
|
+
Requires-Dist: dissect.util<4.0.dev,>=3.0.dev; extra == "dev"
|
86
|
+
Requires-Dist: dissect.vmfs[dev]<4.0.dev,>=3.0.dev; extra == "dev"
|
87
|
+
Requires-Dist: dissect.volume[dev]<4.0.dev,>=3.0.dev; extra == "dev"
|
88
|
+
Requires-Dist: dissect.xfs[dev]<4.0.dev,>=3.0.dev; extra == "dev"
|
98
89
|
Provides-Extra: yara
|
99
|
-
Requires-Dist: dissect.target[full]
|
100
|
-
Requires-Dist: yara-python
|
90
|
+
Requires-Dist: dissect.target[full]; extra == "yara"
|
91
|
+
Requires-Dist: yara-python; extra == "yara"
|
92
|
+
Provides-Extra: smb
|
93
|
+
Requires-Dist: dissect.target[full]; extra == "smb"
|
94
|
+
Requires-Dist: impacket==0.10.0; extra == "smb"
|
95
|
+
Provides-Extra: cb
|
96
|
+
Requires-Dist: dissect.target[full]; extra == "cb"
|
97
|
+
Requires-Dist: carbon-black-cloud-sdk~=1.4.3; extra == "cb"
|
98
|
+
Provides-Extra: mqtt
|
99
|
+
Requires-Dist: dissect.target[full]; extra == "mqtt"
|
100
|
+
Requires-Dist: paho-mqtt==1.6.1; extra == "mqtt"
|
101
101
|
|
102
102
|
# dissect.target
|
103
103
|
|