Abusing Diaghub

1 minute read

This post is based on this article from google project zero. For more details please read their awesome post, I will just give a brief overview.

Microsoft (R) Diagnostics Hub Standard Collector Service (diaghub) is a service that gives diagnostic information by collecting trace information. Its functionality is exposed over a DCOM object. We can talk to this DCOM object and force it to load an arbitrary dll. As diaghub can only load dlls from system32 it is assumed that you have some way to write to system32 (in the referenced blogpost they show a vulnerability utilizing hardlinks to achieve that). I uploaded the exploit here. This is a minimal version of the original poc from project zero. If you want to learn how it works continue reading, otherwise just grab and run it.

DCOM (Distributed COM) is a form of RPC which allows client objects to talk to server objects and request services from them (similar to CORBA). This allows programs written in different programming languages or running on different platforms to interface with each other.

In the following part I will give an overview about the most important steps involved. First we create a GUID with CoCreateGuid(&name) (CoCreateGuid), a unique 128-bit integer that is used for CLSIDs. These CLSIDs identify COM class objects. Then we call CoCreateInstance(CLSID_CollectorService, nullptr, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&service)), (CoCreateInstance) which creates a new, uninitialized object from the COM class. The class is specified by its CLSID value, in this case CLSID_CollectorService.

The next call is CoQueryProxyBlanket(service, &authn_svc, &authz_svc, &principal_name, &authn_level, &imp_level, &identity, &capabilities), (CoQueryProxyBlanket) which retrieves authentication information that the client will use to talk to the proxy. These are then used to authenticate to the proxy with CoSetProxyBlanket(service, authn_svc, authz_svc, principal_name, authn_level, RPC_C_IMP_LEVEL_IMPERSONATE, identity, capabilities) (CoSetProxyBlanket).

We then configure and create a new session on the proxy:

SessionConfiguration config = {};
config.version = 1;
config.monitor_pid = ::GetCurrentProcessId();
bstr_t path = valid_dir;
config.path = path;
ICollectionSessionPtr session;

ThrowOnError(service->CreateSession(&config, nullptr, &session));

Finally we create an agent and add the agent to the session. This triggers the load of the given DLL.

GUID agent_guid;
ThrowOnError(session->AddAgent(targetDll, agent_guid));

You can use any DLL for this, a minimal one that just starts nc would look like this.

To use the exploit, change the strings for valid_dir and target_dll (must be a file in system32, extension does not matter), compile it for the correct target architecture and run diaghub.exe.