dissect.target 3.20.dev47__py3-none-any.whl → 3.20.dev49__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/os/unix/_os.py +43 -32
- dissect/target/plugins/os/unix/linux/fortios/_os.py +68 -64
- dissect/target/plugins/os/unix/log/utmp.py +47 -68
- dissect/target/plugins/os/windows/_os.py +9 -9
- {dissect.target-3.20.dev47.dist-info → dissect.target-3.20.dev49.dist-info}/METADATA +1 -1
- {dissect.target-3.20.dev47.dist-info → dissect.target-3.20.dev49.dist-info}/RECORD +11 -11
- {dissect.target-3.20.dev47.dist-info → dissect.target-3.20.dev49.dist-info}/COPYRIGHT +0 -0
- {dissect.target-3.20.dev47.dist-info → dissect.target-3.20.dev49.dist-info}/LICENSE +0 -0
- {dissect.target-3.20.dev47.dist-info → dissect.target-3.20.dev49.dist-info}/WHEEL +0 -0
- {dissect.target-3.20.dev47.dist-info → dissect.target-3.20.dev49.dist-info}/entry_points.txt +0 -0
- {dissect.target-3.20.dev47.dist-info → dissect.target-3.20.dev49.dist-info}/top_level.txt +0 -0
@@ -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(
|
@@ -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:
|
@@ -1,17 +1,17 @@
|
|
1
|
-
import
|
1
|
+
from __future__ import annotations
|
2
|
+
|
2
3
|
import ipaddress
|
3
4
|
import struct
|
4
5
|
from collections import namedtuple
|
5
6
|
from typing import Iterator
|
6
7
|
|
7
8
|
from dissect.cstruct import cstruct
|
8
|
-
from dissect.util.stream import BufferedStream
|
9
9
|
from dissect.util.ts import from_unix
|
10
10
|
|
11
11
|
from dissect.target.exceptions import UnsupportedPluginError
|
12
|
-
from dissect.target.helpers.fsutil import TargetPath
|
12
|
+
from dissect.target.helpers.fsutil import TargetPath, open_decompress
|
13
13
|
from dissect.target.helpers.record import TargetRecordDescriptor
|
14
|
-
from dissect.target.plugin import
|
14
|
+
from dissect.target.plugin import Plugin, alias, export
|
15
15
|
from dissect.target.target import Target
|
16
16
|
|
17
17
|
UTMP_FIELDS = [
|
@@ -27,16 +27,12 @@ UTMP_FIELDS = [
|
|
27
27
|
|
28
28
|
BtmpRecord = TargetRecordDescriptor(
|
29
29
|
"linux/log/btmp",
|
30
|
-
|
31
|
-
*UTMP_FIELDS,
|
32
|
-
],
|
30
|
+
UTMP_FIELDS,
|
33
31
|
)
|
34
32
|
|
35
33
|
WtmpRecord = TargetRecordDescriptor(
|
36
34
|
"linux/log/wtmp",
|
37
|
-
|
38
|
-
*UTMP_FIELDS,
|
39
|
-
],
|
35
|
+
UTMP_FIELDS,
|
40
36
|
)
|
41
37
|
|
42
38
|
utmp_def = """
|
@@ -104,24 +100,13 @@ UTMP_ENTRY = namedtuple(
|
|
104
100
|
class UtmpFile:
|
105
101
|
"""utmp maintains a full accounting of the current status of the system"""
|
106
102
|
|
107
|
-
def __init__(self,
|
108
|
-
self.fh =
|
109
|
-
|
110
|
-
if "gz" in path:
|
111
|
-
self.compressed = True
|
112
|
-
else:
|
113
|
-
self.compressed = False
|
103
|
+
def __init__(self, path: TargetPath):
|
104
|
+
self.fh = open_decompress(path, "rb")
|
114
105
|
|
115
106
|
def __iter__(self):
|
116
|
-
if self.compressed:
|
117
|
-
gzip_entry = BufferedStream(gzip.open(self.fh, mode="rb"))
|
118
|
-
byte_stream = gzip_entry
|
119
|
-
else:
|
120
|
-
byte_stream = self.fh
|
121
|
-
|
122
107
|
while True:
|
123
108
|
try:
|
124
|
-
entry = c_utmp.entry(
|
109
|
+
entry = c_utmp.entry(self.fh)
|
125
110
|
|
126
111
|
r_type = ""
|
127
112
|
if entry.ut_type in c_utmp.Type:
|
@@ -151,7 +136,7 @@ class UtmpFile:
|
|
151
136
|
# ut_addr_v6 is parsed as IPv4 address. This could not lead to incorrect results.
|
152
137
|
ut_addr = ipaddress.ip_address(struct.pack("<i", entry.ut_addr_v6[0]))
|
153
138
|
|
154
|
-
|
139
|
+
yield UTMP_ENTRY(
|
155
140
|
ts=from_unix(entry.ut_tv.tv_sec),
|
156
141
|
ut_type=r_type,
|
157
142
|
ut_pid=entry.ut_pid,
|
@@ -162,7 +147,6 @@ class UtmpFile:
|
|
162
147
|
ut_addr=ut_addr,
|
163
148
|
)
|
164
149
|
|
165
|
-
yield utmp_entry
|
166
150
|
except EOFError:
|
167
151
|
break
|
168
152
|
|
@@ -170,17 +154,28 @@ class UtmpFile:
|
|
170
154
|
class UtmpPlugin(Plugin):
|
171
155
|
"""Unix utmp log plugin."""
|
172
156
|
|
173
|
-
|
174
|
-
|
157
|
+
def __init__(self, target: Target):
|
158
|
+
super().__init__(target)
|
159
|
+
self.btmp_paths = list(self.target.fs.path("/").glob("var/log/btmp*"))
|
160
|
+
self.wtmp_paths = list(self.target.fs.path("/").glob("var/log/wtmp*"))
|
161
|
+
self.utmp_paths = list(self.target.fs.path("/").glob("var/run/utmp*"))
|
175
162
|
|
176
163
|
def check_compatible(self) -> None:
|
177
|
-
if not self.
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
164
|
+
if not any(self.btmp_paths + self.wtmp_paths + self.utmp_paths):
|
165
|
+
raise UnsupportedPluginError("No wtmp and/or btmp log files found")
|
166
|
+
|
167
|
+
def _build_record(self, record: TargetRecordDescriptor, entry: UTMP_ENTRY) -> Iterator[BtmpRecord | WtmpRecord]:
|
168
|
+
return record(
|
169
|
+
ts=entry.ts,
|
170
|
+
ut_type=entry.ut_type,
|
171
|
+
ut_pid=entry.ut_pid,
|
172
|
+
ut_user=entry.ut_user,
|
173
|
+
ut_line=entry.ut_line,
|
174
|
+
ut_id=entry.ut_id,
|
175
|
+
ut_host=entry.ut_host,
|
176
|
+
ut_addr=entry.ut_addr,
|
177
|
+
_target=self.target,
|
178
|
+
)
|
184
179
|
|
185
180
|
@export(record=BtmpRecord)
|
186
181
|
def btmp(self) -> Iterator[BtmpRecord]:
|
@@ -192,26 +187,18 @@ class UtmpPlugin(Plugin):
|
|
192
187
|
- https://en.wikipedia.org/wiki/Utmp
|
193
188
|
- https://www.thegeekdiary.com/what-is-the-purpose-of-utmp-wtmp-and-btmp-files-in-linux/
|
194
189
|
"""
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
for entry in btmp:
|
200
|
-
yield BtmpRecord(
|
201
|
-
ts=entry.ts,
|
202
|
-
ut_type=entry.ut_type,
|
203
|
-
ut_pid=entry.ut_pid,
|
204
|
-
ut_user=entry.ut_user,
|
205
|
-
ut_line=entry.ut_line,
|
206
|
-
ut_id=entry.ut_id,
|
207
|
-
ut_host=entry.ut_host,
|
208
|
-
ut_addr=entry.ut_addr,
|
209
|
-
_target=self.target,
|
210
|
-
)
|
190
|
+
for path in self.btmp_paths:
|
191
|
+
if not path.is_file():
|
192
|
+
self.target.log.warning("Unable to parse btmp file: %s is not a file", path)
|
193
|
+
continue
|
211
194
|
|
195
|
+
for entry in UtmpFile(path):
|
196
|
+
yield self._build_record(BtmpRecord, entry)
|
197
|
+
|
198
|
+
@alias("utmp")
|
212
199
|
@export(record=WtmpRecord)
|
213
200
|
def wtmp(self) -> Iterator[WtmpRecord]:
|
214
|
-
"""
|
201
|
+
"""Yield contents of wtmp log files.
|
215
202
|
|
216
203
|
The wtmp file contains the historical data of the utmp file. The utmp file contains information about users
|
217
204
|
logins at which terminals, logouts, system events and current status of the system, system boot time
|
@@ -220,19 +207,11 @@ class UtmpPlugin(Plugin):
|
|
220
207
|
References:
|
221
208
|
- https://www.thegeekdiary.com/what-is-the-purpose-of-utmp-wtmp-and-btmp-files-in-linux/
|
222
209
|
"""
|
223
|
-
|
224
|
-
for
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
ut_pid=entry.ut_pid,
|
232
|
-
ut_user=entry.ut_user,
|
233
|
-
ut_line=entry.ut_line,
|
234
|
-
ut_id=entry.ut_id,
|
235
|
-
ut_host=entry.ut_host,
|
236
|
-
ut_addr=entry.ut_addr,
|
237
|
-
_target=self.target,
|
238
|
-
)
|
210
|
+
|
211
|
+
for path in self.wtmp_paths + self.utmp_paths:
|
212
|
+
if not path.is_file():
|
213
|
+
self.target.log.warning("Unable to parse wtmp file: %s is not a file", path)
|
214
|
+
continue
|
215
|
+
|
216
|
+
for entry in UtmpFile(path):
|
217
|
+
yield self._build_record(WtmpRecord, entry)
|
@@ -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"
|
@@ -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,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: dissect.target
|
3
|
-
Version: 3.20.
|
3
|
+
Version: 3.20.dev49
|
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
|
@@ -196,7 +196,7 @@ dissect/target/plugins/general/scrape.py,sha256=Fz7BNXflvuxlnVulyyDhLpyU8D_hJdH6
|
|
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
|
@@ -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
|
@@ -272,9 +272,9 @@ dissect/target/plugins/os/unix/log/auth.py,sha256=9NJvlo7Vbsp_ENJFpKd04PH_sUuOy6
|
|
272
272
|
dissect/target/plugins/os/unix/log/journal.py,sha256=xe8p8MM_95uYjFNzNSP5IsoIthJtxwFEDicYR42RYAI,17681
|
273
273
|
dissect/target/plugins/os/unix/log/lastlog.py,sha256=Wr3-2n1-GwckN9mSx-yM55N6_L0PQyx6TGHoEvuc6c0,2515
|
274
274
|
dissect/target/plugins/os/unix/log/messages.py,sha256=XtjZ0a2budgQm_K5JT3fMf7JcjuD0AelcD3zOFN2xpI,5732
|
275
|
-
dissect/target/plugins/os/unix/log/utmp.py,sha256=
|
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=WoXSq-HVOKqI9p3CMXrOFAjsi9MlVmxE2JVHzN7RH0s,12441
|
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
|
@@ -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.dev49.dist-info/COPYRIGHT,sha256=m-9ih2RVhMiXHI2bf_oNSSgHgkeIvaYRVfKTwFbnJPA,301
|
382
|
+
dissect.target-3.20.dev49.dist-info/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
|
383
|
+
dissect.target-3.20.dev49.dist-info/METADATA,sha256=cyNr191yNPZoEE1uGY1DqaExAYn8H9NCuOL2OUWn1oM,12897
|
384
|
+
dissect.target-3.20.dev49.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
|
385
|
+
dissect.target-3.20.dev49.dist-info/entry_points.txt,sha256=BWuxAb_6AvUAQpIQOQU0IMTlaF6TDht2AIZK8bHd-zE,492
|
386
|
+
dissect.target-3.20.dev49.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
|
387
|
+
dissect.target-3.20.dev49.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
{dissect.target-3.20.dev47.dist-info → dissect.target-3.20.dev49.dist-info}/entry_points.txt
RENAMED
File without changes
|
File without changes
|