After the hype we (@splinter_code and me) created with our recent tweet , it’s time to reveal what we exactly did in order to get our loved JuicyPotato kicking again… (don’t expect something disruptive ūüėČ )

We won’t explain how the *potato exploits works, how it was fixed etc etc, there is so much literature about this and google is always your best friend!

Our starting point will be the “RogueWiRM” exploit.

In fact, we were trying to bypass the OXID resolver restrictions when we came across this strange behavior of BITS. But what was our original idea?

“(…) we found a solution by doing some redirection and implementing our own ‚ÄúOxid Resolver‚ÄĚ . The good news is that yes, we got a SYSTEM token! The bad one: it was only an¬†identification token,¬†really useless

Short recap

  • You try to initialize a DCOM object identified by a particular CLSID from an “IStorage Object” via standard marshalling (OBJREF_STANDARD)
  • The “IStorage” obect contains, among other things, the OXID, OID, and IPID parameters needed for the OXID resolution in order to get the needed bindings to connect to our DCOM object interfaces. Think about it like sort of DNS query
  • From “Inside COM+: Base Services”: The OXID Resolver is a service that runs on every machine that supports COM+. It performs two important duties:
    • It stores the RPC string bindings that are necessary to connect with remote objects and provides them to local clients.
    • It sends ping messages to remote objects for which the local machine has clients and receives ping messages for objects running on the local machine. This aspect of the OXID Resolver supports the COM+ garbage collection mechanism.
  • OXID resolver is part of “rpcss” service and runs on port 135. Starting from Windows 10 1809 & Windows Server 2019, its no more possible to query the OXID resolver on a port different than 135
  • OXID resolutions are normally authenticated.¬† We are only interested in the authentication part, which occurs via NTLM in order to steal the token, so we can specify in our case for OXID, OID and IPID just 32 random bytes.
  • If you specify a remote OXID resolver, the request will be processed with an “ANONYMOUS LOGON“.

So what was our idea in our previous experiments?

  • Instruct the DCOM server to perform a remote OXID query by specifying a remote IP in the binding strings instead of “127.0.0.1”. This is done in the “stringbinding” structure
  • On the remote IP where is running a machine under our control, setup a “socat” listener (or whatever you prefer) for redirecting the OXID resolutions requests to a “fake” OXID RPC Server, created by us and¬† listening on a port different from 135. The fake server can run on the same Windows machine we are trying to exploit, but not necessary.
  • The fake OXID RPC server implements the “ResolveOxid2” server procedure
  • This function will resolve the client (ANONYMOUS LOGON) query¬† by returning the¬† RPC bindings which will point to another “fake” RPC server listening on a dedicated port under our control hosted on the victim machine.
  • The DCOM server will connect to the RPC server in order to perform the IRemUnkown2 interface call. By connecting tho the second RPC Server, an “Autentication Callback” is triggered and if we have SE_IMPERSONATE_NAME privileges, we can impersonate the caller via RpcImpersonateClient() call
  • And yes, it worked! We got a SYSTEM token coming from BITS service in this case, but unfortunately it was an Identification token, really useless.

The good news

So we abandoned the research until some days ago, when two interesting exploits/bugs had been published:

  1. Sharing a Logon Session a Little Too Much published by @tiraniddo . You can also find in this blog  the  post along with a working POC in order to demonstrate how it was possible for the NETWORK SERVICE Account to elevate privileges (bug/feature?)
  2. The marvellous “Print Spoofer” exploit published by @itm4n. In this case (and for our scenario) not for the exploit itself but for the “bug” in the named pipe path validation checks.

On a late evening of some days ago, @splinter_code sent me a message:

(@splinter_code) “If we resolve the fake OXID request by providing an RPC binding with¬† our named pipe instead of the TCP/IP sequence, we should in theory be able to impersonate the NETWORK SERVICE Account and after that… SYSTEM is just a step beyond…”

(me) “Yeah, sounds good, let’s give it a try!”

