TL;DR;

S4U2self can be abused for local privilege escalation (think: Network Service to Local Admin). This is not something new, it’s just the first time I actually ran through the steps myself so why not write a post about it. The attack is covered briefly in the Rubeus manual and in more detail in this post by Charlie Clark, which I recommend you read. I won’t explain S4U in this post so if you are not familiar with the topic, read this post on constrained delegation first.

S4U2self and service accounts

Though constrained delegation needs to be specifically enabled on an account to “make it work” across systems in terms of S4U2proxy, S4U2self can be invoked by any principal with an SPN. From a conceptual perspective it does not seem like much at first, since you can’t use the ticket to invoke S4U2proxy, which means that you end up with a ticket for yourself. And you already are you, so no problem here right?

It depends. If you already have administrative privileges on a computer, then the ticket really is of no use for you. But if you think about a common local privilege escalation scenario in which you managed to compromise a restriced service like IIS (running as AppPool user) or MSSQL (running as network service by default), that ticket can be quite valuable.

The “Network Service” account and the AppPool identities can act as the computer account in terms of Active Directory, they are only restrained locally. Therefore it is possible to invoke S4U2self if you run as one of these and request a service ticket for any user (e.g. someone with local admin rights, like DA) to yourself. There are however two minor obstacles to overcome:

  • we need a TGT or the computer accounts credentials to invoke S4U2self and we start with neither of both
  • the SPN in the ticket returned by S4U2self is set to “Computername$” by default

Getting the TGT

A usable TGT for the computer account can be acquired using @gentilkiwi’s tgt::deleg trick, explained here in the Rubeus manual.

Invoke-Rubeus -Command "tgtdeleg /nowrap"

tgtdeleg

Fixing the SPN

With the TGT from the previous step, we can now invoke S4U2self to request a ticket for the User Chuck Norris, who is obviously a domain admin.

Invoke-Rubeus -Command "s4u /self /nowrap /impersonateuser:cnorris /ticket:base64blobhere..."

tgtdeleg

Here’s how the resulting ticket looks like. As you can see, it is issued to “ADSEC-00$” which is the name of the computer we are running on.

tgtdeleg

We cannot use this ticket from another host since it is not issued to a valid SPN for our usecase. Luckily, the SPN is not part of the protected information inside the ticket and we can simply change it. Rubeus offers a command called tgssub to do just that, which is also explained in the manual. Use it together with the /altservice switch to provide a different SPN.

Invoke-Rubeus -Command "tgssub /altservice:http/adsec-00.contoso.com /ticket:base64blobhere... "

tgtdeleg

You can then copy the ticket to a different host, import it (you do not need local admin rights for that) and use the ticket.

tgtdeleg

In the screenshot below we are using PSRemoting (hence the HTTP/.. SPN).

tgtdeleg

Conclusion

I think this is a very stable alternative to the various potatoe vectors. If you previously considered processes running as LOCAL SYSTEM as your main target for local privilege escalation, you can now safely increase your scope. As long as you have access to another computer in the domain, chances are very high that this will work.