|
54 | 54 | "AllExtendedRights": ACCESS_RIGHTS["AllExtendedRights"] |
55 | 55 | } |
56 | 56 |
|
| 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 | + |
57 | 71 |
|
58 | 72 | class NXCModule: |
59 | 73 | """ |
@@ -92,7 +106,6 @@ def get_domain_sid(self, ldap_session, base_dn): |
92 | 106 | return parsed[0]["objectSid"] |
93 | 107 |
|
94 | 108 | def find_bad_successor_ous(self, ldap_session, entries, base_dn): |
95 | | - |
96 | 109 | domain_sid = self.get_domain_sid(ldap_session, base_dn) |
97 | 110 | results = {} |
98 | 111 | parsed = parse_result_attributes(entries) |
@@ -131,7 +144,6 @@ def find_bad_successor_ous(self, ldap_session, entries, base_dn): |
131 | 144 | owner_sid = str(sd["OwnerSid"]) |
132 | 145 | if not self.is_excluded_sid(owner_sid, domain_sid): |
133 | 146 | results.setdefault(owner_sid, []).append(dn) |
134 | | - |
135 | 147 | return results |
136 | 148 |
|
137 | 149 | 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): |
164 | 176 | return sid |
165 | 177 |
|
166 | 178 | 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.") |
167 | 191 |
|
| 192 | + # Enumerate dMSA objects |
168 | 193 | controls = security_descriptor_control(sdflags=0x07) # OWNER_SECURITY_INFORMATION |
169 | 194 | resp = connection.ldap_connection.search( |
170 | 195 | searchBase=connection.ldap_connection._baseDN, |
|
0 commit comments