dissect.target 3.15.dev12__py3-none-any.whl → 3.15.dev14__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/apps/ssh/openssh.py +11 -54
- dissect/target/plugins/apps/ssh/opensshd.py +4 -3
- dissect/target/plugins/apps/ssh/putty.py +236 -0
- dissect/target/plugins/apps/ssh/ssh.py +58 -0
- dissect/target/plugins/os/windows/registry.py +1 -1
- dissect/target/plugins/os/windows/sru.py +41 -28
- {dissect.target-3.15.dev12.dist-info → dissect.target-3.15.dev14.dist-info}/METADATA +1 -1
- {dissect.target-3.15.dev12.dist-info → dissect.target-3.15.dev14.dist-info}/RECORD +13 -11
- {dissect.target-3.15.dev12.dist-info → dissect.target-3.15.dev14.dist-info}/COPYRIGHT +0 -0
- {dissect.target-3.15.dev12.dist-info → dissect.target-3.15.dev14.dist-info}/LICENSE +0 -0
- {dissect.target-3.15.dev12.dist-info → dissect.target-3.15.dev14.dist-info}/WHEEL +0 -0
- {dissect.target-3.15.dev12.dist-info → dissect.target-3.15.dev14.dist-info}/entry_points.txt +0 -0
- {dissect.target-3.15.dev12.dist-info → dissect.target-3.15.dev14.dist-info}/top_level.txt +0 -0
@@ -5,59 +5,15 @@ from typing import Iterator
|
|
5
5
|
|
6
6
|
from dissect.target import Target
|
7
7
|
from dissect.target.exceptions import UnsupportedPluginError
|
8
|
-
from dissect.target.helpers.descriptor_extensions import UserRecordDescriptorExtension
|
9
8
|
from dissect.target.helpers.fsutil import TargetPath
|
10
|
-
from dissect.target.helpers.record import create_extended_descriptor
|
11
9
|
from dissect.target.helpers.ssh import SSHPrivateKey
|
12
|
-
from dissect.target.plugin import
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
("path", "path"),
|
20
|
-
]
|
21
|
-
|
22
|
-
AuthorizedKeysRecord = OpenSSHUserRecordDescriptor(
|
23
|
-
"application/openssh/authorized_keys",
|
24
|
-
[
|
25
|
-
*COMMON_ELLEMENTS,
|
26
|
-
("string", "public_key"),
|
27
|
-
("string", "options"),
|
28
|
-
],
|
29
|
-
)
|
30
|
-
|
31
|
-
|
32
|
-
KnownHostRecord = OpenSSHUserRecordDescriptor(
|
33
|
-
"application/openssh/known_host",
|
34
|
-
[
|
35
|
-
*COMMON_ELLEMENTS,
|
36
|
-
("string", "hostname_pattern"),
|
37
|
-
("string", "public_key"),
|
38
|
-
("string", "marker"),
|
39
|
-
],
|
40
|
-
)
|
41
|
-
|
42
|
-
|
43
|
-
PrivateKeyRecord = OpenSSHUserRecordDescriptor(
|
44
|
-
"application/openssh/private_key",
|
45
|
-
[
|
46
|
-
*COMMON_ELLEMENTS,
|
47
|
-
("datetime", "mtime_ts"),
|
48
|
-
("string", "key_format"),
|
49
|
-
("string", "public_key"),
|
50
|
-
("boolean", "encrypted"),
|
51
|
-
],
|
52
|
-
)
|
53
|
-
|
54
|
-
PublicKeyRecord = OpenSSHUserRecordDescriptor(
|
55
|
-
"application/openssh/public_key",
|
56
|
-
[
|
57
|
-
*COMMON_ELLEMENTS,
|
58
|
-
("datetime", "mtime_ts"),
|
59
|
-
("string", "public_key"),
|
60
|
-
],
|
10
|
+
from dissect.target.plugin import export
|
11
|
+
from dissect.target.plugins.apps.ssh.ssh import (
|
12
|
+
AuthorizedKeysRecord,
|
13
|
+
KnownHostRecord,
|
14
|
+
PrivateKeyRecord,
|
15
|
+
PublicKeyRecord,
|
16
|
+
SSHPlugin,
|
61
17
|
)
|
62
18
|
|
63
19
|
|
@@ -72,8 +28,8 @@ def find_sshd_directory(target: Target) -> TargetPath:
|
|
72
28
|
return target.fs.path("/etc/ssh/")
|
73
29
|
|
74
30
|
|
75
|
-
class OpenSSHPlugin(
|
76
|
-
__namespace__ = "
|
31
|
+
class OpenSSHPlugin(SSHPlugin):
|
32
|
+
__namespace__ = "openssh"
|
77
33
|
|
78
34
|
SSHD_DIRECTORIES = ["/sysvol/ProgramData/ssh", "/etc/ssh"]
|
79
35
|
|
@@ -136,7 +92,8 @@ class OpenSSHPlugin(Plugin):
|
|
136
92
|
|
137
93
|
for hostname in hostnames:
|
138
94
|
yield KnownHostRecord(
|
139
|
-
|
95
|
+
host=hostname,
|
96
|
+
port=None,
|
140
97
|
key_type=keytype,
|
141
98
|
public_key=public_key,
|
142
99
|
comment=comment,
|
@@ -3,8 +3,9 @@ from typing import TYPE_CHECKING, Any, Callable, Iterator, Optional, Union
|
|
3
3
|
from dissect.target import Target
|
4
4
|
from dissect.target.exceptions import UnsupportedPluginError
|
5
5
|
from dissect.target.helpers.record import DynamicDescriptor, TargetRecordDescriptor
|
6
|
-
from dissect.target.plugin import
|
6
|
+
from dissect.target.plugin import export
|
7
7
|
from dissect.target.plugins.apps.ssh.openssh import find_sshd_directory
|
8
|
+
from dissect.target.plugins.apps.ssh.ssh import SSHPlugin
|
8
9
|
|
9
10
|
if TYPE_CHECKING:
|
10
11
|
from dissect.target.plugins.general.config import ConfigurationTreePlugin
|
@@ -72,8 +73,8 @@ SSHD_MULTIPLE_DEFINITIONS_ALLOWED_FIELDS = (
|
|
72
73
|
)
|
73
74
|
|
74
75
|
|
75
|
-
class SSHServerPlugin(
|
76
|
-
__namespace__ = "
|
76
|
+
class SSHServerPlugin(SSHPlugin):
|
77
|
+
__namespace__ = "opensshd"
|
77
78
|
|
78
79
|
def __init__(self, target: Target):
|
79
80
|
super().__init__(target)
|
@@ -0,0 +1,236 @@
|
|
1
|
+
import logging
|
2
|
+
from datetime import datetime
|
3
|
+
from pathlib import Path
|
4
|
+
from typing import Iterator, Optional, Union
|
5
|
+
|
6
|
+
from Crypto.PublicKey import ECC, RSA
|
7
|
+
from flow.record.fieldtypes import posix_path, windows_path
|
8
|
+
|
9
|
+
from dissect.target.exceptions import RegistryKeyNotFoundError, UnsupportedPluginError
|
10
|
+
from dissect.target.helpers.descriptor_extensions import UserRecordDescriptorExtension
|
11
|
+
from dissect.target.helpers.fsutil import TargetPath, open_decompress
|
12
|
+
from dissect.target.helpers.record import create_extended_descriptor
|
13
|
+
from dissect.target.helpers.regutil import RegistryKey
|
14
|
+
from dissect.target.plugin import export
|
15
|
+
from dissect.target.plugins.apps.ssh.ssh import KnownHostRecord, SSHPlugin
|
16
|
+
from dissect.target.plugins.general.users import UserDetails
|
17
|
+
|
18
|
+
log = logging.getLogger(__name__)
|
19
|
+
|
20
|
+
PuTTYUserRecordDescriptor = create_extended_descriptor([UserRecordDescriptorExtension])
|
21
|
+
PuTTYSessionRecord = PuTTYUserRecordDescriptor(
|
22
|
+
"application/putty/saved_session",
|
23
|
+
[
|
24
|
+
("datetime", "ts"),
|
25
|
+
("string", "session_name"),
|
26
|
+
("string", "protocol"),
|
27
|
+
("string", "host"),
|
28
|
+
("string", "user"),
|
29
|
+
("varint", "port"),
|
30
|
+
("string", "remote_command"),
|
31
|
+
("string", "port_forward"),
|
32
|
+
("string", "manual_ssh_host_keys"),
|
33
|
+
("path", "path"),
|
34
|
+
],
|
35
|
+
)
|
36
|
+
|
37
|
+
|
38
|
+
class PuTTYPlugin(SSHPlugin):
|
39
|
+
"""Extract artifacts from the PuTTY client.
|
40
|
+
|
41
|
+
NOTE:
|
42
|
+
- Does not parse ``$HOME/.putty/randomseed`` (GNU/Linux)
|
43
|
+
and ``HKCU\\Software\\SimonTatham\\PuTTY\\RandSeedFile`` (Windows)
|
44
|
+
|
45
|
+
Resources:
|
46
|
+
- http://www.chiark.greenend.org.uk/~sgtatham/putty/0.78/puttydoc.txt
|
47
|
+
- http://www.chiark.greenend.org.uk/~sgtatham/putty/faq.html#faq-settings
|
48
|
+
"""
|
49
|
+
|
50
|
+
__namespace__ = "putty"
|
51
|
+
|
52
|
+
def __init__(self, target):
|
53
|
+
super().__init__(target)
|
54
|
+
|
55
|
+
self.regf_installs, self.path_installs = self._detect_putty()
|
56
|
+
|
57
|
+
def _detect_putty(
|
58
|
+
self,
|
59
|
+
) -> tuple[list[set[RegistryKey, Optional[UserDetails]]], list[set[TargetPath, Optional[UserDetails]]]]:
|
60
|
+
regf_installs, path_installs = [], []
|
61
|
+
|
62
|
+
if self.target.has_function("registry"):
|
63
|
+
for key in self.target.registry.keys("HKCU\\Software\\SimonTatham\\PuTTY"):
|
64
|
+
user_details = self.target.registry.get_user_details(key)
|
65
|
+
regf_installs.append((key, user_details))
|
66
|
+
|
67
|
+
for user_details in self.target.user_details.all_with_home():
|
68
|
+
if (putty_path := user_details.home_path.joinpath(".putty")).exists():
|
69
|
+
path_installs.append((putty_path, user_details))
|
70
|
+
|
71
|
+
return regf_installs, path_installs
|
72
|
+
|
73
|
+
def check_compatible(self) -> None:
|
74
|
+
if not any(self.regf_installs + self.path_installs):
|
75
|
+
raise UnsupportedPluginError("No PuTTY installations found")
|
76
|
+
|
77
|
+
@export(record=KnownHostRecord)
|
78
|
+
def known_hosts(self) -> Iterator[KnownHostRecord]:
|
79
|
+
"""Parse PuTTY saved SshHostKeys."""
|
80
|
+
|
81
|
+
for putty_key, user_details in self.regf_installs:
|
82
|
+
yield from self._regf_known_hosts(putty_key, user_details)
|
83
|
+
|
84
|
+
for putty_path, user_details in self.path_installs:
|
85
|
+
yield from self._path_known_hosts(putty_path, user_details)
|
86
|
+
|
87
|
+
def _regf_known_hosts(self, putty_key: RegistryKey, user_details: UserDetails) -> Iterator[KnownHostRecord]:
|
88
|
+
"""Parse PuTTY traces in Windows registry."""
|
89
|
+
|
90
|
+
try:
|
91
|
+
ssh_host_keys = putty_key.subkey("SshHostKeys")
|
92
|
+
except RegistryKeyNotFoundError:
|
93
|
+
return
|
94
|
+
|
95
|
+
for entry in ssh_host_keys.values():
|
96
|
+
key_type, host = entry.name.split("@")
|
97
|
+
port, host = host.split(":")
|
98
|
+
|
99
|
+
yield KnownHostRecord(
|
100
|
+
mtime_ts=ssh_host_keys.ts,
|
101
|
+
host=host,
|
102
|
+
port=port,
|
103
|
+
key_type=key_type,
|
104
|
+
public_key=construct_public_key(key_type, entry.value),
|
105
|
+
comment="",
|
106
|
+
marker=None,
|
107
|
+
path=windows_path(ssh_host_keys.path),
|
108
|
+
_target=self.target,
|
109
|
+
_user=user_details.user if user_details else None,
|
110
|
+
)
|
111
|
+
|
112
|
+
def _path_known_hosts(self, putty_path: TargetPath, user_details: UserDetails) -> Iterator[KnownHostRecord]:
|
113
|
+
"""Parse PuTTY traces in ``.putty`` folders"""
|
114
|
+
ssh_host_keys_path = putty_path.joinpath("sshhostkeys")
|
115
|
+
|
116
|
+
if ssh_host_keys_path.exists():
|
117
|
+
ts = ssh_host_keys_path.stat().st_mtime
|
118
|
+
|
119
|
+
for line in open_decompress(ssh_host_keys_path, "rt"):
|
120
|
+
parts = line.split()
|
121
|
+
key_type, host = parts[0].split("@")
|
122
|
+
port, host = host.split(":")
|
123
|
+
|
124
|
+
yield KnownHostRecord(
|
125
|
+
mtime_ts=ts,
|
126
|
+
host=host,
|
127
|
+
port=port,
|
128
|
+
key_type=key_type,
|
129
|
+
public_key=construct_public_key(key_type, parts[1]),
|
130
|
+
comment="",
|
131
|
+
marker=None,
|
132
|
+
path=posix_path(ssh_host_keys_path),
|
133
|
+
_target=self.target,
|
134
|
+
_user=user_details.user if user_details else None,
|
135
|
+
)
|
136
|
+
|
137
|
+
@export(record=PuTTYSessionRecord)
|
138
|
+
def sessions(self) -> Iterator[PuTTYSessionRecord]:
|
139
|
+
"""Parse PuTTY saved session configuration files."""
|
140
|
+
|
141
|
+
for putty_key, user_details in self.regf_installs:
|
142
|
+
yield from self._regf_sessions(putty_key, user_details)
|
143
|
+
|
144
|
+
for putty_path, user_details in self.path_installs:
|
145
|
+
yield from self._path_sessions(putty_path, user_details)
|
146
|
+
|
147
|
+
def _regf_sessions(self, putty_key: RegistryKey, user_details: UserDetails) -> Iterator[PuTTYSessionRecord]:
|
148
|
+
try:
|
149
|
+
sessions = putty_key.subkey("Sessions")
|
150
|
+
except RegistryKeyNotFoundError:
|
151
|
+
return
|
152
|
+
|
153
|
+
for session in sessions.subkeys():
|
154
|
+
cfg = {s.name: s.value for s in session.values()}
|
155
|
+
yield from self._build_session_record(
|
156
|
+
session.ts, session.name, windows_path(session.path), cfg, user_details
|
157
|
+
)
|
158
|
+
|
159
|
+
def _path_sessions(self, putty_path: TargetPath, user_details: UserDetails) -> Iterator[PuTTYSessionRecord]:
|
160
|
+
sessions_dir = putty_path.joinpath("sessions")
|
161
|
+
if sessions_dir.exists():
|
162
|
+
for session in sessions_dir.glob("*"):
|
163
|
+
if session.is_file():
|
164
|
+
cfg = dict(map(str.strip, line.split("=", maxsplit=1)) for line in session.open("rt").readlines())
|
165
|
+
yield from self._build_session_record(
|
166
|
+
session.stat().st_mtime, session.name, session, cfg, user_details
|
167
|
+
)
|
168
|
+
|
169
|
+
def _build_session_record(
|
170
|
+
self, ts: float, name: Union[float, datetime], source: Path, cfg: dict, user_details: UserDetails
|
171
|
+
) -> PuTTYSessionRecord:
|
172
|
+
host, user = parse_host_user(cfg.get("HostName"), cfg.get("UserName"))
|
173
|
+
|
174
|
+
yield PuTTYSessionRecord(
|
175
|
+
ts=ts,
|
176
|
+
session_name=name,
|
177
|
+
protocol=cfg.get("Protocol"),
|
178
|
+
host=host,
|
179
|
+
user=user,
|
180
|
+
port=cfg.get("PortNumber"),
|
181
|
+
remote_command=cfg.get("RemoteCommand"),
|
182
|
+
port_forward=cfg.get("PortForwardings"),
|
183
|
+
manual_ssh_host_keys=cfg.get("SSHManualHostKeys"),
|
184
|
+
path=source,
|
185
|
+
_target=self.target,
|
186
|
+
_user=user_details.user if user_details else None,
|
187
|
+
)
|
188
|
+
|
189
|
+
|
190
|
+
def parse_host_user(host: str, user: str) -> tuple[str, str]:
|
191
|
+
"""Parse host and user from PuTTY hostname component."""
|
192
|
+
if "@" in host:
|
193
|
+
parsed_user, parsed_host = host.split("@")
|
194
|
+
user = user or parsed_user
|
195
|
+
host = parsed_host
|
196
|
+
|
197
|
+
return host, user
|
198
|
+
|
199
|
+
|
200
|
+
def construct_public_key(key_type: str, iv: str) -> str:
|
201
|
+
"""Returns OpenSSH format public key calculated from PuTTY SshHostKeys format.
|
202
|
+
|
203
|
+
PuTTY stores raw public key components instead of OpenSSH-formatted public keys
|
204
|
+
or fingerprints. With RSA public keys the exponent and modulus are stored.
|
205
|
+
With ECC keys the x and y prime coordinates are stored together with the curve type.
|
206
|
+
|
207
|
+
Currently supports ``ssh-ed25519``, ``ecdsa-sha2-nistp256`` and ``rsa2`` key types.
|
208
|
+
|
209
|
+
NOTE:
|
210
|
+
- Sha256 fingerprints of the reconstructed public keys are currently not generated.
|
211
|
+
- More key types could be supported in the future.
|
212
|
+
|
213
|
+
Resources:
|
214
|
+
- https://github.com/github/putty/blob/master/contrib/kh2reg.py
|
215
|
+
- https://pycryptodome.readthedocs.io/en/latest/src/public_key/rsa.html
|
216
|
+
- https://pycryptodome.readthedocs.io/en/latest/src/public_key/ecc.html
|
217
|
+
- https://github.com/mkorthof/reg2kh
|
218
|
+
"""
|
219
|
+
|
220
|
+
if key_type == "ssh-ed25519":
|
221
|
+
x, y = iv.split(",")
|
222
|
+
key = ECC.construct(curve="ed25519", point_x=int(x, 16), point_y=int(y, 16))
|
223
|
+
return key.public_key().export_key(format="OpenSSH").split()[-1]
|
224
|
+
|
225
|
+
if key_type == "ecdsa-sha2-nistp256":
|
226
|
+
_, x, y = iv.split(",")
|
227
|
+
key = ECC.construct(curve="NIST P-256", point_x=int(x, 16), point_y=int(y, 16))
|
228
|
+
return key.public_key().export_key(format="OpenSSH").split()[-1]
|
229
|
+
|
230
|
+
if key_type == "rsa2":
|
231
|
+
exponent, modulus = iv.split(",")
|
232
|
+
key = RSA.construct((int(modulus, 16), int(exponent, 16)))
|
233
|
+
return key.public_key().export_key(format="OpenSSH").decode("utf-8").split()[-1]
|
234
|
+
|
235
|
+
log.warning("Could not reconstruct public key: type %s not implemented.", key_type)
|
236
|
+
return iv
|
@@ -0,0 +1,58 @@
|
|
1
|
+
from dissect.target.helpers.descriptor_extensions import UserRecordDescriptorExtension
|
2
|
+
from dissect.target.helpers.record import create_extended_descriptor
|
3
|
+
from dissect.target.plugin import NamespacePlugin
|
4
|
+
|
5
|
+
OpenSSHUserRecordDescriptor = create_extended_descriptor([UserRecordDescriptorExtension])
|
6
|
+
|
7
|
+
COMMON_ELLEMENTS = [
|
8
|
+
("string", "key_type"),
|
9
|
+
("string", "comment"),
|
10
|
+
("path", "path"),
|
11
|
+
]
|
12
|
+
|
13
|
+
AuthorizedKeysRecord = OpenSSHUserRecordDescriptor(
|
14
|
+
"application/openssh/authorized_keys",
|
15
|
+
[
|
16
|
+
*COMMON_ELLEMENTS,
|
17
|
+
("string", "public_key"),
|
18
|
+
("string", "options"),
|
19
|
+
],
|
20
|
+
)
|
21
|
+
|
22
|
+
|
23
|
+
KnownHostRecord = OpenSSHUserRecordDescriptor(
|
24
|
+
"application/openssh/known_host",
|
25
|
+
[
|
26
|
+
("datetime", "mtime_ts"),
|
27
|
+
*COMMON_ELLEMENTS,
|
28
|
+
("string", "host"),
|
29
|
+
("varint", "port"),
|
30
|
+
("string", "public_key"),
|
31
|
+
("string", "marker"),
|
32
|
+
],
|
33
|
+
)
|
34
|
+
|
35
|
+
|
36
|
+
PrivateKeyRecord = OpenSSHUserRecordDescriptor(
|
37
|
+
"application/openssh/private_key",
|
38
|
+
[
|
39
|
+
("datetime", "mtime_ts"),
|
40
|
+
*COMMON_ELLEMENTS,
|
41
|
+
("string", "key_format"),
|
42
|
+
("string", "public_key"),
|
43
|
+
("boolean", "encrypted"),
|
44
|
+
],
|
45
|
+
)
|
46
|
+
|
47
|
+
PublicKeyRecord = OpenSSHUserRecordDescriptor(
|
48
|
+
"application/openssh/public_key",
|
49
|
+
[
|
50
|
+
("datetime", "mtime_ts"),
|
51
|
+
*COMMON_ELLEMENTS,
|
52
|
+
("string", "public_key"),
|
53
|
+
],
|
54
|
+
)
|
55
|
+
|
56
|
+
|
57
|
+
class SSHPlugin(NamespacePlugin):
|
58
|
+
__namespace__ = "ssh"
|
@@ -329,7 +329,7 @@ class RegistryPlugin(Plugin):
|
|
329
329
|
@internal
|
330
330
|
def get_user_details(self, key: RegistryKey) -> UserDetails:
|
331
331
|
"""Return user details for the user who owns a registry hive that contains the provided key"""
|
332
|
-
if not key.hive or not key.hive
|
332
|
+
if not key.hive or not getattr(key.hive, "filepath", None):
|
333
333
|
return
|
334
334
|
|
335
335
|
return self._hives_to_users.get(key.hive)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
from typing import Iterator, Optional, Union
|
2
|
+
|
1
3
|
from dissect.esedb.exceptions import Error
|
2
4
|
from dissect.esedb.tools import sru
|
3
5
|
|
@@ -223,6 +225,22 @@ SdpNetworkProviderRecord = TargetRecordDescriptor(
|
|
223
225
|
],
|
224
226
|
)
|
225
227
|
|
228
|
+
SRURecord = Union[
|
229
|
+
NetworkDataRecord,
|
230
|
+
NetworkConnectivityRecord,
|
231
|
+
EnergyEstimatorRecord,
|
232
|
+
EnergyUsageRecord,
|
233
|
+
EnergyUsageLTRecord,
|
234
|
+
ApplicationRecord,
|
235
|
+
PushNotificationRecord,
|
236
|
+
ApplicationTimelineRecord,
|
237
|
+
VfuRecord,
|
238
|
+
SdpVolumeProviderRecord,
|
239
|
+
SdpPhysicalDiskProviderRecord,
|
240
|
+
SdpCpuProviderRecord,
|
241
|
+
SdpNetworkProviderRecord,
|
242
|
+
]
|
243
|
+
|
226
244
|
FIELD_MAPPINGS = {
|
227
245
|
"ActiveAcTime": "active_ac_time",
|
228
246
|
"ActiveDcTime": "active_dc_time",
|
@@ -322,7 +340,7 @@ FIELD_MAPPINGS = {
|
|
322
340
|
}
|
323
341
|
|
324
342
|
|
325
|
-
def transform_app_id(value):
|
343
|
+
def transform_app_id(value: Optional[Union[bytes, str]]) -> Optional[str]:
|
326
344
|
if value is not None:
|
327
345
|
if isinstance(value, bytes):
|
328
346
|
value = value.decode()
|
@@ -364,10 +382,11 @@ class SRUPlugin(Plugin):
|
|
364
382
|
if not self._sru:
|
365
383
|
raise UnsupportedPluginError("No SRUDB found")
|
366
384
|
|
367
|
-
def read_records(self, table_name, record_type):
|
385
|
+
def read_records(self, table_name: str, record_type: SRURecord) -> Iterator[SRURecord]:
|
368
386
|
table = self._sru.get_table(table_name=table_name)
|
369
387
|
if not table:
|
370
|
-
|
388
|
+
self.target.log.warning("Table not found: %s", table_name)
|
389
|
+
return iter(())
|
371
390
|
|
372
391
|
columns = [c.name for c in table.columns]
|
373
392
|
if columns[:4] != ["AutoIncId", "TimeStamp", "AppId", "UserId"]:
|
@@ -392,90 +411,84 @@ class SRUPlugin(Plugin):
|
|
392
411
|
)
|
393
412
|
|
394
413
|
@export(record=NetworkDataRecord)
|
395
|
-
def network_data(self):
|
396
|
-
"""
|
397
|
-
Return the contents of Windows Network Data Usage Monitor table from the SRUDB.dat file.
|
414
|
+
def network_data(self) -> Iterator[NetworkDataRecord]:
|
415
|
+
"""Return the contents of Windows Network Data Usage Monitor table from the SRUDB.dat file.
|
398
416
|
|
399
417
|
Gives insight into the network usage of the system.
|
400
418
|
"""
|
401
419
|
yield from self.read_records("network_data", NetworkDataRecord)
|
402
420
|
|
403
421
|
@export(record=NetworkConnectivityRecord)
|
404
|
-
def network_connectivity(self):
|
405
|
-
"""
|
406
|
-
Return the contents of Windows Network Connectivity Usage Monitor table from the SRUDB.dat file.
|
422
|
+
def network_connectivity(self) -> Iterator[NetworkConnectivityRecord]:
|
423
|
+
"""Return the contents of Windows Network Connectivity Usage Monitor table from the SRUDB.dat file.
|
407
424
|
|
408
425
|
Gives insight into the network connectivity usage of the system.
|
409
426
|
"""
|
410
427
|
yield from self.read_records("network_connectivity", NetworkConnectivityRecord)
|
411
428
|
|
412
429
|
@export(record=EnergyEstimatorRecord)
|
413
|
-
def energy_estimator(self):
|
430
|
+
def energy_estimator(self) -> Iterator[EnergyEstimatorRecord]:
|
414
431
|
"""Return the contents of Energy Estimator table from the SRUDB.dat file."""
|
415
432
|
yield from self.read_records("energy_estimator", EnergyEstimatorRecord)
|
416
433
|
|
417
434
|
@export(record=EnergyUsageRecord)
|
418
|
-
def energy_usage(self):
|
419
|
-
"""
|
420
|
-
Return the contents of Energy Usage Provider table from the SRUDB.dat file.
|
435
|
+
def energy_usage(self) -> Iterator[EnergyUsageRecord]:
|
436
|
+
"""Return the contents of Energy Usage Provider table from the SRUDB.dat file.
|
421
437
|
|
422
438
|
Gives insight into the energy usage of the system.
|
423
439
|
"""
|
424
440
|
yield from self.read_records("energy_usage", EnergyUsageRecord)
|
425
441
|
|
426
442
|
@export(record=EnergyUsageLTRecord)
|
427
|
-
def energy_usage_lt(self):
|
428
|
-
"""
|
429
|
-
Return the contents of Energy Usage Provider Long Term table from the SRUDB.dat file.
|
443
|
+
def energy_usage_lt(self) -> Iterator[EnergyUsageLTRecord]:
|
444
|
+
"""Return the contents of Energy Usage Provider Long Term table from the SRUDB.dat file.
|
430
445
|
|
431
446
|
Gives insight into the energy usage of the system looking over the long term.
|
432
447
|
"""
|
433
448
|
yield from self.read_records("energy_usage_lt", EnergyUsageLTRecord)
|
434
449
|
|
435
450
|
@export(record=ApplicationRecord)
|
436
|
-
def application(self):
|
437
|
-
"""
|
438
|
-
Return the contents of Application Resource Usage table from the SRUDB.dat file.
|
451
|
+
def application(self) -> Iterator[ApplicationRecord]:
|
452
|
+
"""Return the contents of Application Resource Usage table from the SRUDB.dat file.
|
439
453
|
|
440
454
|
Gives insights into the resource usage of applications on the system.
|
441
455
|
"""
|
442
456
|
yield from self.read_records("application", ApplicationRecord)
|
443
457
|
|
444
458
|
@export(record=PushNotificationRecord)
|
445
|
-
def push_notification(self):
|
446
|
-
"""
|
447
|
-
Return the contents of Windows Push Notification Data table from the SRUDB.dat file.
|
459
|
+
def push_notification(self) -> Iterator[PushNotificationRecord]:
|
460
|
+
"""Return the contents of Windows Push Notification Data table from the SRUDB.dat file.
|
448
461
|
|
449
462
|
Gives insight into the notification usage of the system.
|
450
463
|
"""
|
451
464
|
yield from self.read_records("push_notifications", PushNotificationRecord)
|
452
465
|
|
453
466
|
@export(record=ApplicationTimelineRecord)
|
454
|
-
def application_timeline(self):
|
467
|
+
def application_timeline(self) -> Iterator[ApplicationTimelineRecord]:
|
455
468
|
"""Return the contents of App Timeline Provider table from the SRUDB.dat file."""
|
456
469
|
yield from self.read_records("application_timeline", ApplicationTimelineRecord)
|
457
470
|
|
458
471
|
@export(record=VfuRecord)
|
459
|
-
def vfu(self):
|
472
|
+
def vfu(self) -> Iterator[VfuRecord]:
|
460
473
|
"""Return the contents of vfuprov table from the SRUDB.dat file."""
|
461
474
|
yield from self.read_records("vfu", VfuRecord)
|
462
475
|
|
463
476
|
@export(record=SdpVolumeProviderRecord)
|
464
|
-
def sdp_volume_provider(self):
|
477
|
+
def sdp_volume_provider(self) -> Iterator[SdpVolumeProviderRecord]:
|
465
478
|
"""Return the contents of SDP Volume Provider table from the SRUDB.dat file."""
|
466
479
|
yield from self.read_records("sdp_volume_provider", SdpVolumeProviderRecord)
|
467
480
|
|
468
481
|
@export(record=SdpPhysicalDiskProviderRecord)
|
469
|
-
def sdp_physical_disk_provider(self):
|
482
|
+
def sdp_physical_disk_provider(self) -> Iterator[SdpPhysicalDiskProviderRecord]:
|
470
483
|
"""Return the contents of SDP Physical Disk Provider table from the SRUDB.dat file."""
|
471
484
|
yield from self.read_records("sdp_physical_disk_provider", SdpPhysicalDiskProviderRecord)
|
472
485
|
|
473
486
|
@export(record=SdpCpuProviderRecord)
|
474
|
-
def sdp_cpu_provider(self):
|
487
|
+
def sdp_cpu_provider(self) -> Iterator[SdpCpuProviderRecord]:
|
475
488
|
"""Return the contents of SDP CPU Provider table from the SRUDB.dat file."""
|
476
489
|
yield from self.read_records("sdp_cpu_provider", SdpCpuProviderRecord)
|
477
490
|
|
478
491
|
@export(record=SdpNetworkProviderRecord)
|
479
|
-
def sdp_network_provider(self):
|
492
|
+
def sdp_network_provider(self) -> Iterator[SdpNetworkProviderRecord]:
|
480
493
|
"""Return the contents of SDP Network Provider table from the SRUDB.dat file."""
|
481
494
|
yield from self.read_records("sdp_network_provider", SdpNetworkProviderRecord)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: dissect.target
|
3
|
-
Version: 3.15.
|
3
|
+
Version: 3.15.dev14
|
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
|
@@ -117,8 +117,10 @@ dissect/target/plugins/apps/remoteaccess/teamviewer.py,sha256=SiEH36HM2NvdPuCjfL
|
|
117
117
|
dissect/target/plugins/apps/shell/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
118
118
|
dissect/target/plugins/apps/shell/powershell.py,sha256=biPSMRWxPI6kRqP0-75yMtrw0Ti2Bzfl_xI3xbmmF48,2641
|
119
119
|
dissect/target/plugins/apps/ssh/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
120
|
-
dissect/target/plugins/apps/ssh/openssh.py,sha256=
|
121
|
-
dissect/target/plugins/apps/ssh/opensshd.py,sha256=
|
120
|
+
dissect/target/plugins/apps/ssh/openssh.py,sha256=jDNP8aq9JHivosexPlxWRUgeJo1MHclb336dzO1zRJc,7086
|
121
|
+
dissect/target/plugins/apps/ssh/opensshd.py,sha256=DaXKdgGF3GYHHA4buEvphcm6FF4C8YFjgD96Dv6rRnM,5510
|
122
|
+
dissect/target/plugins/apps/ssh/putty.py,sha256=N8ssjutUVN50JNA5fEIVISbP5sJ7bGTFidRbX3uNG5Y,9404
|
123
|
+
dissect/target/plugins/apps/ssh/ssh.py,sha256=uCaoWlT2bgKLUHA1aL6XymJDWJ8JmLsN8PB1C66eidY,1409
|
122
124
|
dissect/target/plugins/apps/vpn/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
123
125
|
dissect/target/plugins/apps/vpn/openvpn.py,sha256=NZeFSFgGAifevGIQBusdbBRFOPxu0584Th8rKE-XSus,6875
|
124
126
|
dissect/target/plugins/apps/vpn/wireguard.py,sha256=45WvCqQQGrG3DVDH5ghcsGpM_BomF4RcTLzcIvnyuNs,6554
|
@@ -237,10 +239,10 @@ dissect/target/plugins/os/windows/locale.py,sha256=yXVdclpUqss9h8Nq7N4kg3OHwWGDf
|
|
237
239
|
dissect/target/plugins/os/windows/notifications.py,sha256=64xHHueHwtJCc8RTAF70oa0RxvqfCu_DBPWRSZBnYZc,17386
|
238
240
|
dissect/target/plugins/os/windows/prefetch.py,sha256=5hRxdIP9sIV5Q9TAScMjLbl_mImZ37abvdE_pAd6rh4,10398
|
239
241
|
dissect/target/plugins/os/windows/recyclebin.py,sha256=4GSj0Q3YvONufnqANbnG0ffiMQyToCiL5s35Wmu4JOQ,4898
|
240
|
-
dissect/target/plugins/os/windows/registry.py,sha256=
|
242
|
+
dissect/target/plugins/os/windows/registry.py,sha256=IBRqltJ_4fZpVuwMVCAH_nS8JUaNVjsC1jh9AZSNHL4,12788
|
241
243
|
dissect/target/plugins/os/windows/sam.py,sha256=Es_8ROQ6R6-akuTtegCdsJHXzZJNhzgoFuS8y9xNN8E,15267
|
242
244
|
dissect/target/plugins/os/windows/services.py,sha256=_6YkuoZD8LUxk72R3n1p1bOBab3A1wszdB1NuPavIGM,6037
|
243
|
-
dissect/target/plugins/os/windows/sru.py,sha256=
|
245
|
+
dissect/target/plugins/os/windows/sru.py,sha256=sOM7CyMkW8XIXzI75GL69WoqUrSK2X99TFIfdQR2D64,17767
|
244
246
|
dissect/target/plugins/os/windows/startupinfo.py,sha256=kl8Y7M4nVfmJ71I33VCegtbHj-ZOeEsYAdlNbgwtUOA,3406
|
245
247
|
dissect/target/plugins/os/windows/syscache.py,sha256=WBDx6rixaVnCRsJHLLN_9YWoTDbzkKGbTnk3XmHSSUM,3443
|
246
248
|
dissect/target/plugins/os/windows/tasks.py,sha256=H0a5Q1DhobaBFtOwqAyJils16hxRRlhtecXSce88fFc,5638
|
@@ -306,10 +308,10 @@ dissect/target/volumes/luks.py,sha256=v_mHW05KM5iG8JDe47i2V4Q9O0r4rnAMA9m_qc9cYw
|
|
306
308
|
dissect/target/volumes/lvm.py,sha256=wwQVR9I3G9YzmY6UxFsH2Y4MXGBcKL9aayWGCDTiWMU,2269
|
307
309
|
dissect/target/volumes/md.py,sha256=j1K1iKmspl0C_OJFc7-Q1BMWN2OCC5EVANIgVlJ_fIE,1673
|
308
310
|
dissect/target/volumes/vmfs.py,sha256=-LoUbn9WNwTtLi_4K34uV_-wDw2W5hgaqxZNj4UmqAQ,1730
|
309
|
-
dissect.target-3.15.
|
310
|
-
dissect.target-3.15.
|
311
|
-
dissect.target-3.15.
|
312
|
-
dissect.target-3.15.
|
313
|
-
dissect.target-3.15.
|
314
|
-
dissect.target-3.15.
|
315
|
-
dissect.target-3.15.
|
311
|
+
dissect.target-3.15.dev14.dist-info/COPYRIGHT,sha256=m-9ih2RVhMiXHI2bf_oNSSgHgkeIvaYRVfKTwFbnJPA,301
|
312
|
+
dissect.target-3.15.dev14.dist-info/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
|
313
|
+
dissect.target-3.15.dev14.dist-info/METADATA,sha256=a7gsrN05qksoHcTNVGfHVUklhofWCTLyKBiNfwWLru0,11107
|
314
|
+
dissect.target-3.15.dev14.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
315
|
+
dissect.target-3.15.dev14.dist-info/entry_points.txt,sha256=tvFPa-Ap-gakjaPwRc6Fl6mxHzxEZ_arAVU-IUYeo_s,447
|
316
|
+
dissect.target-3.15.dev14.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
|
317
|
+
dissect.target-3.15.dev14.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
{dissect.target-3.15.dev12.dist-info → dissect.target-3.15.dev14.dist-info}/entry_points.txt
RENAMED
File without changes
|
File without changes
|