Proxying COM For Stable Hijacks

Introduction

COM hijacking presents a unique way to load your rogue DLL into another process. In a world with increasing optics into in-memory tactics, COM hijacking may provide an alternative to get code execution inside a process. This post will attempt to explain what’s going on when a COM object is hijacked and share a method to proxy the original COM server to avoid crashing the process.

Previous Work

COM hijacking was first discussed back in 2011 by Jon Larimer who foresaw the potential security concerns of per-user COM objects. Since then there was some malware that leveraged the technique, @enigma0x3 released a solid blog post of leveraging COM hijacking and scheduled tasks for persistence in 2016, and @bohops released two posts adding more information around abusing COM. It’s also listed on MITRE ATT&CK as T1122.

When talking COM, it would also be remiss of me to not mention oleviewdotnet by James Forshaw . He also presented my favorite talk on the subject, COM in 60 Seconds, and has tons of other research surrounding COM.

tl;dr

Proxying the legitimate COM server DLL can lead to more stability and more options for COM hijacks. The PoC code can be found here: https://github.com/leoloobeek/COMProxy

Refresher

COM is very complex, I’m going to only cover the pieces that are relevant here and might “hand wave” over some details. I will refer you to the previous work above or this book if you want to go further.

Most COM classes are registered and discovered by their CLSID (class identifier) which is a GUID. If you have ever created a COM object you’ve likely given a name such as “WScript.Shell”, this is called a ProgID. When you attempt to access a COM object the process will query HKEY_CLASSES_ROOT\CLSID which contains hundreds of subkeys named for each CLSID registered on the host. Within the CLSID’s path will contain additional registry keys that the COM subsystem can use to load the correct COM server.

COM servers are essentially DLLs that provide COM interfaces to the calling process (client).  COM servers can be in-process or out-of-process, for this blog post we’ll only worry about COM in-process servers.

Hijacking COM

The issue that leads to COM hijacking is when querying HKEY_CLASSES_ROOT\CLSID, Windows will look at HKEY_CURRENT_USER\Software\Classes\CLSID for the provided CLSID. If the key does NOT exist then Windows looks in HKEY_LOCAL_MACHINE\Software\Classes\CLSID for the provided CLSID. In almost all cases COM classes are registered in HKLM. Since Windows will check HKCU first, it is possible to add a CLSID of an existing, legitimate COM class pointing to a rogue COM server, and the process will load the rogue DLL rather than the expected COM server. No adminstrator privileges required.

Lots of previous work covers how to find them, in short load up Process Monitor, filter Path looking for InProcServer32, filter for the process you want to load into, and let it run.

For example, on Windows 7, {7D096C5F-AC08-4F1F-BEB7-5C22C517CE39} is a GUID Internet Explorer queries for soon after starting. Writing out a DLL to initiate HTTPS remote access within Internet Explorer can help blend in within a scrutinized environment. Setting the registry keys as follows will set up the hijack.

Important Note: I, mistakenly, chose a Windows 7 hijack I had written down for this example. COM hijacking is absolutely still prevalent in Windows 10 environments, but with  Code Integrity Guard (CIG) it may limit which processes you will find success. I’ll leave this up to the reader as the focus is not on finding hijacks and more on the internals of COM hijacking. The PoC COM client and server for hijacking released work on both Windows 7 and 10.

Screen Shot 2019-08-28 at 7.03.36 PM.png

Opening up Internet Explorer and… we crashed the process.

Screen Shot 2019-08-28 at 7.10.50 PM.png

Well, taking a step back, we are forcing a process to load our DLL instead of the DLL it expects, and our DLL doesn’t have any of the functionality the process requires. It seems logical that the process would crash once it realizes our DLL isn’t what they’re expecting. If you’ve ever looked for COM hijacks, this can become pretty common, or worse, everything appears OK but certain features may become unstable.

What’s in a COM Server

In order to provide COM interfaces to clients, a COM server needs DllGetClassObject in its export table. Once an in-process COM server is loaded, the process will call the DLL’s DllGetClassObject with the CLSID and the server will return pointers to the interface.

Capture

When the COM object is no longer used, it should be released to free up memory. Furthermore, periodically the process should call CoFreeUnusedLibraries which will tell the process to check each loaded COM server for any COM objects instantiated. If no COM objects are instantiated, the process will call the COM server’s exported function DllCanUnloadNow. Legitimate COM servers will perform any cleanup, return to the process, and the process will free the library (FreeLibrary) from its memory.

