Exploit-DB #42020
Description: Microsoft Windows - COM Aggregate Marshaler/IRemUnknown2 Type Confusion Privilege Escalation
Type: local
Platform: windows
Date: 2017-05-17
Author: Google Security Research

Exploit:
/*
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1107

Windows: COM Aggregate Marshaler/IRemUnknown2 Type Confusion EoP
Platform: Windows 10 10586/14393 not tested 8.1 Update 2
Class: Elevation of Privilege

Summary:
When accessing an OOP COM object using IRemUnknown2 the local unmarshaled proxy can be for a different interface to that requested by QueryInterface resulting in a type confusion which can result in EoP.

Description:

Querying for an IID on a OOP (or remote) COM object calls the ORPC method RemQueryInterface or RemQueryInterface2 on the default proxy. This request is passed to the remote object which queries the implementation object and if successful returns a marshaled representation of that interface to the caller. 

The difference between RemQueryInterface and RemQueryInterface2 (RQI2) is how the objects are passed back to the caller. For RemQueryInterface the interface is passed back as a STDOBJREF which only contains the basic OXID/OID/IPID information to connect back. RemQueryInterface2 on the other hand passes back MInterfacePointer structures which is an entire OBJREF. The rationale, as far as I can tell, is that RQI2 is used for implementing in-process handlers, some interfaces can be marshaled using the standard marshaler and others can be custom marshaled. This is exposed through the Aggregate Standard Marshaler. 

The bug lies in the implementation of unpacking the results of the the RQI2 request in CStdMarshal::Finish_RemQIAndUnmarshal2. For each MInterfacePointer CStdMarshal::UnmarshalInterface is called passing the IID of the expected interface and the binary data wrapped in an IStream. CStdMarshal::UnmarshalInterface blindly unmarshals the interface, which creates a local proxy object but the proxy is created for the IID in the OBJREF stream and NOT the IID requested in RQI2. No further verification occurs at this point and the created proxy is passed back up the call stack until the received by the caller (through a void** obviously). 

If the IID in the OBJREF doesn’t match the IID requested the caller doesn’t know, if it calls any methods on the expected interface it will be calling a type confused object. This could result in crashes in the caller when it tries to access methods on the expected interface which aren’t there or are implemented differently. You could probably also return a standard OBJREF to a object local to the caller, this will result in returning the local object itself which might have more scope for exploiting the type confusion. In order to get the caller to use RQI2 we just need to pass it back an object which is custom marshaled with the Aggregate Standard Marshaler. This will set a flag on the marshaler which indicates to always use the aggregate marshaler which results in using RQI2 instead of RQI. As this class is a core component of COM it’s trusted and so isn’t affected by the EOAC_NO_CUSTOM_MARSHAL setting.

In order to exploit this a different caller needs to call QueryInterface on an object under a less trusted user's control. This could be a more privileged user (such as a sandbox broker), or a privileged service. This is pretty easy pattern to find, any method in an exposed interface on a more trusted COM object which takes an interface pointer or variant would potentially be vulnerable. For example IPersistStream takes an IStream interface pointer and will call methods on it. Another type of method is one of the various notification interfaces such as IBackgroundCopyCallback for BITS. This can probably also be used remotely if the attacker has the opportunity to inject an OBJREF stream into a connection which is set to CONNECT level security (which seems to be the default activation security). 

On to exploitation, as you well know I’ve little interest in exploiting memory corruptions, especially as this would  either this will trigger CFG on modern systems or would require a very precise lineup of expected method and actual called method which could be tricky to exploit reliably. However I think at least using this to escape a sandbox it might be your only option. So I’m not going to do that, instead I’m going to exploit it logically, the only problem is this is probably unexploitable from a sandbox (maybe) and requires a very specific type of callback into our object. 

The thing I’m going to exploit is in the handling of OLE Automation auto-proxy creation from type libraries. When you implement an Automation compatible object you could implement an explicit proxy but if you’ve already got a Type library built from your IDL then OLEAUT32 provides an alternative. If you register your interface with a Proxy CLSID for PSOAInterface or PSDispatch then instead of loading your PS DLL it will load OLEAUT32. The proxy loader code will lookup the interface entry for the passed IID to see if there’s a registered type library associated with it. If there is the code will call LoadTypeLib on that library and look up the interface entry in the type library. It will then construct a custom proxy object based on the type library information. 

The trick here is while in general we don’t control the location of the type library (so it’s probably in a location we can write to such as system32) if we can get an object unmarshaled which indicates it’s IID is one of these auto-proxy interfaces while the privileged service is impersonating us we can redirect the C: drive to anywhere we like and so get the service to load an arbitrary type library file instead of a the system one. One easy place where this exact scenario occurs is in the aforementioned BITS SetNotifyInterface function. The service first impersonates the caller before calling QI on the notify interface. We can then return an OBJREF for a automation IID even though the service asked for a BITS callback interface.

So what? Well it’s been known for almost 10 years that the Type library file format is completely unsafe. It was re