Anti-virus Exploitation: Malwarebytes 4.0.4 - Protection Not Found - Hijacking Malwarebytes via COM IPC

Hijacking Malwarebytes via COM IPC

Attacking K7 Security was my first attempt at discovering, analysing, and exploiting software at the protocol level. It made me curious as to how other vendors designed and developed their inter-process communication (IPC) methods between the untrusted client (the user-controlled software; usually the GUI) and the high integrity service process. Here is the diagram that shows the interaction between these two components again, for completeness:

This article will be about diving into reverse engineering the communication protocol used in Malwarebytes and the issues that I identified as a result of bypassing the intended (and assumed?) approach towards controlling functionality.

Disclaimer: I do not claim to know everything on the topics discussed here as fact, this is purely what I have inferred from my research. Especially if the COM information is inaccurate in any way, shape or form, please let me know and I will fix it as soon as possible. PoC code snippets has been withheld until the vendor applies a patch or until a reasonable amount of time has passed.

Recommended Pre-requisite Knowledge

  • Windows API
  • C/C++ and Intel Assembly
  • Inter-process communication
    • Named Pipes
    • Component Object Model (COM)

Discovering IPC Methods

There are multiple ways with which software can perform IPC. How do we figure out which ones Malwabytes uses? Let’s start with analysing the imported functions of the GUI and service executables in IDA. Starting with the service executable, MBAMService.exe, we can identify named pipe functions:

Named Pipe API

While we’re here, let’s see if we can extract the pipe name. CreateNamedPipe is documented to receive the name of the pipe:

Following the references of CreateNamedPipeW will lead us to:

Named pipe name

But what does MBLG mean…? If we take a look at the ConnectNamedPipe references, there are strings which will give us a hint:

Perhaps MalwareBytes License Generator? Nevertheless, we’ve identified one of the IPC techniques.

In the documentation for the available IPC methods, it states that “the foundation of OLE is the Component Object Model (COM)”. If we look into the ole32 library imports, we can see this:

COM imports

The CoInitializeEx documentation states:

This verifies that the service process also uses COM IPC.

What about the GUI executable, mbam.exe? Let’s look for the same IPC methods beginning with named pipes:

Named pipe imports

CallNamedPipe is documented to receive the target pipe name:

CallNamedPipe docs

Again, we will follow the reference to that function and again, we’ll see the \\.\pipe\MBLG string:

Named pipe name

This time, it’s accompanied with another string NeedAKey which is passed into the input buffer for the service process.

mbam.exe also imports the COM functions from the ole32 library:

COM imports

Reverse Engineering the COM Protocol

One of the many amazing tools released by James Foreshaw is OleViewDotNet. Using this, we can discover COM objects available on a system.

Firing up OleViewDotNet, we can list all the COM classes exposed through their CLSIDs. Filtering by servers, we can see that the MBAMService.exe executable is packaged with type libraries that define protocol information in human-readable and code form.

Here is the RTPController interface:

and here is the LicenseController interface:

How can we extract this information so we can use it? The OleViewDotNet tool is based on Microsoft’s OleView which can pull the type library information into a compilable Interface Definition Language (IDL) file.

Notice that at the top of the generated IDL file there is a typelib filename: 12 which probably indicates that there are at least 12 type libraries. After extracting all of the IDL files, we should have fourteen files:

All IDL files

Compiling IDL Files

To compile these into code, we can use Microsoft’s midl.exe utility like so:

midl /out <output directory path> /header <header output file path> <path to IDL file>

But we have to do this is a specific order. Looking back at the generated AEControllerCOMLib IDL file in OleView, there are dependencies specified with importlib("<file>"). These are the other compiled IDL files used by Malwarebytes. We must first find and compile the IDL file with none of these dependencies and then gradually work our way up until we have all of the dependencies required to compile all of the other IDL files. Let’s take a brief look at an example.

The first file we need to compile is the LogController. We can see that it only has the stdole2.tlb type library as its dependency which is provided by Microsoft.

If we compile this using midl, we’ll get three files (depending on how you named them on the command line):

LogController.h
LogController.tlb
LogController_i.c

The header file will contain the definition of all of the enums, structs, and class methods for the COM object:

The C file will contain the interface identifiers (IID) and CLSIDs to query and use the COM object:

