dissect.target 3.20.dev48__py3-none-any.whl → 3.20.dev50__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.
- dissect/target/plugins/general/network.py +5 -5
- dissect/target/plugins/os/unix/_os.py +43 -32
- dissect/target/plugins/os/unix/bsd/osx/_os.py +1 -4
- dissect/target/plugins/os/unix/linux/_os.py +4 -6
- dissect/target/plugins/os/unix/linux/fortios/_os.py +68 -64
- dissect/target/plugins/os/windows/_os.py +10 -10
- dissect/target/plugins/os/windows/network.py +102 -86
- dissect/target/tools/info.py +1 -1
- {dissect.target-3.20.dev48.dist-info → dissect.target-3.20.dev50.dist-info}/METADATA +2 -2
- {dissect.target-3.20.dev48.dist-info → dissect.target-3.20.dev50.dist-info}/RECORD +15 -15
- {dissect.target-3.20.dev48.dist-info → dissect.target-3.20.dev50.dist-info}/COPYRIGHT +0 -0
- {dissect.target-3.20.dev48.dist-info → dissect.target-3.20.dev50.dist-info}/LICENSE +0 -0
- {dissect.target-3.20.dev48.dist-info → dissect.target-3.20.dev50.dist-info}/WHEEL +0 -0
- {dissect.target-3.20.dev48.dist-info → dissect.target-3.20.dev50.dist-info}/entry_points.txt +0 -0
- {dissect.target-3.20.dev48.dist-info → dissect.target-3.20.dev50.dist-info}/top_level.txt +0 -0
@@ -53,22 +53,22 @@ class NetworkPlugin(Plugin):
|
|
53
53
|
@export
|
54
54
|
def ips(self) -> list[IPAddress]:
|
55
55
|
"""Return IP addresses as list of :class:`IPAddress`."""
|
56
|
-
return list(self._get_record_type("ip"))
|
56
|
+
return list(set(self._get_record_type("ip")))
|
57
57
|
|
58
58
|
@export
|
59
59
|
def gateways(self) -> list[IPAddress]:
|
60
60
|
"""Return gateways as list of :class:`IPAddress`."""
|
61
|
-
return list(self._get_record_type("gateway"))
|
61
|
+
return list(set(self._get_record_type("gateway")))
|
62
62
|
|
63
63
|
@export
|
64
64
|
def macs(self) -> list[str]:
|
65
65
|
"""Return MAC addresses as list of :class:`str`."""
|
66
|
-
return list(self._get_record_type("mac"))
|
66
|
+
return list(set(self._get_record_type("mac")))
|
67
67
|
|
68
68
|
@export
|
69
|
-
def dns(self) -> list[str]:
|
69
|
+
def dns(self) -> list[str | IPAddress]:
|
70
70
|
"""Return DNS addresses as list of :class:`str`."""
|
71
|
-
return list(self._get_record_type("dns"))
|
71
|
+
return list(set(self._get_record_type("dns")))
|
72
72
|
|
73
73
|
@internal
|
74
74
|
def with_ip(self, ip_addr: str) -> Iterator[InterfaceRecord]:
|
@@ -4,7 +4,6 @@ import logging
|
|
4
4
|
import re
|
5
5
|
import uuid
|
6
6
|
from pathlib import Path
|
7
|
-
from struct import unpack
|
8
7
|
from typing import Iterator
|
9
8
|
|
10
9
|
from flow.record.fieldtypes import posix_path
|
@@ -19,6 +18,25 @@ from dissect.target.target import Target
|
|
19
18
|
log = logging.getLogger(__name__)
|
20
19
|
|
21
20
|
|
21
|
+
# https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#ISA
|
22
|
+
ARCH_MAP = {
|
23
|
+
0x00: "unknown",
|
24
|
+
0x02: "sparc",
|
25
|
+
0x03: "x86",
|
26
|
+
0x08: "mips",
|
27
|
+
0x14: "powerpc32",
|
28
|
+
0x15: "powerpc64",
|
29
|
+
0x16: "s390", # and s390x
|
30
|
+
0x28: "aarch32", # armv7
|
31
|
+
0x2A: "superh",
|
32
|
+
0x32: "ia-64",
|
33
|
+
0x3E: "x86_64",
|
34
|
+
0xB7: "aarch64", # armv8
|
35
|
+
0xF3: "riscv64",
|
36
|
+
0xF7: "bpf",
|
37
|
+
}
|
38
|
+
|
39
|
+
|
22
40
|
class UnixPlugin(OSPlugin):
|
23
41
|
def __init__(self, target: Target):
|
24
42
|
super().__init__(target)
|
@@ -301,37 +319,30 @@ class UnixPlugin(OSPlugin):
|
|
301
319
|
continue
|
302
320
|
return os_release
|
303
321
|
|
304
|
-
def _get_architecture(self, os: str = "unix", path: str = "/bin/ls") -> str | None:
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
arch = unpack("H", fh.read(2))[0]
|
329
|
-
arch = arch_strings.get(arch)
|
330
|
-
|
331
|
-
if bits == 1: # 32 bit system
|
332
|
-
return f"{arch}_32-{os}"
|
333
|
-
else:
|
334
|
-
return f"{arch}-{os}"
|
322
|
+
def _get_architecture(self, os: str = "unix", path: Path | str = "/bin/ls") -> str | None:
|
323
|
+
"""Determine architecture by reading an ELF header of a binary on the target.
|
324
|
+
|
325
|
+
Resources:
|
326
|
+
- https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#ISA
|
327
|
+
"""
|
328
|
+
|
329
|
+
if not isinstance(path, TargetPath):
|
330
|
+
for fs in [self.target.fs, *self.target.filesystems]:
|
331
|
+
if (path := fs.path(path)).exists():
|
332
|
+
break
|
333
|
+
|
334
|
+
if not path.exists():
|
335
|
+
return
|
336
|
+
|
337
|
+
fh = path.open("rb")
|
338
|
+
fh.seek(4) # ELF - e_ident[EI_CLASS]
|
339
|
+
bits = fh.read(1)[0]
|
340
|
+
|
341
|
+
fh.seek(18) # ELF - e_machine
|
342
|
+
e_machine = int.from_bytes(fh.read(2), "little")
|
343
|
+
arch = ARCH_MAP.get(e_machine, "unknown")
|
344
|
+
|
345
|
+
return f"{arch}_32-{os}" if bits == 1 and not arch[-2:] == "32" else f"{arch}-{os}"
|
335
346
|
|
336
347
|
|
337
348
|
def parse_fstab(
|
@@ -41,10 +41,7 @@ class MacPlugin(BsdPlugin):
|
|
41
41
|
|
42
42
|
@export(property=True)
|
43
43
|
def ips(self) -> Optional[list[str]]:
|
44
|
-
|
45
|
-
for ip in self.target.network.ips():
|
46
|
-
ips.add(str(ip))
|
47
|
-
return list(ips)
|
44
|
+
return list(set(map(str, self.target.network.ips())))
|
48
45
|
|
49
46
|
@export(property=True)
|
50
47
|
def version(self) -> Optional[str]:
|
@@ -34,17 +34,15 @@ class LinuxPlugin(UnixPlugin, LinuxNetworkManager):
|
|
34
34
|
@export(property=True)
|
35
35
|
def ips(self) -> list[str]:
|
36
36
|
"""Returns a list of static IP addresses and DHCP lease IP addresses found on the host system."""
|
37
|
-
ips =
|
37
|
+
ips = set()
|
38
38
|
|
39
39
|
for ip_set in self.network_manager.get_config_value("ips"):
|
40
|
-
|
41
|
-
ips.append(ip)
|
40
|
+
ips.update(ip_set)
|
42
41
|
|
43
42
|
for ip in parse_unix_dhcp_log_messages(self.target, iter_all=False):
|
44
|
-
|
45
|
-
ips.append(ip)
|
43
|
+
ips.add(ip)
|
46
44
|
|
47
|
-
return ips
|
45
|
+
return list(ips)
|
48
46
|
|
49
47
|
@export(property=True)
|
50
48
|
def dns(self) -> list[str]:
|
@@ -6,7 +6,7 @@ from base64 import b64decode
|
|
6
6
|
from datetime import datetime
|
7
7
|
from io import BytesIO
|
8
8
|
from tarfile import ReadError
|
9
|
-
from typing import BinaryIO, Iterator,
|
9
|
+
from typing import BinaryIO, Iterator, TextIO
|
10
10
|
|
11
11
|
from dissect.util import cpio
|
12
12
|
from dissect.util.compression import xz
|
@@ -73,10 +73,11 @@ class FortiOSPlugin(LinuxPlugin):
|
|
73
73
|
return config
|
74
74
|
|
75
75
|
@classmethod
|
76
|
-
def detect(cls, target: Target) ->
|
76
|
+
def detect(cls, target: Target) -> Filesystem | None:
|
77
77
|
for fs in target.filesystems:
|
78
|
-
# Tested on FortiGate
|
79
|
-
|
78
|
+
# Tested on FortiGate, FortiAnalyzer and FortiManager.
|
79
|
+
# Other Fortinet devices may look different.
|
80
|
+
if fs.exists("/rootfs.gz") and (any(map(fs.exists, (".fgtsum", ".fmg_sign", "flatkc", "system.conf")))):
|
80
81
|
return fs
|
81
82
|
|
82
83
|
@classmethod
|
@@ -212,7 +213,7 @@ class FortiOSPlugin(LinuxPlugin):
|
|
212
213
|
return "FortiOS Unknown"
|
213
214
|
|
214
215
|
@export(record=FortiOSUserRecord)
|
215
|
-
def users(self) -> Iterator[
|
216
|
+
def users(self) -> Iterator[FortiOSUserRecord | UnixUserRecord]:
|
216
217
|
"""Return local users of the FortiOS system."""
|
217
218
|
|
218
219
|
# Possible unix-like users
|
@@ -224,7 +225,7 @@ class FortiOSPlugin(LinuxPlugin):
|
|
224
225
|
yield FortiOSUserRecord(
|
225
226
|
name=username,
|
226
227
|
password=":".join(entry.get("password", [])),
|
227
|
-
groups=
|
228
|
+
groups=list(entry.get("accprofile", [])),
|
228
229
|
home="/root",
|
229
230
|
_target=self.target,
|
230
231
|
)
|
@@ -233,69 +234,72 @@ class FortiOSPlugin(LinuxPlugin):
|
|
233
234
|
self.target.log.debug("", exc_info=e)
|
234
235
|
|
235
236
|
# FortiManager administrative users
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
237
|
+
if self._config.get("global-config", {}).get("system", {}).get("admin", {}).get("user"):
|
238
|
+
try:
|
239
|
+
for username, entry in self._config["global-config"]["system"]["admin"]["user"].items():
|
240
|
+
yield FortiOSUserRecord(
|
241
|
+
name=username,
|
242
|
+
password=":".join(entry.get("password", [])),
|
243
|
+
groups=list(entry.get("profileid", [])),
|
244
|
+
home="/root",
|
245
|
+
_target=self.target,
|
246
|
+
)
|
247
|
+
except KeyError as e:
|
248
|
+
self.target.log.warning("Exception while parsing FortiManager admin users")
|
249
|
+
self.target.log.debug("", exc_info=e)
|
250
|
+
|
251
|
+
if self._config.get("root-config"):
|
252
|
+
# Local users
|
253
|
+
try:
|
254
|
+
local_groups = local_groups_to_users(self._config["root-config"]["user"]["group"])
|
255
|
+
for username, entry in self._config["root-config"]["user"].get("local", {}).items():
|
256
|
+
try:
|
257
|
+
password = decrypt_password(entry["passwd"][-1])
|
258
|
+
except (ValueError, RuntimeError):
|
259
|
+
password = ":".join(entry.get("passwd", []))
|
260
|
+
|
261
|
+
yield FortiOSUserRecord(
|
262
|
+
name=username,
|
263
|
+
password=password,
|
264
|
+
groups=local_groups.get(username, []),
|
265
|
+
home=None,
|
266
|
+
_target=self.target,
|
267
|
+
)
|
268
|
+
except KeyError as e:
|
269
|
+
self.target.log.warning("Exception while parsing FortiOS local users")
|
270
|
+
self.target.log.debug("", exc_info=e)
|
271
|
+
|
272
|
+
# Temporary guest users
|
273
|
+
try:
|
274
|
+
for _, entry in (
|
275
|
+
self._config["root-config"]["user"]["group"].get("guestgroup", {}).get("guest", {}).items()
|
276
|
+
):
|
277
|
+
try:
|
278
|
+
password = decrypt_password(entry.get("password")[-1])
|
279
|
+
except (ValueError, RuntimeError):
|
280
|
+
password = ":".join(entry.get("password"))
|
281
|
+
|
282
|
+
yield FortiOSUserRecord(
|
283
|
+
name=entry["user-id"][0],
|
284
|
+
password=password,
|
285
|
+
groups=["guestgroup"],
|
286
|
+
home=None,
|
287
|
+
_target=self.target,
|
288
|
+
)
|
289
|
+
except KeyError as e:
|
290
|
+
self.target.log.warning("Exception while parsing FortiOS temporary guest users")
|
291
|
+
self.target.log.debug("", exc_info=e)
|
287
292
|
|
288
293
|
@export(property=True)
|
289
294
|
def os(self) -> str:
|
290
295
|
return OperatingSystem.FORTIOS.value
|
291
296
|
|
292
297
|
@export(property=True)
|
293
|
-
def architecture(self) ->
|
298
|
+
def architecture(self) -> str | None:
|
294
299
|
"""Return architecture FortiOS runs on."""
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
return self._get_architecture(path=path)
|
300
|
+
for path in ["/lib/libav.so", "/bin/ctr", "/bin/grep"]:
|
301
|
+
if (bin := self.target.fs.path(path)).exists():
|
302
|
+
return self._get_architecture(path=bin)
|
299
303
|
|
300
304
|
|
301
305
|
class ConfigNode(dict):
|
@@ -528,7 +532,7 @@ def decrypt_rootfs(fh: BinaryIO, key: bytes, iv: bytes) -> BinaryIO:
|
|
528
532
|
return BytesIO(result)
|
529
533
|
|
530
534
|
|
531
|
-
def _kdf_7_4_x(key_data:
|
535
|
+
def _kdf_7_4_x(key_data: str | bytes) -> tuple[bytes, bytes]:
|
532
536
|
"""Derive 32 byte key and 16 byte IV from 32 byte seed.
|
533
537
|
|
534
538
|
As the IV needs to be 16 bytes, we return the first 16 bytes of the sha256 hash.
|
@@ -542,7 +546,7 @@ def _kdf_7_4_x(key_data: Union[str, bytes]) -> tuple[bytes, bytes]:
|
|
542
546
|
return key, iv
|
543
547
|
|
544
548
|
|
545
|
-
def get_kernel_hash(sysvol: Filesystem) ->
|
549
|
+
def get_kernel_hash(sysvol: Filesystem) -> str | None:
|
546
550
|
"""Return the SHA256 hash of the (compressed) kernel."""
|
547
551
|
kernel_files = ["flatkc", "vmlinuz", "vmlinux"]
|
548
552
|
for k in kernel_files:
|
@@ -12,6 +12,14 @@ from dissect.target.helpers.record import WindowsUserRecord
|
|
12
12
|
from dissect.target.plugin import OperatingSystem, OSPlugin, export
|
13
13
|
from dissect.target.target import Target
|
14
14
|
|
15
|
+
ARCH_MAP = {
|
16
|
+
"x86": 32,
|
17
|
+
"IA64": 64,
|
18
|
+
"ARM64": 64,
|
19
|
+
"EM64T": 64,
|
20
|
+
"AMD64": 64,
|
21
|
+
}
|
22
|
+
|
15
23
|
|
16
24
|
class WindowsPlugin(OSPlugin):
|
17
25
|
CURRENT_VERSION_KEY = "HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion"
|
@@ -101,7 +109,7 @@ class WindowsPlugin(OSPlugin):
|
|
101
109
|
|
102
110
|
@export(property=True)
|
103
111
|
def ips(self) -> list[str]:
|
104
|
-
return self.target.network.ips()
|
112
|
+
return list(set(map(str, self.target.network.ips())))
|
105
113
|
|
106
114
|
def _get_version_reg_value(self, value_name: str) -> Any:
|
107
115
|
try:
|
@@ -265,19 +273,11 @@ class WindowsPlugin(OSPlugin):
|
|
265
273
|
Dict: arch: architecture, bitness: bits
|
266
274
|
"""
|
267
275
|
|
268
|
-
arch_strings = {
|
269
|
-
"x86": 32,
|
270
|
-
"IA64": 64,
|
271
|
-
"ARM64": 64,
|
272
|
-
"EM64T": 64,
|
273
|
-
"AMD64": 64,
|
274
|
-
}
|
275
|
-
|
276
276
|
key = "HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment"
|
277
277
|
|
278
278
|
try:
|
279
279
|
arch = self.target.registry.key(key).value("PROCESSOR_ARCHITECTURE").value
|
280
|
-
bits =
|
280
|
+
bits = ARCH_MAP.get(arch)
|
281
281
|
|
282
282
|
# return {"arch": arch, "bitness": bits}
|
283
283
|
if bits == 64:
|
@@ -1,6 +1,7 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
from enum import IntEnum
|
4
|
+
from functools import lru_cache
|
4
5
|
from typing import Iterator
|
5
6
|
|
6
7
|
from dissect.util.ts import wintimestamp
|
@@ -12,6 +13,7 @@ from dissect.target.exceptions import (
|
|
12
13
|
from dissect.target.helpers.record import WindowsInterfaceRecord
|
13
14
|
from dissect.target.helpers.regutil import RegistryKey
|
14
15
|
from dissect.target.plugins.general.network import NetworkPlugin
|
16
|
+
from dissect.target.target import Target
|
15
17
|
|
16
18
|
|
17
19
|
class IfTypes(IntEnum):
|
@@ -222,15 +224,32 @@ def _try_value(subkey: RegistryKey, value: str) -> str | list | None:
|
|
222
224
|
return None
|
223
225
|
|
224
226
|
|
227
|
+
def _get_config_value(key: RegistryKey, name: str) -> set:
|
228
|
+
value = _try_value(key, name)
|
229
|
+
if not value or value in ("", "0.0.0.0", None, [], ["0.0.0.0"]):
|
230
|
+
return set()
|
231
|
+
|
232
|
+
if isinstance(value, list):
|
233
|
+
return set(value)
|
234
|
+
|
235
|
+
return {value}
|
236
|
+
|
237
|
+
|
225
238
|
class WindowsNetworkPlugin(NetworkPlugin):
|
226
239
|
"""Windows network interface plugin."""
|
227
240
|
|
241
|
+
def __init__(self, target: Target):
|
242
|
+
super().__init__(target)
|
243
|
+
self._extract_network_device_config = lru_cache(128)(self._extract_network_device_config)
|
244
|
+
|
228
245
|
def _interfaces(self) -> Iterator[WindowsInterfaceRecord]:
|
246
|
+
"""Yields found Windows interfaces used by :meth:`NetworkPlugin.interfaces() <dissect.target.plugins.general.network.NetworkPlugin.interfaces>`.""" # noqa: E501
|
247
|
+
|
229
248
|
# Get all the network interfaces
|
230
|
-
for
|
249
|
+
for key in self.target.registry.keys(
|
231
250
|
"HKLM\\SYSTEM\\CurrentControlSet\\Control\\Class\\{4d36e972-e325-11ce-bfc1-08002be10318}"
|
232
251
|
):
|
233
|
-
for subkey in
|
252
|
+
for subkey in key.subkeys():
|
234
253
|
device_info = {}
|
235
254
|
|
236
255
|
if (net_cfg_instance_id := _try_value(subkey, "NetCfgInstanceId")) is None:
|
@@ -239,24 +258,26 @@ class WindowsNetworkPlugin(NetworkPlugin):
|
|
239
258
|
|
240
259
|
# Extract the network device configuration for given interface id
|
241
260
|
config = self._extract_network_device_config(net_cfg_instance_id)
|
242
|
-
if config is None or all(not conf for conf in config):
|
243
|
-
# if no configuration is found or all configurations are empty, skip this network interface
|
244
|
-
continue
|
245
261
|
|
246
|
-
# Extract
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
262
|
+
# Extract a network device name for given interface id
|
263
|
+
try:
|
264
|
+
name_key = self.target.registry.key(
|
265
|
+
f"HKLM\\SYSTEM\\CurrentControlSet\\Control\\Network\\{{4D36E972-E325-11CE-BFC1-08002BE10318}}\\{net_cfg_instance_id}\\Connection" # noqa: E501
|
266
|
+
)
|
267
|
+
if value_name := _try_value(name_key, "Name"):
|
268
|
+
device_info["name"] = value_name
|
269
|
+
except RegistryKeyNotFoundError:
|
270
|
+
pass
|
271
|
+
|
272
|
+
# Extract the metric value from the interface registry key
|
273
|
+
try:
|
274
|
+
interface_key = self.target.registry.key(
|
275
|
+
f"HKLM\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\{net_cfg_instance_id}" # noqa: E501
|
276
|
+
)
|
277
|
+
if value_metric := _try_value(interface_key, "InterfaceMetric"):
|
278
|
+
device_info["metric"] = value_metric
|
279
|
+
except RegistryKeyNotFoundError:
|
280
|
+
pass
|
260
281
|
|
261
282
|
# Extract the rest of the device information
|
262
283
|
device_info["mac"] = _try_value(subkey, "NetworkAddress")
|
@@ -270,26 +291,57 @@ class WindowsNetworkPlugin(NetworkPlugin):
|
|
270
291
|
|
271
292
|
# Yield a record for each non-empty configuration
|
272
293
|
for conf in config:
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
294
|
+
# If no configuration is found or all configurations are empty,
|
295
|
+
# skip this network interface.
|
296
|
+
if not conf or not any(
|
297
|
+
[
|
298
|
+
conf["dns"],
|
299
|
+
conf["ip"],
|
300
|
+
conf["gateway"],
|
301
|
+
conf["subnetmask"],
|
302
|
+
conf["search_domain"],
|
303
|
+
]
|
304
|
+
):
|
305
|
+
continue
|
306
|
+
|
307
|
+
# Create a copy of device_info to avoid overwriting
|
308
|
+
record_info = device_info.copy()
|
309
|
+
record_info.update(conf)
|
310
|
+
yield WindowsInterfaceRecord(
|
311
|
+
**record_info,
|
312
|
+
source=f"HKLM\\SYSTEM\\{subkey.path}",
|
313
|
+
_target=self.target,
|
314
|
+
)
|
282
315
|
|
283
316
|
def _extract_network_device_config(
|
284
317
|
self, interface_id: str
|
285
318
|
) -> list[dict[str, str | list], dict[str, str | list]] | None:
|
286
|
-
|
287
|
-
|
319
|
+
"""Extract network device configuration from the given interface_id for all ControlSets on the system."""
|
320
|
+
|
321
|
+
dhcp_config = {
|
322
|
+
"gateway": set(),
|
323
|
+
"ip": set(),
|
324
|
+
"dns": set(),
|
325
|
+
"subnetmask": set(),
|
326
|
+
"search_domain": set(),
|
327
|
+
"network": set(),
|
328
|
+
}
|
329
|
+
|
330
|
+
static_config = {
|
331
|
+
"ip": set(),
|
332
|
+
"dns": set(),
|
333
|
+
"subnetmask": set(),
|
334
|
+
"search_domain": set(),
|
335
|
+
"gateway": set(),
|
336
|
+
"network": set(),
|
337
|
+
}
|
288
338
|
|
289
339
|
# Get the registry keys for the given interface id
|
290
340
|
try:
|
291
|
-
keys =
|
292
|
-
|
341
|
+
keys = list(
|
342
|
+
self.target.registry.keys(
|
343
|
+
f"HKLM\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\{interface_id}"
|
344
|
+
)
|
293
345
|
)
|
294
346
|
except RegistryKeyNotFoundError:
|
295
347
|
return None
|
@@ -297,69 +349,33 @@ class WindowsNetworkPlugin(NetworkPlugin):
|
|
297
349
|
if not len(keys):
|
298
350
|
return None
|
299
351
|
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
dhcp_config["
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
if dhcp_subnetmask not in ["", "0.0.0.0", None]:
|
315
|
-
dhcp_config["subnetmask"] = [dhcp_subnetmask]
|
316
|
-
|
317
|
-
dhcp_domain = _try_value(keys, "DhcpDomain")
|
318
|
-
if dhcp_domain not in ["", None]:
|
319
|
-
dhcp_config["search_domain"] = [dhcp_domain]
|
352
|
+
for key in keys:
|
353
|
+
# Extract DHCP configuration from the registry
|
354
|
+
dhcp_config["gateway"].update(_get_config_value(key, "DhcpDefaultGateway"))
|
355
|
+
dhcp_config["ip"].update(_get_config_value(key, "DhcpIPAddress"))
|
356
|
+
dhcp_config["subnetmask"].update(_get_config_value(key, "DhcpSubnetMask"))
|
357
|
+
dhcp_config["search_domain"].update(_get_config_value(key, "DhcpDomain"))
|
358
|
+
dhcp_config["dns"].update(_get_config_value(key, "DhcpNameServer"))
|
359
|
+
|
360
|
+
# Extract static configuration from the registry
|
361
|
+
static_config["gateway"].update(_get_config_value(key, "DefaultGateway"))
|
362
|
+
static_config["dns"].update(_get_config_value(key, "NameServer"))
|
363
|
+
static_config["search_domain"].update(_get_config_value(key, "Domain"))
|
364
|
+
static_config["ip"].update(_get_config_value(key, "IPAddress"))
|
365
|
+
static_config["subnetmask"].update(_get_config_value(key, "SubnetMask"))
|
320
366
|
|
321
367
|
if len(dhcp_config) > 0:
|
322
|
-
|
323
|
-
dhcp_config["enabled"] = dhcp_enable == 1
|
368
|
+
dhcp_config["enabled"] = _try_value(key, "EnableDHCP") == 1
|
324
369
|
dhcp_config["dhcp"] = True
|
325
370
|
|
326
|
-
# Extract static configuration from the registry
|
327
|
-
static_gateway = _try_value(keys, "DefaultGateway")
|
328
|
-
if static_gateway not in ["", None, []]:
|
329
|
-
static_config["gateway"] = static_gateway
|
330
|
-
|
331
|
-
static_ip = _try_value(keys, "IPAddress")
|
332
|
-
if static_ip not in ["", "0.0.0.0", ["0.0.0.0"], None, []]:
|
333
|
-
static_config["ip"] = static_ip if isinstance(static_ip, list) else [static_ip]
|
334
|
-
|
335
|
-
static_dns = _try_value(keys, "NameServer")
|
336
|
-
if static_dns not in ["", "0.0.0.0", None]:
|
337
|
-
static_config["dns"] = static_dns.split(",")
|
338
|
-
|
339
|
-
static_subnetmask = _try_value(keys, "SubnetMask")
|
340
|
-
if static_subnetmask not in ["", "0.0.0.0", ["0.0.0.0"], None, []]:
|
341
|
-
static_config["subnetmask"] = (
|
342
|
-
static_subnetmask if isinstance(static_subnetmask, list) else [static_subnetmask]
|
343
|
-
)
|
344
|
-
|
345
|
-
static_domain = _try_value(keys, "Domain")
|
346
|
-
if static_domain not in ["", None]:
|
347
|
-
static_config["search_domain"] = [static_domain]
|
348
|
-
|
349
371
|
if len(static_config) > 0:
|
350
372
|
static_config["enabled"] = None
|
351
373
|
static_config["dhcp"] = False
|
352
374
|
|
353
|
-
# Combine ip and subnetmask for extraction
|
354
|
-
combined_configs = [
|
355
|
-
(dhcp_config, dhcp_config.get("ip", []), dhcp_config.get("subnetmask", [])),
|
356
|
-
(static_config, static_config.get("ip", []), static_config.get("subnetmask", [])),
|
357
|
-
]
|
358
|
-
|
359
375
|
# Iterate over combined ip/subnet lists
|
360
|
-
for config
|
361
|
-
|
362
|
-
config
|
376
|
+
for config in (dhcp_config, static_config):
|
377
|
+
if (ips := config.get("ip")) and (masks := config.get("subnetmask")):
|
378
|
+
config["network"].update(set(self.calculate_network(ips, masks)))
|
363
379
|
|
364
380
|
# Return both configurations
|
365
381
|
return [dhcp_config, static_config]
|
dissect/target/tools/info.py
CHANGED
@@ -137,7 +137,7 @@ def print_target_info(target: Target) -> None:
|
|
137
137
|
continue
|
138
138
|
|
139
139
|
if isinstance(value, list):
|
140
|
-
value = ", ".join(value)
|
140
|
+
value = ", ".join(map(str, value))
|
141
141
|
|
142
142
|
if isinstance(value, datetime):
|
143
143
|
value = value.isoformat(timespec="microseconds")
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: dissect.target
|
3
|
-
Version: 3.20.
|
3
|
+
Version: 3.20.dev50
|
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
|
@@ -31,7 +31,7 @@ Requires-Dist: dissect.ntfs <4,>=3.4
|
|
31
31
|
Requires-Dist: dissect.regf <4,>=3.3
|
32
32
|
Requires-Dist: dissect.util <4,>=3
|
33
33
|
Requires-Dist: dissect.volume <4,>=2
|
34
|
-
Requires-Dist: flow.record ~=3.
|
34
|
+
Requires-Dist: flow.record ~=3.17.0
|
35
35
|
Requires-Dist: structlog
|
36
36
|
Provides-Extra: cb
|
37
37
|
Requires-Dist: dissect.target[full] ; extra == 'cb'
|
@@ -189,14 +189,14 @@ dissect/target/plugins/general/config.py,sha256=Mdy9uhWn4OJ96zfXpLgjVifV5SrViqHn
|
|
189
189
|
dissect/target/plugins/general/default.py,sha256=8W_9JV3jKEeETlyTrB25sACoIIFmmO8wlVU5Zoi51W0,1425
|
190
190
|
dissect/target/plugins/general/example.py,sha256=mYAbhtfQmUBj2L2C1DFt9bWpI7rQLJwCIYUsNLcA_pc,6053
|
191
191
|
dissect/target/plugins/general/loaders.py,sha256=z_t55Q1XNjmTOxq0E4tCwpZ-utFyxiLKyAJIFgJMlJs,1508
|
192
|
-
dissect/target/plugins/general/network.py,sha256=
|
192
|
+
dissect/target/plugins/general/network.py,sha256=TWfSdI5fTgwe1_nV7u_ldtvvRwgmkVFLd4XFzy4cEZU,3257
|
193
193
|
dissect/target/plugins/general/osinfo.py,sha256=oU-vmMiA-oaSEQWTSyn6-yQiH2sLQT6aTQHRd0677wo,1415
|
194
194
|
dissect/target/plugins/general/plugins.py,sha256=9KJ70YvYwBfxt19C9yISv8YE4mOdHNvP16fTCTHC68U,6033
|
195
195
|
dissect/target/plugins/general/scrape.py,sha256=Fz7BNXflvuxlnVulyyDhLpyU8D_hJdH6vWVtER9vjTg,6651
|
196
196
|
dissect/target/plugins/general/users.py,sha256=yy9gvRXfN9BT71v4Xqo5hpwfgN9he9Otu8TBPZ_Tegs,3009
|
197
197
|
dissect/target/plugins/os/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
198
198
|
dissect/target/plugins/os/unix/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
199
|
-
dissect/target/plugins/os/unix/_os.py,sha256=
|
199
|
+
dissect/target/plugins/os/unix/_os.py,sha256=mk2yxWGqdZMzdr8hyYT5nyjSIEN3F5JuoPaaiz0Rvf8,15311
|
200
200
|
dissect/target/plugins/os/unix/applications.py,sha256=AUgZRP35FzswGyFyChj2o4dfGO34Amc6nqHgiMEaqdI,3129
|
201
201
|
dissect/target/plugins/os/unix/cronjobs.py,sha256=tgWQ3BUZpfyvRzodMwGtwFUdPjZ17k7ZRbZ9Q8wmXPk,3393
|
202
202
|
dissect/target/plugins/os/unix/datetime.py,sha256=gKfBdPyUirt3qmVYfOJ1oZXRPn8wRzssbZxR_ARrtk8,1518
|
@@ -218,7 +218,7 @@ dissect/target/plugins/os/unix/bsd/ios/_os.py,sha256=VlJXGxkQZ4RbGbSC-FlbR2YWOJp
|
|
218
218
|
dissect/target/plugins/os/unix/bsd/openbsd/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
219
219
|
dissect/target/plugins/os/unix/bsd/openbsd/_os.py,sha256=9npz-osM-wHmjOACUqof5N5HJeps7J8KuyenUS5MZDs,923
|
220
220
|
dissect/target/plugins/os/unix/bsd/osx/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
221
|
-
dissect/target/plugins/os/unix/bsd/osx/_os.py,sha256=
|
221
|
+
dissect/target/plugins/os/unix/bsd/osx/_os.py,sha256=hNFB1rwahLwgZD1kc3T4xalFusT88EoxM2Mh-8jOW_w,3440
|
222
222
|
dissect/target/plugins/os/unix/bsd/osx/network.py,sha256=0Qf1jsCDNPmc_L-AmrvHjXaN_x-AtT1Ow3tdQOvFRsk,3734
|
223
223
|
dissect/target/plugins/os/unix/bsd/osx/user.py,sha256=5rsGhsntBW9IXYIOrLpfYpSsJcBDL61QJkuZ456lXlE,2411
|
224
224
|
dissect/target/plugins/os/unix/esxi/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -226,7 +226,7 @@ dissect/target/plugins/os/unix/esxi/_os.py,sha256=s6pAgUyfHh3QcY6sgvk5uVMmLvqK1t
|
|
226
226
|
dissect/target/plugins/os/unix/etc/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
227
227
|
dissect/target/plugins/os/unix/etc/etc.py,sha256=QngR0nA1azvbNTau4U9-jKOjSoGdyduDpyEna_6yxWY,2636
|
228
228
|
dissect/target/plugins/os/unix/linux/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
229
|
-
dissect/target/plugins/os/unix/linux/_os.py,sha256=
|
229
|
+
dissect/target/plugins/os/unix/linux/_os.py,sha256=k1aHhWqocSHMVbF54VDw9wqwa0QSToOa69TMKAyQcxw,2979
|
230
230
|
dissect/target/plugins/os/unix/linux/cmdline.py,sha256=n_Uetoplx33XpIY27oPtMaw1E2AbAEeGLCSkxHshWgY,1673
|
231
231
|
dissect/target/plugins/os/unix/linux/environ.py,sha256=n7KttVzUtBHTIXQuS1DI5Azv6tM__d9gGqhPR_3ArIE,1932
|
232
232
|
dissect/target/plugins/os/unix/linux/iptables.py,sha256=qTzY5PHHXA33WnPYb5NESgoSwI7ECZ8YPoEe_Fmln-8,6045
|
@@ -251,7 +251,7 @@ dissect/target/plugins/os/unix/linux/debian/vyos/__init__.py,sha256=47DEQpj8HBSa
|
|
251
251
|
dissect/target/plugins/os/unix/linux/debian/vyos/_os.py,sha256=TPjcfv1n68RCe3Er4aCVQwQDCZwJT-NLvje3kPjDfhk,1744
|
252
252
|
dissect/target/plugins/os/unix/linux/fortios/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
253
253
|
dissect/target/plugins/os/unix/linux/fortios/_keys.py,sha256=jDDHObfsUn9BGoIir9p4J_-rg9rI1rgoOfnL3R3lg4o,123358
|
254
|
-
dissect/target/plugins/os/unix/linux/fortios/_os.py,sha256=
|
254
|
+
dissect/target/plugins/os/unix/linux/fortios/_os.py,sha256=381VI9TDMR2-XPwLsvCU8hcRgTz1H5yJ-q_sCNQzSiM,19790
|
255
255
|
dissect/target/plugins/os/unix/linux/fortios/generic.py,sha256=dc6YTDLV-VZq9k8IWmY_PE0sTGkkp3yamR-cYNUCtes,1265
|
256
256
|
dissect/target/plugins/os/unix/linux/fortios/locale.py,sha256=Pe7Bdj8UemCiktLeQnQ50TpY_skARAzRJA0ewAB4710,5243
|
257
257
|
dissect/target/plugins/os/unix/linux/redhat/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -274,7 +274,7 @@ dissect/target/plugins/os/unix/log/lastlog.py,sha256=Wr3-2n1-GwckN9mSx-yM55N6_L0
|
|
274
274
|
dissect/target/plugins/os/unix/log/messages.py,sha256=XtjZ0a2budgQm_K5JT3fMf7JcjuD0AelcD3zOFN2xpI,5732
|
275
275
|
dissect/target/plugins/os/unix/log/utmp.py,sha256=k2A69s2qUT2JunJrH8GO6nQ0zMDotXMTaj8OzQ7ljj8,7336
|
276
276
|
dissect/target/plugins/os/windows/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
277
|
-
dissect/target/plugins/os/windows/_os.py,sha256
|
277
|
+
dissect/target/plugins/os/windows/_os.py,sha256=SUTfCPEVi2ADfjsQQJad6dEsnKUzRtsKJXOlEuiT9Xk,12462
|
278
278
|
dissect/target/plugins/os/windows/activitiescache.py,sha256=BbGD-vETHm1IRMoazVer_vqSJIoQxxhWcJ_xlBeOMds,6899
|
279
279
|
dissect/target/plugins/os/windows/adpolicy.py,sha256=ul8lKlG9ExABnd6yVLMPFFgVxN74CG4T3MvcRuBLHJc,7158
|
280
280
|
dissect/target/plugins/os/windows/amcache.py,sha256=1jq-S80_FIzGegrqQ6HqrjmaAPTyxyn69HxnbRBlaUc,27608
|
@@ -288,7 +288,7 @@ dissect/target/plugins/os/windows/generic.py,sha256=Z4eb9SrVMiO871bi5GS8V-rGF6QJ
|
|
288
288
|
dissect/target/plugins/os/windows/jumplist.py,sha256=3gZk6O1B3lKK2Jxe0B-HapOCEehk94CYNvCVDpQC9nQ,11773
|
289
289
|
dissect/target/plugins/os/windows/lnk.py,sha256=KTqhw0JMW-KjAxe4xlRDNSRSx-th-_nPVgTGyBaKmW0,7891
|
290
290
|
dissect/target/plugins/os/windows/locale.py,sha256=QiLWGgWrGBGHiXgep5iSOo6VNim4YC-xd4MdW0BUJPA,2486
|
291
|
-
dissect/target/plugins/os/windows/network.py,sha256=
|
291
|
+
dissect/target/plugins/os/windows/network.py,sha256=cffJmQwHJmTAGZkAEKKGxNi1ZYLiDomfOcPczZn85Fo,11284
|
292
292
|
dissect/target/plugins/os/windows/notifications.py,sha256=xxfMEY_noDxMVqvT3QS1a3j-X3qAYikOtT6v2owxuCY,17480
|
293
293
|
dissect/target/plugins/os/windows/prefetch.py,sha256=wbbYoy05gWbJfRsM2ci4wPG7kM58OocVwXD3hkQlbRw,10647
|
294
294
|
dissect/target/plugins/os/windows/recyclebin.py,sha256=zx58hDCvcrD_eJl9nJmr_i80krSN03ya8nQzWFr2Tw0,4917
|
@@ -358,7 +358,7 @@ dissect/target/tools/build_pluginlist.py,sha256=5fomcuMwsVzcnYx5Htf5f9lSwsLeUUvo
|
|
358
358
|
dissect/target/tools/dd.py,sha256=rTM-lgXxrYBpVAtJqFqAatDz45bLoD8-mFt_59Q3Lio,1928
|
359
359
|
dissect/target/tools/fs.py,sha256=3Ny8zoooVeeF7OUkQ0nxZVdEaQeU7vPRjDOYhz6XfRA,5385
|
360
360
|
dissect/target/tools/fsutils.py,sha256=q0t9gFwKHaPr2Ya-MN2o4LsYledde7kp2DZZTd8roIc,8314
|
361
|
-
dissect/target/tools/info.py,sha256=
|
361
|
+
dissect/target/tools/info.py,sha256=t2bWENeyaEh87ayE_brdKvz9kHAWOLqkKJcGixl6hGo,5725
|
362
362
|
dissect/target/tools/logging.py,sha256=5ZnumtMWLyslxfrUGZ4ntRyf3obOOhmn8SBjKfdLcEg,4174
|
363
363
|
dissect/target/tools/mount.py,sha256=8GRYnu4xEmFBHxuIZAYhOMyyTGX8fat1Ou07DNiUnW4,3945
|
364
364
|
dissect/target/tools/query.py,sha256=OYWVmCx2nFx85x1r8Y6D17UdUIi8PJm304xBfT-H8vs,15605
|
@@ -378,10 +378,10 @@ dissect/target/volumes/luks.py,sha256=OmCMsw6rCUXG1_plnLVLTpsvE1n_6WtoRUGQbpmu1z
|
|
378
378
|
dissect/target/volumes/lvm.py,sha256=wwQVR9I3G9YzmY6UxFsH2Y4MXGBcKL9aayWGCDTiWMU,2269
|
379
379
|
dissect/target/volumes/md.py,sha256=7ShPtusuLGaIv27SvEETtgsuoQyAa4iAAeOR1NEaajI,1689
|
380
380
|
dissect/target/volumes/vmfs.py,sha256=-LoUbn9WNwTtLi_4K34uV_-wDw2W5hgaqxZNj4UmqAQ,1730
|
381
|
-
dissect.target-3.20.
|
382
|
-
dissect.target-3.20.
|
383
|
-
dissect.target-3.20.
|
384
|
-
dissect.target-3.20.
|
385
|
-
dissect.target-3.20.
|
386
|
-
dissect.target-3.20.
|
387
|
-
dissect.target-3.20.
|
381
|
+
dissect.target-3.20.dev50.dist-info/COPYRIGHT,sha256=m-9ih2RVhMiXHI2bf_oNSSgHgkeIvaYRVfKTwFbnJPA,301
|
382
|
+
dissect.target-3.20.dev50.dist-info/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
|
383
|
+
dissect.target-3.20.dev50.dist-info/METADATA,sha256=GXXc4LbwWhRuEYw8FhQSkRDdbCUApDrAwJQss7yANgY,12897
|
384
|
+
dissect.target-3.20.dev50.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
|
385
|
+
dissect.target-3.20.dev50.dist-info/entry_points.txt,sha256=BWuxAb_6AvUAQpIQOQU0IMTlaF6TDht2AIZK8bHd-zE,492
|
386
|
+
dissect.target-3.20.dev50.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
|
387
|
+
dissect.target-3.20.dev50.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
{dissect.target-3.20.dev48.dist-info → dissect.target-3.20.dev50.dist-info}/entry_points.txt
RENAMED
File without changes
|
File without changes
|