dissect.target 3.19.dev58__py3-none-any.whl → 3.20__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (180) hide show
  1. dissect/target/container.py +1 -1
  2. dissect/target/exceptions.py +6 -5
  3. dissect/target/filesystem.py +2 -2
  4. dissect/target/filesystems/btrfs.py +14 -5
  5. dissect/target/filesystems/config.py +5 -1
  6. dissect/target/filesystems/extfs.py +5 -4
  7. dissect/target/filesystems/fat.py +22 -16
  8. dissect/target/filesystems/ffs.py +11 -4
  9. dissect/target/filesystems/jffs.py +12 -7
  10. dissect/target/filesystems/ntfs.py +22 -6
  11. dissect/target/filesystems/overlay.py +14 -4
  12. dissect/target/filesystems/smb.py +3 -3
  13. dissect/target/filesystems/squashfs.py +4 -4
  14. dissect/target/filesystems/vmfs.py +4 -4
  15. dissect/target/filesystems/xfs.py +15 -8
  16. dissect/target/helpers/compat/path_common.py +5 -5
  17. dissect/target/helpers/configutil.py +128 -32
  18. dissect/target/helpers/cyber.py +2 -0
  19. dissect/target/helpers/data/windowsZones.xml +19 -23
  20. dissect/target/helpers/docs.py +1 -1
  21. dissect/target/helpers/keychain.py +2 -0
  22. dissect/target/helpers/mount.py +2 -1
  23. dissect/target/helpers/record.py +29 -2
  24. dissect/target/helpers/record_modifier.py +5 -1
  25. dissect/target/helpers/regutil.py +56 -26
  26. dissect/target/loader.py +1 -1
  27. dissect/target/loaders/mqtt.py +104 -9
  28. dissect/target/loaders/proxmox.py +68 -0
  29. dissect/target/loaders/vma.py +1 -1
  30. dissect/target/loaders/xva.py +1 -1
  31. dissect/target/plugin.py +24 -21
  32. dissect/target/plugins/apps/av/mcafee.py +2 -0
  33. dissect/target/plugins/apps/av/sophos.py +2 -0
  34. dissect/target/plugins/apps/av/trendmicro.py +2 -0
  35. dissect/target/plugins/apps/browser/chromium.py +27 -6
  36. dissect/target/plugins/apps/container/docker.py +48 -32
  37. dissect/target/plugins/apps/editor/__init__.py +0 -0
  38. dissect/target/plugins/apps/editor/editor.py +23 -0
  39. dissect/target/plugins/apps/{texteditor → editor}/windowsnotepad.py +40 -31
  40. dissect/target/plugins/apps/other/__init__.py +0 -0
  41. dissect/target/plugins/apps/other/env.py +56 -0
  42. dissect/target/plugins/apps/shell/powershell.py +6 -2
  43. dissect/target/plugins/apps/shell/wget.py +91 -0
  44. dissect/target/plugins/apps/ssh/openssh.py +2 -0
  45. dissect/target/plugins/apps/ssh/opensshd.py +2 -0
  46. dissect/target/plugins/apps/virtualization/__init__.py +0 -0
  47. dissect/target/plugins/apps/virtualization/vmware_workstation.py +61 -0
  48. dissect/target/plugins/apps/vpn/wireguard.py +9 -9
  49. dissect/target/plugins/apps/webhosting/cpanel.py +2 -0
  50. dissect/target/plugins/apps/webserver/caddy.py +2 -0
  51. dissect/target/plugins/apps/webserver/nginx.py +2 -0
  52. dissect/target/plugins/child/esxi.py +3 -1
  53. dissect/target/plugins/child/parallels.py +68 -0
  54. dissect/target/plugins/child/proxmox.py +23 -0
  55. dissect/target/plugins/child/virtuozzo.py +12 -8
  56. dissect/target/plugins/child/vmware_workstation.py +23 -8
  57. dissect/target/plugins/filesystem/acquire_hash.py +2 -1
  58. dissect/target/plugins/filesystem/icat.py +15 -11
  59. dissect/target/plugins/filesystem/ntfs/mft.py +10 -6
  60. dissect/target/plugins/filesystem/ntfs/mft_timeline.py +3 -1
  61. dissect/target/plugins/filesystem/ntfs/usnjrnl.py +2 -0
  62. dissect/target/plugins/filesystem/ntfs/utils.py +3 -1
  63. dissect/target/plugins/filesystem/unix/suid.py +4 -1
  64. dissect/target/plugins/filesystem/walkfs.py +2 -0
  65. dissect/target/plugins/general/example.py +2 -2
  66. dissect/target/plugins/general/loaders.py +18 -5
  67. dissect/target/plugins/general/network.py +20 -5
  68. dissect/target/plugins/general/osinfo.py +1 -0
  69. dissect/target/plugins/general/plugins.py +53 -10
  70. dissect/target/plugins/os/unix/_os.py +70 -44
  71. dissect/target/plugins/os/unix/applications.py +78 -0
  72. dissect/target/plugins/os/unix/bsd/citrix/history.py +2 -0
  73. dissect/target/plugins/os/unix/bsd/osx/_os.py +4 -21
  74. dissect/target/plugins/os/unix/bsd/osx/network.py +92 -0
  75. dissect/target/plugins/os/unix/bsd/osx/user.py +4 -0
  76. dissect/target/plugins/os/unix/cronjobs.py +8 -4
  77. dissect/target/plugins/os/unix/etc/etc.py +4 -0
  78. dissect/target/plugins/os/unix/generic.py +2 -0
  79. dissect/target/plugins/os/unix/history.py +27 -25
  80. dissect/target/plugins/os/unix/linux/_os.py +8 -10
  81. dissect/target/plugins/os/unix/linux/cmdline.py +2 -0
  82. dissect/target/plugins/os/unix/linux/debian/apt.py +4 -1
  83. dissect/target/plugins/os/unix/linux/debian/dpkg.py +3 -3
  84. dissect/target/plugins/os/unix/linux/debian/proxmox/__init__.py +0 -0
  85. dissect/target/plugins/os/unix/linux/debian/proxmox/_os.py +141 -0
  86. dissect/target/plugins/os/unix/linux/debian/proxmox/vm.py +29 -0
  87. dissect/target/plugins/os/unix/linux/debian/snap.py +79 -0
  88. dissect/target/plugins/os/unix/linux/environ.py +2 -0
  89. dissect/target/plugins/os/unix/linux/fortios/_os.py +74 -63
  90. dissect/target/plugins/os/unix/linux/fortios/generic.py +2 -0
  91. dissect/target/plugins/os/unix/linux/fortios/locale.py +2 -0
  92. dissect/target/plugins/os/unix/linux/modules.py +2 -0
  93. dissect/target/plugins/os/unix/linux/netstat.py +2 -0
  94. dissect/target/{helpers → plugins/os/unix/linux}/network_managers.py +11 -9
  95. dissect/target/plugins/os/unix/linux/processes.py +2 -0
  96. dissect/target/plugins/os/unix/linux/redhat/yum.py +4 -1
  97. dissect/target/plugins/os/unix/linux/services.py +5 -3
  98. dissect/target/plugins/os/unix/linux/sockets.py +2 -0
  99. dissect/target/plugins/os/unix/linux/suse/zypper.py +4 -1
  100. dissect/target/plugins/os/unix/locale.py +2 -0
  101. dissect/target/plugins/os/unix/locate/gnulocate.py +4 -2
  102. dissect/target/plugins/os/unix/locate/mlocate.py +2 -0
  103. dissect/target/plugins/os/unix/locate/plocate.py +3 -1
  104. dissect/target/plugins/os/unix/log/atop.py +2 -0
  105. dissect/target/plugins/os/unix/log/audit.py +3 -1
  106. dissect/target/plugins/os/unix/log/auth.py +351 -38
  107. dissect/target/plugins/os/unix/log/journal.py +123 -101
  108. dissect/target/plugins/os/unix/log/lastlog.py +5 -3
  109. dissect/target/plugins/os/unix/log/messages.py +51 -27
  110. dissect/target/plugins/os/unix/log/utmp.py +52 -71
  111. dissect/target/plugins/os/unix/packagemanager.py +5 -38
  112. dissect/target/plugins/os/unix/shadow.py +3 -1
  113. dissect/target/plugins/os/unix/trash.py +132 -0
  114. dissect/target/plugins/os/windows/_os.py +22 -41
  115. dissect/target/plugins/os/windows/activitiescache.py +9 -4
  116. dissect/target/plugins/os/windows/adpolicy.py +2 -1
  117. dissect/target/plugins/os/windows/amcache.py +16 -13
  118. dissect/target/plugins/os/windows/defender.py +4 -3
  119. dissect/target/plugins/os/windows/dpapi/keyprovider/credhist.py +3 -0
  120. dissect/target/plugins/os/windows/dpapi/keyprovider/empty.py +3 -0
  121. dissect/target/plugins/os/windows/dpapi/keyprovider/keychain.py +3 -0
  122. dissect/target/plugins/os/windows/dpapi/keyprovider/lsa.py +3 -0
  123. dissect/target/plugins/os/windows/env.py +1 -2
  124. dissect/target/plugins/os/windows/exchange/exchange.py +6 -4
  125. dissect/target/plugins/os/windows/generic.py +68 -19
  126. dissect/target/plugins/os/windows/lnk.py +2 -0
  127. dissect/target/plugins/os/windows/locale.py +9 -3
  128. dissect/target/plugins/os/windows/log/etl.py +5 -4
  129. dissect/target/plugins/os/windows/log/evt.py +12 -8
  130. dissect/target/plugins/os/windows/log/evtx.py +9 -7
  131. dissect/target/plugins/os/windows/log/mssql.py +103 -0
  132. dissect/target/plugins/os/windows/log/pfro.py +2 -1
  133. dissect/target/plugins/os/windows/network.py +380 -0
  134. dissect/target/plugins/os/windows/notifications.py +6 -4
  135. dissect/target/plugins/os/windows/prefetch.py +7 -2
  136. dissect/target/plugins/os/windows/regf/7zip.py +9 -1
  137. dissect/target/plugins/os/windows/regf/applications.py +62 -0
  138. dissect/target/plugins/os/windows/regf/auditpol.py +2 -1
  139. dissect/target/plugins/os/windows/regf/bam.py +3 -1
  140. dissect/target/plugins/os/windows/regf/cit.py +14 -12
  141. dissect/target/plugins/os/windows/regf/clsid.py +6 -3
  142. dissect/target/plugins/os/windows/regf/firewall.py +2 -1
  143. dissect/target/plugins/os/windows/regf/mru.py +9 -8
  144. dissect/target/plugins/os/windows/regf/nethist.py +6 -3
  145. dissect/target/plugins/os/windows/regf/recentfilecache.py +3 -1
  146. dissect/target/plugins/os/windows/regf/regf.py +5 -1
  147. dissect/target/plugins/os/windows/regf/shellbags.py +351 -345
  148. dissect/target/plugins/os/windows/regf/shimcache.py +1 -1
  149. dissect/target/plugins/os/windows/regf/usb.py +2 -1
  150. dissect/target/plugins/os/windows/regf/userassist.py +2 -1
  151. dissect/target/plugins/os/windows/registry.py +11 -0
  152. dissect/target/plugins/os/windows/services.py +3 -2
  153. dissect/target/plugins/os/windows/startupinfo.py +7 -2
  154. dissect/target/plugins/os/windows/syscache.py +5 -2
  155. dissect/target/plugins/os/windows/tasks.py +1 -1
  156. dissect/target/plugins/os/windows/thumbcache.py +11 -5
  157. dissect/target/plugins/os/windows/ual.py +12 -9
  158. dissect/target/plugins/os/windows/wer.py +21 -6
  159. dissect/target/plugins/os/windows/wua_history.py +0 -1
  160. dissect/target/target.py +13 -8
  161. dissect/target/tools/dump/utils.py +4 -0
  162. dissect/target/tools/fsutils.py +1 -1
  163. dissect/target/tools/info.py +1 -1
  164. dissect/target/tools/mount.py +15 -5
  165. dissect/target/tools/query.py +15 -9
  166. dissect/target/tools/shell.py +98 -9
  167. dissect/target/tools/utils.py +7 -7
  168. dissect/target/volume.py +4 -4
  169. {dissect.target-3.19.dev58.dist-info → dissect.target-3.20.dist-info}/METADATA +6 -2
  170. {dissect.target-3.19.dev58.dist-info → dissect.target-3.20.dist-info}/RECORD +176 -160
  171. {dissect.target-3.19.dev58.dist-info → dissect.target-3.20.dist-info}/WHEEL +1 -1
  172. dissect/target/helpers/targetd.py +0 -58
  173. dissect/target/loaders/targetd.py +0 -223
  174. dissect/target/plugins/apps/texteditor/texteditor.py +0 -13
  175. dissect/target/plugins/os/unix/etc.py +0 -9
  176. /dissect/target/plugins/apps/{texteditor → database}/__init__.py +0 -0
  177. {dissect.target-3.19.dev58.dist-info → dissect.target-3.20.dist-info}/COPYRIGHT +0 -0
  178. {dissect.target-3.19.dev58.dist-info → dissect.target-3.20.dist-info}/LICENSE +0 -0
  179. {dissect.target-3.19.dev58.dist-info → dissect.target-3.20.dist-info}/entry_points.txt +0 -0
  180. {dissect.target-3.19.dev58.dist-info → dissect.target-3.20.dist-info}/top_level.txt +0 -0