And guess what? IT WORKED!!!

Let’s dig into the details.

The “fake” OXID Resolver

First of all a  little bit of context on how the OXID resolution works is required to understand the whole picture.
This is how the flow looks like, taken from msdn :

OXID resolution sequence

The client will be the RPCSS service that will try to connect to our rogue oxid resolver (server) in order to locate the binding information to connect to the specified dcom.

Consider that all the above requests done by the client in the OXID resolution sequence are authenticated (RPC Security Callback) impersonating the user running the COM behind the CLSID we choose (usually the one running as SYSTEM are of interests).
What *potato exploits does is intercepting this authentication and steal the token (well technically is a little bit more complicated because the authentication is forwarded to the local system OXID resolver that will do the real authentication and *potato will just alter some packets to steal the token… a classic MITM attack).
When this is done over the network (due to the MS fix) this will be an Anonymous Logon so quite useless for an EoP scenario.

Our initial idea was to exploit one of the OXID resolver (technically called IObjectExporter) method and forge a response that could trigger a privileged authentication to our controlled listener.

Looking at the scheme above 2 functions caught our attention:

So the first request was not of our interest because we couldn’t¬† specify endpoint information (that’s what we needed) so we were always answering with a response of RPC_S_OK. This is an example of what a standard response looks like:

serveralive2_pcap

So we focused in the next one (ResolveOxid2) and what we saw is something interesting that we could abuse:

resolveoxid2_pcap

Observing the above traffic, that is a standard response captured on the real OXID resolver on a windows machine, we quickly spot that we could abuse this call by forging our own ResolveOxid2 response and specify as an endpoint our controlled listener.
We can  specify endpoint information in the format ipaddress[endpoint] and also the TowerId (more on that later).

But… Why not registering the binding information we require on the system OXID resolver, getting the OID and OXID from the system and ask the unmarshalling of that?
Well as our knowledge the only way to do that is by registering a CLSID on the system and to do that you need Administrator privileges.

So our idea was to implement a whole OXID resolver that would answer always with our listener binding for any oxid oid it will receive, just a Fake OXID resolver.

Let’s analyze the function ResolveOxid2 to understand how to forge our response:

[idempotent] error_status_t ResolveOxid2(
   [in] handle_t hRpc,
   [in] OXID* pOxid,
   [in] unsigned short cRequestedProtseqs,
   [in, ref, size_is(cRequestedProtseqs)] 
     unsigned short arRequestedProtseqs[],
   [out, ref] DUALSTRINGARRAY** ppdsaOxidBindings,
   [out, ref] IPID* pipidRemUnknown,
   [out, ref] DWORD* pAuthnHint,
   [out, ref] COMVERSION* pComVersion
 );

What we need to do is to fill the DUALSTRINGARRAY ppdsaOxidBindings with our controlled listener.
Well that was a little bit tricky, but it is well documented by MS (in 1 and 2) so it was just a matter of trial and errors to forge the right offsets/sizes for the packet.

Let’s recap, we can redirect the client to our controlled endpoint (aNetworkAddr) and we can choose the protocol sequence identifier constant that identifies the protocol to be used in RPC calls (wTowerId).

There are multiple protocols supported by RPC (here a list).

In the first attempt we tried ncacn_ip_tcp, as TowerId, that allows RPC straight over TCP.
We run an RPC server (keep in mind that a “standard” user can setup and register an RPC Server) with the IRemUnknown2 interface and tried to authenticate the request in our SecurityCallback calling RpcImpersonateClient.
Returning ncacn_ip_tcp:localhost[9998] in the ResolveOxid2 response, an authentication to our RPC server (IRemUnknown2) were triggered, but unfortunately was just an identification token…

iremunkown2

 

So that was a dead end… But what about “Connection-oriented named pipesncacn_np ?

The named pipe Endpoint mapper

First of all what is the “epmapper” ? Well it’s related to the “RpcEptMapper” service. This service resolves “RPC interfaces identifiers to transport endpoints”.¬† Same concept as OXID Resolver, but for RPC.

