Parsing the msDS-KeyCredentialLink value for ShadowCredentials attack

Table of contents :


Active Directory Certificate Services (AD CS) is a server role that allows you to build a public key infrastructure (PKI) and provide public key cryptography, digital certificates, and digital signature capabilities for your organization. Since the publication of “Certified Pre-Owned: Abusing Active Directory Certificate Services” in 2021 by Will Schroeder (@harmj0y) and Lee Christensen (@tifkin_), AD CS is prone to many attacks. One of them is more of a persistance technique, and is known as a shadow credentials attack.

A shadow credentials attack on Active Directory involves an attacker adding a certificate to a machine account that they control. This allows the attacker to authenticate as that machine and perform actions on its behalf, potentially gaining unauthorized access to resources. At the core of this technique is the LDAP attribute msDS-KeyCredentialLink that stores the certificate used to authenticate to the machine account.

The LDAP attribute msDS-KeyCredentialLink is used to store the public key credentials associated with a computer or user object. When a certificate is added to a machine account, it is stored in this attribute.

You can view these as a system administrator by going in the Active Directory Users and Computers console, and activate Advanced features.

Then on the machine account that has certificates installed, go into Properties then Attribute Editor then scroll down until finding the msDS-KeyCredentialLink attribute.

In this attribute editor, we see:

|  msDS-KeyCredentialLink  | 'B:828:0002000020000108E2E5....' |

This string is actually a string version of a DN with Binary data blob.

Now that we know where to find it, it would be cool to understand the format and parse it!

Parsing the DN with Binary data blob

The DN with Binary data blob is a unique format that combines a distinguished name (DN) with a binary large object (BLOB). The distinguished name (DN) is a string that uniquely identifies an entry in the LDAP directory, while the BLOB is used to store binary data as an hexadecimal string. In the context of the msDS-KeyCredentialLink attribute, the DN with Binary data blob is used to store the certificate added to a machine account. Parsing this data involves extracting the DN and the binary data from the blob, which can then be parsed.

Here is what the raw value of this attribute looks like:

5606E06DA01080009A7E1A5606E06DA01:CN=DC01,OU=Domain Controllers,DC=LAB,DC=local

The DN with Binary string is divided into three parts:

  1. A letter indicating the type of the object. This is the prefix that indicates that the string is a DN-Binary (If it starts with a S it is a DN-String object).

  2. The length of the hexadecimal string. The number following the colon (828 in this case) is the length of the hexadecimal string containing the binary data.

  3. The hexadecimal string of raw data This is the binary data. In the context of the msDS-KeyCredentialLink attribute, this data represents the certificate added to a machine account.

  4. The distinguished name of the object in LDAP. This distinguished name (DN) uniquely identifies an entry in the LDAP directory. In this example the distinguished name is CN=podalirius,CN=Users,DC=lab,DC=local.

To parse this data, you would first separate the three parts based on the colons. Then, you would convert the binary data from hexadecimal to binary and the DN from its string representation to a structured format. Here is a summary of this DN with binary format:

Now we know how to parse the DN-Binary structure, we still have to parse the raw data that is present inside it.

Parsing the certificate

The raw certificate data is a BCRYPT_RSAKEY_BLOB structure, a structure that represents a RSA key. In this case it is a public key but the structure can also be used to represent private keys. The BCRYPT_RSAKEY_BLOB structure contains information about the key, such as the key type, the length of the key, and the public exponent, followed by the modulus of the RSA key. Here is a schema to help visualize this structure:

Writing a library

To be able to write a Python version of Elad Shamir’s Whisker with my colleague Shutdown (we’ve called it pyWhisker), and to make the process of parsing and generating msDS-KeyCredentialLink values easier, I have created a Python library called pydsinternals. This library is inspired by the DSInternals library by Michael Grafnetter. The pydsinternals library provides a set of tools and functions that allow you to parse and generate msDS-KeyCredentialLink values from within your Python scripts.

The library includes classes such as DNWithBinary and KeyCredential, which represent the previously described DN with Binary data blob and key credential respectively. These classes provide methods to parse the raw data into a structured format and to generate a new X509 certificate and export it in the expected format for the msDS-KeyCredentialLink value.

Here is an example of how you can use the pydsinternals library to parse a msDS-KeyCredentialLink value:

# Import the necessary modules
from import KeyCredential
from import DNWithBinary

# The msDS_KeyCredentialLink attribute is a DN with Binary that contains the certificate added to a machine account
msDS_KeyCredentialLink = b"B:828:0002000020000108E2E5700BC0E9522D434C139C15B767678284D922DF7E92BA0DD17D62407E9D200002A786DBE1C8FD5259753E75E32DE90CA2CBE04D2A2AF4DACC29DB7C6B06FE3E411B0103525341310008000003000000000100000000000000000000010001CC86F6DEB74305A202C68F94489B82C499C6F21A74D5E290869E82FFF5B5774B961251741E42D7FEC1F5EEAE52B5C759DE321491987D6586F9F3672B4E5B88EB32827480D4444D958275113832EA7B52E91E8ED414796E6AE9061BE323D3BBFACF4448FE2451DF9325393FE1189CE53E7AE6D02E7710D71EB1F16B8ACCF13EB63F34834021DAF3398962A6C1DF4F359CE9A81BD2E6FA3D9DD095898C9FC2E2316DD10B59A5C0C09A71EA12CE70E3AC6EA42C74E258A0C13F102577B9AB2B55658A4F72CAFCDF26B0EBB124EEB3F7D97BD705D04FFA4B0D4C442F68CDC724A5DD4B42B114BB3A667A54F7A733A26F7AFC6FA09CEC688246EC32494668148C09950100040101000500100006335A9368151ACC785211B3C9DA8EC9720200070100080008A7E1A5606E06DA01080009A7E1A5606E06DA01:CN=DC01,OU=Domain Controllers,DC=LAB,DC=local"

# Parse the DN with Binary data blob
data = DNWithBinary.fromRawDNWithBinary(msDS_KeyCredentialLink)

# Create a KeyCredential object from the parsed data
kc = KeyCredential.fromDNWithBinary(data)

# Display the parsed contents of the KeyCredential object

And you will get a complete description of your certificate: