dissect.database 1.2.dev9__py3-none-any.whl → 1.2.dev10__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/ntds.py +5 -0
- dissect/database/ese/ntds/objects/c_dnsnode.py +109 -0
- dissect/database/ese/ntds/objects/c_dnsnode.pyi +146 -0
- dissect/database/ese/ntds/objects/dnsnode.py +430 -0
- dissect/database/ese/ntds/util.py +3 -0
- {dissect_database-1.2.dev9.dist-info → dissect_database-1.2.dev10.dist-info}/METADATA +1 -1
- {dissect_database-1.2.dev9.dist-info → dissect_database-1.2.dev10.dist-info}/RECORD +12 -10
- {dissect_database-1.2.dev9.dist-info → dissect_database-1.2.dev10.dist-info}/WHEEL +0 -0
- {dissect_database-1.2.dev9.dist-info → dissect_database-1.2.dev10.dist-info}/entry_points.txt +0 -0
- {dissect_database-1.2.dev9.dist-info → dissect_database-1.2.dev10.dist-info}/licenses/COPYRIGHT +0 -0
- {dissect_database-1.2.dev9.dist-info → dissect_database-1.2.dev10.dist-info}/licenses/LICENSE +0 -0
- {dissect_database-1.2.dev9.dist-info → dissect_database-1.2.dev10.dist-info}/top_level.txt +0 -0
|
@@ -11,6 +11,7 @@ if TYPE_CHECKING:
|
|
|
11
11
|
|
|
12
12
|
from dissect.database.ese.ntds.objects import (
|
|
13
13
|
Computer,
|
|
14
|
+
DnsNode,
|
|
14
15
|
DomainDNS,
|
|
15
16
|
Group,
|
|
16
17
|
GroupPolicyContainer,
|
|
@@ -118,6 +119,10 @@ class NTDS:
|
|
|
118
119
|
"""Get all secret objects from the database."""
|
|
119
120
|
yield from self.search(objectClass="secret")
|
|
120
121
|
|
|
122
|
+
def dns_nodes(self) -> Iterator[DnsNode]:
|
|
123
|
+
"""Get all DnsNode objects from the database."""
|
|
124
|
+
yield from self.search(objectClass="dnsNode")
|
|
125
|
+
|
|
121
126
|
def backup_keys(self) -> Iterator[BackupKey]:
|
|
122
127
|
"""Get all DPAPI backup keys from the database."""
|
|
123
128
|
if not self.pek.unlocked:
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dissect.cstruct import cstruct
|
|
4
|
+
|
|
5
|
+
dns_record_def = """
|
|
6
|
+
|
|
7
|
+
// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dnsp/39b03b89-2264-4063-8198-d62f62a6441a
|
|
8
|
+
enum DNS_RECORD_TYPE : WORD {
|
|
9
|
+
ZERO = 0x0000, // An empty record type ([RFC1034] section 3.6 and [RFC1035] section 3.2.2).
|
|
10
|
+
A = 0x0001, // An A record type, used for storing an IP address ([RFC1035] section 3.2.2).
|
|
11
|
+
NS = 0x0002, // An authoritative name-server
|
|
12
|
+
// record type ([RFC1034] section 3.6 and [RFC1035] section 3.2.2).
|
|
13
|
+
MD = 0x0003, // A mail-destination record type ([RFC1035] section 3.2.2).
|
|
14
|
+
MF = 0x0004, // A mail forwarder record type ([RFC1035] section 3.2.2).
|
|
15
|
+
CNAME = 0x0005, // A record type that contains the canonical name of a DNS alias ([RFC1035] section 3.2.2).
|
|
16
|
+
SOA = 0x0006, // A Start of Authority (SOA) record type ([RFC1035] section 3.2.2).
|
|
17
|
+
MB = 0x0007, // A mailbox record type ([RFC1035] section 3.2.2).
|
|
18
|
+
MG = 0x0008, // A mail group member record type ([RFC1035] section 3.2.2).
|
|
19
|
+
MR = 0x0009, // A mail-rename record type ([RFC1035] section 3.2.2).
|
|
20
|
+
NULL = 0x000A, // A record type for completion queries ([RFC1035] section 3.2.2).
|
|
21
|
+
WKS = 0x000B, // A record type for a well-known service ([RFC1035] section 3.2.2).
|
|
22
|
+
PTR = 0x000C, // A record type containing FQDN pointer ([RFC1035] section 3.2.2).
|
|
23
|
+
HINFO = 0x000D, // A host information record type ([RFC1035] section 3.2.2).
|
|
24
|
+
MINFO = 0x000E, // A mailbox or mailing list information record type ([RFC1035] section 3.2.2).
|
|
25
|
+
MX = 0x000F, // A mail-exchanger record type ([RFC1035] section 3.2.2).
|
|
26
|
+
TXT = 0x0010, // A record type containing a text string ([RFC1035] section 3.2.2).
|
|
27
|
+
RP = 0x0011, // A responsible-person record type [RFC1183].
|
|
28
|
+
AFSDB = 0x0012, // A record type containing AFS database location [RFC1183].
|
|
29
|
+
X25 = 0x0013, // An X25 PSDN address record type [RFC1183].
|
|
30
|
+
ISDN = 0x0014, // An ISDN address record type [RFC1183].
|
|
31
|
+
RT = 0x0015, // A route through record type [RFC1183].
|
|
32
|
+
SIG = 0x0018, // A cryptographic public key signature record type [RFC2931].
|
|
33
|
+
KEY = 0x0019, // A record type containing public key used in DNSSEC [RFC2535].
|
|
34
|
+
AAAA = 0x001C, // An IPv6 address record type [RFC3596].
|
|
35
|
+
LOC = 0x001D, // A location information record type [RFC1876].
|
|
36
|
+
NXT = 0x001E, // A next-domain record type [RFC2065].
|
|
37
|
+
SRV = 0x0021, // A server selection record type [RFC2782].
|
|
38
|
+
ATMA = 0x0022, // An Asynchronous Transfer Mode (ATM) address record type [ATMA].
|
|
39
|
+
NAPTR = 0x0023, // An NAPTR record type [RFC2915].
|
|
40
|
+
DNAME = 0x0027, // A DNAME record type [RFC2672].
|
|
41
|
+
DS = 0x002B, // A DS record type [RFC4034].
|
|
42
|
+
RRSIG = 0x002E, // An RRSIG record type [RFC4034].
|
|
43
|
+
NSEC = 0x002F, // An NSEC record type [RFC4034].
|
|
44
|
+
DNSKEY = 0x0030, // A DNSKEY record type [RFC4034].
|
|
45
|
+
DHCID = 0x0031, // A DHCID record type [RFC4701].
|
|
46
|
+
NSEC3 = 0x0032, // An NSEC3 record type [RFC5155].
|
|
47
|
+
NSEC3PARAM = 0x0033, // An NSEC3PARAM record type [RFC5155].
|
|
48
|
+
TLSA = 0x0034, // A TLSA record type [RFC6698].
|
|
49
|
+
ALL = 0x00FF, // A query-only type requesting all records [RFC1035].
|
|
50
|
+
WINS = 0xFF01, // A record type containing Windows Internet Name Service (WINS)
|
|
51
|
+
// forward lookup data [MS-WINSRADNS_TYPE_WINSR].
|
|
52
|
+
WINSR = 0xFF02 // A record type containing WINS reverse lookup data [MS-WINSRA].
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dnsp/6912b338-5472-4f59-b912-0edb536b6ed8
|
|
56
|
+
typedef struct DNS_RECORD_HEADER {
|
|
57
|
+
WORD DataLength;
|
|
58
|
+
DNS_RECORD_TYPE Type;
|
|
59
|
+
BYTE Version; // Must be 0x05
|
|
60
|
+
BYTE Rank;
|
|
61
|
+
WORD Flags; // Must be 0x00
|
|
62
|
+
DWORD Serial;
|
|
63
|
+
DWORD TtlSeconds; // Big Endian
|
|
64
|
+
DWORD Reserved; // MUST be 0x00000000.
|
|
65
|
+
DWORD TimeStamp;
|
|
66
|
+
CHAR Data[DataLength];
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dnsp/3fd41adc-c69e-407b-979e-721251403132
|
|
70
|
+
// MS docs indicate that structure is 4 byte aligned, and that the string MUST NOT be null-terminated.
|
|
71
|
+
// But observed reality is a null terminated string (null char not counted in NameLength)
|
|
72
|
+
typedef struct DNS_RPC_NAME{
|
|
73
|
+
BYTE NameLength;
|
|
74
|
+
CHAR dnsName[NameLength];
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dnsp/db37cab7-f121-43ba-81c5-ca0e198d4b9a
|
|
78
|
+
typedef struct DNS_RPC_RECORD_SRV {
|
|
79
|
+
WORD Priority;
|
|
80
|
+
WORD Weight;
|
|
81
|
+
WORD Port;
|
|
82
|
+
DNS_RPC_NAME nameTarget;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dnsp/f647d391-6614-4c3e-b38b-4df971590eb6
|
|
86
|
+
typedef struct DNS_RPC_RECORD_NAME_PREFERENCE {
|
|
87
|
+
WORD Preference;
|
|
88
|
+
DNS_RPC_NAME nameExchange;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dnsp/dcd3ec16-d6bf-4bb4-9128-6172f9e5f066
|
|
92
|
+
typedef struct DNS_RPC_RECORD_SOA {
|
|
93
|
+
DWORD Serial;
|
|
94
|
+
DWORD Refresh;
|
|
95
|
+
DWORD Retry;
|
|
96
|
+
DWORD Expire;
|
|
97
|
+
DWORD MinimumTtl;
|
|
98
|
+
DNS_RPC_NAME namePrimaryServer;
|
|
99
|
+
BYTE _pad;
|
|
100
|
+
DNS_RPC_NAME ZoneAdministratorEmail;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dnsp/def7736a-dd09-4b4a-b8d6-6a702a7ecde0
|
|
104
|
+
typedef struct DNS_RPC_RECORD_TS {
|
|
105
|
+
QWORD EntombedTime;
|
|
106
|
+
};
|
|
107
|
+
"""
|
|
108
|
+
c_dns_record = cstruct(dns_record_def)
|
|
109
|
+
DNS_RECORD_TYPE = c_dns_record.DNS_RECORD_TYPE
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# Generated by cstruct-stubgen
|
|
2
|
+
from typing import BinaryIO, Literal, TypeAlias, overload
|
|
3
|
+
|
|
4
|
+
import dissect.cstruct as __cs__
|
|
5
|
+
|
|
6
|
+
class _c_dns_record(__cs__.cstruct):
|
|
7
|
+
class DNS_RECORD_TYPE(__cs__.Enum):
|
|
8
|
+
ZERO = ...
|
|
9
|
+
A = ...
|
|
10
|
+
NS = ...
|
|
11
|
+
MD = ...
|
|
12
|
+
MF = ...
|
|
13
|
+
CNAME = ...
|
|
14
|
+
SOA = ...
|
|
15
|
+
MB = ...
|
|
16
|
+
MG = ...
|
|
17
|
+
MR = ...
|
|
18
|
+
NULL = ...
|
|
19
|
+
WKS = ...
|
|
20
|
+
PTR = ...
|
|
21
|
+
HINFO = ...
|
|
22
|
+
MINFO = ...
|
|
23
|
+
MX = ...
|
|
24
|
+
TXT = ...
|
|
25
|
+
RP = ...
|
|
26
|
+
AFSDB = ...
|
|
27
|
+
X25 = ...
|
|
28
|
+
ISDN = ...
|
|
29
|
+
RT = ...
|
|
30
|
+
SIG = ...
|
|
31
|
+
KEY = ...
|
|
32
|
+
AAAA = ...
|
|
33
|
+
LOC = ...
|
|
34
|
+
NXT = ...
|
|
35
|
+
SRV = ...
|
|
36
|
+
ATMA = ...
|
|
37
|
+
NAPTR = ...
|
|
38
|
+
DNAME = ...
|
|
39
|
+
DS = ...
|
|
40
|
+
RRSIG = ...
|
|
41
|
+
NSEC = ...
|
|
42
|
+
DNSKEY = ...
|
|
43
|
+
DHCID = ...
|
|
44
|
+
NSEC3 = ...
|
|
45
|
+
NSEC3PARAM = ...
|
|
46
|
+
TLSA = ...
|
|
47
|
+
ALL = ...
|
|
48
|
+
WINS = ...
|
|
49
|
+
WINSR = ...
|
|
50
|
+
|
|
51
|
+
class DNS_RECORD_HEADER(__cs__.Structure):
|
|
52
|
+
DataLength: _c_dns_record.uint16
|
|
53
|
+
Type: _c_dns_record.DNS_RECORD_TYPE
|
|
54
|
+
Version: _c_dns_record.uint8
|
|
55
|
+
Rank: _c_dns_record.uint8
|
|
56
|
+
Flags: _c_dns_record.uint16
|
|
57
|
+
Serial: _c_dns_record.uint32
|
|
58
|
+
TtlSeconds: _c_dns_record.uint32
|
|
59
|
+
Reserved: _c_dns_record.uint32
|
|
60
|
+
TimeStamp: _c_dns_record.uint32
|
|
61
|
+
Data: __cs__.CharArray
|
|
62
|
+
@overload
|
|
63
|
+
def __init__(
|
|
64
|
+
self,
|
|
65
|
+
DataLength: _c_dns_record.uint16 | None = ...,
|
|
66
|
+
Type: _c_dns_record.DNS_RECORD_TYPE | None = ...,
|
|
67
|
+
Version: _c_dns_record.uint8 | None = ...,
|
|
68
|
+
Rank: _c_dns_record.uint8 | None = ...,
|
|
69
|
+
Flags: _c_dns_record.uint16 | None = ...,
|
|
70
|
+
Serial: _c_dns_record.uint32 | None = ...,
|
|
71
|
+
TtlSeconds: _c_dns_record.uint32 | None = ...,
|
|
72
|
+
Reserved: _c_dns_record.uint32 | None = ...,
|
|
73
|
+
TimeStamp: _c_dns_record.uint32 | None = ...,
|
|
74
|
+
Data: __cs__.CharArray | None = ...,
|
|
75
|
+
): ...
|
|
76
|
+
@overload
|
|
77
|
+
def __init__(self, fh: bytes | memoryview | bytearray | BinaryIO, /): ...
|
|
78
|
+
|
|
79
|
+
class DNS_RPC_NAME(__cs__.Structure):
|
|
80
|
+
NameLength: _c_dns_record.uint8
|
|
81
|
+
dnsName: __cs__.CharArray
|
|
82
|
+
@overload
|
|
83
|
+
def __init__(self, NameLength: _c_dns_record.uint8 | None = ..., dnsName: __cs__.CharArray | None = ...): ...
|
|
84
|
+
@overload
|
|
85
|
+
def __init__(self, fh: bytes | memoryview | bytearray | BinaryIO, /): ...
|
|
86
|
+
|
|
87
|
+
class DNS_RPC_RECORD_SRV(__cs__.Structure):
|
|
88
|
+
Priority: _c_dns_record.uint16
|
|
89
|
+
Weight: _c_dns_record.uint16
|
|
90
|
+
Port: _c_dns_record.uint16
|
|
91
|
+
nameTarget: _c_dns_record.DNS_RPC_NAME
|
|
92
|
+
@overload
|
|
93
|
+
def __init__(
|
|
94
|
+
self,
|
|
95
|
+
Priority: _c_dns_record.uint16 | None = ...,
|
|
96
|
+
Weight: _c_dns_record.uint16 | None = ...,
|
|
97
|
+
Port: _c_dns_record.uint16 | None = ...,
|
|
98
|
+
nameTarget: _c_dns_record.DNS_RPC_NAME | None = ...,
|
|
99
|
+
): ...
|
|
100
|
+
@overload
|
|
101
|
+
def __init__(self, fh: bytes | memoryview | bytearray | BinaryIO, /): ...
|
|
102
|
+
|
|
103
|
+
class DNS_RPC_RECORD_NAME_PREFERENCE(__cs__.Structure):
|
|
104
|
+
Preference: _c_dns_record.uint16
|
|
105
|
+
nameExchange: _c_dns_record.DNS_RPC_NAME
|
|
106
|
+
@overload
|
|
107
|
+
def __init__(
|
|
108
|
+
self, Preference: _c_dns_record.uint16 | None = ..., nameExchange: _c_dns_record.DNS_RPC_NAME | None = ...
|
|
109
|
+
): ...
|
|
110
|
+
@overload
|
|
111
|
+
def __init__(self, fh: bytes | memoryview | bytearray | BinaryIO, /): ...
|
|
112
|
+
|
|
113
|
+
class DNS_RPC_RECORD_SOA(__cs__.Structure):
|
|
114
|
+
Serial: _c_dns_record.uint32
|
|
115
|
+
Refresh: _c_dns_record.uint32
|
|
116
|
+
Retry: _c_dns_record.uint32
|
|
117
|
+
Expire: _c_dns_record.uint32
|
|
118
|
+
MinimumTtl: _c_dns_record.uint32
|
|
119
|
+
namePrimaryServer: _c_dns_record.DNS_RPC_NAME
|
|
120
|
+
_pad: _c_dns_record.uint8
|
|
121
|
+
ZoneAdministratorEmail: _c_dns_record.DNS_RPC_NAME
|
|
122
|
+
@overload
|
|
123
|
+
def __init__(
|
|
124
|
+
self,
|
|
125
|
+
Serial: _c_dns_record.uint32 | None = ...,
|
|
126
|
+
Refresh: _c_dns_record.uint32 | None = ...,
|
|
127
|
+
Retry: _c_dns_record.uint32 | None = ...,
|
|
128
|
+
Expire: _c_dns_record.uint32 | None = ...,
|
|
129
|
+
MinimumTtl: _c_dns_record.uint32 | None = ...,
|
|
130
|
+
namePrimaryServer: _c_dns_record.DNS_RPC_NAME | None = ...,
|
|
131
|
+
_pad: _c_dns_record.uint8 | None = ...,
|
|
132
|
+
ZoneAdministratorEmail: _c_dns_record.DNS_RPC_NAME | None = ...,
|
|
133
|
+
): ...
|
|
134
|
+
@overload
|
|
135
|
+
def __init__(self, fh: bytes | memoryview | bytearray | BinaryIO, /): ...
|
|
136
|
+
|
|
137
|
+
class DNS_RPC_RECORD_TS(__cs__.Structure):
|
|
138
|
+
EntombedTime: _c_dns_record.uint64
|
|
139
|
+
@overload
|
|
140
|
+
def __init__(self, EntombedTime: _c_dns_record.uint64 | None = ...): ...
|
|
141
|
+
@overload
|
|
142
|
+
def __init__(self, fh: bytes | memoryview | bytearray | BinaryIO, /): ...
|
|
143
|
+
|
|
144
|
+
# Technically `c_dns_record` is an instance of `_c_dns_record`, but then we can't use it in type hints
|
|
145
|
+
c_dns_record: TypeAlias = _c_dns_record
|
|
146
|
+
DNS_RECORD_TYPE: TypeAlias = _c_dns_record.DNS_RECORD_TYPE
|
|
@@ -1,13 +1,443 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import datetime
|
|
4
|
+
import logging
|
|
5
|
+
import socket
|
|
6
|
+
import typing
|
|
7
|
+
from functools import cached_property
|
|
8
|
+
from typing import Any, ClassVar, NamedTuple
|
|
9
|
+
|
|
10
|
+
from dissect.cstruct.utils import swap16, swap32
|
|
11
|
+
|
|
12
|
+
from dissect.database.ese.ntds.objects.c_dnsnode import DNS_RECORD_TYPE, c_dns_record
|
|
3
13
|
from dissect.database.ese.ntds.objects.top import Top
|
|
4
14
|
|
|
15
|
+
if typing.TYPE_CHECKING:
|
|
16
|
+
from dissect.database.ese.ntds.objects.object import DecoderMap
|
|
17
|
+
log = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def parse_rfc1035_dns_name(data: bytes) -> str:
|
|
21
|
+
"""Parse DNS name as specified in ``rfc1035#section-3.1`` format.
|
|
22
|
+
|
|
23
|
+
References:
|
|
24
|
+
- https://datatracker.ietf.org/doc/html/rfc1035#section-3.1
|
|
25
|
+
"""
|
|
26
|
+
if not data:
|
|
27
|
+
return ""
|
|
28
|
+
_nb_segment = data[0]
|
|
29
|
+
name_parts = []
|
|
30
|
+
offset = 1
|
|
31
|
+
# Domain names in messages are expressed in terms of a sequence of labels.
|
|
32
|
+
# Each label is represented as a one octet length field followed by that
|
|
33
|
+
# number of octets. Since every domain name ends with the null label of
|
|
34
|
+
# the root, a domain name is terminated by a length byte of zero.
|
|
35
|
+
while offset < len(data):
|
|
36
|
+
length = data[offset]
|
|
37
|
+
if length == 0:
|
|
38
|
+
name_parts.append("")
|
|
39
|
+
break
|
|
40
|
+
# The high order two bits of every length octet must be zero, and the
|
|
41
|
+
# remaining six bits of the length field limit the label to 63 octets or
|
|
42
|
+
# less.
|
|
43
|
+
if length > 63: # Compression pointer
|
|
44
|
+
return "<error>"
|
|
45
|
+
|
|
46
|
+
offset += 1
|
|
47
|
+
if offset + length > len(data):
|
|
48
|
+
return "<error>"
|
|
49
|
+
|
|
50
|
+
part = data[offset : offset + length].decode("utf-8", errors="backslashreplace")
|
|
51
|
+
name_parts.append(part)
|
|
52
|
+
offset += length
|
|
53
|
+
return ".".join(name_parts) if name_parts else ""
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class DnsARecord(NamedTuple):
|
|
57
|
+
"""``A`` resource records."""
|
|
58
|
+
|
|
59
|
+
ipv4_address: str
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
def ip_address(self) -> str:
|
|
63
|
+
return self.ipv4_address
|
|
64
|
+
|
|
65
|
+
@classmethod
|
|
66
|
+
def from_bytes(cls, data: bytes) -> DnsARecord:
|
|
67
|
+
"""Parse ``A`` record (IPv4 address).
|
|
68
|
+
|
|
69
|
+
References:
|
|
70
|
+
- https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dnsp/117c2ff9-9094-45b2-83c2-5e44518e0bac
|
|
71
|
+
|
|
72
|
+
Raises:
|
|
73
|
+
EOFError: Issue while unpacking structure.
|
|
74
|
+
"""
|
|
75
|
+
if len(data) >= 4:
|
|
76
|
+
ip = socket.inet_ntop(socket.AF_INET, data[:4])
|
|
77
|
+
return cls(ipv4_address=ip)
|
|
78
|
+
raise EOFError("A records with less than 4 bytes")
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class DnsAAAARecord(NamedTuple):
|
|
82
|
+
"""``AAAA`` resource records."""
|
|
83
|
+
|
|
84
|
+
ipv6_address: str
|
|
85
|
+
|
|
86
|
+
@property
|
|
87
|
+
def ip_address(self) -> str:
|
|
88
|
+
return self.ipv6_address
|
|
89
|
+
|
|
90
|
+
@classmethod
|
|
91
|
+
def from_bytes(cls, data: bytes) -> DnsAAAARecord:
|
|
92
|
+
"""Parse ``AAAA`` record (IPv6 address).
|
|
93
|
+
|
|
94
|
+
References:
|
|
95
|
+
- https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dnsp/ee33fef1-6e82-42d0-8107-0f6d21be072a
|
|
96
|
+
|
|
97
|
+
Raises:
|
|
98
|
+
EOFError: Issue while unpacking structure.
|
|
99
|
+
"""
|
|
100
|
+
if len(data) >= 16:
|
|
101
|
+
ip = socket.inet_ntop(socket.AF_INET6, data[:16])
|
|
102
|
+
return cls(ipv6_address=ip)
|
|
103
|
+
raise EOFError("AAAA records with less than 16 bytes")
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class SOARecord(NamedTuple):
|
|
107
|
+
"""The ``DNS_RPC_RECORD_SOA`` structure contains information about a ``SOA`` record."""
|
|
108
|
+
|
|
109
|
+
name_primary_server: str
|
|
110
|
+
# Serial does not match value seen using DNS request/management interface
|
|
111
|
+
# As this is not the most important field, we simply ignore it instead a showing a errored value
|
|
112
|
+
# serial: int
|
|
113
|
+
refresh: int
|
|
114
|
+
retry: int
|
|
115
|
+
minimum_ttl: int
|
|
116
|
+
zone_administrator_email: str
|
|
117
|
+
|
|
118
|
+
@classmethod
|
|
119
|
+
def from_bytes(cls, data: bytes) -> SOARecord | None:
|
|
120
|
+
"""Parse ``SOA`` records.
|
|
121
|
+
|
|
122
|
+
References:
|
|
123
|
+
https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dnsp/dcd3ec16-d6bf-4bb4-9128-6172f9e5f066
|
|
124
|
+
|
|
125
|
+
Raises:
|
|
126
|
+
EOFError: Issue while unpacking structure.
|
|
127
|
+
"""
|
|
128
|
+
record = c_dns_record.DNS_RPC_RECORD_SOA(data)
|
|
129
|
+
return cls(
|
|
130
|
+
name_primary_server=parse_rfc1035_dns_name(record.namePrimaryServer.dnsName),
|
|
131
|
+
# Serial does not match value seen using DNS request/management interface
|
|
132
|
+
# As this is not the most important field, we simply ignore it instead a showing an errored value
|
|
133
|
+
# serial=swap32(dns_rpc_record_soa.Serial, int_len=4),
|
|
134
|
+
refresh=swap32(record.Refresh),
|
|
135
|
+
retry=swap32(record.Retry),
|
|
136
|
+
minimum_ttl=swap32(record.MinimumTtl),
|
|
137
|
+
zone_administrator_email=parse_rfc1035_dns_name(record.ZoneAdministratorEmail.dnsName),
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
class NodeNameRecord(NamedTuple):
|
|
142
|
+
"""The ``DNS_RPC_RECORD_NODE_NAME`` structure contains information about a DNS record referring to another DNS name.
|
|
143
|
+
|
|
144
|
+
This corresponds to the following types:
|
|
145
|
+
- ``DNS_TYPE_PTR``
|
|
146
|
+
- ``DNS_TYPE_NS``
|
|
147
|
+
- ``DNS_TYPE_CNAME``
|
|
148
|
+
- ``DNS_TYPE_DNAME``
|
|
149
|
+
- ``DNS_TYPE_MB``
|
|
150
|
+
- ``DNS_TYPE_MR``
|
|
151
|
+
- ``DNS_TYPE_MG``
|
|
152
|
+
- ``DNS_TYPE_MD``
|
|
153
|
+
- ``DNS_TYPE_MF``
|
|
154
|
+
"""
|
|
155
|
+
|
|
156
|
+
name_node: str
|
|
157
|
+
|
|
158
|
+
@classmethod
|
|
159
|
+
def from_bytes(cls, data: bytes) -> NodeNameRecord | None:
|
|
160
|
+
"""Parse Node Name type record (e.g. ``CNAME``, ``PTR``).
|
|
161
|
+
|
|
162
|
+
References:
|
|
163
|
+
- https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dnsp/8f986756-f151-4f5b-bfcf-0d85be8b0d7e
|
|
164
|
+
|
|
165
|
+
Raises:
|
|
166
|
+
EOFError: Issue while unpacking structure.
|
|
167
|
+
"""
|
|
168
|
+
return NodeNameRecord(parse_rfc1035_dns_name(c_dns_record.DNS_RPC_NAME(data).dnsName))
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
class StringRecord(NamedTuple):
|
|
172
|
+
"""The ``DNS_RPC_RECORD_STRING`` structure contains information about a DNS record containing text data.
|
|
173
|
+
|
|
174
|
+
This corresponds to the following types:
|
|
175
|
+
- ``DNS_TYPE_HINFO``
|
|
176
|
+
- ``DNS_TYPE_ISDN``
|
|
177
|
+
- ``DNS_TYPE_TXT``
|
|
178
|
+
- ``DNS_TYPE_X25``
|
|
179
|
+
- ``DNS_TYPE_LOC``
|
|
180
|
+
"""
|
|
181
|
+
|
|
182
|
+
string_data: str
|
|
183
|
+
|
|
184
|
+
@classmethod
|
|
185
|
+
def from_bytes(cls, data: bytes) -> StringRecord | None:
|
|
186
|
+
"""Parse Node Name type record (e.g. ``TXT``).
|
|
187
|
+
|
|
188
|
+
Test using GUI does not allow to create record with a line length > 255 char.
|
|
189
|
+
|
|
190
|
+
References:
|
|
191
|
+
- https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dnsp/69166ff5-36c1-4542-9243-13b8931fa447
|
|
192
|
+
|
|
193
|
+
Raises:
|
|
194
|
+
EOFError: Issue while unpacking structure.
|
|
195
|
+
"""
|
|
196
|
+
records = []
|
|
197
|
+
data_consumed = 0
|
|
198
|
+
|
|
199
|
+
while data_consumed < len(data):
|
|
200
|
+
rpc_name = c_dns_record.DNS_RPC_NAME(data[data_consumed:])
|
|
201
|
+
data_consumed += len(rpc_name)
|
|
202
|
+
|
|
203
|
+
records.append(rpc_name.dnsName.decode("utf-8", errors="backslashreplace"))
|
|
204
|
+
return cls("\n".join(records))
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
class NamePreferenceRecord(NamedTuple):
|
|
208
|
+
"""The ``DNS_RPC_RECORD_NAME_PREFERENCE`` structure specifies information about a DNS
|
|
209
|
+
record referring to another DNS name with a preference.
|
|
210
|
+
|
|
211
|
+
This corresponds to the following types:
|
|
212
|
+
- ``DNS_TYPE_MX``
|
|
213
|
+
- ``DNS_TYPE_AFSDB``
|
|
214
|
+
- ``DNS_TYPE_RT``
|
|
215
|
+
"""
|
|
216
|
+
|
|
217
|
+
name_exchange: str
|
|
218
|
+
preference: int
|
|
219
|
+
|
|
220
|
+
@classmethod
|
|
221
|
+
def from_bytes(cls, data: bytes) -> NamePreferenceRecord | None:
|
|
222
|
+
"""Parse ``DNS_RPC_RECORD_NAME_PREFERENCE`` record (e.g. ``MX``).
|
|
223
|
+
|
|
224
|
+
References:
|
|
225
|
+
- https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dnsp/f647d391-6614-4c3e-b38b-4df971590eb6
|
|
226
|
+
|
|
227
|
+
Raises:
|
|
228
|
+
EOFError: Issue while unpacking structure.
|
|
229
|
+
"""
|
|
230
|
+
record = c_dns_record.DNS_RPC_RECORD_NAME_PREFERENCE(data)
|
|
231
|
+
return cls(
|
|
232
|
+
preference=swap16(record.Preference),
|
|
233
|
+
name_exchange=parse_rfc1035_dns_name(record.nameExchange.dnsName),
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
class SRVRecord(NamedTuple):
|
|
238
|
+
"""``SRV`` resource records."""
|
|
239
|
+
|
|
240
|
+
name_target: str
|
|
241
|
+
port: int
|
|
242
|
+
weight: int
|
|
243
|
+
priority: int
|
|
244
|
+
|
|
245
|
+
@classmethod
|
|
246
|
+
def from_bytes(cls, data: bytes) -> SRVRecord | None:
|
|
247
|
+
"""Parse ``SRV`` record.
|
|
248
|
+
|
|
249
|
+
References:
|
|
250
|
+
- https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dnsp/db37cab7-f121-43ba-81c5-ca0e198d4b9a
|
|
251
|
+
|
|
252
|
+
Raises:
|
|
253
|
+
EOFError: Issue while unpacking structure.
|
|
254
|
+
"""
|
|
255
|
+
record = c_dns_record.DNS_RPC_RECORD_SRV(data)
|
|
256
|
+
target = parse_rfc1035_dns_name(record.nameTarget.dnsName)
|
|
257
|
+
return SRVRecord(
|
|
258
|
+
priority=record.Priority,
|
|
259
|
+
weight=swap16(record.Weight),
|
|
260
|
+
port=swap16(record.Port),
|
|
261
|
+
name_target=target,
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
class TombStonedRecord(NamedTuple):
|
|
266
|
+
"""``ZERO`` resource records."""
|
|
267
|
+
|
|
268
|
+
entombed_time: datetime.datetime
|
|
269
|
+
|
|
270
|
+
@classmethod
|
|
271
|
+
def from_bytes(cls, data: bytes) -> TombStonedRecord | None:
|
|
272
|
+
"""The ``DNS_RPC_RECORD_TS`` specifies information for a node that has been tombstoned,
|
|
273
|
+
used for record type ``DNS_TYPE_ZERO``.
|
|
274
|
+
|
|
275
|
+
References:
|
|
276
|
+
- https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dnsp/69166ff5-36c1-4542-9243-13b8931fa447
|
|
277
|
+
|
|
278
|
+
Raises:
|
|
279
|
+
EOFError: Issue while unpacking structure.
|
|
280
|
+
"""
|
|
281
|
+
record = c_dns_record.DNS_RPC_RECORD_TS(data).EntombedTime
|
|
282
|
+
if record == 0:
|
|
283
|
+
return None
|
|
284
|
+
base_date = datetime.datetime(1601, 1, 1, tzinfo=datetime.timezone.utc)
|
|
285
|
+
return TombStonedRecord(base_date + datetime.timedelta(microseconds=record / 10))
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
class DnsRecord:
|
|
289
|
+
"""DNS resource record definitions.
|
|
290
|
+
|
|
291
|
+
References:
|
|
292
|
+
- https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dnsp/6912b338-5472-4f59-b912-0edb536b6ed8
|
|
293
|
+
"""
|
|
294
|
+
|
|
295
|
+
def __init__(self, data: bytes):
|
|
296
|
+
self.raw = data
|
|
297
|
+
self.header = c_dns_record.DNS_RECORD_HEADER(data)
|
|
298
|
+
self.type = self.header.Type
|
|
299
|
+
self.ttl_seconds = swap32(self.header.TtlSeconds)
|
|
300
|
+
|
|
301
|
+
def __repr__(self) -> str:
|
|
302
|
+
return (
|
|
303
|
+
f"<DnsRecord type={self.type.name!r} ttl_seconds={self.ttl_seconds!r} "
|
|
304
|
+
f"timestamp={self.timestamp} data={self.data}>"
|
|
305
|
+
)
|
|
306
|
+
|
|
307
|
+
@property
|
|
308
|
+
def timestamp(self) -> datetime.datetime | None:
|
|
309
|
+
"""Timestamp is stored in hours since 1601-01-01.
|
|
310
|
+
|
|
311
|
+
Raises:
|
|
312
|
+
OverflowError: Number of hours cause an overflow.
|
|
313
|
+
"""
|
|
314
|
+
if self.header.TimeStamp == 0:
|
|
315
|
+
return None
|
|
316
|
+
# Windows timestamp is hours since 1601-01-01
|
|
317
|
+
base_date = datetime.datetime(1601, 1, 1, tzinfo=datetime.timezone.utc)
|
|
318
|
+
return base_date + datetime.timedelta(hours=self.header.TimeStamp)
|
|
319
|
+
|
|
320
|
+
@property
|
|
321
|
+
def data(
|
|
322
|
+
self,
|
|
323
|
+
) -> (
|
|
324
|
+
bytes
|
|
325
|
+
| DnsARecord
|
|
326
|
+
| DnsAAAARecord
|
|
327
|
+
| NodeNameRecord
|
|
328
|
+
| NamePreferenceRecord
|
|
329
|
+
| StringRecord
|
|
330
|
+
| TombStonedRecord
|
|
331
|
+
| SRVRecord
|
|
332
|
+
| SOARecord
|
|
333
|
+
| None
|
|
334
|
+
):
|
|
335
|
+
"""Parse the data part of a record, which contains a structure that depends on the record type.
|
|
336
|
+
|
|
337
|
+
Raises:
|
|
338
|
+
EOFError: Issue while unpacking structure.
|
|
339
|
+
"""
|
|
340
|
+
header_data = self.header.Data
|
|
341
|
+
|
|
342
|
+
# Process most common DNS records types
|
|
343
|
+
match self.type:
|
|
344
|
+
case DNS_RECORD_TYPE.A:
|
|
345
|
+
return DnsARecord.from_bytes(header_data)
|
|
346
|
+
case c_dns_record.DNS_RECORD_TYPE.AAAA:
|
|
347
|
+
return DnsAAAARecord.from_bytes(header_data)
|
|
348
|
+
case (
|
|
349
|
+
DNS_RECORD_TYPE.PTR
|
|
350
|
+
| DNS_RECORD_TYPE.NS
|
|
351
|
+
| DNS_RECORD_TYPE.CNAME
|
|
352
|
+
| DNS_RECORD_TYPE.DNAME
|
|
353
|
+
| DNS_RECORD_TYPE.MB
|
|
354
|
+
| DNS_RECORD_TYPE.MR
|
|
355
|
+
| DNS_RECORD_TYPE.MG
|
|
356
|
+
| DNS_RECORD_TYPE.MD
|
|
357
|
+
| DNS_RECORD_TYPE.MF
|
|
358
|
+
):
|
|
359
|
+
return NodeNameRecord.from_bytes(header_data)
|
|
360
|
+
case DNS_RECORD_TYPE.MX | DNS_RECORD_TYPE.AFSDB | DNS_RECORD_TYPE.RT:
|
|
361
|
+
return NamePreferenceRecord.from_bytes(header_data)
|
|
362
|
+
case DNS_RECORD_TYPE.SRV:
|
|
363
|
+
return SRVRecord.from_bytes(header_data)
|
|
364
|
+
case DNS_RECORD_TYPE.SOA:
|
|
365
|
+
return SOARecord.from_bytes(header_data)
|
|
366
|
+
case (
|
|
367
|
+
DNS_RECORD_TYPE.HINFO
|
|
368
|
+
| DNS_RECORD_TYPE.ISDN
|
|
369
|
+
| DNS_RECORD_TYPE.TXT
|
|
370
|
+
| DNS_RECORD_TYPE.X25
|
|
371
|
+
| DNS_RECORD_TYPE.LOC
|
|
372
|
+
):
|
|
373
|
+
return StringRecord.from_bytes(header_data)
|
|
374
|
+
case DNS_RECORD_TYPE.ZERO:
|
|
375
|
+
return TombStonedRecord.from_bytes(header_data)
|
|
376
|
+
return header_data
|
|
377
|
+
|
|
378
|
+
def as_dict(self) -> dict[str, Any]:
|
|
379
|
+
"""Return a dictionary representation of the record, with parsed data if possible."""
|
|
380
|
+
try:
|
|
381
|
+
data = self.data
|
|
382
|
+
except EOFError:
|
|
383
|
+
log.warning("Error processing DNS record: failed to parse data (record type: %s)", self.type.name)
|
|
384
|
+
data = None
|
|
385
|
+
|
|
386
|
+
try:
|
|
387
|
+
timestamp = self.timestamp
|
|
388
|
+
except OverflowError:
|
|
389
|
+
log.warning("Error processing DNS record: invalid record timestamp")
|
|
390
|
+
timestamp = None
|
|
391
|
+
return {
|
|
392
|
+
"type": self.type.name,
|
|
393
|
+
"ttl_seconds": self.ttl_seconds,
|
|
394
|
+
"timestamp": timestamp,
|
|
395
|
+
# isinstance(X, NamedTuple) does not work, but NamedTuple are subtype of tuple
|
|
396
|
+
"data": data._asdict() if isinstance(data, tuple) else data,
|
|
397
|
+
}
|
|
398
|
+
|
|
5
399
|
|
|
6
400
|
class DnsNode(Top):
|
|
7
401
|
"""Represents a DNS node object in the Active Directory.
|
|
8
402
|
|
|
9
403
|
References:
|
|
10
404
|
- https://learn.microsoft.com/en-us/windows/win32/adschema/c-dnsnode
|
|
405
|
+
- https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dnsp/6912b338-5472-4f59-b912-0edb536b6ed8
|
|
11
406
|
"""
|
|
12
407
|
|
|
13
408
|
__object_class__ = "dnsNode"
|
|
409
|
+
__decoders__: ClassVar[DecoderMap] = {"dnsRecord": lambda x, value: [DnsRecord(x) for x in value] if value else []}
|
|
410
|
+
|
|
411
|
+
def __repr_body__(self) -> str:
|
|
412
|
+
return f"dns_name={self.dns_name} dns_record={self.dns_record}"
|
|
413
|
+
|
|
414
|
+
@property
|
|
415
|
+
def dns_record(self) -> list[DnsRecord]:
|
|
416
|
+
"""Return DNS records as objects.
|
|
417
|
+
|
|
418
|
+
Raises:
|
|
419
|
+
EOFError: Issue while unpacking structure.
|
|
420
|
+
"""
|
|
421
|
+
return self.get("dnsRecord")
|
|
422
|
+
|
|
423
|
+
@cached_property
|
|
424
|
+
def dns_name(self) -> str:
|
|
425
|
+
"""Create a DNS name from node and parent names.
|
|
426
|
+
|
|
427
|
+
Examples:
|
|
428
|
+
DC=NORTH,DC=SEVENKINGDOMS.LOCAL,CN=MICROSOFTDNS,DC=DOMAINDNSZONES,DC=SEVENKINGDOMS,DC=LOCAL ->
|
|
429
|
+
north.sevenkingdoms.local
|
|
430
|
+
"""
|
|
431
|
+
node = self.distinguished_name
|
|
432
|
+
ret = [self.name] if self.name != "@" else [] # @ means same as parent folder
|
|
433
|
+
while (i := node.parent).object.__object_class__ in ["dnsNode", "dnsZone"]:
|
|
434
|
+
ret.append(i.object.name)
|
|
435
|
+
node = i
|
|
436
|
+
return ".".join(ret).replace("\n", "\\n")
|
|
437
|
+
|
|
438
|
+
def as_dict(self) -> dict[str, Any]:
|
|
439
|
+
result = super().as_dict()
|
|
440
|
+
result["dns_name"] = self.dns_name
|
|
441
|
+
if "dnsRecord" in result:
|
|
442
|
+
result["dnsRecord"] = [r.as_dict() for r in result.get("dnsRecord", [])]
|
|
443
|
+
return result
|
|
@@ -405,6 +405,9 @@ class DN(str):
|
|
|
405
405
|
|
|
406
406
|
__slots__ = ("object", "parent")
|
|
407
407
|
|
|
408
|
+
object: Object
|
|
409
|
+
parent: DN | None
|
|
410
|
+
|
|
408
411
|
def __new__(cls, value: str, object: Object, parent: DN | None = None):
|
|
409
412
|
instance = super().__new__(cls, value)
|
|
410
413
|
instance.object = object
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dissect.database
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.dev10
|
|
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
|
|
@@ -30,16 +30,18 @@ dissect/database/ese/ntds/c_pek.pyi,sha256=lHfhvHWABT1vLmknu66phOXsylgwzGIWVdbqD
|
|
|
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
32
|
dissect/database/ese/ntds/database.py,sha256=fPMgTzHm1rsPZ3Hvt7SQqtjdXQNNLa51wGEK3i5_afw,16776
|
|
33
|
-
dissect/database/ese/ntds/ntds.py,sha256=
|
|
33
|
+
dissect/database/ese/ntds/ntds.py,sha256=zKtLcID8GGtpuzZ9kYaNRa_qRij5HFmtZZWS-f15zr4,5681
|
|
34
34
|
dissect/database/ese/ntds/pek.py,sha256=BEmxO175T8QkGVvFQLN9MI9uDCcK4jztuZetbwbbYqU,4154
|
|
35
35
|
dissect/database/ese/ntds/query.py,sha256=pDLLCVdrCRNq3ripvMDiyxXoFWsVJLwwsRMplRf7C9s,8063
|
|
36
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=31j6YwGmIVirTlvpQ_l_C-JIEm6JoTUdS4dH1we2x3g,20493
|
|
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
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/c_dnsnode.py,sha256=lk7emP30eftyWWeDSBCeA4NWRSd-Oesp2xOZt9g4_mk,6087
|
|
44
|
+
dissect/database/ese/ntds/objects/c_dnsnode.pyi,sha256=DQXT0zRuVXuQRckuw_XjrpQf_onWYAflwv98bXVSKcU,5063
|
|
43
45
|
dissect/database/ese/ntds/objects/certificationauthority.py,sha256=XWGzSImJ7Qo1TEMTUznAslp-810lWe8Xpk-Cjo99nIc,532
|
|
44
46
|
dissect/database/ese/ntds/objects/classschema.py,sha256=Hrpfgl_mR6ciHL7qya63mvzsrouFIy4BJVHU5wJm_Hg,1544
|
|
45
47
|
dissect/database/ese/ntds/objects/classstore.py,sha256=VqWGm4ZqonQQGnFE67AyGGUYuTLdBmPQzZ34X-fRG5M,321
|
|
@@ -53,7 +55,7 @@ dissect/database/ese/ntds/objects/crossrefcontainer.py,sha256=YeEnVCVYpt6p1jQ8gr
|
|
|
53
55
|
dissect/database/ese/ntds/objects/dfsconfiguration.py,sha256=Ofgj8Nnfw4_kGTjGnqaSDB6opshqQMNAJFFk_AuTbbo,345
|
|
54
56
|
dissect/database/ese/ntds/objects/displayspecifier.py,sha256=Kuc7usI-zLK0TadGAm_fnuu6DurHNYZD6-hQMlQ3F6g,345
|
|
55
57
|
dissect/database/ese/ntds/objects/dmd.py,sha256=SnJLgFO5rMmsVjgYN0z0klE5tQkZxnmAaqsWefitV0U,324
|
|
56
|
-
dissect/database/ese/ntds/objects/dnsnode.py,sha256=
|
|
58
|
+
dissect/database/ese/ntds/objects/dnsnode.py,sha256=8lqzUcos4YB-SUJLZqmJXskYNAX7f9tVhIoNr2dgZxQ,14920
|
|
57
59
|
dissect/database/ese/ntds/objects/dnszone.py,sha256=rJ_3zdsxrR3FvzXU1qbbGqnh67FR64CRClO3dF7wBXU,659
|
|
58
60
|
dissect/database/ese/ntds/objects/domain.py,sha256=aWQN-5P1MMh2aPXJoyPORxhyE_5dIt7aIfBB7Bxp8mM,304
|
|
59
61
|
dissect/database/ese/ntds/objects/domaindns.py,sha256=bHJQukHnhmBJwgGMTiwWHyF5PXQYhv6sdYrJP2QH2CY,780
|
|
@@ -159,10 +161,10 @@ dissect/database/sqlite3/encryption/__init__.py,sha256=kJdFWXD9Z_O_QipC-_A9dlVfR
|
|
|
159
161
|
dissect/database/sqlite3/encryption/sqlcipher/__init__.py,sha256=kJdFWXD9Z_O_QipC-_A9dlVfR6AOPSOoT8WBhpFbSsE,238
|
|
160
162
|
dissect/database/sqlite3/encryption/sqlcipher/exception.py,sha256=GKNtzcnAKlWkvjLluruA8LfzCwjRRWubibbH8WM9l2o,121
|
|
161
163
|
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.
|
|
164
|
+
dissect_database-1.2.dev10.dist-info/licenses/COPYRIGHT,sha256=pFH-OBYz6Xj23UB0Odz5IhoTR8nsTbJQNlCRV_wMaiE,317
|
|
165
|
+
dissect_database-1.2.dev10.dist-info/licenses/LICENSE,sha256=PhUqiw6jAh2KbBdVRPBq_hfAvfcTBin7nZ3CK7NQbTM,11341
|
|
166
|
+
dissect_database-1.2.dev10.dist-info/METADATA,sha256=V508YEp3xBaiq_9Y8tn_58GMSRwLaAHZzzm1mHp4vUM,5541
|
|
167
|
+
dissect_database-1.2.dev10.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
168
|
+
dissect_database-1.2.dev10.dist-info/entry_points.txt,sha256=ZVVKj3Nzjkgm1kBXGWyGNVUJzTbmVgivv9lgFcuLkpk,343
|
|
169
|
+
dissect_database-1.2.dev10.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
|
|
170
|
+
dissect_database-1.2.dev10.dist-info/RECORD,,
|
|
File without changes
|
{dissect_database-1.2.dev9.dist-info → dissect_database-1.2.dev10.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{dissect_database-1.2.dev9.dist-info → dissect_database-1.2.dev10.dist-info}/licenses/COPYRIGHT
RENAMED
|
File without changes
|
{dissect_database-1.2.dev9.dist-info → dissect_database-1.2.dev10.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
|
File without changes
|