diff --git a/dissect/database/ese/ntds/objects/user.py b/dissect/database/ese/ntds/objects/user.py index 150c748..4900262 100644 --- a/dissect/database/ese/ntds/objects/user.py +++ b/dissect/database/ese/ntds/objects/user.py @@ -3,7 +3,7 @@ from typing import TYPE_CHECKING from dissect.database.ese.ntds.objects.organizationalperson import OrganizationalPerson -from dissect.database.ese.ntds.util import UserAccountControl +from dissect.database.ese.ntds.util import SAMAccountType, UserAccountControl if TYPE_CHECKING: from collections.abc import Iterator @@ -29,6 +29,11 @@ def sam_account_name(self) -> str: """Return the user's sAMAccountName.""" return self.get("sAMAccountName") + @property + def sam_account_type(self) -> SAMAccountType: + """Return the user's sAMAccountType.""" + return self.get("sAMAccountType") + @property def primary_group_id(self) -> str | None: """Return the user's primaryGroupID.""" diff --git a/dissect/database/ese/ntds/util.py b/dissect/database/ese/ntds/util.py index db0b22d..6587b77 100644 --- a/dissect/database/ese/ntds/util.py +++ b/dissect/database/ese/ntds/util.py @@ -1,7 +1,7 @@ from __future__ import annotations import struct -from enum import IntFlag +from enum import IntEnum, IntFlag from typing import TYPE_CHECKING, Any from uuid import UUID @@ -136,6 +136,19 @@ class UserAccountControl(IntFlag): TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION = 0x01000000 +class SAMAccountType(IntEnum): + SAM_DOMAIN_OBJECT = 0x0 + SAM_GROUP_OBJECT = 0x10000000 + SAM_NON_SECURITY_GROUP_OBJECT = 0x10000001 + SAM_ALIAS_OBJECT = 0x20000000 + SAM_NON_SECURITY_ALIAS_OBJECT = 0x20000001 + SAM_USER_OBJECT = 0x30000000 + SAM_MACHINE_ACCOUNT = 0x30000001 + SAM_TRUST_ACCOUNT = 0x30000002 + SAM_APP_BASIC_GROUP = 0x40000000 + SAM_APP_QUERY_GROUP = 0x40000001 + + class SearchFlags(IntFlag): Indexed = 0x00000001 ContainerIndexed = 0x00000002 @@ -274,6 +287,7 @@ def _decode_supplemental_credentials(db: Database, value: bytes) -> dict[str, by "instanceType": (lambda db, value: int(value), lambda db, value: InstanceType(int(value))), "systemFlags": (lambda db, value: int(value), lambda db, value: SystemFlags(int(value))), "searchFlags": (lambda db, value: int(value), lambda db, value: SearchFlags(int(value))), + "sAMAccountType": (lambda db, value: int(value), lambda db, value: SAMAccountType(int(value))), "userAccountControl": (lambda db, value: int(value), lambda db, value: UserAccountControl(int(value))), "objectGUID": (lambda db, value: value.bytes_le, lambda db, value: UUID(bytes_le=value)), "badPasswordTime": (None, lambda db, value: wintimestamp(int(value))), diff --git a/tests/ese/ntds/test_ntds.py b/tests/ese/ntds/test_ntds.py index c06e5c2..6c18e3e 100644 --- a/tests/ese/ntds/test_ntds.py +++ b/tests/ese/ntds/test_ntds.py @@ -5,6 +5,7 @@ import pytest from dissect.database.ese.ntds.objects import Computer, Group, Server, SubSchema, User +from dissect.database.ese.ntds.util import SAMAccountType if TYPE_CHECKING: from dissect.database.ese.ntds import NTDS @@ -87,6 +88,7 @@ def test_users(goad: NTDS) -> None: ] assert users[3].distinguished_name == "CN=BRANDON.STARK,CN=USERS,DC=NORTH,DC=SEVENKINGDOMS,DC=LOCAL" + assert users[3].sam_account_type == SAMAccountType.SAM_USER_OBJECT assert users[3].cn == "brandon.stark" assert users[3].city == "Winterfell" @@ -105,6 +107,7 @@ def test_computers(goad: NTDS) -> None: computers: list[Computer] = sorted(goad.computers(), key=lambda x: x.name) assert len(computers) == 3 assert computers[0].name == "CASTELBLACK" + assert computers[0].sam_account_type == SAMAccountType.SAM_MACHINE_ACCOUNT assert computers[1].name == "KINGSLANDING" assert computers[2].name == "WINTERFELL"