The mapper runs also on TCP port 135 but can also be queried via a special named pipe “epmapper”.

This service shares the same process space as the “rpcss” service and both of them run under the NETWORK SERVICE account.¬† So if we are able to impersonate the account under this process we can steal the SYSTEM token (because this process hosts juicy tokens)…

The first try we gave was to return a named pipe under our control in the ResolveOxid2 response:

ncacn_np:localhost[\pipe\roguepotato]

But observing the network traffic the RPCSS still connected to the \pipe\epmapper . This is because, by protocol design, the named pipe epmapper must be used, and this is obviously a “reserved” name:

Capture

No way…

When we read the PrintSpoofer post we were impressed by clever trick of the named pipe validation path bypass (credits to @itm4n and @jonasLyk) where inserting ‘/’ in the hostname will be converted in partial path of the named pipe!

With that in mind we returned the following binding information:

ncacn_np:localhost/pipe/roguepotato[\pipe\epmapper]

And you know what? The RPCSS were trying to connect to nonexistent named pipe \roguepotato\pipe\epmapper :

named_pipe_not_found

Great! So we setup a pipe listener on \\.\pipe\roguepotato\pipe\epmapper, got the connection and impersonated the client. Then we inspected the token with TokenViewer :

token_viewer

So we had an Impersonation token of the NETWORK SERVICE account and also the LUID of the RPCSS service! 

Why that? Well, the answer was in the post mentioned above:

if you can trick the ‚ÄúNetwork Service‚ÄĚ account to write to a¬† named pipe over the ‚Äúnetwork‚ÄĚ and are able to impersonate the pipe, you can access the tokens stored in RPCSS service

All the “magic” about the fake ResolveOxid2 response is happening in this piece of code:

resolveoxid2

The Token “Kidnapper”

Perfect! Now we just needed to perform the old and well known Token Kidnapping technique to steal some SYSTEM token from the RPCSS service.

We setup a minimalist “stealer” which performs the following operations:

  • get the PID of the “rpcss” service
  • open the process, list all handles and for each handle try to duplicate it and get the handle type
  • if handle type is “Token” and token owner is SYSTEM, try to impersonate and launch a process with CreatProcessAsUser() or CreateProcessWithToken()
  • In order to get rid of the occasional “Access Denied” when trying to launch a processes in Session 0, we also setup the correct permissions for the Windows Station/Desktop¬†

Well, let’s unleash RoguePotato and see our SYSTEM shell popping ūüėÄ

system_privs

Final Thoughts

Probably you are a little bit confused at this point, let’s do a recap. Under which circumstances can I use this exploit to get SYSTEM privileges?

  • You need a compromised account on the victim machine with Impersonate privileges (but this is the prerequisite for all these type of exploits). A common scenario is code execution on default IIS/MSSQL configuration.
  • If you are able to impersonate NETWORK SERVICE account or if the “spooler” service is not stopped you can first try the other exploits mentioned before…
  • You need to have¬† a machine under your control where you can perform the redirect and this machine must be accessible on port 135 by the victim¬†¬†
  • We setup a POC with 2 exe files. In fact it is also possible to launch the fake OXID Resolver in standalone mode on a Windows machine¬† under our control when the victim’s firewall won’t accept incoming connections.
  • Extra mile: In fact, in the old *potato exploit, an alternate way for stealing the token was just to setup a local RPC listener on dedicated port instead of forging the local NTLM Authentication,¬† RpcImpersonateClient() would have done the rest.

To sum it up:

flow_graph_2

You can find the source code and POC of RoguePotato here.

Final note: We didn’t bother to report this “misbehavior?” to MS because they stated that elevating from a Local Service process (with SeImpersonate) to SYSTEM is an ‚Äúexpected behavior‚ÄĚ. (RogueWinRm – Disclosure Timeline)

That’ all ūüėČ

@slpinter_code, @decoder_it

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s