The type library (tlb) file is required for dependencies to compile the other IDL files. This file name should correspond with what’s specified in the IDL file’s typelib filename - in this case, it’s just 2.

The next IDL to be compiled is the PoliciesController. The IDL file states that its dependencies are stdole2.tlb and 2, both of which we have.

Now we just repeat the steps as before with the LogController and the rest of the other IDL files.

Querying Malwarebytes’ COM Object Classes

To figure out how we can interact with the COM classes, we can look at how mbam.exe does it using Rohitab’s API Monitor. With this information, hopefully we can re-implement it ourselves. We’ll set the filter to monitor for COM and Pipe API calls only in the mbam.exe module and it should look like this when monitoring the startup of the application:

Let’s ignore the first call to CoCreateInstance, because it fails, and move onto CallNamedPipeW. We saw this call earlier with the NeedAKey string in the input buffer. Here is what the output buffer contains:

Looks like a randomly-generated sequence of wide ASCII characters (we’ll call this the “license string”), and we can see it used in calls to SysAllocStringLen and SysFreeString which returns a BSTR type of the input string and frees it, respectively. The BSTR type is used in passing data in COM objects. The license string is also used in IClassFactory2::CreateInstanceLic which is documented as so:

That’s good to know! But how do we get here and what is this IClassFactory2 used for? Let’s jump back to the call to CoGetClassObject and its arguments. The MBAMServiceController CLSID is specified to retrieve its corresponding pointer to its object which is returned as an IClassFactory. The IClassFactory::QueryInterface method is then used to obtain the IClassFactory2 interface. But what’s the point in all of this? As it turns out - after a lot of experimentation - that the IClassFactory2::CreateInstanceLic interface can be used to acquire a pointer to the IMBAMServiceController interface. Using this interface, we can gain access to the COM object classes exposed by Malwarebytes, i.e. the RTPController class, the LicenseController class, etc. So just to summarise this section, here is what the flow looks like:

1. Get a license string with CallNamedPipe("NeedAKey"),
2. Get an IClassFactory interface with CoGetClassObject(CLSID_MBAMServiceControllerClass)
3. Get an IClassFactory2 interface with IClassFactory::QueryInterface(IID_IClassFactory2),
4. Get a BSTR for the license string with SysAllocStringLen("LicenseKey"), 
5. Get an IMBAMServiceController interface with IClassFactory2::CreateInstanceLic("BSTR_LicenseString"),
6. Get the desired MBAM COM class's interface with the IMBAMServiceController interface.

Bypassing Security Checks

Of course it wouldn’t be so easy. Malwarebytes’ service implements some verification on the process that requests a license string on ConnectNamedPipe:

Verification

We can see it in log files too:

To use my time effectively, I opted to try a few methods to try to bypass the verification checks before digging into the assembly. I’ve seen these problems exist in other products so I had a few ideas. The immediate method that came into my head was to do process hollowing on mbam.exe. However, I don’t believe I can get that to work on the 64-bit architecture since I had never gotten it to work before. Perhaps it could work in the case of 32-bit? The next method was to append the signature using SigThief. Unfortunately, that did not work:

The last technique involves injecting shellcode into a mbam.exe process. Though this requires a fair bit of work to generate the shellcode, it was what ended up working. The shellcode can be generated through the compiler, thanks to Matt Graeber’s excellent post on Writing Optimized Windows Shellcode in C. Once the binary is compiled, simply extract the code from the .text section and copy it into another project that performs basic shellcode injection into a target process. Personally, I just used the classic CreateRemoteThread method.

There are also two other security measures that I have not mentioned yet. The first is the User access option which, when set, requires a password to modify any selected settings. The second is a UAC prompt for when a non-administrative user tries to change critical settings such as self-protection or real-time protection. As I’ve discovered, directly interacting with the settings through the COM classes entirely bypasses these two security components.

Demonstration


Conclusion

This post shows yet another example of attacking security products via their communication channels. Although there were layers of protection for preventing unauthorised access, the trust granted in the verification procedure was subverted using trivial impersonation that has impacted other products in the past and present. Perhaps the self-protection was insufficient and needs to extend to all of the Malwarebytes processes. This could stop the shellcode injection and therefore, this attack vector.

As always, the PoC code (currently withheld) can be found on my Antimalware-Research GitHub.

Thanks for reading and I hope you learned something!

– dtm

15 Likes