@@ -1,7 +1,9 @@
1
+ from __future__ import annotations
2
+
1
3
  import datetime
2
4
  import re
3
5
  from functools import lru_cache
4
- from typing import Any, Generator, Optional
6
+ from typing import Any, Iterator
5
7
 
6
8
  from dissect.eventlog import evtx
7
9
  from dissect.eventlog.exceptions import MalformedElfChnkException
@@ -19,7 +21,7 @@ EVTX_GLOB = "*.evtx"
19
21
 
20
22
 
21
23
  class EvtxPlugin(WindowsEventlogsMixin, plugin.Plugin):
22
- """Plugin for fetching and parsing Windows Eventlog Files (*.evtx)"""
24
+ """Plugin for fetching and parsing Windows Eventlog Files (``*.evtx``)."""
23
25
 
24
26
  RECORD_NAME = "filesystem/windows/evtx"
25
27
  LOGS_DIR_PATH = "sysvol/windows/system32/winevt/logs"
@@ -34,11 +36,11 @@ class EvtxPlugin(WindowsEventlogsMixin, plugin.Plugin):
34
36
  @plugin.arg("--logs-dir", help="logs directory to scan")
35
37
  @plugin.arg("--log-file-glob", default=EVTX_GLOB, help="glob pattern to match a log file name")
