Skip to content

Commit e75512a

Browse files
committed
Add domain functional level check
1 parent fb75416 commit e75512a

1 file changed

Lines changed: 27 additions & 2 deletions

File tree

nxc/modules/badsuccessor.py

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,20 @@
5454
"AllExtendedRights": ACCESS_RIGHTS["AllExtendedRights"]
5555
}
5656

57+
FUNCTIONAL_LEVELS = {
58+
"Windows 2000": 0,
59+
"Windows Server 2003": 1,
60+
"Windows Server 2003 R2": 2,
61+
"Windows Server 2008": 3,
62+
"Windows Server 2008 R2": 4,
63+
"Windows Server 2012": 5,
64+
"Windows Server 2012 R2": 6,
65+
"Windows Server 2016": 7,
66+
"Windows Server 2019": 8,
67+
"Windows Server 2022": 9,
68+
"Windows Server 2025": 10,
69+
}
70+
5771

5872
class NXCModule:
5973
"""
@@ -92,7 +106,6 @@ def get_domain_sid(self, ldap_session, base_dn):
92106
return parsed[0]["objectSid"]
93107

94108
def find_bad_successor_ous(self, ldap_session, entries, base_dn):
95-
96109
domain_sid = self.get_domain_sid(ldap_session, base_dn)
97110
results = {}
98111
parsed = parse_result_attributes(entries)
@@ -131,7 +144,6 @@ def find_bad_successor_ous(self, ldap_session, entries, base_dn):
131144
owner_sid = str(sd["OwnerSid"])
132145
if not self.is_excluded_sid(owner_sid, domain_sid):
133146
results.setdefault(owner_sid, []).append(dn)
134-
135147
return results
136148

137149
def resolve_sid_to_name(self, ldap_session, sid, base_dn):
@@ -164,7 +176,20 @@ def resolve_sid_to_name(self, ldap_session, sid, base_dn):
164176
return sid
165177

166178
def on_login(self, context, connection):
179+
# Check functional domain level
180+
resp = connection.ldap_connection.search(
181+
searchBase=connection.ldap_connection._baseDN,
182+
searchFilter="(objectClass=domain)",
183+
attributes=["msDS-Behavior-Version"]
184+
)
185+
parsed_resp = parse_result_attributes(resp)
186+
functional_domain_level = list(FUNCTIONAL_LEVELS.keys())[list(FUNCTIONAL_LEVELS.values()).index(int(parsed_resp[0]["msDS-Behavior-Version"]))]
187+
if int(parsed_resp[0]["msDS-Behavior-Version"]) < FUNCTIONAL_LEVELS["Windows Server 2025"]:
188+
context.log.fail(f"Attack won't work, domain functional level '{functional_domain_level}' is lower than Windows Server 2025, enumerating dMSA objects anyways.")
189+
else:
190+
context.log.success("Domain functional level is Windows Server 2025 or higher, attack is possible.")
167191

192+
# Enumerate dMSA objects
168193
controls = security_descriptor_control(sdflags=0x07) # OWNER_SECURITY_INFORMATION
169194
resp = connection.ldap_connection.search(
170195
searchBase=connection.ldap_connection._baseDN,

0 commit comments

Comments
 (0)