Skip to content

Commit 8911ec6

Browse files
JSCU-CNISchamper
andauthored
Fix inconsistent duplicate field mappings in various plugins (part 2) (#1189)
Co-authored-by: Erik Schamper <1254028+Schamper@users.noreply.github.com>
1 parent a7ab2b4 commit 8911ec6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+409
-144
lines changed

dissect/target/helpers/regutil.py

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import fnmatch
66
import re
77
from collections import defaultdict
8-
from enum import IntEnum
98
from functools import cached_property
109
from io import BytesIO
1110
from typing import TYPE_CHECKING, BinaryIO, NewType, TextIO, Union
@@ -17,6 +16,7 @@
1716
RegistryKeyNotFoundError,
1817
RegistryValueNotFoundError,
1918
)
19+
from dissect.target.helpers.utils import IntEnumMissing
2020

2121
if TYPE_CHECKING:
2222
from collections.abc import Iterator
@@ -33,7 +33,7 @@
3333
"""The possible value types that can be returned from the registry."""
3434

3535

36-
class RegistryValueType(IntEnum):
36+
class RegistryValueType(IntEnumMissing):
3737
"""Registry value types as defined in ``winnt.h``.
3838
3939
Resources:
@@ -54,14 +54,6 @@ class RegistryValueType(IntEnum):
5454
RESOURCE_REQUIREMENTS_LIST = c_regf.REG_RESOURCE_REQUIREMENTS_LIST
5555
QWORD = c_regf.REG_QWORD
5656

57-
@classmethod
58-
def _missing_(cls, value: int) -> IntEnum:
59-
# Allow values other than defined members
60-
member = int.__new__(cls, value)
61-
member._name_ = None
62-
member._value_ = value
63-
return member
64-
6557

6658
class RegistryHive:
6759
"""Base class for registry hives."""

dissect/target/helpers/utils.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import re
55
import urllib.parse
66
from datetime import datetime, timezone, tzinfo
7-
from enum import Enum
7+
from enum import Enum, IntEnum
88
from typing import TYPE_CHECKING, BinaryIO, TypeVar
99

1010
from dissect.util.ts import from_unix
@@ -53,6 +53,17 @@ class StrEnum(str, Enum):
5353
"""Sortable and serializible string-based enum."""
5454

5555

56+
class IntEnumMissing(IntEnum):
57+
"""Integer-based enum that allows for values other than defined members."""
58+
59+
@classmethod
60+
def _missing_(cls, value: int) -> IntEnum:
61+
member = int.__new__(cls, value)
62+
member._name_ = str(value)
63+
member._value_ = value
64+
return member
65+
66+
5667
def parse_path_uri(path: Path) -> tuple[str | None, str | None, str | None]:
5768
if path is None:
5869
return None, None, None

dissect/target/plugins/apps/av/symantec.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@
2727
("path", "source_file"),
2828
("string", "action_taken"),
2929
("string", "virus_type"),
30-
("varint", "scan_id"),
31-
("varint", "quarantine_id"),
30+
("string", "scan_id"),
31+
("string", "quarantine_id"),
3232
("varint", "virus_id"),
3333
("varint", "depth"),
3434
("boolean", "still_infected"),
@@ -312,7 +312,7 @@ def logs(self) -> Iterator[SEPLogRecord]:
312312
source_file (path): File that contains the virus.
313313
action_taken (string): Action taken by SEP.
314314
virus_type (string): Description of the type of virus.
315-
scan_id (varint): ID of the scan associated with the event.
315+
scan_id (string): ID of the scan associated with the event.
316316
event_data (string): String or bytes from a virus event.
317317
quarantine_id (varint): ID associated with the quarantined virus.
318318
still_infected (boolean): Whether the system is still infected.

dissect/target/plugins/apps/browser/browser.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,15 @@
1919
("path", "path"),
2020
("uri", "url"),
2121
("filesize", "size"),
22-
("varint", "state"),
22+
("string", "state"),
2323
("path", "source"),
2424
]
2525

2626
GENERIC_EXTENSION_RECORD_FIELDS = [
2727
("datetime", "ts_install"),
2828
("datetime", "ts_update"),
2929
("string", "browser"),
30-
("string", "id"),
30+
("string", "extension_id"),
3131
("string", "name"),
3232
("string", "short_name"),
3333
("string", "default_title"),
@@ -58,14 +58,14 @@
5858
GENERIC_HISTORY_RECORD_FIELDS = [
5959
("datetime", "ts"),
6060
("string", "browser"),
61-
("string", "id"),
61+
("varint", "id"),
6262
("uri", "url"),
6363
("string", "title"),
6464
("string", "description"),
6565
("string", "rev_host"),
6666
("varint", "visit_type"),
6767
("varint", "visit_count"),
68-
("string", "hidden"),
68+
("boolean", "hidden"),
6969
("string", "typed"),
7070
("varint", "session"),
7171
("varint", "from_visit"),

dissect/target/plugins/apps/browser/chromium.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,16 @@
7171
"""
7272
c_elevation = cstruct(endian="<").load(elevation_def)
7373

