When doing security research I regularly use my NtObjectManager PowerShell module to discover and call RPC servers on Windows. Typically I'll use the Get-RpcServer command, passing the name of a DLL or EXE file to extract the embedded RPC servers. I can then use the returned server objects to create a client to access the server and call its methods. A good blog post about how some of this works was written recently by blueclearjar.
Using Get-RpcServer only gives you a list of what RPC servers could possibly be running, not whether they are running and if so in what process. This is where the RpcView does better, as it parses a process' in-memory RPC structures to find what is registered and where. Unfortunately this is something that I'm yet to implement in NtObjectManager.
However, it turns out there's various ways to get the running RPC server information which are provided by OS and the RPC runtime which we can use to get a more or less complete list of running servers. I've exposed all the ones I know about with some recent updates to the module. Let's go through the various ways you can piece together this information.
NOTE some of the examples of PowerShell code will need a recent build of the NtObjectManager module. For various reasons I've not been updating the version of the PS gallery, so get the source code from github and build it yourself.
RPC Endpoint Mapper
If you're lucky this is simplest way to find out if a particular RPC server is running. When an RPC server is started the service can register an RPC interface with the function RpcEpRegister specifying the interface UUID and version along with the binding information with the RPC endpoint mapper service running in RPCSS. This registers all current RPC endpoints the server is listening on keyed against the RPC interface.
You can query the endpoint table using the RpcMgmtEpEltInqBegin and RpcMgmtEpEltInqNext APIs. I expose this through the Get-RpcEndpoint command. Running Get-RpcEndpoint with no parameters returns all interfaces the local endpoint mapper knows about as shown below.
Note that in addition to the interface UUID and version the output shows the binding information for the endpoint, such as the protocol sequence and endpoint. There is also a free form annotation field, but that can be set to anything the server likes when it calls RpcEpRegister.
The APIs also allow you to specify a remote server hosting the endpoint mapper. You can use this to query what RPC servers are running on a remote server, assuming the firewall doesn't block you. To do this you'd need to specify a binding string for the SearchBinding parameter as shown.
---- ------- -------- -------- ----------
d95afe70-a6d5-4259-822e-2c84da1ddb0d 1.0 ncacn_ip_tcp 49664
5b821720-f63b-11d0-aad2-00c04fc324db 1.0 ncacn_ip_tcp 49688
650a7e26-eab8-5533-ce43-9c1dfce11511 1.0 ncacn_np \PIPE\ROUTER Vpn APIs
...
The big issue with the RPC endpoint mapper is it only contains RPC interfaces which were explicitly registered against an endpoint. The server could contain many more interfaces which could be accessible, but as they weren't registered they won't be returned from the endpoint mapper. Registration will typically only be used if the server is using an ephemeral name for the endpoint, such as a random TCP port or auto-generated ALPC name.
Pros:
- Simple command to run to get a good list of running RPC servers.
- Can be run against remote servers to find out remotely accessible RPC servers.
- Only returns the RPC servers intentionally registered.
- Doesn't directly give you the hosting process, although the optional annotation might give you a clue.
- Doesn't give you any information about what the RPC server does, you'll need to find what executable it's hosted in and parse it using Get-RpcServer.
Service Executable
If the RPC servers you extract are in a registered system service executable then the module will try and work out what service that corresponds to by querying the SCM. The default output from the Get-RpcServer command will show this as the Service column shown below.
Name UUID Ver Procs EPs Service Running
---- ---- --- ----- --- ------- -------
appinfo.dll 0497b57d-2e66-424f-a0c6-157cd5d41700 1.0 7 1 Appinfo True
appinfo.dll 58e604e8-9adb-4d2e-a464-3b0683fb1480 1.0 1 1 Appinfo True
appinfo.dll fd7a0523-dc70-43dd-9b2e-9c5ed48225b1 1.0 1 1 Appinfo True
appinfo.dll 5f54ce7d-5b79-4175-8584-cb65313a0e98 1.0 1 1 Appinfo True
appinfo.dll 201ef99a-7fa0-444c-9399-19ba84f12a1a 1.0 7 1 Appinfo True
The output also shows the appinfo.dll executable is the implementation of the Appinfo service, which is the general name for the UAC service. Note here that is also shows whether the service is running, but that's just for convenience. You can use this information to find what process is likely to be hosting the RPC server by querying for the service PID if it's running.
Name Status ProcessId
---- ------ ---------
Appinfo Running 6020
The output also shows that each of the interfaces have an endpoint which is registered against the interface UUID and version. This is extracted from the endpoint mapper which makes it again only for convenience. However, if you pick an executable which isn't a service implementation the results are less useful:
The efslsaext.dll implements one of the EFS implementations, which are all hosted in LSASS. However, it's not a registered service so the output doesn't show any service name. And it's also not registered with the endpoint mapper so doesn't show any endpoints, but it is running.
Pros:
- If the executable's a service it gives you a good idea of who's hosting the RPC servers and if they're currently running.
- You can get the RPC server interface information along with that information.
- If the executable isn't a service it doesn't directly help.
- It doesn't ensure the RPC servers are running if they're not registered in the endpoint mapper.
- Even if the service is running it might not have enabled the RPC servers.
Enumerating Process Modules
Extracting the RPC servers from an arbitrary executable is fine offline, but what if you want to know what RPC servers are running right now? This is similar to RpcView's process list GUI, you can look at a process and find all all the services running within it.
It turns out there's a really obvious way of getting a list of the potential services running in a process, enumerate the loaded DLLs using an API such as EnumerateLoadedModules, and then run Get-RpcServer on each one to extract the potential services. To use the APIs you'd need to have at least read access to the target process, which means you'd really want to be an administrator, but that's no different to RpcView's limitations.
The big problem is just because a module is loaded it doesn't mean the RPC server is running. For example the WinHTTP DLL has a built-in RPC server which is only loaded when running the WinHTTP proxy service, but the DLL could be loaded in any process which uses the APIs.
To simplify things I expose this approach through the Get-RpcServer function with the ProcessId parameter. You can also use the ServiceName parameter to lookup a service PID if you're interested in a specific service.
Name UUID Ver Procs EPs Service Running ---- ---- --- ----- --- ------- -------
RPCRT4.dll afa8bd80-7d8a-11c9-bef4-... 1.0 5 0 False
combase.dll e1ac57d7-2eeb-4553-b980-... 0.0 0 0 False
combase.dll 00000143-0000-0000-c000-... 0.0 0 0 False
Pros:
- You can determine all RPC servers which could be potentially running for an arbitrary process.
- It doesn't ensure the RPC servers are running if they're not registered in the endpoint mapper.
- You can't directly enumerate the module list, except for the main executable, from a protected process (there's are various tricks do so, but out of scope here).
Asking an RPC Endpoint Nicely
Pros:
- You can determine exactly what RPC servers are running in a process.
- You can't directly determine what the RPC server does as the list gives you no information about which module is hosting it.