Indicator of Compromise: NTLM Relay Attack with Shadow Credentials
TL;DR
The current implementation of the shadow credentials attack in the Impacket
framework,
most notably used by the ntlmrelayx.py
script, contains multiple bugs,
leaving unique signatures on the NGC data structures written to the msDS-KeyCredentialLink
LDAP attribute by malicious actors.
Heuristics could be used to identify most malicious NGC keys, regardless of the hacktool they were generated by.
Technical Details
I noticed by chance that the current implementation of the shadow credentials attack (a term coined and popularized by Elad Shamir) in the Impacket framework produces malformed KEYCREDENTIALLINK_BLOB binary data structures, having the following issues:
- The
KeyHash
entry should contain a SHA256 hash of all other entries, but it is only calculated from theKeyMaterial
entry. - The
KeyCreationTime
entry should be in the FILETIME format but is incorrectly skewed by 1600 years. - The
DeviceId
entry is expected to be present only on user accounts, but it is populated for computer accounts as well. And instead of referencing existing device objects, it contains random values.
These bugs are located in the shadow_credentials.py script,
which is then optionally used by the ntlmrelayx.py script when performing the NTLM Relay attack against the LDAP protocol.
The shadow credentials attack was originally implemented in version 0.10.0
of Impacket
, released in May 2022.
The bugs were introduced to the master
branch in March 2024 and published in version 0.12.0
, released in September 2024.
As a result, the DSInternals PowerShell module can be used to identify malformed NGC keys (AKA shadow credentials) that are still present in Active Directory (AD):
#Requires -Modules DSInternals,ActiveDirectory
Get-ADObject -LDAPFilter '(msDS-KeyCredentialLink=*)' -Properties msDS-KeyCredentialLink |
Select-Object -ExpandProperty msDS-KeyCredentialLink |
Get-ADKeyCredential |
Where-Object Usage -eq NGC
Sample output:
Usage Source Flags DeviceId Created Owner
----- ------ ----- -------- ------- -----
NGC AD None ff53f58e-81a9-5d40-96bb-4980c91008ae 3625-02-23 CN=PC04,CN=Computers,DC=contoso,DC=com
NGC AD None e49d674f-0259-44f3-a3bd-8343b76046fc 2025-02-02 CN=Administrator,CN=Users,DC=contoso,DC=com
NGC AD None cfe9a872-13ff-4751-a777-aec88c30a762 2019-08-01 CN=John Doe,CN=Users,DC=contoso,DC=com
NGC AzureAD None fd591087-245c-4ff5-a5ea-c14de5e2b32d 2017-07-19 CN=John Doe,CN=Users,DC=contoso,DC=com
NGC AD MFANotUsed 2025-02-01 CN=PC01,CN=Computers,DC=contoso,DC=com
NGC AD MFANotUsed 2017-08-23 CN=PC02,CN=Computers,DC=contoso,DC=com
NGC AD 2021-06-11 CN=PC03,CN=Computers,DC=contoso,DC=com
The first NGC key in the output above, supposedly created in the year 3625 instead of 2025,
can serve as a very reliable indicator of AD compromise (IoC).
Moreover, all open-source implementations of the shadow credentials attack generate random values for the DeviceId
attribute.
It is therefore possible to use Microsoft’s WHfBTools PowerShell module to identify orphaned NGC keys with non-existing device identifiers.
The sample data also shows that the CUSTOMKEYINFO_FLAGS_MFA_NOT_USED flag
in the CustomKeyInformation
entry is used inconsistently by Windows 10+ computers, making it an unreliable indicator of malicious NGC keys.
Future Work
As other implementations of the shadow credential attack might contain similar issues, broader research on this topic should be conducted. Although hacktool authors will probably react to the information contained in this article and improve their implementations accordingly, these changes will not affect pre-existing shadow credentials.
Although the current version of DSInternals
does not validate the KeyHash
entries when parsing existing NGC keys,
it correctly implements the hash calculation when generating new NGC keys or serializing existing ones.
It should not be hard to implement hash validation as well.