dissect.database 1.2.dev8__py3-none-any.whl → 1.2.dev9__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/database/ese/ntds/database.py +6 -6
- dissect/database/ese/ntds/ntds.py +12 -3
- dissect/database/ese/ntds/objects/attributeschema.py +15 -0
- dissect/database/ese/ntds/objects/certificationauthority.py +5 -0
- dissect/database/ese/ntds/objects/computer.py +15 -0
- dissect/database/ese/ntds/objects/configuration.py +5 -0
- dissect/database/ese/ntds/objects/crossref.py +14 -0
- dissect/database/ese/ntds/objects/crossrefcontainer.py +5 -0
- dissect/database/ese/ntds/objects/domaindns.py +5 -0
- dissect/database/ese/ntds/objects/group.py +10 -0
- dissect/database/ese/ntds/objects/grouppolicycontainer.py +5 -0
- dissect/database/ese/ntds/objects/ntdsdsa.py +5 -0
- dissect/database/ese/ntds/objects/object.py +36 -10
- dissect/database/ese/ntds/objects/organizationalperson.py +16 -1
- dissect/database/ese/ntds/objects/organizationalunit.py +26 -1
- dissect/database/ese/ntds/objects/person.py +10 -0
- dissect/database/ese/ntds/objects/pkienrollmentservice.py +5 -0
- dissect/database/ese/ntds/objects/server.py +5 -0
- dissect/database/ese/ntds/objects/site.py +16 -1
- dissect/database/ese/ntds/objects/top.py +5 -0
- dissect/database/ese/ntds/objects/trusteddomain.py +36 -0
- dissect/database/ese/ntds/objects/user.py +71 -4
- dissect/database/ese/ntds/schema.py +3 -3
- dissect/database/ese/ntds/util.py +103 -33
- {dissect_database-1.2.dev8.dist-info → dissect_database-1.2.dev9.dist-info}/METADATA +1 -1
- {dissect_database-1.2.dev8.dist-info → dissect_database-1.2.dev9.dist-info}/RECORD +31 -31
- {dissect_database-1.2.dev8.dist-info → dissect_database-1.2.dev9.dist-info}/WHEEL +0 -0
- {dissect_database-1.2.dev8.dist-info → dissect_database-1.2.dev9.dist-info}/entry_points.txt +0 -0
- {dissect_database-1.2.dev8.dist-info → dissect_database-1.2.dev9.dist-info}/licenses/COPYRIGHT +0 -0
- {dissect_database-1.2.dev8.dist-info → dissect_database-1.2.dev9.dist-info}/licenses/LICENSE +0 -0
- {dissect_database-1.2.dev8.dist-info → dissect_database-1.2.dev9.dist-info}/top_level.txt +0 -0
|
@@ -11,7 +11,7 @@ from dissect.database.ese.ntds.pek import PEK
|
|
|
11
11
|
from dissect.database.ese.ntds.query import Query
|
|
12
12
|
from dissect.database.ese.ntds.schema import Schema
|
|
13
13
|
from dissect.database.ese.ntds.sd import SecurityDescriptor
|
|
14
|
-
from dissect.database.ese.ntds.util import DN,
|
|
14
|
+
from dissect.database.ese.ntds.util import DN, DatabaseFlag, SearchFlag, encode_value
|
|
15
15
|
|
|
16
16
|
if TYPE_CHECKING:
|
|
17
17
|
from collections.abc import Iterator
|
|
@@ -44,14 +44,14 @@ class Database:
|
|
|
44
44
|
self.data._make_dn.cache_clear()
|
|
45
45
|
|
|
46
46
|
@cached_property
|
|
47
|
-
def flags(self) ->
|
|
47
|
+
def flags(self) -> DatabaseFlag | None:
|
|
48
48
|
"""Return the database flags."""
|
|
49
49
|
if self.hiddeninfo is None:
|
|
50
50
|
return None
|
|
51
51
|
|
|
52
|
-
result =
|
|
52
|
+
result = DatabaseFlag(0)
|
|
53
53
|
flags = self.hiddeninfo.get("flags_col")
|
|
54
|
-
for idx, member in enumerate(
|
|
54
|
+
for idx, member in enumerate(DatabaseFlag.__members__.values()):
|
|
55
55
|
if flags[idx] == ord(b"1"):
|
|
56
56
|
result = member if result is None else result | member
|
|
57
57
|
|
|
@@ -256,9 +256,9 @@ class DataTable:
|
|
|
256
256
|
if schema.search_flags is None:
|
|
257
257
|
raise ValueError(f"Attribute is not indexed: {attribute!r}")
|
|
258
258
|
|
|
259
|
-
if
|
|
259
|
+
if SearchFlag.Indexed in schema.search_flags:
|
|
260
260
|
name = f"INDEX_{schema.id:08x}"
|
|
261
|
-
elif
|
|
261
|
+
elif SearchFlag.TupleIndexed in schema.search_flags:
|
|
262
262
|
name = f"INDEX_T_{schema.id:08x}"
|
|
263
263
|
else:
|
|
264
264
|
# TODO add ContainerIndexed
|
|
@@ -20,6 +20,7 @@ if TYPE_CHECKING:
|
|
|
20
20
|
TrustedDomain,
|
|
21
21
|
User,
|
|
22
22
|
)
|
|
23
|
+
from dissect.database.ese.ntds.objects.organizationalunit import OrganizationalUnit
|
|
23
24
|
from dissect.database.ese.ntds.pek import PEK
|
|
24
25
|
|
|
25
26
|
|
|
@@ -83,11 +84,11 @@ class NTDS:
|
|
|
83
84
|
|
|
84
85
|
def groups(self) -> Iterator[Group]:
|
|
85
86
|
"""Get all group objects from the database."""
|
|
86
|
-
yield from self.search(
|
|
87
|
+
yield from self.search(objectClass="group")
|
|
87
88
|
|
|
88
89
|
def servers(self) -> Iterator[Server]:
|
|
89
90
|
"""Get all server objects from the database."""
|
|
90
|
-
yield from self.search(
|
|
91
|
+
yield from self.search(objectClass="server")
|
|
91
92
|
|
|
92
93
|
def users(self) -> Iterator[User]:
|
|
93
94
|
"""Get all user objects from the database."""
|
|
@@ -95,7 +96,11 @@ class NTDS:
|
|
|
95
96
|
|
|
96
97
|
def computers(self) -> Iterator[Computer]:
|
|
97
98
|
"""Get all computer objects from the database."""
|
|
98
|
-
yield from self.search(
|
|
99
|
+
yield from self.search(objectClass="computer")
|
|
100
|
+
|
|
101
|
+
def domains(self) -> Iterator[DomainDNS]:
|
|
102
|
+
"""Get all domain objects from the database."""
|
|
103
|
+
yield from self.search(objectClass="domainDNS")
|
|
99
104
|
|
|
100
105
|
def trusts(self) -> Iterator[TrustedDomain]:
|
|
101
106
|
"""Get all trust objects from the database."""
|
|
@@ -105,6 +110,10 @@ class NTDS:
|
|
|
105
110
|
"""Get all group policy objects (GPO) objects from the database."""
|
|
106
111
|
yield from self.search(objectClass="groupPolicyContainer")
|
|
107
112
|
|
|
113
|
+
def organizational_units(self) -> Iterator[OrganizationalUnit]:
|
|
114
|
+
"""Get all organizational unit (OU) objects from the database."""
|
|
115
|
+
yield from self.search(objectClass="organizationalUnit")
|
|
116
|
+
|
|
108
117
|
def secrets(self) -> Iterator[Secret]:
|
|
109
118
|
"""Get all secret objects from the database."""
|
|
110
119
|
yield from self.search(objectClass="secret")
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from typing import TYPE_CHECKING, ClassVar
|
|
4
|
+
|
|
3
5
|
from dissect.database.ese.ntds.objects.top import Top
|
|
6
|
+
from dissect.database.ese.ntds.util import SearchFlag, SystemFlagAttribute
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from dissect.database.ese.ntds.objects.object import DecoderMap
|
|
4
10
|
|
|
5
11
|
|
|
6
12
|
class AttributeSchema(Top):
|
|
@@ -11,3 +17,12 @@ class AttributeSchema(Top):
|
|
|
11
17
|
"""
|
|
12
18
|
|
|
13
19
|
__object_class__ = "attributeSchema"
|
|
20
|
+
__decoders__: ClassVar[DecoderMap] = {
|
|
21
|
+
"searchFlags": lambda db, value: SearchFlag(value),
|
|
22
|
+
"systemFlags": lambda db, value: SystemFlagAttribute(value),
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@property
|
|
26
|
+
def search_flags(self) -> SearchFlag | None:
|
|
27
|
+
"""Return the searchFlags of this attribute schema."""
|
|
28
|
+
return self.get("searchFlags")
|
|
@@ -23,6 +23,21 @@ class Computer(User):
|
|
|
23
23
|
def __repr_body__(self) -> str:
|
|
24
24
|
return f"name={self.name!r}"
|
|
25
25
|
|
|
26
|
+
@property
|
|
27
|
+
def dns_host_name(self) -> str | None:
|
|
28
|
+
"""Return the dNSHostName of this computer."""
|
|
29
|
+
return self.get("dNSHostName")
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def operating_system(self) -> str | None:
|
|
33
|
+
"""Return the operatingSystem of this computer."""
|
|
34
|
+
return self.get("operatingSystem")
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def operating_system_version(self) -> str | None:
|
|
38
|
+
"""Return the operatingSystemVersion of this computer."""
|
|
39
|
+
return self.get("operatingSystemVersion")
|
|
40
|
+
|
|
26
41
|
def fve_recovery_information(self) -> Iterator[MSFVERecoveryInformation]:
|
|
27
42
|
"""Return the BitLocker recovery information objects associated with this computer."""
|
|
28
43
|
for child in self.children():
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from typing import TYPE_CHECKING, ClassVar
|
|
4
|
+
|
|
3
5
|
from dissect.database.ese.ntds.objects.top import Top
|
|
6
|
+
from dissect.database.ese.ntds.util import SystemFlagCrossRef
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from dissect.database.ese.ntds.objects.object import DecoderMap
|
|
4
10
|
|
|
5
11
|
|
|
6
12
|
class CrossRef(Top):
|
|
@@ -11,3 +17,11 @@ class CrossRef(Top):
|
|
|
11
17
|
"""
|
|
12
18
|
|
|
13
19
|
__object_class__ = "crossRef"
|
|
20
|
+
__decoders__: ClassVar[DecoderMap] = {
|
|
21
|
+
"systemFlags": lambda db, value: SystemFlagCrossRef(value),
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@property
|
|
25
|
+
def behavior_version(self) -> int | None:
|
|
26
|
+
"""Return the msDS-Behavior-Version of this cross-reference."""
|
|
27
|
+
return self.get("msDS-Behavior-Version")
|
|
@@ -11,3 +11,8 @@ class CrossRefContainer(Top):
|
|
|
11
11
|
"""
|
|
12
12
|
|
|
13
13
|
__object_class__ = "crossRefContainer"
|
|
14
|
+
|
|
15
|
+
@property
|
|
16
|
+
def behavior_version(self) -> int | None:
|
|
17
|
+
"""Return the msDS-Behavior-Version of this cross-reference container."""
|
|
18
|
+
return self.get("msDS-Behavior-Version")
|
|
@@ -19,3 +19,8 @@ class DomainDNS(Domain):
|
|
|
19
19
|
if (pek := self.get("pekList")) is not None:
|
|
20
20
|
return PEK(pek)
|
|
21
21
|
return None
|
|
22
|
+
|
|
23
|
+
@property
|
|
24
|
+
def behavior_version(self) -> int | None:
|
|
25
|
+
"""Return the msDS-Behavior-Version of this domain DNS object."""
|
|
26
|
+
return self.get("msDS-Behavior-Version")
|
|
@@ -24,6 +24,16 @@ class Group(Top):
|
|
|
24
24
|
"""Return the group's sAMAccountName."""
|
|
25
25
|
return self.get("sAMAccountName")
|
|
26
26
|
|
|
27
|
+
@property
|
|
28
|
+
def mail(self) -> str | None:
|
|
29
|
+
"""Return the mail address of this group."""
|
|
30
|
+
return self.get("mail")
|
|
31
|
+
|
|
32
|
+
@property
|
|
33
|
+
def admin_count(self) -> int | None:
|
|
34
|
+
"""Return the group's adminCount."""
|
|
35
|
+
return self.get("adminCount")
|
|
36
|
+
|
|
27
37
|
def managed_by(self) -> Iterator[Object]:
|
|
28
38
|
"""Return the objects that manage this group."""
|
|
29
39
|
self._assert_local()
|
|
@@ -19,6 +19,11 @@ class NTDSDSA(ApplicationSettings):
|
|
|
19
19
|
|
|
20
20
|
__object_class__ = "nTDSDSA"
|
|
21
21
|
|
|
22
|
+
@property
|
|
23
|
+
def behavior_version(self) -> int | None:
|
|
24
|
+
"""Return the msDS-Behavior-Version of this NTDS DSA object."""
|
|
25
|
+
return self.get("msDS-Behavior-Version")
|
|
26
|
+
|
|
22
27
|
def domain(self) -> DomainDNS | None:
|
|
23
28
|
"""Return the domain object associated with this NTDS DSA object, if any."""
|
|
24
29
|
self._assert_local()
|
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import struct
|
|
3
4
|
from functools import cached_property
|
|
4
|
-
from typing import TYPE_CHECKING, Any, ClassVar
|
|
5
|
+
from typing import TYPE_CHECKING, Any, ClassVar, TypeAlias
|
|
6
|
+
from uuid import UUID
|
|
5
7
|
|
|
6
|
-
from dissect.database.ese.ntds.util import InstanceType, decode_value
|
|
8
|
+
from dissect.database.ese.ntds.util import InstanceType, SystemFlag, decode_value
|
|
7
9
|
|
|
8
10
|
if TYPE_CHECKING:
|
|
9
|
-
from collections.abc import Iterator
|
|
11
|
+
from collections.abc import Callable, Iterator
|
|
10
12
|
from datetime import datetime
|
|
11
13
|
|
|
12
14
|
from dissect.database.ese.ntds.database import Database
|
|
13
15
|
from dissect.database.ese.ntds.sd import SecurityDescriptor
|
|
14
|
-
from dissect.database.ese.ntds.util import DN
|
|
16
|
+
from dissect.database.ese.ntds.util import DN
|
|
15
17
|
from dissect.database.ese.record import Record
|
|
16
18
|
|
|
19
|
+
DecoderMap: TypeAlias = dict[str, Callable[[Database, Any], Any]]
|
|
20
|
+
|
|
17
21
|
|
|
18
22
|
class Object:
|
|
19
23
|
"""Base class for all objects in the NTDS database.
|
|
@@ -29,7 +33,19 @@ class Object:
|
|
|
29
33
|
- https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adsc/041c6068-c710-4c74-968f-3040e4208701
|
|
30
34
|
"""
|
|
31
35
|
|
|
36
|
+
# Subclasses must override this to specify their object class
|
|
32
37
|
__object_class__: str
|
|
38
|
+
"""The objectClass value for this object."""
|
|
39
|
+
|
|
40
|
+
# Decoders for specific attributes to this object
|
|
41
|
+
__decoders__: ClassVar[DecoderMap] = {
|
|
42
|
+
"Ancestors": lambda db, value: [v[0] for v in struct.iter_unpack("<I", value)],
|
|
43
|
+
"instanceType": lambda db, value: InstanceType(value),
|
|
44
|
+
"systemFlags": lambda db, value: SystemFlag(value),
|
|
45
|
+
"objectGUID": lambda db, value: UUID(bytes_le=value),
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
# All known object classes
|
|
33
49
|
__known_classes__: ClassVar[dict[str, type[Object]]] = {}
|
|
34
50
|
|
|
35
51
|
def __init__(self, db: Database, record: Record):
|
|
@@ -39,6 +55,12 @@ class Object:
|
|
|
39
55
|
def __init_subclass__(cls):
|
|
40
56
|
cls.__known_classes__[cls.__object_class__] = cls
|
|
41
57
|
|
|
58
|
+
# Merge parent decoders with any new ones defined on the new class
|
|
59
|
+
decoders = {}
|
|
60
|
+
for parent in reversed(cls.__mro__[1:]):
|
|
61
|
+
decoders |= getattr(parent, "__decoders__", {})
|
|
62
|
+
cls.__decoders__ = decoders | cls.__decoders__
|
|
63
|
+
|
|
42
64
|
def __repr__(self) -> str:
|
|
43
65
|
suffix = self.__repr_suffix__()
|
|
44
66
|
return f"<{self.__class__.__name__} {self.__repr_body__()}{' ' + suffix if suffix else ''}>"
|
|
@@ -89,7 +111,13 @@ class Object:
|
|
|
89
111
|
name: The attribute name to retrieve.
|
|
90
112
|
raw: Whether to return the raw value without decoding.
|
|
91
113
|
"""
|
|
92
|
-
|
|
114
|
+
value = _get_attribute(self.db, self.record, name, raw=raw)
|
|
115
|
+
|
|
116
|
+
# Allow custom decoders to override the default decoding logic for specific attributes
|
|
117
|
+
# This is convenient for things like enums or timestamps that we want to represent as more meaningful types
|
|
118
|
+
if value is not None and name in self.__decoders__:
|
|
119
|
+
value = self.__decoders__[name](self.db, value)
|
|
120
|
+
return value
|
|
93
121
|
|
|
94
122
|
def as_dict(self) -> dict[str, Any]:
|
|
95
123
|
"""Return the object's attributes as a dictionary."""
|
|
@@ -97,7 +125,7 @@ class Object:
|
|
|
97
125
|
for key in self.record.as_dict():
|
|
98
126
|
if (schema := self.db.data.schema.lookup_attribute(column=key)) is not None:
|
|
99
127
|
key = schema.name
|
|
100
|
-
result[key] =
|
|
128
|
+
result[key] = self.get(key)
|
|
101
129
|
return result
|
|
102
130
|
|
|
103
131
|
def parent(self) -> Object | None:
|
|
@@ -221,7 +249,7 @@ class Object:
|
|
|
221
249
|
return self.get("instanceType")
|
|
222
250
|
|
|
223
251
|
@property
|
|
224
|
-
def system_flags(self) ->
|
|
252
|
+
def system_flags(self) -> SystemFlag | None:
|
|
225
253
|
"""Return the object's system flags."""
|
|
226
254
|
return self.get("systemFlags")
|
|
227
255
|
|
|
@@ -240,9 +268,7 @@ class Object:
|
|
|
240
268
|
@cached_property
|
|
241
269
|
def sd(self) -> SecurityDescriptor | None:
|
|
242
270
|
"""Return the Security Descriptor for this object."""
|
|
243
|
-
|
|
244
|
-
return self.db.sd.sd(sd_id)
|
|
245
|
-
return None
|
|
271
|
+
return self.get("nTSecurityDescriptor")
|
|
246
272
|
|
|
247
273
|
@cached_property
|
|
248
274
|
def well_known_objects(self) -> list[Object]:
|
|
@@ -13,6 +13,21 @@ class OrganizationalPerson(Person):
|
|
|
13
13
|
__object_class__ = "organizationalPerson"
|
|
14
14
|
|
|
15
15
|
@property
|
|
16
|
-
def city(self) -> str:
|
|
16
|
+
def city(self) -> str | None:
|
|
17
17
|
"""Return the city (l) of this organizational person."""
|
|
18
18
|
return self.get("l") # "l" (localityName) represents the city/locality.
|
|
19
|
+
|
|
20
|
+
@property
|
|
21
|
+
def mail(self) -> str | None:
|
|
22
|
+
"""Return the mail address of this organizational person."""
|
|
23
|
+
return self.get("mail")
|
|
24
|
+
|
|
25
|
+
@property
|
|
26
|
+
def title(self) -> str | None:
|
|
27
|
+
"""Return the title of this organizational person."""
|
|
28
|
+
return self.get("title")
|
|
29
|
+
|
|
30
|
+
@property
|
|
31
|
+
def allowed_to_act_on_behalf_of_other_identity(self) -> str | None:
|
|
32
|
+
"""Return the msDS-AllowedToActOnBehalfOfOtherIdentity attribute of this organizational person."""
|
|
33
|
+
return self.get("msDS-AllowedToActOnBehalfOfOtherIdentity")
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import TYPE_CHECKING
|
|
3
|
+
from typing import TYPE_CHECKING, ClassVar
|
|
4
4
|
|
|
5
5
|
from dissect.database.ese.ntds.objects.top import Top
|
|
6
|
+
from dissect.database.ese.ntds.util import GroupPolicyOption
|
|
6
7
|
|
|
7
8
|
if TYPE_CHECKING:
|
|
8
9
|
from collections.abc import Iterator
|
|
9
10
|
|
|
10
11
|
from dissect.database.ese.ntds.objects import Object
|
|
12
|
+
from dissect.database.ese.ntds.objects.object import DecoderMap
|
|
11
13
|
|
|
12
14
|
|
|
13
15
|
class OrganizationalUnit(Top):
|
|
@@ -18,6 +20,29 @@ class OrganizationalUnit(Top):
|
|
|
18
20
|
"""
|
|
19
21
|
|
|
20
22
|
__object_class__ = "organizationalUnit"
|
|
23
|
+
__decoders__: ClassVar[DecoderMap] = {
|
|
24
|
+
"gPOptions": lambda db, value: GroupPolicyOption(value),
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@property
|
|
28
|
+
def gp_link(self) -> str | None:
|
|
29
|
+
"""Return the group policy link of the organizational unit."""
|
|
30
|
+
return self.get("gPLink")
|
|
31
|
+
|
|
32
|
+
@property
|
|
33
|
+
def gp_options(self) -> int | None:
|
|
34
|
+
"""Return the group policy options of the organizational unit."""
|
|
35
|
+
return self.get("gPOptions")
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
def telephone_number(self) -> str | None:
|
|
39
|
+
"""Return the telephone number of this organizational unit."""
|
|
40
|
+
return self.get("telephoneNumber")
|
|
41
|
+
|
|
42
|
+
@property
|
|
43
|
+
def user_password(self) -> str | None:
|
|
44
|
+
"""Return the userPassword of this organizational unit."""
|
|
45
|
+
return self.get("userPassword")
|
|
21
46
|
|
|
22
47
|
def managed_by(self) -> Iterator[Object]:
|
|
23
48
|
"""Return the objects that manage this organizational unit."""
|
|
@@ -11,3 +11,13 @@ class Person(Top):
|
|
|
11
11
|
"""
|
|
12
12
|
|
|
13
13
|
__object_class__ = "person"
|
|
14
|
+
|
|
15
|
+
@property
|
|
16
|
+
def telephone_number(self) -> str | None:
|
|
17
|
+
"""Return the telephone number of this person."""
|
|
18
|
+
return self.get("telephoneNumber")
|
|
19
|
+
|
|
20
|
+
@property
|
|
21
|
+
def user_password(self) -> str | None:
|
|
22
|
+
"""Return the userPassword attribute of this person."""
|
|
23
|
+
return self.get("userPassword")
|
|
@@ -19,6 +19,11 @@ class Server(Top):
|
|
|
19
19
|
|
|
20
20
|
__object_class__ = "server"
|
|
21
21
|
|
|
22
|
+
@property
|
|
23
|
+
def dns_host_name(self) -> str | None:
|
|
24
|
+
"""Return the dNSHostName of this server."""
|
|
25
|
+
return self.get("dNSHostName")
|
|
26
|
+
|
|
22
27
|
def computer(self) -> Computer | None:
|
|
23
28
|
"""Return the computer object associated with this server, if any."""
|
|
24
29
|
self._assert_local()
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import TYPE_CHECKING
|
|
3
|
+
from typing import TYPE_CHECKING, ClassVar
|
|
4
4
|
|
|
5
5
|
from dissect.database.ese.ntds.objects.top import Top
|
|
6
|
+
from dissect.database.ese.ntds.util import GroupPolicyOption
|
|
6
7
|
|
|
7
8
|
if TYPE_CHECKING:
|
|
8
9
|
from collections.abc import Iterator
|
|
9
10
|
|
|
10
11
|
from dissect.database.ese.ntds.objects import Object
|
|
12
|
+
from dissect.database.ese.ntds.objects.object import DecoderMap
|
|
11
13
|
|
|
12
14
|
|
|
13
15
|
class Site(Top):
|
|
@@ -18,6 +20,19 @@ class Site(Top):
|
|
|
18
20
|
"""
|
|
19
21
|
|
|
20
22
|
__object_class__ = "site"
|
|
23
|
+
__decoders__: ClassVar[DecoderMap] = {
|
|
24
|
+
"gPOptions": lambda db, value: GroupPolicyOption(value),
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@property
|
|
28
|
+
def gp_link(self) -> str:
|
|
29
|
+
"""Return the group policy link of the site."""
|
|
30
|
+
return self.get("gPLink")
|
|
31
|
+
|
|
32
|
+
@property
|
|
33
|
+
def gp_options(self) -> int:
|
|
34
|
+
"""Return the group policy options of the site."""
|
|
35
|
+
return self.get("gPOptions", 0)
|
|
21
36
|
|
|
22
37
|
def managed_by(self) -> Iterator[Object]:
|
|
23
38
|
"""Return the objects that manage this site."""
|
|
@@ -19,3 +19,8 @@ class Top(Object):
|
|
|
19
19
|
def display_name(self) -> str | None:
|
|
20
20
|
"""Return the displayName for this object."""
|
|
21
21
|
return self.get("displayName")
|
|
22
|
+
|
|
23
|
+
@property
|
|
24
|
+
def description(self) -> str | None:
|
|
25
|
+
"""Return the description for this object."""
|
|
26
|
+
return self.get("description")
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from typing import TYPE_CHECKING, ClassVar
|
|
4
|
+
|
|
3
5
|
from dissect.database.ese.ntds.objects.leaf import Leaf
|
|
6
|
+
from dissect.database.ese.ntds.util import TrustAttribute, TrustDirection, TrustType
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from dissect.database.ese.ntds.objects.object import DecoderMap
|
|
4
10
|
|
|
5
11
|
|
|
6
12
|
class TrustedDomain(Leaf):
|
|
@@ -11,3 +17,33 @@ class TrustedDomain(Leaf):
|
|
|
11
17
|
"""
|
|
12
18
|
|
|
13
19
|
__object_class__ = "trustedDomain"
|
|
20
|
+
__decoders__: ClassVar[DecoderMap] = {
|
|
21
|
+
"trustType": lambda db, value: TrustType(value),
|
|
22
|
+
"trustDirection": lambda db, value: TrustDirection(value),
|
|
23
|
+
"trustAttributes": lambda db, value: TrustAttribute(value),
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def trust_type(self) -> TrustType | None:
|
|
28
|
+
"""Return the trustType of this trusted domain."""
|
|
29
|
+
return self.get("trustType")
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def trust_direction(self) -> TrustDirection | None:
|
|
33
|
+
"""Return the trustDirection of this trusted domain."""
|
|
34
|
+
return self.get("trustDirection")
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def trust_attributes(self) -> TrustAttribute | None:
|
|
38
|
+
"""Return the trustAttributes of this trusted domain."""
|
|
39
|
+
return self.get("trustAttributes")
|
|
40
|
+
|
|
41
|
+
@property
|
|
42
|
+
def trust_partner(self) -> str | None:
|
|
43
|
+
"""Return the trustPartner of this trusted domain."""
|
|
44
|
+
return self.get("trustPartner")
|
|
45
|
+
|
|
46
|
+
@property
|
|
47
|
+
def security_identifier(self) -> str | None:
|
|
48
|
+
"""Return the securityIdentifier of this trusted domain."""
|
|
49
|
+
return self.get("securityIdentifier")
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import TYPE_CHECKING
|
|
3
|
+
from typing import TYPE_CHECKING, ClassVar
|
|
4
|
+
|
|
5
|
+
from dissect.util.ts import wintimestamp
|
|
4
6
|
|
|
5
7
|
from dissect.database.ese.ntds.objects.organizationalperson import OrganizationalPerson
|
|
6
|
-
from dissect.database.ese.ntds.util import UserAccountControl
|
|
8
|
+
from dissect.database.ese.ntds.util import SAMAccountType, UserAccountControl
|
|
7
9
|
|
|
8
10
|
if TYPE_CHECKING:
|
|
9
11
|
from collections.abc import Iterator
|
|
12
|
+
from datetime import datetime
|
|
10
13
|
|
|
11
14
|
from dissect.database.ese.ntds.objects.group import Group
|
|
12
|
-
from dissect.database.ese.ntds.objects.object import Object
|
|
13
|
-
from dissect.database.ese.ntds.util import SAMAccountType
|
|
15
|
+
from dissect.database.ese.ntds.objects.object import DecoderMap, Object
|
|
14
16
|
|
|
15
17
|
|
|
16
18
|
class User(OrganizationalPerson):
|
|
@@ -21,6 +23,16 @@ class User(OrganizationalPerson):
|
|
|
21
23
|
"""
|
|
22
24
|
|
|
23
25
|
__object_class__ = "user"
|
|
26
|
+
__decoders__: ClassVar[DecoderMap] = {
|
|
27
|
+
"sAMAccountType": lambda db, value: SAMAccountType(value),
|
|
28
|
+
"userAccountControl": lambda db, value: UserAccountControl(value),
|
|
29
|
+
"badPasswordTime": lambda db, value: None if value == 0 else wintimestamp(value),
|
|
30
|
+
"lastLogonTimestamp": lambda db, value: None if value == 0 else wintimestamp(value),
|
|
31
|
+
"lastLogon": lambda db, value: None if value == 0 else wintimestamp(value),
|
|
32
|
+
"lastLogoff": lambda db, value: None if value == 0 else wintimestamp(value),
|
|
33
|
+
"pwdLastSet": lambda db, value: None if value == 0 else wintimestamp(value),
|
|
34
|
+
"accountExpires": lambda db, value: None if value in (0, ((1 << 63) - 1)) else wintimestamp(value),
|
|
35
|
+
}
|
|
24
36
|
|
|
25
37
|
def __repr_body__(self) -> str:
|
|
26
38
|
return f"name={self.name!r} sam_account_name={self.sam_account_name!r} is_machine_account={self.is_machine_account()}" # noqa: E501
|
|
@@ -45,6 +57,61 @@ class User(OrganizationalPerson):
|
|
|
45
57
|
"""Return the user's userAccountControl flags."""
|
|
46
58
|
return self.get("userAccountControl")
|
|
47
59
|
|
|
60
|
+
@property
|
|
61
|
+
def user_principal_name(self) -> str | None:
|
|
62
|
+
"""Return the user's userPrincipalName."""
|
|
63
|
+
return self.get("userPrincipalName")
|
|
64
|
+
|
|
65
|
+
@property
|
|
66
|
+
def service_principal_name(self) -> list[str]:
|
|
67
|
+
"""Return the user's servicePrincipalName."""
|
|
68
|
+
return self.get("servicePrincipalName") or []
|
|
69
|
+
|
|
70
|
+
@property
|
|
71
|
+
def home_directory(self) -> str | None:
|
|
72
|
+
"""Return the user's home directory."""
|
|
73
|
+
return self.get("homeDirectory")
|
|
74
|
+
|
|
75
|
+
@property
|
|
76
|
+
def home_drive(self) -> str | None:
|
|
77
|
+
"""Return the user's home drive."""
|
|
78
|
+
return self.get("homeDrive")
|
|
79
|
+
|
|
80
|
+
@property
|
|
81
|
+
def script_path(self) -> str | None:
|
|
82
|
+
"""Return the user's script path."""
|
|
83
|
+
return self.get("scriptPath")
|
|
84
|
+
|
|
85
|
+
@property
|
|
86
|
+
def password_last_set(self) -> datetime | None:
|
|
87
|
+
"""Return the last time the user's password was set."""
|
|
88
|
+
return self.get("pwdLastSet")
|
|
89
|
+
|
|
90
|
+
@property
|
|
91
|
+
def logon_last_failed(self) -> datetime | None:
|
|
92
|
+
"""Return the last time the user had a failed logon attempt."""
|
|
93
|
+
return self.get("badPasswordTime")
|
|
94
|
+
|
|
95
|
+
@property
|
|
96
|
+
def logon_last_local(self) -> datetime | None:
|
|
97
|
+
"""Return the last time the user had a successful local logon."""
|
|
98
|
+
return self.get("lastLogon")
|
|
99
|
+
|
|
100
|
+
@property
|
|
101
|
+
def logon_last_replicated(self) -> datetime | None:
|
|
102
|
+
"""Return the last time the user had a successful logon replicated across domain controllers."""
|
|
103
|
+
return self.get("lastLogonTimestamp")
|
|
104
|
+
|
|
105
|
+
@property
|
|
106
|
+
def account_expires(self) -> datetime | None:
|
|
107
|
+
"""Return the time the user's account expires."""
|
|
108
|
+
return self.get("accountExpires")
|
|
109
|
+
|
|
110
|
+
@property
|
|
111
|
+
def admin_count(self) -> int | None:
|
|
112
|
+
"""Return the user's adminCount."""
|
|
113
|
+
return self.get("adminCount")
|
|
114
|
+
|
|
48
115
|
def is_machine_account(self) -> bool:
|
|
49
116
|
"""Return whether this user is a machine account."""
|
|
50
117
|
return UserAccountControl.WORKSTATION_TRUST_ACCOUNT in self.user_account_control
|
|
@@ -7,7 +7,7 @@ from dissect.database.ese.ntds.c_ds import c_ds
|
|
|
7
7
|
|
|
8
8
|
if TYPE_CHECKING:
|
|
9
9
|
from dissect.database.ese.ntds.database import Database
|
|
10
|
-
from dissect.database.ese.ntds.util import
|
|
10
|
+
from dissect.database.ese.ntds.util import SearchFlag
|
|
11
11
|
|
|
12
12
|
# These are fixed columns in the NTDS database
|
|
13
13
|
# They do not exist in the schema, but are required for basic operation
|
|
@@ -121,7 +121,7 @@ class AttributeEntry(NamedTuple):
|
|
|
121
121
|
om_object_class: bytes | None
|
|
122
122
|
is_single_valued: bool
|
|
123
123
|
link_id: int | None
|
|
124
|
-
search_flags:
|
|
124
|
+
search_flags: SearchFlag | None
|
|
125
125
|
|
|
126
126
|
|
|
127
127
|
class Schema:
|
|
@@ -255,7 +255,7 @@ class Schema:
|
|
|
255
255
|
om_object_class: bytes | None,
|
|
256
256
|
is_single_valued: bool,
|
|
257
257
|
link_id: int | None,
|
|
258
|
-
search_flags:
|
|
258
|
+
search_flags: SearchFlag | None,
|
|
259
259
|
) -> None:
|
|
260
260
|
entry = AttributeEntry(
|
|
261
261
|
dnt=dnt,
|
|
@@ -3,7 +3,6 @@ from __future__ import annotations
|
|
|
3
3
|
import struct
|
|
4
4
|
from enum import Flag, IntEnum, IntFlag, auto
|
|
5
5
|
from typing import TYPE_CHECKING, Any
|
|
6
|
-
from uuid import UUID
|
|
7
6
|
|
|
8
7
|
from dissect.util.sid import read_sid, write_sid
|
|
9
8
|
from dissect.util.ts import wintimestamp
|
|
@@ -18,7 +17,7 @@ if TYPE_CHECKING:
|
|
|
18
17
|
from dissect.database.ese.ntds.schema import AttributeEntry
|
|
19
18
|
|
|
20
19
|
|
|
21
|
-
class
|
|
20
|
+
class DatabaseFlag(Flag):
|
|
22
21
|
"""Database flags that are stored in the hiddentable.
|
|
23
22
|
|
|
24
23
|
The flags are weirdly stored as ``1``, ``0`` or ``\x00`` in a byte array.
|
|
@@ -45,19 +44,71 @@ class InstanceType(IntFlag):
|
|
|
45
44
|
NamingContextDeleting = 0x00000020
|
|
46
45
|
|
|
47
46
|
|
|
48
|
-
# https://learn.microsoft.com/en-us/windows/win32/adschema/a-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
47
|
+
# https://learn.microsoft.com/en-us/windows/win32/adschema/a-systemflags
|
|
48
|
+
# https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/1e38247d-8234-4273-9de3-bbf313548631
|
|
49
|
+
class SystemFlag(IntFlag):
|
|
50
|
+
# The first 3 flags have an overlap whether it's set on an attributeSchema or crossRef object
|
|
51
|
+
# We don't specify them here, see SystemFlagAttribute and SystemFlagCrossRef
|
|
52
|
+
|
|
53
|
+
# The following flags are also specific to certain objects, but have no overlap
|
|
54
|
+
ATTR_IS_OPERATIONAL = 0x00000008
|
|
55
|
+
SCHEMA_BASE_OBJECT = 0x00000010
|
|
56
|
+
ATTR_IS_RDN = 0x00000020
|
|
57
|
+
DISALLOW_MOVE_ON_DELETE = 0x02000000
|
|
58
|
+
DOMAIN_DISALLOW_MOVE = 0x04000000
|
|
59
|
+
DOMAIN_DISALLOW_RENAME = 0x08000000
|
|
60
|
+
CONFIG_ALLOW_LIMITED_MOVE = 0x10000000
|
|
61
|
+
CONFIG_ALLOW_MOVE = 0x20000000
|
|
62
|
+
CONFIG_ALLOW_RENAME = 0x40000000
|
|
63
|
+
DISALLOW_DELETE = 0x80000000
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
# System flags that overlap with other flags and are specific to attributeSchema objects
|
|
67
|
+
class SystemFlagAttribute(IntFlag):
|
|
68
|
+
ATTR_NOT_REPLICATED = 0x00000001
|
|
69
|
+
ATTR_REQ_PARTIAL_SET_MEMBER = 0x00000002
|
|
70
|
+
ATTR_IS_CONSTRUCTED = 0x00000004
|
|
71
|
+
|
|
72
|
+
# TODO: When we drop Python 3.10 support, we can subclass SystemFlag
|
|
73
|
+
# For now, just duplicate the flags here
|
|
74
|
+
ATTR_IS_OPERATIONAL = 0x00000008
|
|
75
|
+
SCHEMA_BASE_OBJECT = 0x00000010
|
|
76
|
+
ATTR_IS_RDN = 0x00000020
|
|
77
|
+
DISALLOW_MOVE_ON_DELETE = 0x02000000
|
|
78
|
+
DOMAIN_DISALLOW_MOVE = 0x04000000
|
|
79
|
+
DOMAIN_DISALLOW_RENAME = 0x08000000
|
|
80
|
+
CONFIG_ALLOW_LIMITED_MOVE = 0x10000000
|
|
81
|
+
CONFIG_ALLOW_MOVE = 0x20000000
|
|
82
|
+
CONFIG_ALLOW_RENAME = 0x40000000
|
|
83
|
+
DISALLOW_DELETE = 0x80000000
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
# For better readability when printing attributeSchema objects, we reset the name
|
|
87
|
+
SystemFlagAttribute.__name__ = "SystemFlag"
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
# System flags that overlap with other flags and are specific to crossRef objects
|
|
91
|
+
class SystemFlagCrossRef(IntFlag):
|
|
92
|
+
CR_NTDS_NC = 0x00000001
|
|
93
|
+
CR_NTDS_DOMAIN = 0x00000002
|
|
94
|
+
CR_NTDS_NOT_GC_REPLICATED = 0x00000004
|
|
95
|
+
|
|
96
|
+
# TODO: When we drop Python 3.10 support, we can subclass SystemFlag
|
|
97
|
+
# For now, just duplicate the flags here
|
|
98
|
+
ATTR_IS_OPERATIONAL = 0x00000008
|
|
99
|
+
SCHEMA_BASE_OBJECT = 0x00000010
|
|
100
|
+
ATTR_IS_RDN = 0x00000020
|
|
101
|
+
DISALLOW_MOVE_ON_DELETE = 0x02000000
|
|
102
|
+
DOMAIN_DISALLOW_MOVE = 0x04000000
|
|
103
|
+
DOMAIN_DISALLOW_RENAME = 0x08000000
|
|
104
|
+
CONFIG_ALLOW_LIMITED_MOVE = 0x10000000
|
|
105
|
+
CONFIG_ALLOW_MOVE = 0x20000000
|
|
106
|
+
CONFIG_ALLOW_RENAME = 0x40000000
|
|
107
|
+
DISALLOW_DELETE = 0x80000000
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
# For better readability when printing crossRef objects, we reset the name
|
|
111
|
+
SystemFlagCrossRef.__name__ = "SystemFlag"
|
|
61
112
|
|
|
62
113
|
|
|
63
114
|
# https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/dd302fd1-0aa7-406b-ad91-2a6b35738557
|
|
@@ -98,7 +149,7 @@ class SAMAccountType(IntEnum):
|
|
|
98
149
|
SAM_APP_QUERY_GROUP = 0x40000001
|
|
99
150
|
|
|
100
151
|
|
|
101
|
-
class
|
|
152
|
+
class SearchFlag(IntFlag):
|
|
102
153
|
Indexed = 0x00000001
|
|
103
154
|
ContainerIndexed = 0x00000002
|
|
104
155
|
Anr = 0x00000004
|
|
@@ -109,6 +160,41 @@ class SearchFlags(IntFlag):
|
|
|
109
160
|
Confidential = 0x00000080
|
|
110
161
|
|
|
111
162
|
|
|
163
|
+
class TrustType(IntEnum):
|
|
164
|
+
DOWNLEVEL = 0x00000001
|
|
165
|
+
UPLEVEL = 0x00000002
|
|
166
|
+
MIT = 0x00000003
|
|
167
|
+
DCE = 0x00000004
|
|
168
|
+
AAD = 0x00000005
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
class TrustDirection(IntEnum):
|
|
172
|
+
DISABLED = 0
|
|
173
|
+
INBOUND = 1
|
|
174
|
+
OUTBOUND = 2
|
|
175
|
+
BIDIRECTIONAL = 3
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
class TrustAttribute(IntFlag):
|
|
179
|
+
NON_TRANSITIVE = 0x00000001
|
|
180
|
+
UPLEVEL_ONLY = 0x00000002
|
|
181
|
+
FILTER_SIDS = 0x00000004
|
|
182
|
+
FOREST_TRANSITIVE = 0x00000008
|
|
183
|
+
CROSS_ORGANIZATION = 0x00000010
|
|
184
|
+
WITHIN_FOREST = 0x00000020
|
|
185
|
+
TREAT_AS_EXTERNAL = 0x00000040
|
|
186
|
+
TRUST_USES_RC4_ENCRYPTION = 0x00000080
|
|
187
|
+
TRUST_USES_AES_KEYS = 0x00000100
|
|
188
|
+
CROSS_ORGANIZATION_NO_TGT_DELEGATION = 0x00000200
|
|
189
|
+
PIM_TRUST = 0x00000400
|
|
190
|
+
TREE_PARENT = 0x00400000
|
|
191
|
+
TREE_ROOT = 0x00800000
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
class GroupPolicyOption(IntFlag):
|
|
195
|
+
BLOCK_POLICY = 0x00000001
|
|
196
|
+
|
|
197
|
+
|
|
112
198
|
def _pek_decrypt(db: Database, value: bytes) -> bytes:
|
|
113
199
|
"""Decrypt a PEK-encrypted blob using the database's PEK, if it's unlocked.
|
|
114
200
|
|
|
@@ -255,22 +341,6 @@ def _decode_pwd_history(db: Database, value: list[bytes]) -> list[bytes]:
|
|
|
255
341
|
ATTRIBUTE_ENCODE_DECODE_MAP: dict[
|
|
256
342
|
str, tuple[Callable[[Database, Any], Any] | None, Callable[[Database, Any], Any] | None]
|
|
257
343
|
] = {
|
|
258
|
-
"Ancestors": (None, lambda db, value: [v[0] for v in struct.iter_unpack("<I", value)]),
|
|
259
|
-
"instanceType": (lambda db, value: int(value), lambda db, value: InstanceType(int(value))),
|
|
260
|
-
"systemFlags": (lambda db, value: int(value), lambda db, value: SystemFlags(int(value))),
|
|
261
|
-
"searchFlags": (lambda db, value: int(value), lambda db, value: SearchFlags(int(value))),
|
|
262
|
-
"sAMAccountType": (lambda db, value: int(value), lambda db, value: SAMAccountType(int(value))),
|
|
263
|
-
"userAccountControl": (lambda db, value: int(value), lambda db, value: UserAccountControl(int(value))),
|
|
264
|
-
"objectGUID": (lambda db, value: value.bytes_le, lambda db, value: UUID(bytes_le=value)),
|
|
265
|
-
"badPasswordTime": (None, lambda db, value: wintimestamp(int(value))),
|
|
266
|
-
"lastLogonTimestamp": (None, lambda db, value: wintimestamp(int(value))),
|
|
267
|
-
"lastLogon": (None, lambda db, value: wintimestamp(int(value))),
|
|
268
|
-
"lastLogoff": (None, lambda db, value: wintimestamp(int(value))),
|
|
269
|
-
"pwdLastSet": (None, lambda db, value: wintimestamp(int(value))),
|
|
270
|
-
"accountExpires": (
|
|
271
|
-
None,
|
|
272
|
-
lambda db, value: float("inf") if int(value) == ((1 << 63) - 1) else wintimestamp(int(value)),
|
|
273
|
-
),
|
|
274
344
|
# Protected attributes
|
|
275
345
|
"unicodePwd": (None, _pek_decrypt),
|
|
276
346
|
"dBCSPwd": (None, _pek_decrypt),
|
|
@@ -432,7 +502,7 @@ SYNTAX_ENCODE_DECODE_MAP: dict[
|
|
|
432
502
|
# TODO: Object(DN-String); A DN-String plus a Unicode string
|
|
433
503
|
14: (None, None),
|
|
434
504
|
# NTSecurityDescriptor; A security descriptor
|
|
435
|
-
15: (None, lambda db, value: int.from_bytes(value, byteorder="little")),
|
|
505
|
+
15: (None, lambda db, value: db.sd.sd(int.from_bytes(value, byteorder="little"))),
|
|
436
506
|
# LargeInteger; A 64-bit number
|
|
437
507
|
16: (None, lambda db, value: int(value)),
|
|
438
508
|
# String(Sid); Security identifier (SID)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dissect.database
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.dev9
|
|
4
4
|
Summary: A Dissect module implementing parsers for various database formats, including Berkeley DB, Microsofts Extensible Storage Engine (ESE) and SQLite3
|
|
5
5
|
Author-email: Dissect Team <dissect@fox-it.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -29,40 +29,40 @@ dissect/database/ese/ntds/c_pek.py,sha256=YU_rRpOEf8uB8OE6bGb25KIGm9e-yrn0tTItRC
|
|
|
29
29
|
dissect/database/ese/ntds/c_pek.pyi,sha256=lHfhvHWABT1vLmknu66phOXsylgwzGIWVdbqDIZU5Qw,4683
|
|
30
30
|
dissect/database/ese/ntds/c_sd.py,sha256=DYICZsWCBzj0OtvhO6vhzzVjK9YP6tzBCsgKgr0pc-k,4294
|
|
31
31
|
dissect/database/ese/ntds/c_sd.pyi,sha256=7717Y0EBVu37Liu26rqsDWkLIdSCqWn9KK9svtniLqY,5279
|
|
32
|
-
dissect/database/ese/ntds/database.py,sha256=
|
|
33
|
-
dissect/database/ese/ntds/ntds.py,sha256=
|
|
32
|
+
dissect/database/ese/ntds/database.py,sha256=fPMgTzHm1rsPZ3Hvt7SQqtjdXQNNLa51wGEK3i5_afw,16776
|
|
33
|
+
dissect/database/ese/ntds/ntds.py,sha256=Uws58HSUKUUIs3qEc3zlrQfwNK-cKwyzkAt3320aHs8,5506
|
|
34
34
|
dissect/database/ese/ntds/pek.py,sha256=BEmxO175T8QkGVvFQLN9MI9uDCcK4jztuZetbwbbYqU,4154
|
|
35
35
|
dissect/database/ese/ntds/query.py,sha256=pDLLCVdrCRNq3ripvMDiyxXoFWsVJLwwsRMplRf7C9s,8063
|
|
36
|
-
dissect/database/ese/ntds/schema.py,sha256=
|
|
36
|
+
dissect/database/ese/ntds/schema.py,sha256=qAC9STfmJqUMp7633ZcOZOQgWI-UymwX3h4PUUjUV1U,16641
|
|
37
37
|
dissect/database/ese/ntds/sd.py,sha256=Y-oYnJPcLMDB_4X8TLEGtt-n_nC4HLA0WqIS8qYAwAs,5995
|
|
38
|
-
dissect/database/ese/ntds/util.py,sha256=
|
|
38
|
+
dissect/database/ese/ntds/util.py,sha256=3aIvxX3B2-LXQgmHA6rrFiN0obIZHdfD1-wKfecqaI8,20451
|
|
39
39
|
dissect/database/ese/ntds/objects/__init__.py,sha256=LpZ9nHGxmuhVPQkD-qwh-OwFM1T4OzjcklAcEF2Zmrs,10868
|
|
40
40
|
dissect/database/ese/ntds/objects/applicationsettings.py,sha256=j7UzmF8yxm3LR2lLnmGb7vFvUhYokCUOdhJXnk9xxzE,358
|
|
41
|
-
dissect/database/ese/ntds/objects/attributeschema.py,sha256=
|
|
41
|
+
dissect/database/ese/ntds/objects/attributeschema.py,sha256=E8JioZAc_OgnK60nbrxHFxgFBvR1HKAz0tCdj4xt6DI,892
|
|
42
42
|
dissect/database/ese/ntds/objects/builtindomain.py,sha256=KEo-YQl-r748Hnkod21qej2qsLGj7jM4vt6nbufMPWQ,334
|
|
43
|
-
dissect/database/ese/ntds/objects/certificationauthority.py,sha256=
|
|
43
|
+
dissect/database/ese/ntds/objects/certificationauthority.py,sha256=XWGzSImJ7Qo1TEMTUznAslp-810lWe8Xpk-Cjo99nIc,532
|
|
44
44
|
dissect/database/ese/ntds/objects/classschema.py,sha256=Hrpfgl_mR6ciHL7qya63mvzsrouFIy4BJVHU5wJm_Hg,1544
|
|
45
45
|
dissect/database/ese/ntds/objects/classstore.py,sha256=VqWGm4ZqonQQGnFE67AyGGUYuTLdBmPQzZ34X-fRG5M,321
|
|
46
|
-
dissect/database/ese/ntds/objects/computer.py,sha256=
|
|
47
|
-
dissect/database/ese/ntds/objects/configuration.py,sha256=
|
|
46
|
+
dissect/database/ese/ntds/objects/computer.py,sha256=F6twYcQNvfiY1Ba5BmYwhgMEwpqU53wKTPxBaQ0BnO0,1636
|
|
47
|
+
dissect/database/ese/ntds/objects/configuration.py,sha256=jPef8omT1QinAQ51ST_YaBcGGEzOzn-pZ9-Bg5uYMUY,483
|
|
48
48
|
dissect/database/ese/ntds/objects/container.py,sha256=fYtFfWHpcr_4wMN0_vfN9pRx2UXt26Fw31c4FOH9uEQ,316
|
|
49
49
|
dissect/database/ese/ntds/objects/controlaccessright.py,sha256=Xh0hYp7rOQ2oZEA2hOALY_uGZNAxkiuhzhrgK1pLM2U,354
|
|
50
50
|
dissect/database/ese/ntds/objects/crldistributionpoint.py,sha256=f9G1uDI3Pq9hQ6ldfvv6eEuAWpFrnwxgbKTELYlQlrY,358
|
|
51
|
-
dissect/database/ese/ntds/objects/crossref.py,sha256
|
|
52
|
-
dissect/database/ese/ntds/objects/crossrefcontainer.py,sha256=
|
|
51
|
+
dissect/database/ese/ntds/objects/crossref.py,sha256=G6WGZsXwny0nX77bJ5rMf5LiE2c9p7ENxjPofxfhCAg,811
|
|
52
|
+
dissect/database/ese/ntds/objects/crossrefcontainer.py,sha256=YeEnVCVYpt6p1jQ8grctPz3r9DWZj55DwDWc-zJubmo,548
|
|
53
53
|
dissect/database/ese/ntds/objects/dfsconfiguration.py,sha256=Ofgj8Nnfw4_kGTjGnqaSDB6opshqQMNAJFFk_AuTbbo,345
|
|
54
54
|
dissect/database/ese/ntds/objects/displayspecifier.py,sha256=Kuc7usI-zLK0TadGAm_fnuu6DurHNYZD6-hQMlQ3F6g,345
|
|
55
55
|
dissect/database/ese/ntds/objects/dmd.py,sha256=SnJLgFO5rMmsVjgYN0z0klE5tQkZxnmAaqsWefitV0U,324
|
|
56
56
|
dissect/database/ese/ntds/objects/dnsnode.py,sha256=os48qV-nvqa80PiyDLXVSST31NI_KfFC32jlkm30FzY,309
|
|
57
57
|
dissect/database/ese/ntds/objects/dnszone.py,sha256=rJ_3zdsxrR3FvzXU1qbbGqnh67FR64CRClO3dF7wBXU,659
|
|
58
58
|
dissect/database/ese/ntds/objects/domain.py,sha256=aWQN-5P1MMh2aPXJoyPORxhyE_5dIt7aIfBB7Bxp8mM,304
|
|
59
|
-
dissect/database/ese/ntds/objects/domaindns.py,sha256=
|
|
59
|
+
dissect/database/ese/ntds/objects/domaindns.py,sha256=bHJQukHnhmBJwgGMTiwWHyF5PXQYhv6sdYrJP2QH2CY,780
|
|
60
60
|
dissect/database/ese/ntds/objects/domainpolicy.py,sha256=SjvVx1Tx0_ckkf4_rIGlA5YMBHQ3POoMn5vQJl2yzwA,687
|
|
61
61
|
dissect/database/ese/ntds/objects/dsuisettings.py,sha256=hklM6JRYVQ-28nL_yv8S53yOOLc-ph93eEwJr2rM5CA,330
|
|
62
62
|
dissect/database/ese/ntds/objects/filelinktracking.py,sha256=UmsPb_pKSjCIy6K7pbcdNlZVLhF3FaehbbqYM8SpTRY,346
|
|
63
63
|
dissect/database/ese/ntds/objects/foreignsecurityprincipal.py,sha256=w87K7yXSwGBrka6IFntVPtOhihyN5Dy5pM_ZNp8qYAM,378
|
|
64
|
-
dissect/database/ese/ntds/objects/group.py,sha256=
|
|
65
|
-
dissect/database/ese/ntds/objects/grouppolicycontainer.py,sha256=
|
|
64
|
+
dissect/database/ese/ntds/objects/group.py,sha256=ONPHhZo27rFOxhRvVAFEQ9LFSyAGVkzQ63s-67Uq0hQ,1662
|
|
65
|
+
dissect/database/ese/ntds/objects/grouppolicycontainer.py,sha256=dglJ-M85cGV2ltPL6eYD6FhYYQ-ZX2cg9Lo5-Fu9Lpg,548
|
|
66
66
|
dissect/database/ese/ntds/objects/infrastructureupdate.py,sha256=g5qvuqaFJRMUTfREd9B2NkQoF_Oavg8XsMn3_WPYRtQ,362
|
|
67
67
|
dissect/database/ese/ntds/objects/intersitetransport.py,sha256=1-4Hh1jFFM4EyRQigHBiPnCfWRON_irZp4LTKowVVpQ,355
|
|
68
68
|
dissect/database/ese/ntds/objects/intersitetransportcontainer.py,sha256=UuVsYRk4PHtE8SGXNnmo0x5NYWhTUtWDI7bawVFZYpI,386
|
|
@@ -112,17 +112,17 @@ dissect/database/ese/ntds/objects/mspki_privatekeyrecoveryagent.py,sha256=BA7NKZ
|
|
|
112
112
|
dissect/database/ese/ntds/objects/msspp_activationobjectscontainer.py,sha256=l_OpFUHcRZ7LYvXAdfrDXSClX9f78Ca5UJPgNszo3ZE,405
|
|
113
113
|
dissect/database/ese/ntds/objects/mstpm_informationobjectscontainer.py,sha256=84wqeKMwcShtr6uzgHoG6rMpk_3r22xe6BTvpt24pSg,404
|
|
114
114
|
dissect/database/ese/ntds/objects/ntdsconnection.py,sha256=mWgzUTQ0o6Gsc6CsyBoakyXV5UejzTlsVp8j3vm10bw,341
|
|
115
|
-
dissect/database/ese/ntds/objects/ntdsdsa.py,sha256=
|
|
115
|
+
dissect/database/ese/ntds/objects/ntdsdsa.py,sha256=g9YtoARzN6IWk0ai0dcwWYQf1B4afjc6OV2ec1twTe8,1408
|
|
116
116
|
dissect/database/ese/ntds/objects/ntdsservice.py,sha256=mTdpd2tzm8OOiGm6rJN35_dyeWtvzPYI_rVDBZz0gNc,326
|
|
117
117
|
dissect/database/ese/ntds/objects/ntdssitesettings.py,sha256=VNlke-Vgxjh0fzd5o2X-4fwCBrkEI1coR4oto5OenPo,709
|
|
118
118
|
dissect/database/ese/ntds/objects/ntfrssettings.py,sha256=PwIKT6t_zRxfdacWuvzMfq_mIhj_wyIhHzORNcF2eOU,745
|
|
119
|
-
dissect/database/ese/ntds/objects/object.py,sha256=
|
|
120
|
-
dissect/database/ese/ntds/objects/organizationalperson.py,sha256=
|
|
121
|
-
dissect/database/ese/ntds/objects/organizationalunit.py,sha256=
|
|
122
|
-
dissect/database/ese/ntds/objects/person.py,sha256=
|
|
119
|
+
dissect/database/ese/ntds/objects/object.py,sha256=cEBfgi6vLplql2fZbDeRJHDcHVHk9pLIxhMX90SfGLY,11320
|
|
120
|
+
dissect/database/ese/ntds/objects/organizationalperson.py,sha256=KUfpx76IObfdf8feLTVjJj3tAONS7np3st9xVPtPmCQ,1123
|
|
121
|
+
dissect/database/ese/ntds/objects/organizationalunit.py,sha256=3PrtKri5Unmcg_poLWVFDmF2m0BdiibKgSwq4c6kG-w,1631
|
|
122
|
+
dissect/database/ese/ntds/objects/person.py,sha256=pDnOHNFWD3phbipS0gCQLrFzXpqroI8O_5pUuAQk8Ko,628
|
|
123
123
|
dissect/database/ese/ntds/objects/physicallocation.py,sha256=Wp-lGM8TVEaPa0syzHe07vHRL98nXwP_iCtlHv0650s,719
|
|
124
124
|
dissect/database/ese/ntds/objects/pkicertificatetemplate.py,sha256=zLNujYL62arZy0w9UzVUgMr8htPSygeygG5ZDROS0F0,370
|
|
125
|
-
dissect/database/ese/ntds/objects/pkienrollmentservice.py,sha256=
|
|
125
|
+
dissect/database/ese/ntds/objects/pkienrollmentservice.py,sha256=jaS-OmAOu-fpg8wXuq_lcacACeY2gUA_54-PzIIZKCU,524
|
|
126
126
|
dissect/database/ese/ntds/objects/querypolicy.py,sha256=W6O1qevlVEn6Y1yRi1Ki8FErrNCE5leYE4J_y_eNhrc,325
|
|
127
127
|
dissect/database/ese/ntds/objects/ridmanager.py,sha256=magfnp-sk3Nb6BapzUbcphM-UVxOMBAVQgiaFGYCJpU,319
|
|
128
128
|
dissect/database/ese/ntds/objects/ridset.py,sha256=xpmfNsqKwSIL4D9bNvaOokbz-95bcxhbeFxgRtf-muY,303
|
|
@@ -131,16 +131,16 @@ dissect/database/ese/ntds/objects/rrasadministrationdictionary.py,sha256=dzS3xag
|
|
|
131
131
|
dissect/database/ese/ntds/objects/samserver.py,sha256=q32pI-Pjd1TOQle_LuR53rjZlDjCY2U2aAYCWjLEaDg,348
|
|
132
132
|
dissect/database/ese/ntds/objects/secret.py,sha256=0278o0wpy3n5JmhYKFpNDy1MgNcHBbjX0aUYXxeCUlQ,3392
|
|
133
133
|
dissect/database/ese/ntds/objects/securityobject.py,sha256=hR0a0wjyrLFtSMtRZOwPCYXpfuOCtNMhozK4bkzly-A,330
|
|
134
|
-
dissect/database/ese/ntds/objects/server.py,sha256=
|
|
134
|
+
dissect/database/ese/ntds/objects/server.py,sha256=k1iqvIUHttxXz3aQLJPJkN2FH-pAz4SE3Z2tdzJS2-U,1039
|
|
135
135
|
dissect/database/ese/ntds/objects/serverscontainer.py,sha256=NnJ0M23RO-hsKd2vWcvViOMRV8psGJkwiaRC-ghmrk0,345
|
|
136
|
-
dissect/database/ese/ntds/objects/site.py,sha256=
|
|
136
|
+
dissect/database/ese/ntds/objects/site.py,sha256=Ozc_TNvXKhIbHJShLpBuHMWkS82IpxSoYErziJ9B9dE,1175
|
|
137
137
|
dissect/database/ese/ntds/objects/sitelink.py,sha256=cNHis9jsxFPtxfiCfxd4klP495XfjcwrF507wduyADk,313
|
|
138
138
|
dissect/database/ese/ntds/objects/sitescontainer.py,sha256=C09THsbE-tBz2fFsYj5UkdbNuzIBqTo65F71a0oEY3w,337
|
|
139
139
|
dissect/database/ese/ntds/objects/subnetcontainer.py,sha256=IEwSBFxoPXBIKuH-V7rK5yueAEDaMIuVXbtTEmGUlCg,341
|
|
140
140
|
dissect/database/ese/ntds/objects/subschema.py,sha256=-vE76P_Yhj-Ny6ZAYnTTPMS0dtLNFZRUgyh9IXIm5Po,317
|
|
141
|
-
dissect/database/ese/ntds/objects/top.py,sha256=
|
|
142
|
-
dissect/database/ese/ntds/objects/trusteddomain.py,sha256=
|
|
143
|
-
dissect/database/ese/ntds/objects/user.py,sha256=
|
|
141
|
+
dissect/database/ese/ntds/objects/top.py,sha256=jXH9u3g3EhPAA4Tiw9g201BaZPJ1-4FeLOnKL5ma3Vg,676
|
|
142
|
+
dissect/database/ese/ntds/objects/trusteddomain.py,sha256=PhioFfl5gkGFQIS0_D70rIH0x0g3Hp9ZhaNMxCh6afs,1645
|
|
143
|
+
dissect/database/ese/ntds/objects/user.py,sha256=mMZ9CE6YL5sNm6KxAJWk50lxdB-P-pYeIKvEwsWSSL4,5213
|
|
144
144
|
dissect/database/ese/ntds/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
145
145
|
dissect/database/ese/ntds/tools/ntds.py,sha256=6hgpoSr-QKgbz8ABkYsM-MZf6kkH_nlJbz_BCqbrGzE,861
|
|
146
146
|
dissect/database/ese/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -159,10 +159,10 @@ dissect/database/sqlite3/encryption/__init__.py,sha256=kJdFWXD9Z_O_QipC-_A9dlVfR
|
|
|
159
159
|
dissect/database/sqlite3/encryption/sqlcipher/__init__.py,sha256=kJdFWXD9Z_O_QipC-_A9dlVfR6AOPSOoT8WBhpFbSsE,238
|
|
160
160
|
dissect/database/sqlite3/encryption/sqlcipher/exception.py,sha256=GKNtzcnAKlWkvjLluruA8LfzCwjRRWubibbH8WM9l2o,121
|
|
161
161
|
dissect/database/sqlite3/encryption/sqlcipher/sqlcipher.py,sha256=y_oJRKZqoJBeOQaBbniesZKm1sVTFvXZ466rJYZj2xE,11217
|
|
162
|
-
dissect_database-1.2.
|
|
163
|
-
dissect_database-1.2.
|
|
164
|
-
dissect_database-1.2.
|
|
165
|
-
dissect_database-1.2.
|
|
166
|
-
dissect_database-1.2.
|
|
167
|
-
dissect_database-1.2.
|
|
168
|
-
dissect_database-1.2.
|
|
162
|
+
dissect_database-1.2.dev9.dist-info/licenses/COPYRIGHT,sha256=pFH-OBYz6Xj23UB0Odz5IhoTR8nsTbJQNlCRV_wMaiE,317
|
|
163
|
+
dissect_database-1.2.dev9.dist-info/licenses/LICENSE,sha256=PhUqiw6jAh2KbBdVRPBq_hfAvfcTBin7nZ3CK7NQbTM,11341
|
|
164
|
+
dissect_database-1.2.dev9.dist-info/METADATA,sha256=lpFACmhxqvnFHoHk3_cI8ydgt--hK4JpVhbHVksYfVU,5540
|
|
165
|
+
dissect_database-1.2.dev9.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
166
|
+
dissect_database-1.2.dev9.dist-info/entry_points.txt,sha256=ZVVKj3Nzjkgm1kBXGWyGNVUJzTbmVgivv9lgFcuLkpk,343
|
|
167
|
+
dissect_database-1.2.dev9.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
|
|
168
|
+
dissect_database-1.2.dev9.dist-info/RECORD,,
|
|
File without changes
|
{dissect_database-1.2.dev8.dist-info → dissect_database-1.2.dev9.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{dissect_database-1.2.dev8.dist-info → dissect_database-1.2.dev9.dist-info}/licenses/COPYRIGHT
RENAMED
|
File without changes
|
{dissect_database-1.2.dev8.dist-info → dissect_database-1.2.dev9.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
|
File without changes
|