74+
# Resources:
75+
# - https://github.com/chromium/chromium/blob/main/components/download/public/common/download_item.h
76+
DOWNLOAD_STATES = {
77+
0: "in_progress",
78+
1: "complete",
79+
2: "cancelled",
80+
3: "interrupted",
81+
4: "interrupted", # Older versions of Chromium can have DownloadState value 4 as interrupted.
82+
}
83+
7484

7585
class ChromiumMixin:
7686
"""Mixin class with methods for Chromium-based browsers."""
@@ -363,6 +373,10 @@ def downloads(self, browser_name: str | None = None) -> Iterator[BrowserDownload
363373
url = download_chain[-1].url
364374
url = try_idna(url)
365375

376+
# https://github.com/chromium/chromium/blob/main/components/download/public/common/download_item.h
377+
if state := row.get("state"):
378+
state = DOWNLOAD_STATES.get(state)
379+
366380
yield self.BrowserDownloadRecord(
367381
ts_start=webkittimestamp(row.start_time),
368382
ts_end=webkittimestamp(row.end_time) if row.end_time else None,
@@ -374,7 +388,7 @@ def downloads(self, browser_name: str | None = None) -> Iterator[BrowserDownload
374388
url=url,
375389
size=row.get("total_bytes"),
376390
mime_type=row.get("mime_type"),
377-
state=row.get("state"),
391+
state=state,
378392
source=db_file,
379393
_target=self.target,
380394
_user=user.user,
@@ -453,7 +467,7 @@ def extensions(self, browser_name: str | None = None) -> Iterator[BrowserExtensi
453467
ts_install=ts_install,
454468
ts_update=ts_update,
455469
browser=browser_name,
456-
id=extension_id,
470+
extension_id=extension_id,
457471
name=name,
458472
short_name=short_name,
459473
default_title=default_title,
@@ -643,7 +657,7 @@ def decryption_keys(self, local_state_path: TargetPath, username: str) -> Chromi
643657
cipher = ChaCha20_Poly1305.new(key=key, nonce=data.iv)
644658

645659
else:
646-
raise ValueError("Unsupported ElevationService key flag {data.flag!r}") # noqa: TRY301
660+
raise ValueError(f"Unsupported ElevationService key flag {data.flag!r}") # noqa: TRY301
647661

648662
aes_key = cipher.decrypt_and_verify(data.ciphertext, data.mac_tag)
649663

dissect/target/plugins/apps/browser/firefox.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@ def extensions(self) -> Iterator[BrowserExtensionRecord]:
403403
ts_install=from_unix_ms(extension.get("installDate", 0)),
404404
ts_update=from_unix_ms(extension.get("updateDate", 0)),
405405
browser="firefox",
406-
id=extension.get("id"),
406+
extension_id=extension.get("id"),
407407
name=(extension.get("defaultLocale", {}) or {}).get("name"),
408408
short_name=None,
409409
default_title=None,

dissect/target/plugins/apps/vpn/wireguard.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@
2424
("string", "private_key"),
2525
("varint", "listen_port"),
2626
("string", "fw_mark"),
27-
("string", "dns"),
28-
("varint", "table"),
27+
("net.ipaddress[]", "dns"),
28+
("string", "table"),
2929
("varint", "mtu"),
3030
("string", "preup"),
3131
("string", "postup"),
@@ -55,6 +55,7 @@ class WireGuardPlugin(Plugin):
5555
References:
5656
- https://manpages.debian.org/testing/wireguard-tools/wg.8.en.html#CONFIGURATION_FILE_FORMAT
5757
- https://github.com/pirate/wireguard-docs
58+
- https://wiresock.net/documentation/wireguard/config.html
5859
"""
5960

6061
__namespace__ = "wireguard"
@@ -121,7 +122,7 @@ def config(self) -> Iterator[WireGuardInterfaceRecord | WireGuardPeerRecord]:
121122
listen_port=config_dict("ListenPort"),
122123
private_key=config_dict("PrivateKey"),
123124
fw_mark=config_dict("FwMark"),
124-
dns=config_dict("DNS"),
125+
dns=[ip.strip() for ip in config_dict("DNS").split(",")] if config_dict("DNS") else None,
125126
table=config_dict("Table"),
126127
mtu=config_dict("MTU"),
127128
preup=config_dict("PreUp"),

dissect/target/plugins/filesystem/ntfs/usnjrnl.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
[
1818
("datetime", "ts"),
1919
("varint", "usn"),
20-
("string", "segment"),
20+
("string", "segment_id"),
2121
("path", "path"),
2222
("string", "reason"),
2323
("uint32", "security_id"),
@@ -82,13 +82,13 @@ def usnjrnl(self) -> Iterator[UsnjrnlRecord]:
8282
segment = segment_reference(record.record.FileReferenceNumber)
8383
yield UsnjrnlRecord(
8484
ts=ts,
85-
segment=f"{segment}#{record.FileReferenceNumber.SequenceNumber}",
86-
path=self.target.fs.path(path),
8785
usn=record.Usn,
86+
segment_id=f"{segment}#{record.FileReferenceNumber.SequenceNumber}",
87+
path=self.target.fs.path(path),
8888
reason=str(record.Reason).replace("USN_REASON.", ""),
89-
attr=str(record.FileAttributes).replace("FILE_ATTRIBUTE.", ""),
90-
source=str(record.SourceInfo).replace("USN_SOURCE.", ""),
9189
security_id=record.SecurityId,
90+
source=str(record.SourceInfo).replace("USN_SOURCE.", ""),
91+
attr=str(record.FileAttributes).replace("FILE_ATTRIBUTE.", ""),
9292
major=record.MajorVersion,
9393
minor=record.MinorVersion,
9494
_target=target,

dissect/target/plugins/os/unix/linux/sockets.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from dissect.target.target import Target
1919

2020
NetSocketRecord = TargetRecordDescriptor(
21-
"linux/proc/sockets",
21+
"linux/proc/socket/net",
2222
[
2323
("string", "protocol"),
2424
("uint32", "rx_queue"),
@@ -37,11 +37,11 @@
3737
)
3838

3939
UnixSocketRecord = TargetRecordDescriptor(
40-
"linux/proc/sockets",
40+
"linux/proc/socket/unix",
4141
[
4242
("string", "protocol"),
4343
("uint32", "ref"),
44-
("string", "flags"),
44+
("string", "socket_flags"),
4545
("string", "type"),
4646
("string", "state"),
4747
("uint32", "inode"),
@@ -50,17 +50,17 @@
5050
)
5151

5252
PacketSocketRecord = TargetRecordDescriptor(
53-
"linux/proc/sockets",
53+
"linux/proc/socket/packet",
5454
[
5555
("string", "protocol"),
5656
("string", "protocol_type"),
57-
("string", "sk"),
57+
("uint32", "socket_type"),
58+
("uint32", "sk"),
5859
("uint32", "ref"),
59-
("uint32", "type"),
6060
("uint32", "iface"),
6161
("uint32", "r"),
6262
("uint32", "rmem"),
63-
("uint32", "user"),
63+
("uint32", "uid"),
6464
("string", "owner"),
6565
("uint32", "inode"),
6666
("uint32", "pid"),
@@ -93,14 +93,14 @@ def packet(self) -> Iterator[PacketSocketRecord]:
9393
9494
hostname (string): The target hostname.
9595
domain (string): The target domain.
96-
protocol (int): The captured protocol i.e. 0003 is ETH_P_ALL
97-
protocol_type (str): The canonical name of the captured protocol.
98-
sk (string): The socket number.
99-
type (int): The integer type of the socket (packet).
96+
protocol (str): packet.
97+
protocol_type (str): The canonical name of the captured protocol i.e. ETH_P_ALL.
98+
socket_type (int): The integer type of the socket (packet).
99+
sk (int): The socket number.
100100
iface (int): The interface index of the socket.
101101
r (int): The number of bytes that have been received by the socket and are waiting to be processed.
102102
rmem (int): The size of the receive buffer for the socket.
103-
user (int): The user ID of the process that created the socket.
103+
uid (int): The user ID of the process that created the socket.
104104
inode (int): The inode associated to the socket.
105105
pid (int): The pid associated with this socket.
106106
name (string): The process name associated to this socket.
@@ -120,7 +120,7 @@ def unix(self) -> Iterator[UnixSocketRecord]:
120120
hostname (string): The target hostname.
121121
domain (string): The target domain.
122122
protocol (string): The protocol used by the socket.
123-
flags (bytes): The flags associated with the socket.
123+
socket_flags (bytes): The flags associated with the socket.
124124
type (string): The stream type of the socket.
125125
state (string): The state of the socket.
126126
inode (int): The inode associated to the socket.
@@ -210,7 +210,7 @@ def _generate_unix_socket_record(self, data: UnixSocket) -> UnixSocketRecord:
210210
return UnixSocketRecord(
211211
protocol=data.protocol_string,
212212
ref=data.ref,
213-
flags=data.flags,
213+
socket_flags=data.flags,
214214
type=data.stream_type_string,
215215
state=data.state_string,
216216
inode=data.inode,
@@ -222,13 +222,13 @@ def _generate_packet_socket_record(self, data: PacketSocket) -> PacketSocketReco
222222
return PacketSocketRecord(
223223
protocol=data.protocol_string,
224224
protocol_type=data.protocol_type,
225+
socket_type=data.type,
225226
sk=data.sk,
226227
ref=data.ref,
227-
type=data.type,
228228
iface=data.iface,
229229
r=data.r,
230230
rmem=data.rmem,
231-
user=data.user,
231+
uid=data.user,
232232
inode=data.inode,
233233
pid=data.pid,
234234
name=data.name,

0 commit comments

Comments
 (0)