36
38
  @plugin.export(record=DynamicDescriptor(["datetime"]))
37
- def evtx(self, log_file_glob: str = EVTX_GLOB, logs_dir: Optional[str] = None) -> Generator[Record, None, None]:
38
- """Return entries from Windows Event log files (*.evtx).
39
+ def evtx(self, log_file_glob: str = EVTX_GLOB, logs_dir: str | None = None) -> Iterator[DynamicDescriptor]:
40
+ """Return entries from Windows Event log files (``*.evtx``).
39
41
 
40
42
  Windows Event log is a detailed record of system, security and application notifications. It can be used to
41
- diagnose a system or find future issues. Up until Windows XP the extension .evt was used, hereafter .evtx
43
+ diagnose a system or find future issues. Up until Windows XP the extension .evt was used, hereafter ``.evtx``
42
44
  became the new standard.
43
45
 
44
46
  References:
@@ -77,7 +79,7 @@ class EvtxPlugin(WindowsEventlogsMixin, plugin.Plugin):
77
79
  yield self._build_record(event)
78
80
 
79
81
  @plugin.export(record=DynamicDescriptor(["datetime"]))
80
- def scraped_evtx(self) -> Generator[Record, None, None]:
82
+ def scraped_evtx(self) -> Iterator[DynamicDescriptor]:
81
83
  """Return EVTX log file records scraped from target disks"""
