I Am a Domain Controller
In the previous section, we demonstrated that an application
or service running on a machine with unconstrained delegation
can lead to a complete domain compromise.
However, the attack we performed relied on a
privileged user accessing the target application.
In this section, we’ll demonstrate a technique that will
allow us to force a high-privileged authentication
without any user interaction.
This will allow us to compromise the entire domain
if we succeed in an initial compromise of a single instance
of unconstrained delegation.
We previously exploited the printer bug
to escalate our privileges on a target.
We achieved this by coercing the SYSTEM account
to authenticate locally via the MS-RPRN RPC interface.
However, as stated earlier, this attack was originally designed
to work in an Active Directory environment.
Specifically, the idea behind the
SpoolSample tool we used in a previous module
is to force a Domain Controller to connect back
to a system configured with unconstrained delegation.
This eventually allows the attacker to steal a
TGT for the domain controller computer account.
The RPC interface we leveraged locally is indeed also accessible over the network
through TCP port 445 if the host firewall allows it.
TCP port 445 is typically open on Windows servers,
including domain controllers,
and the print spooler service runs automatically at startup
in the context of the computer account.
In order to exploit the printer bug in this scenario,
we must determine if the print spooler service is running
and available on the domain controller from appsrv01.
The MS-RPRN documentation specifies that the RPC endpoint for the print spooler
is \pipe\spoolss and that no authentication is required.
To test this out, we’ll log in to appsrv01 as the Offsec user.
and attempt to access the named pipe with the dir command.
The output reveals that the print spooler service is running and accessible.
Recall that this access is by design and
RpcRemoteFindFirst PrinterChangeNotification
allows us to simulate a print client
and subscribe to notifications of changes on the print server.
These notifications are sent over the network
by the print spooler service via RPC over a named pipe.
When the “target” spooler accesses the named pipe on the “attacking” machine,
it will present a forwardable TGT along with the TGS
if the “attacking” machine is configured with unconstrained delegation.
As we did for the local privilege escalation, we’ll call the RpcOpenPrinter,
and RpcRemoteFindFirstPrinter ChangeNotification APIs
through SpoolSample to facilitate the attack.
Once the authentication has taken place,
we’ll look for tickets in memory
originating from the domain controller machine account.
A compiled version of SpoolSample is located in the
C:\Tools folder of appsrv01.
However, we're missing one final item before we launch the attack.
In the last section, we used Mimikatz to find and extract the forwardable TGT,
but the sheer number of returned TGTs and TGSs makes monitoring difficult.
In addition, we had to write the TGT to disk to reuse it.
To solve these challenges, @harmj0y developed the Rubeus C# application,
which is also located in C:\Tools on appsrv01.
Let’s launch Rubeus from an administrative command prompt in monitor mode,
specify a refresh interval of 5 seconds,
and filter on the domain controller machine account.
With Rubeus monitoring for TGTs
originating from the domain controller machine account,
we’ll open a second command prompt.
w we’ll trigger the print spooler change notification
with SpoolSample.exe by specifying the target machine,
and capture server.
The SpoolSample output is not always accurate,
and it may be necessary to run the tool multiple times
before the change notification callback takes place.
After waiting a few seconds, we’ll switch back to Rubeus,
which displays the TGT for the domain controller account.
We have forced the domain controller machine account
to authenticate to us and give us a TGT
without any user interaction.
Very nice!
Now that we’ve managed to avoid user interaction,
we can further improve this technique by avoiding the write to disk.
Rubeus monitor outputs the Base64-encoded TGT
but it can also inject the ticket into memory with the ptt command.
With the TGT of the domain controller machine account injected into memory,
we can perform actions in the context of that TGT.
However, the CDC01$ account is not a local administrator on the domain controller
so we cannot directly perform lateral movement with it.
On the other hand, the account has domain replication permissions,
which means we can perform dcsync,
and dump the password hash of any user,
including the special krbtgt account.
Armed with the krbtgt NTLM hash,
we can craft a golden ticket and obtain access to any resource in the domain.
Alternatively, we can dump the password hash
of a member of the Domain Admins group.
The technique shown in this section illustrates
just how dangerous unconstrained Kerberos delegation is.
If we are able to compromise a server that has unconstrained delegation configured,
we can obtain complete domain compromise with default Active Directory settings.
In the next section, we’ll investigate a more secure variant of Kerberos delegation
and demonstrate various attacks against it.