Crafting a COM Server For Hijacking

To begin, COM servers should export DllGetClassObject and DllCanUnloadNow at a minimum. What’s interesting about DllGetClassObject is the main output from the function is a pointer to the interface. Since are an in-process COM server will be loaded into a process, and we’re returning a pointer, it’s trivial to proxy the legitimate COM object. Loading the legitimate COM server, finding its DllGetClassObject export, then calling it will obtain all the valid pointers.

typedef HRESULT(__stdcall *_DllGetClassObject)(REFCLSID rclsid, REFIID riid, LPVOID* ppv);
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
{
    // Load up the original COM server
    HMODULE hDLL = LoadLibrary("C:\\Windows\\legitimate\\COMServer.dll);
    // Find the DllGetClassObject for original COM server
    _DllGetClassObject lpGetClassObject = (_DllGetClassObject)GetProcAddress(hDLL, "DllGetClassObject");
    return lpGetClassObject(rclsid, riid, ppv);
}

At this point, the process is receiving the COM interface its expecting. Although what if the process uses the class shorter than the malicious activities you hope to accomplish? The process will release the object and call DllCanUnloadNow which will remove the rogue DLL from its memory. One (somewhat hacky) way to ensure your code runs before unloading is to use a global variable and loop when DllCanUnloadNow is entered.

UINT g_uThreadFinished;
extern UINT g_uThreadFinished;
// Set g_uThreadFinished to 0 in DLL_PROCESS_ATTACH, set to 1 when you're finished
STDAPI DllCanUnloadNow(void)
{
    do 
    {
        Sleep(1);
    } while (g_uThreadFinished == 0);
    return S_OK;
}

A full PoC proxy COM server is available at https://github.com/leoloobeek/COMProxy. It includes some code that will dynamically find the COM server that its hijacking and proxy the DllGetClassObject call. I also have a test COM client that will load WScript.Shell, run calc, and call the COM cleanup Windows API calls.

Operationalize COM Hijacking

When evaluating techniques to see where they fit in an offensive operation, its important to understand the limitations and detection points. Going through the work to proxy the legitimate COM server was important to ensure reliability on successful hijacks.

The technique does require dropping a DLL to disk which may push people away. Frankly, in this era which includes better in-memory optics, I’m open to dropping files to disk again as long as I understand the endpoint controls and feel comfortable with the file. Also, maybe you don’t have to drop a .dll to disk (hint, hint). This does present an interesting scenario: you set a COM hijack and laid down your COM server for persistence. While it wasn’t detected initially, it eventually gets scrubbed for $Reason. At this point, since the rogue DLL doesn’t exist but the registry key is still set, the legitimate DLL will NOT be loaded and this will impact the target user or system. Unfortunately, the COM subsystem does not check HKLM if the COM server in HKCU doesn’t exist.

Given this issue, hijacking COM and proxying the original object for stability might be best leveraged for execution. A few execution scenarios may be migrating to another process or lateral movement. Persistence with COM hijacking may be best for abandoned keys or the scheduled task handler hijack outlined by @enigma0x3 (listed in previous work).

Additionally, detecting COM hijacking via registry modifications is straight forward. In fact, the popular @SwiftOnSecurity Sysmon config has a rule exactly for COM hijacking here. There’s not many subkeys in  HKEY_CURRENT_USER\Software\Classes\CLSID which will make new keys added maybe appear suspicious. With that said, armed with this proxying technique, overwriting key values to COM servers is an option which may blend in. For example, Microsoft Teams starts on boot and also registers a COM class in HKCU: {CB965DF1-B8EA-49C7-BDAD-5457FDC1BF92}. There are hundreds of CLSID keys in HKLM, overwriting those may also blend in better, although they’re owned by TrustedInstaller.

With all this said, there’s not much to be said around automated detection from NGAV for COM object hijacking. In other words, detection relies on the blue team and tuning of their tools. As blue team training is the main overall objective of most red team operations, this technique may be a good training opportunity for the defenders.

Conclusion

That wraps COM hijacking for me. Feel free to reach out to me on Twitter if you have any questions or feedback on this technique. Also, at 10am Saturday, September 7 at DerbyCon a very smart dude David Tulis (@kafkaesqu3) will cover more around COM hijacking with his presentation!

Keying Payloads for Scripting Languages

Introduction

I’ve been a huge fan of the Ebowla project and find keying payloads valuable in both standard penetration testing engagements along with red team operations. Using environmental keying helps evade sandbox detection, makes it harder on endpoint security products, and can slow down incident response. There’s not many techniques out there that can have an impact on all the above defenses.

I commonly use scripting languages, such as PowerShell/VBS/JS, as an initial execution vector for phishing or when setting up persistence. I went down the rabbit hole to create GoGreen, which incorporates environmental keying to protect scripting languages from to get the benefits from this technique. Throughout this post I will outline the advantages, limitations, and how incorporating another keying technique can further improve your payloads.

Previous Work

As mentioned above, Ebowla is the first application of environmental keying payloads and the result of Josh Pitt‘s great research into this technique. Please check out the slides from his presentations along with his project. A base understanding of those materials is assumed going forward.

Also, check out this blog post from @Killswitch_GUI about HTTP keying. More on that in a bit!

Environmental Keying High Level Review

First off, why is environmental keying powerful? At a high level, we encrypt your “malicious payload” (such as CACTUSTORCH) with a series of variables you expect to be on the target workstation. These variables could be a file path you expect, maybe you know Photoshop will be installed: “C:\Program files 86\Adobe\Photoshop CS6”. Or maybe you expect to know the username, system architecture, and domain name: “jdoeamd64contoso.com”.

The final payload will NOT include the value of these variables, which means the payload does NOT include the decryption key for your final payload. It will search for all file paths on a system, pull in environmental variables, and then try combinations attempting to decrypt the final payload and execute it if successful. Again, if you’re fuzzy on this or want more info, see the research from above in Previous Work.

Environmental Keying with GoGreen

GoGreen takes a lot of what Ebowla offers and just applies it to PowerShell (v2+), JScript, or VBScript.

This is done by the payload by spidering/walking the directory tree from a start directory (such as C:\Program Files) and harvesting all file paths found. Next, it reads in all environment variables specified in the code (which is chosen by you in the config file), and creates all possible combinations (not permutations). Then goes the following steps:

  1. Loop through all file paths
  2. For each file path, loop through each combination of environmental vars
  3. Build a key with: sha512([file path][env var combo])
  4. Try first 32 chars of sha512 hash above as key
  5. If error, or sha512(decrypted) doesn’t match payload hash, move onto next key

Below is a sample config file for GoGreen. This will start spidering the file paths at C:\Program Files (x86)” and only go two folder paths deep (for performance). The actual key will be the PathKey, which is keying on whether Office is installed. It will also include generating all possible combinations of the five listed environmental variables, while only using three.

{
"Language": "jscript",
"WSHAutoVersion": "Yes",

"StartDir": "C:\\Program Files (x86)",
"Depth": "2",
"PathKey": "C:\\Program Files (x86)\\Microsoft Office\\root",

"EnvVars": {
"USERNAME": "jdoe",
"COMPUTERNAME": "win7pc35",
"USERDNSDOMAIN": "contoso",
"PROCESSOR_ARCHITECTURE": "",
"LOGONSERVER": ""
},

"Payload": "",
"PayloadPath": "/tmp/CACTUSTORCH.js",
"MinusBytes": "3"
}

Environmental Keying Trade Offs

As you see above, I only chose a spidering depth of 2. While this will quickly speed up harvesting all the file pahts to start trying to decyrpt, it also makes a far less number of possibilities if you were to not specify a depth at all and grab all folders and files under the start directory. This is a deployment consideration you must take into account and understand your needs. The more environmental variables and more file/folder paths, the longer it will take and the CPU will definitely spike as it goes on.

GoGreen’s Limitation

The limitation of using environmental keying with scripting languages, is the ease of decrypting and finding the final payload once the environmental keys or target system is identified. Obviously, since scripting languages are in cleartext (and not compiled binaries), it is easy to modify the output from GoGreen to determine the final payload.

As an example, let’s say I discover an active phishing attack in my environment. After responding to the event I get my hands on the payload, an HTA. After reviewing the source code it could be determined that it is attempting to decrypt off of environmental variables and I identify the line with “eval”:

gogreen-eval-statement
Excerpt from GoGreen JScript output highlighting “eval” statement

The “eval” statement will execute the decrypted payload if the variables exist. I could edit the JScript code inside the HTA to replace “eval” with Wscript.Echo and write it to a new .js file. Finally, I could use some means to execute this script on all the targeted end users’ workstations. If the expected environment variables exist, it will print out the final payload to the screen. I will then either have the shellcode or the C2 server address.

I still see value in using this technique to get through sandbox detections or bypass endpoint security products, and it still may slow down the incident response. Although I think using a compiled binary with Ebowla would be better as you would need to reverse the binary and then likely perform dynamic analysis of the payload with the right environmental values.

I should note, I am a penetration tester by trade and if any blue teamers have a different idea or approach to responding to these types of payloads, let me know!

Strengthening GoGreen with HTTP Keying

I wanted to make my payloads even more difficult for incident responders which reminded me of this blog post on HTTP keying. I noticed this Veil payload type is no longer included in Veil 3.0, but you can still use it in the unsupported version of Veil-Evasion.

HTTP Keying is a technique where you host a webpage somewhere on the Internet. The payload reaches out to this webpage, hashes the HTML response, and uses that hash as the key to decrypt the payload. The benefit here is that you have full control over this decryption key and you can remove it, as you can easily change the pages contents to your liking. Below is two easy examples to demonstrate the power here:

  • Create a web page, setup the HTTP keying, then change the page to something else. Have the payload keep checking and trying to decrypt (similar to a beacon). After waiting several hours, switch the web page back to the original and the payload should decrypt and execute your underlying payload.
  • You set scheduled task persistence on your beachhead calling back to your longhaul domain. You expect the persistence to call back every day at 9am. You set the expected webpage to decrypt your payload at 8:58am and revert back to a 404 page after you receive your call back.

Those are just two examples that can be further expanded on. Let’s go over how this works with GoGreen. I decided to have GoGreen first setup the HTTP Keying code, and then use environmental keying to mask the HTTP Keying code. The steps go as follows:

  1. GoGreen uses environmental keying (directory/env vars) to decrypt and execute code
  2. The code decrypted will handle the HTTP keying, which is executed
  3. The new executed code will go out to HttpKeyUrl and hash the page
  4. The new executed code will use the hash and decrypt and execute your payload
GoGreen Flow
GoGreen Flow

The benefit here is at first glance, the payload is doing environmental keying, with no code that initiates an HTTP call. For PowerShell , this means there is no “Net.WebClient” in here.

Due to differing charsets and other side effects of hashing and encrypting text, along with other factors such as different languages, GoGreen will output a “tester” file which can be used to verify that the HTTP key is setup appropriately. To avoid headaches here, it’s recommended to use a simple web page. Even the standard Microsoft 403 page would be benign and something that would be easy to use.

I don’t want to only push GoGreen here, this can also be done by generating a payload with Veil-Evasion to do HTTP Keying and then take the output and put it through Ebowla.

Putting It All Together

Putting all the pieces together, below I have a configuration setup for environmental keys: Office folder path and expecting the target username to be “username”. I also have set the configuration to grab an HTTP key at a given URL and to retry 300 times before giving up and exiting. For more information on how to use GoGreen see the README on the GitHub page. There is also releases for Windows, Linux and Mac for those that don’t want to setup Golang.

gogreen-example
Example GoGreen configuration and execution

GoGreen will generate all the keys and code needed and will also access the site provided in the configuration and determine the HTTP Key. You can also specify a custom key if you prefer with GoGreen -httpkey <HttpKey>. The result will output both the payload file and an HTTP key “tester” file. I would recommend running the tester file with your HTTP Key page up to ensure the payload format generates the same key.

gogreen-httpkey-tester
Running the HTTP Key tester file to ensure key/hashing works as expected

The payload file is now ready to deploy on your target!

Finishing Up

I think keying payloads is incredibly beneficial to offensive operations. If you are dropping persistence with a scripting language you are running a risk if it gets identified by the blue team.

While these keying techniques don’t make it impossible, it may buy you time during an operation to stay in the network and keep your infrastructure protected. It also gives the blue team some new things to learn and be prepared for.

Keying payloads is another cog in your offense-in-depth strategy, and strong when used with obfuscation, red team infrastructure, and other popular techniques in the industry right now.