82
84
  yield from self.target.scrape.scrape_chunks_from_disks(
83
85
  needle=self.NEEDLE,
@@ -85,7 +87,7 @@ class EvtxPlugin(WindowsEventlogsMixin, plugin.Plugin):
85
87
  chunk_parser=self._parse_chunk,
86
88
  )
87
89
 
88
- def _parse_chunk(self, _, chunk: bytes) -> Generator[Any, None, None]:
90
+ def _parse_chunk(self, _, chunk: bytes) -> Iterator[Record]:
89
91
  chnk = evtx.ElfChnk(chunk)
90
92
  try:
91
93
  for event in chnk.read():
@@ -0,0 +1,103 @@
1
+ import re
2
+ from datetime import datetime, timezone
3
+ from typing import Iterator
4
+
5
+ from dissect.target.exceptions import UnsupportedPluginError
6
+ from dissect.target.helpers.fsutil import TargetPath
7
+ from dissect.target.helpers.record import TargetRecordDescriptor
8
+ from dissect.target.plugin import Plugin, export
9
+ from dissect.target.target import Target
10
+
11
+ MssqlErrorlogRecord = TargetRecordDescriptor(
12
+ "microsoft/sql/errorlog",
13
+ [
14
+ ("datetime", "ts"),
15
+ ("string", "instance"),
16
+ ("string", "process"),
17
+ ("string", "message"),
18
+ ("path", "path"),
19
+ ],
20
+ )
21
+
22
+ RE_TIMESTAMP_PATTERN = re.compile(r"^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}.\d{2}")
23
+
24
+
25
+ class MssqlPlugin(Plugin):
26
+ """Return information related to Microsoft SQL Server.
27
+
28
+ Currently returns ERRORLOG messages. These log files contain information such as:
29
+ - Logon failures
30
+ - Enabling/disabling of features, such as xp_cmdshell
31
+
32
+ References:
33
+ - https://learn.microsoft.com/en-us/sql/relational-databases/logs/view-offline-log-files
34
+ """
35
+
36
+ __namespace__ = "mssql"
37
+
38
+ MSSQL_KEY = "HKLM\\SOFTWARE\\Microsoft\\Microsoft SQL Server"
39
+ FILE_GLOB = "ERRORLOG*"
40
+
41
+ def __init__(self, target: Target):
42
+ super().__init__(target)
43
+ self.instances = self._find_instances()
44
+
45
+ def check_compatible(self) -> None:
46
+ if not self.instances:
47
+ raise UnsupportedPluginError("System does not seem to be running SQL Server")
48
+
49
+ @export(record=MssqlErrorlogRecord)
50
+ def errorlog(self) -> Iterator[MssqlErrorlogRecord]:
51
+ """Return all Microsoft SQL Server ERRORLOG messages.
52
+
53
+ These log files contain information such as:
54
+ - Logon failures
55
+ - Enabling/disabling of features, such as xp_cmdshell
56
+
57
+ Yields MssqlErrorlogRecord instances with fields:
58
+
59
+ .. code-block:: text
60
+
61
+ ts (datetime): Timestamp of the log line.
62
+ instance (str): SQL Server instance name.
63
+ process (str): Process name.
64
+ message (str): Log message.
65
+ path (Path): Path to the log file.
66
+
67
+ References:
68
+ - https://learn.microsoft.com/en-us/sql/relational-databases/logs/view-offline-log-files
69
+ """
70
+
71
+ for instance, log_path in self.instances:
72
+ for errorlog in log_path.glob(self.FILE_GLOB):
73
+ # The errorlog includes a BOM, so endianess gets determined automatically
74
+ fh = errorlog.open(mode="rt", encoding="utf-16", errors="surrogateescape")
75
+ buf = ""
76
+
77
+ for line in fh:
78
+ if ts := RE_TIMESTAMP_PATTERN.match(line):
79
+ yield MssqlErrorlogRecord(
80
+ ts=datetime.strptime(ts.group(), "%Y-%m-%d %H:%M:%S.%f").replace(tzinfo=timezone.utc),
81
+ instance=instance,
82
+ # The process name is a fixed-width field and is always 12 characters long.
83
+ process=buf[23:35].strip(),
84
+ message=buf[35:].strip(),
85
+ path=errorlog,
86
+ _target=self.target,
87
+ )
88
+ buf = ""
89
+
90
+ buf += line
91
+
92
+ def _find_instances(self) -> list[str, TargetPath]:
93
+ instances = []
94
+
95
+ for subkey in self.target.registry.key(self.MSSQL_KEY).subkeys():
96
+ if subkey.name.startswith("MSSQL") and "." in subkey.name:
97
+ instances.append(
98
+ (
99
+ subkey.name,
100
+ self.target.fs.path(subkey.subkey("SQLServerAgent").value("ErrorLogFile").value).parent,
101
+ )
102
+ )
103
+ return instances
@@ -1,5 +1,6 @@
1
1
  import datetime
