Dumping Kerberos Keys for Machine Accounts
There are a ton of resources online for how to dump stored NT hashes out of Windows registry, but not much that I could find on getting the Kerberos keys (AES128 and AES256) for machine accounts. While NT hashes are great for Pass-the-Hash attacks, AES keys are sometimes required for Overpass-the-Hash/Pass-the-Key attacks (obtaining TGTs) and, for machine accounts specifically, Silver Ticket attacks.
This post will describe some theory and practice for obtaining these Kerberos keys for machine accounts on domain-joined Windows boxes. I assume the reader already has a basic familiarity with pentesting terminology related to Windows, AD, and Kerberos tickets.
Note: This post focuses on Microsoft’s Active Directory, and any references to Kerberos are referring to the Microsoft implementation of Kerberos unless otherwise specified.
TL;DR
For machine accounts, the AES Kerberos keys are not stored in the registry directly. Instead, the “plaintext” binary password is stored, and the Kerberos “ekeys” (encryption keys) have to be derived from it.
Use secretsdump.py or a similar tool to extract the hex-string representation of the password, then use https://github.com/Aptimex/krbHash to derive the keys:
./krbHash.py -d domain.local -u machine123 -m -x 0A2B3C...
[*] Salt: DOMAIN.LOCALhostmachine123.domain.local
Parsing password as hex string
[+] NT Hash: EC4A82F434A9A50F5F28B3C79C5DA6CE
[+] AES128 Key: D64263164A86D0F07342D2A135554ABF
[+] AES256 Key: 25F29C6C2046DA7DD086D3ADB432873C7E0BEBB32858641F39AFF9F573F15B6F
- If your dumped NT hash matches the NT hash produced by the script, the AES keys should be correct as well, assuming you specified the correct combination of domain, user, and machine account flag.
Now you have AES keys that are usually well-supported in other pentesting tools, such as the -aesKey flag in Impacket tools.
Kerberos Keys vs. NT Hash
The NT hash of a password is the result of encoding a password string as UTF-16LE and then applying the MD4 hash to it. Under the hood, this hash is what Windows stores and compares almost any time you use plaintext password authentication. As far as Windows is concerned, this hash is your password for most purposes, which is why Pass-the-Hash attacks work.
Kerberos provides a (generally) better centralized security model compared to distributed NT hashes, and is the primary authentication protocol used by Active Directory. It supports three primary encryption types for its tickets: RC4, AES128, and AES256.
- There are technically some other encryption types that no one ever uses. I don’t even know if AD Kerberos has support for them.
RC4 is an old stream cipher, and Kerberos uses the NT hash as the key for it when encrypting tickets.
AES is a modern block cipher, and Kerberos uses a more complex (and more crack-resistant) process to turn a plaintext password into a key for these ciphers. Unlike the RC4 implementation, this key-derivation process also requires knowing the domain name and the account name, not just the password. So if two users have the same password, then their NT hashes will be the same, but their AES key(s) will be different. The two AES encryption types are functionally identical from a pentesting perspective, they just take different key sizes.
These Kerberos AES keys that are derived from a user’s password are referred to as “ekeys,” short for “Encryption Keys.” Makes sense since they are the keys used to encrypt user tickets and other sensitive data.
All three encryptions types can be used to encrypt TGTs. The type of hash/key used to authenticate when requesting the TGT determines the type of encryption applied to the ticket that is returned by the DC: an NT hash results in an RC4-encrypted ticket, while an AES key results in an AES-encrypted ticket. Using a hash or ekey directly to obtain a TGT (instead of the plaintext password) is referred to as Overpass-the-Hash or Pass-the-Key, respectively. Though since the only difference between them is the encryption type, I’m not sure why we bother having different names for the attacks.
From an OpSec perspective, using the AES256 ekey is usually preferred when possible since most legitimate Kerberos services will use the strongest key option they can support, and AES256 is usually the strongest available. Additionally, the RC4 type is sometimes disabled domain-wide as a hardening measure, which makes NT hashes useless for directly obtaining TGTs.
Machine Account Ekey Storage
Machine account password material has to be stored on disk because Windows needs to be able to retrieve and use it between reboots. Windows stores this password material in the SECURITY registry hive, which is only accessible to the local NT AUTHORITY\SYSTEM account. Impacket’s secretsdump.py is a classic tool that can be used to extract this.
Windows directly stores the machine account’s NT hash in the registry. But the ekeys can’t (well, shouldn’t) be stored directly because their values are dependant on the domain you are authenticating to. Since there could be multiple trusted domains in an AD forest, Windows needs to have the ability to to calculate ekeys for different domains on-the-fly. Consequently, Windows stores the “plaintext” password for the local machine account in the registry, instead of storing the ekeys directly.
- Exception: Domain Controllers actually do store ekeys in the NTDS.dit file, and secretsdump will extract those in addition to the normal registry stuff.
Unlike normal user accounts, machine accounts are usually automatically managed by AD. Since there’s no real legitimate reason for a user to ever need to know or use the password for these accounts, they are set to 120-byte random binary values- not printable strings. They are also automatically changed every 30 days by default. This makes them extremely secure against brute-force and password-cracking attacks.
Since machine account binary passwords are not typically printable, tools that dump or extract them usually represent them as a long hexstring.
Converting Passwords to Ekeys
Most of the Impacket tools support using an ekey for authentication via the -aesKey flag. Other pentesting tools also usually have similar support. But no tools that I’m familiar with support using a hexstring representation of a plaintext password for authentication. So most of the time a dumped “plaintext” machine account password is useless in that form.
Unlike the simple MD4 cipher used for NT hashes, calculating ekeys is quite a bit more involved. I forked and improved an existing Python script to do this for you, available here. You provide the username, domain, and plaintext password (either as a string or in hex format), and specify whether it’s a machine account, and out pops the NT hash and ekeys:
./krbHash.py -d domain.local -u machine123 -m -x 0A2B3C...
[*] Salt: DOMAIN.LOCALhostmachine123.domain.local
Parsing password as hex string
[+] NT Hash: EC4A82F434A9A50F5F28B3C79C5DA6CE
[+] AES128 Key: D64263164A86D0F07342D2A135554ABF
[+] AES256 Key: 25F29C6C2046DA7DD086D3ADB432873C7E0BEBB32858641F39AFF9F573F15B6F
You should be able to directly copy-paste whatever hexstring your dumping tool printed for the plaintext password and pass it to -x in that tool. But beware that some dumping tools truncate these long hexstrings, often indicated by a ... at the end. As a sanity check, if the NT hash generated by the script matches the NT hash that was dumped alongside this hexstring, then you correctly copy-pasted the full password. In that case, the ekeys should be correct as well- assuming you specified the right domain, user, and machine account flag.
Using ekeys
Most tools that let you do an Overpass-the-Hash attack using the NT hash for a domain account will also support doing a Pass-the-Key attack using an ekey. But remember that ekeys are specific to Kerberos- you can’t use them for a traditional Pass-the-Hash attack, at least as far as I’m aware.
If the tool you’re using doesn’t have direct support for authentication using Kerberos AES keys, but does support using Kerberos tickets (usually -k), you can first use Impacket’s getTGT.py to get a TGT using one of those ekeys:
getTGT.py domain.local/machine123 -aesKey <AES128/256 key>
And of course you can use an ekey to directly generate Silver Tickets without needing to talk to a DC at all. For example, with Impacket’s ticketer.py:
ticketer.py -aesKey "<AES128/256 key>" -domain-sid "<domain_SID>" -domain "domain.local" -spn "cifs/machine123" "some_admin_user"