2
2
  import re
3
+ from typing import Iterator
3
4
 
4
5
  from dissect.target.exceptions import UnsupportedPluginError
5
6
  from dissect.target.helpers.record import TargetRecordDescriptor
@@ -29,7 +30,7 @@ class PfroPlugin(Plugin):
29
30
  raise UnsupportedPluginError("No PFRO log found")
30
31
 
31
32
  @export(record=PfroRecord)
32
- def pfro(self):
33
+ def pfro(self) -> Iterator[PfroRecord]:
33
34
  """Return the content of sysvol/Windows/PFRO.log
34
35
 
35
36
  A Pending File Rename Operation log file (PFRO.log) holds information about the process of deleting or renaming
@@ -0,0 +1,380 @@
1
+ from __future__ import annotations
2
+
3
+ from enum import IntEnum
4
+ from functools import lru_cache
5
+ from typing import Iterator
6
+
7
+ from dissect.util.ts import wintimestamp
8
+
9
+ from dissect.target.exceptions import (
10
+ RegistryKeyNotFoundError,
11
+ RegistryValueNotFoundError,
12
+ )
13
+ from dissect.target.helpers.record import WindowsInterfaceRecord
14
+ from dissect.target.helpers.regutil import RegistryKey
15
+ from dissect.target.plugins.general.network import NetworkPlugin
16
+ from dissect.target.target import Target
17
+
18
+
19
+ class IfTypes(IntEnum):
20
+ OTHER = 1
21
+ REGULAR_1822 = 2
22
+ HDH_1822 = 3
23
+ DDN_X25 = 4
24
+ RFC877_X25 = 5
25
+ ETHERNET_CSMACD = 6
26
+ IS088023_CSMACD = 7
27
+ ISO88024_TOKENBUS = 8
28
+ ISO88025_TOKENRING = 9
29
+ ISO88026_MAN = 10
30
+ STARLAN = 11
31
+ PROTEON_10MBIT = 12
32
+ PROTEON_80MBIT = 13
33
+ HYPERCHANNEL = 14
34
+ FDDI = 15
35
+ LAP_B = 16
36
+ SDLC = 17
37
+ DS1 = 18
38
+ E1 = 19
39
+ BASIC_ISDN = 20
40
+ PRIMARY_ISDN = 21
41
+ PROP_POINT2POINT_SERIAL = 22
42
+ PPP = 23
43
+ SOFTWARE_LOOPBACK = 24
44
+ EON = 25
45
+ ETHERNET_3MBIT = 26
46
+ NSIP = 27
47
+ SLIP = 28
48
+ ULTRA = 29
49
+ DS3 = 30
50
+ SIP = 31
51
+ FRAMERELAY = 32
52
+ RS232 = 33
53
+ PARA = 34
54
+ ARCNET = 35
55
+ ARCNET_PLUS = 36
56
+ ATM = 37
57
+ MIO_X25 = 38
58
+ SONET = 39
59
+ X25_PLE = 40
60
+ ISO88022_LLC = 41
61
+ LOCALTALK = 42
62
+ SMDS_DXI = 43
63
+ FRAMERELAY_SERVICE = 44
64
+ V35 = 45
65
+ HSSI = 46
66
+ HIPPI = 47
67
+ MODEM = 48
68
+ AAL5 = 49
69
+ SONET_PATH = 50
70
+ SONET_VT = 51
71
+ SMDS_ICIP = 52
72
+ PROP_VIRTUAL = 53
73
+ PROP_MULTIPLEXOR = 54
74
+ IEEE80212 = 55
75
+ FIBRECHANNEL = 56
76
+ HIPPIINTERFACE = 57
77
+ FRAMERELAY_INTERCONNECT = 58
78
+ AFLANE_8023 = 59
79
+ AFLANE_8025 = 60
80
+ CCTEMUL = 61
81
+ FASTETHER = 62
82
+ ISDN = 63
83
+ V11 = 64
84
+ V36 = 65
85
+ G703_64K = 66
86
+ G703_2MB = 67
87
+ QLLC = 68
88
+ FASTETHER_FX = 69
89
+ CHANNEL = 70
90
+ IEEE80211 = 71
91
+ IBM370PARCHAN = 72
92
+ ESCON = 73
93
+ DLSW = 74
94
+ ISDN_S = 75
95
+ ISDN_U = 76
96
+ LAP_D = 77
97
+ IPSWITCH = 78
98
+ RSRB = 79
99
+ ATM_LOGICAL = 80
100
+ DS0 = 81
101
+ DS0_BUNDLE = 82
102
+ BSC = 83
103
+ ASYNC = 84
104
+ CNR = 85
105
+ ISO88025R_DTR = 86
106
+ EPLRS = 87
107
+ ARAP = 88
108
+ PROP_CNLS = 89
109
+ HOSTPAD = 90
110
+ TERMPAD = 91
111
+ FRAMERELAY_MPI = 92
112
+ X213 = 93
113
+ ADSL = 94
114
+ RADSL = 95
115
+ SDSL = 96
116
+ VDSL = 97
117
+ ISO88025_CRFPRINT = 98
118
+ MYRINET = 99
119
+ VOICE_EM = 100
120
+ VOICE_FXO = 101
121
+ VOICE_FXS = 102
122
+ VOICE_ENCAP = 103
123
+ VOICE_OVERIP = 104
124
+ ATM_DXI = 105
125
+ ATM_FUNI = 106
126
+ ATM_IMA = 107
127
+ PPPMULTILINKBUNDLE = 108
128
+ IPOVER_CDLC = 109
129
+ IPOVER_CLAW = 110
130
+ STACKTOSTACK = 111
131
+ VIRTUALIPADDRESS = 112
132
+ MPC = 113
133
+ IPOVER_ATM = 114
134
+ ISO88025_FIBER = 115
135
+ TDLC = 116
136
+ GIGABITETHERNET = 117
137
+ HDLC = 118
138
+ LAP_F = 119
139
+ V37 = 120
140
+ X25_MLP = 121
141
+ X25_HUNTGROUP = 122
142
+ TRANSPHDLC = 123
143
+ INTERLEAVE = 124
144
+ FAST = 125
145
+ IP = 126
146
+ DOCSCABLE_MACLAYER = 127
147
+ DOCSCABLE_DOWNSTREAM = 128
148
+ DOCSCABLE_UPSTREAM = 129
149
+ A12MPPSWITCH = 130
150
+ TUNNEL = 131
151
+ COFFEE = 132
152
+ CES = 133
153
+ ATM_SUBINTERFACE = 134
154
+ L2_VLAN = 135
155
+ L3_IPVLAN = 136
156
+ L3_IPXVLAN = 137
157
+ DIGITALPOWERLINE = 138
158
+ MEDIAMAILOVERIP = 139
159
+ DTM = 140
160
+ DCN = 141
161
+ IPFORWARD = 142
162
+ MSDSL = 143
163
+ IEEE1394 = 144
164
+ IF_GSN = 145
165
+ DVBRCC_MACLAYER = 146
166
+ DVBRCC_DOWNSTREAM = 147
167
+ DVBRCC_UPSTREAM = 148
168
+ ATM_VIRTUAL = 149
169
+ MPLS_TUNNEL = 150
170
+ SRP = 151
171
+ VOICEOVERATM = 152
172
+ VOICEOVERFRAMERELAY = 153
173
+ IDSL = 154
174
+ COMPOSITELINK = 155
175
+ SS7_SIGLINK = 156
176
+ PROP_WIRELESS_P2P = 157
177
+ FR_FORWARD = 158
178
+ RFC1483 = 159
179
+ USB = 160
180
+ IEEE8023AD_LAG = 161
181
+ BGP_POLICY_ACCOUNTING = 162
182
+ FRF16_MFR_BUNDLE = 163
183
+ H323_GATEKEEPER = 164
184
+ H323_PROXY = 165
185
+ MPLS = 166
186
+ MF_SIGLINK = 167
187
+ HDSL2 = 168
188
+ SHDSL = 169
189
+ DS1_FDL = 170
190
+ POS = 171
191
+ DVB_ASI_IN = 172
192
+ DVB_ASI_OUT = 173
193
+ PLC = 174
194
+ NFAS = 175
195
+ TR008 = 176
196
+ GR303_RDT = 177
197
+ GR303_IDT = 178
198
+ ISUP = 179
199
+ PROP_DOCS_WIRELESS_MACLAYER = 180
200
+ PROP_DOCS_WIRELESS_DOWNSTREAM = 181
201
+ PROP_DOCS_WIRELESS_UPSTREAM = 182
202
+ HIPERLAN2 = 183
203
+ PROP_BWA_P2MP = 184
204
+ SONET_OVERHEAD_CHANNEL = 185
205
+ DIGITAL_WRAPPER_OVERHEAD_CHANNEL = 186
206
+ AAL2 = 187
207
+ RADIO_MAC = 188
208
+ ATM_RADIO = 189
209
+ IMT = 190
210
+ MVL = 191
211
+ REACH_DSL = 192
212
+ FR_DLCI_ENDPT = 193
213
+ ATM_VCI_ENDPT = 194
214
+ OPTICAL_CHANNEL = 195
215
+ OPTICAL_TRANSPORT = 196
216
+ WWANPP = 243
217
+ WWANPP2 = 244
218
+
219
+
220
+ def _try_value(subkey: RegistryKey, value: str) -> str | list | None:
221
+ try:
222
+ return subkey.value(value).value
223
+ except RegistryValueNotFoundError:
224
+ return None
225
+
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
+
238
+ class WindowsNetworkPlugin(NetworkPlugin):
239
+ """Windows network interface plugin."""
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
+
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
+
248
+ # Get all the network interfaces
249
+ for key in self.target.registry.keys(
250
+ "HKLM\\SYSTEM\\CurrentControlSet\\Control\\Class\\{4d36e972-e325-11ce-bfc1-08002be10318}"
251
+ ):
252
+ for subkey in key.subkeys():
253
+ device_info = {}
254
+
255
+ if (net_cfg_instance_id := _try_value(subkey, "NetCfgInstanceId")) is None:
256
+ # if no NetCfgInstanceId is found, skip this network interface
257
+ continue
258
+
259
+ # Extract the network device configuration for given interface id
260
+ if not (config := self._extract_network_device_config(net_cfg_instance_id)):
261
+ continue
262
+
263
+ # Extract a network device name for given interface id
264
+ try:
265
+ name_key = self.target.registry.key(
266
+ f"HKLM\\SYSTEM\\CurrentControlSet\\Control\\Network\\{{4D36E972-E325-11CE-BFC1-08002BE10318}}\\{net_cfg_instance_id}\\Connection" # noqa: E501
267
+ )
268
+ if value_name := _try_value(name_key, "Name"):
269
+ device_info["name"] = value_name
270
+ except RegistryKeyNotFoundError:
271
+ pass
272
+
273
+ # Extract the metric value from the interface registry key
274
+ try:
275
+ interface_key = self.target.registry.key(
276
+ f"HKLM\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\{net_cfg_instance_id}" # noqa: E501
277
+ )
278
+ if value_metric := _try_value(interface_key, "InterfaceMetric"):
279
+ device_info["metric"] = value_metric
280
+ except RegistryKeyNotFoundError:
281
+ pass
282
+
283
+ # Extract the rest of the device information
284
+ device_info["mac"] = _try_value(subkey, "NetworkAddress")
285
+ device_info["vlan"] = _try_value(subkey, "VlanID")
286
+
287
+ if timestamp := _try_value(subkey, "NetworkInterfaceInstallTimestamp"):
288
+ device_info["first_connected"] = wintimestamp(timestamp)
289
+
290
+ if type_device := _try_value(subkey, "*IfType"):
291
+ device_info["type"] = IfTypes(int(type_device)).name
292
+
293
+ # Yield a record for each non-empty configuration
294
+ for conf in config:
295
+ # If no configuration is found or all configurations are empty,
296
+ # skip this network interface.
297
+ if not conf or not any(
298
+ [
299
+ conf["dns"],
300
+ conf["ip"],
301
+ conf["gateway"],
302
+ conf["subnetmask"],
303
+ conf["search_domain"],
304
+ ]
305
+ ):
306
+ continue
307
+
308
+ # Create a copy of device_info to avoid overwriting
309
+ record_info = device_info.copy()
310
+ record_info.update(conf)
311
+ yield WindowsInterfaceRecord(
312
+ **record_info,
313
+ source=f"HKLM\\SYSTEM\\{subkey.path}",
314
+ _target=self.target,
315
+ )
316
+
317
+ def _extract_network_device_config(self, interface_id: str) -> list[dict[str, set | bool | None]]:
318
+ """Extract network device configuration from the given interface_id for all ControlSets on the system."""
319
+
320
+ dhcp_config = {
321
+ "gateway": set(),
322
+ "ip": set(),
323
+ "dns": set(),
324
+ "subnetmask": set(),
325
+ "search_domain": set(),
326
+ "network": set(),
327
+ }
328
+
329
+ static_config = {
330
+ "ip": set(),
331
+ "dns": set(),
332
+ "subnetmask": set(),
333
+ "search_domain": set(),
334
+ "gateway": set(),
335
+ "network": set(),
336
+ }
337
+
338
+ # Get the registry keys for the given interface id
339
+ try:
340
+ keys = list(
341
+ self.target.registry.keys(
342
+ f"HKLM\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\{interface_id}"
343
+ )
344
+ )
345
+ except RegistryKeyNotFoundError:
346
+ return []
347
+
348
+ if not len(keys):
349
+ return []
350
+
351
+ for key in keys:
352
+ # Extract DHCP configuration from the registry
353
+ dhcp_config["gateway"].update(_get_config_value(key, "DhcpDefaultGateway"))
354
+ dhcp_config["ip"].update(_get_config_value(key, "DhcpIPAddress"))
355
+ dhcp_config["subnetmask"].update(_get_config_value(key, "DhcpSubnetMask"))
356
+ dhcp_config["search_domain"].update(_get_config_value(key, "DhcpDomain"))
357
+ dhcp_config["dns"].update(_get_config_value(key, "DhcpNameServer"))
358
+
359
+ # Extract static configuration from the registry
360
+ static_config["gateway"].update(_get_config_value(key, "DefaultGateway"))
361
+ static_config["dns"].update(_get_config_value(key, "NameServer"))
362
+ static_config["search_domain"].update(_get_config_value(key, "Domain"))
363
+ static_config["ip"].update(_get_config_value(key, "IPAddress"))
364
+ static_config["subnetmask"].update(_get_config_value(key, "SubnetMask"))
365
+
366
+ if len(dhcp_config) > 0:
367
+ dhcp_config["enabled"] = _try_value(key, "EnableDHCP") == 1
368
+ dhcp_config["dhcp"] = True
369
+
370
+ if len(static_config) > 0:
371
+ static_config["enabled"] = None
372
+ static_config["dhcp"] = False
373
+
374
+ # Iterate over combined ip/subnet lists
375
+ for config in (dhcp_config, static_config):
376
+ if (ips := config.get("ip")) and (masks := config.get("subnetmask")):
377
+ config["network"].update(set(self.calculate_network(ips, masks)))
378
+
379
+ # Return both configurations
380
+ return [dhcp_config, static_config]
@@ -1,5 +1,7 @@
1
+ from __future__ import annotations
2
+
1
3
  import datetime
2
- from typing import Iterator, Optional
4
+ from typing import Iterator
3
5
  from uuid import UUID
4
6
 
5
7
  from dissect.cstruct import cstruct
@@ -253,7 +255,7 @@ class NotificationsPlugin(Plugin):
253
255
  chunk: c_appdb.Chunk,
254
256
  chunk_num: int,
255
257
  user: WindowsUserRecord,
256
- ) -> Optional[AppDBPushRecord]:
258
+ ) -> AppDBPushRecord | None:
257
259
  badge_record = None
258
260
  push_uri = chunk.Push.Uri.split(b"\x00")[0]
259
261
  push_uri = push_uri.decode("utf-8", errors="surrogateescape")
@@ -282,7 +284,7 @@ class NotificationsPlugin(Plugin):
282
284
  chunk: c_appdb.Chunk,
283
285
  chunk_num: int,
284
286
  user: WindowsUserRecord,
285
- ) -> Optional[AppDBBadgeRecord]:
287
+ ) -> AppDBBadgeRecord | None:
286
288
  badge_record = None
287
289
  badge_id = chunk.Badge.Id
288
290
 
@@ -432,7 +434,7 @@ class NotificationsPlugin(Plugin):
432
434
  yield toast_record
433
435
 
434
436
  @export(record=[WpnDatabaseNotificationRecord, WpnDatabaseNotificationHandlerRecord])
435
- def wpndatabase(self):
437
+ def wpndatabase(self) -> Iterator[WpnDatabaseNotificationRecord | WpnDatabaseNotificationHandlerRecord]:
436
438
  """Returns Windows Notifications from wpndatabase.db (post Windows 10 Anniversary).
437
439
 
438
440
  References:
@@ -1,4 +1,7 @@
1
+ from __future__ import annotations
2
+
1
3
  from io import BytesIO
4
+ from typing import Iterator
2
5
 
3
6
  from dissect.cstruct import cstruct
4
7
  from dissect.util import lzxpress_huffman
@@ -237,6 +240,8 @@ class Prefetch:
237
240
 
238
241
 
239
242
  class PrefetchPlugin(Plugin):
243
+ """Windows prefetch plugin."""
244
+
240
245
  def __init__(self, target):
241
246
  super().__init__(target)
242
247
  self.prefetchdir = self.target.fs.path("sysvol/windows/prefetch")
@@ -247,7 +252,7 @@ class PrefetchPlugin(Plugin):
247
252
 
248
253
  @export(record=[PrefetchRecord, GroupedPrefetchRecord])
249
254
  @arg("--grouped", action="store_true", help="Group the prefetch record")
250
- def prefetch(self, grouped=False):
255
+ def prefetch(self, grouped=False) -> Iterator[PrefetchRecord | GroupedPrefetchRecord]:
251
256
  """Return the content of all prefetch files.
252
257
 
253
258
  Prefetch is a memory management feature in Windows. It contains information (for example run count and
@@ -268,7 +273,7 @@ class PrefetchPlugin(Plugin):
268
273
  linkedfile (path): The linked file entry.
269
274
  runcount (int): The run count.
270
275
 
271
- with --grouped:
276
+ with ``--grouped``:
272
277
 
273
278
  Yields PrefetchRecords with fields:
274
279
 
@@ -1,3 +1,7 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Iterator
4
+
1
5
  from dissect.target.exceptions import RegistryError, UnsupportedPluginError
2
6
  from dissect.target.helpers.record import TargetRecordDescriptor
3
7
  from dissect.target.plugin import Plugin, export
@@ -48,6 +52,8 @@ FolderHistoryRecord = TargetRecordDescriptor(
48
52
 
49
53
 
50
54
  class SevenZipPlugin(Plugin):
55
+ """Windows 7-Zip GUI plugin."""
56
+
51
57
  KEY = "HKCU\\Software\\7-Zip"
52
58
 
53
59
  def check_compatible(self) -> None:
@@ -71,7 +77,9 @@ class SevenZipPlugin(Plugin):
71
77
  pass
72
78
 
73
79
  @export(record=[PanelPathRecord, ArcHistoryRecord, PathHistoryRecord, CopyHistoryRecord, FolderHistoryRecord])
74
- def sevenzip(self):
80
+ def sevenzip(
81
+ self,
82
+ ) -> Iterator[PanelPathRecord | ArcHistoryRecord | PathHistoryRecord | CopyHistoryRecord | FolderHistoryRecord]:
75
83
  """Return 7-Zip history information from the registry.
76
84
 
77
85
  7-Zip is an open source file archiver. If the HKCU\\Software\\7-Zip registry key exists, it checks for