Will the real #GrimResource please stand up? – Abusing the MSC file format

In this blog post we describe how the MSC file format can be leveraged to execute arbitrary code via MMC (Microsoft Management Console) for initial access or lateral movement purposes. A sample payload that implements this technique was publicly shared recently. This sample was generated using our Outflank Security Tooling (OST) offering and hence we decided to publish additional details on this method and its discovery.

Context of this blog post

Recently, Elastic released details on a new initial access vector technique leveraging MSC files, which they dubbed “GrimResource”. These files can be used to execute code within MMC (Microsoft Management Console). This technique was researched and developed by Outflank as part of the Outflank Security Tooling (OST) toolkit. The analyzed sample was a payload generated using our In-Phase Builder, which is one of the tools in our OST offering that allows you to create script-based payloads for initial access.

As part of our OST toolkit we develop initial access payload formats for our customers. These payloads then get used in attack simulations (“red teaming”), and eventually it happens that some payloads get uploaded to VirusTotal (accidentally – for example, by a blue team that picked up a sample). Our clients are vetted and we ensure we comply with export control regulations while delivering these payloads. In this case, an initial access vector used for attack simulations was picked up and documented publicly, which could potentially extend its use beyond the vetted community.

Now that the cat is out of the bag, we wanted to clarify a few aspects why we sometimes release techniques and tools publicly or keep them internally, for vetted clients, to be used in attack simulations. Secondly, we will go into the technical details of how this vector was built, why it works and provide additional guidance on the great detection rules published by Elastic.

History of discovery

We started looking into MSC files about five years ago, which is long before North Korean actors started abusing this file format. We were triggered by the file format’s presence in the Outlook blocked attachment list.

While we quite quickly discovered a way to leverage MSC files for process execution, we did not find the file format of real interest compared to more prevalent techniques back then. Remember that this was the period in which macros and XLL files were much better options for initial access. This changed over the years when Microsoft Office files came under more scrutiny and when additional effort from our team on researching the MSC file format led to a novel way for abusing this file format for in-process shellcode loading (more on that later).

So who’s the real GrimResource? It’s a combination of the following of our researchers: Stan doing the intial research on the file format, Cedric developing the in-process shellcode loading technique. Kyle developing the actual loader and Max pulling it into our initial access framework so that we could deliver it to our OST clients.

As you may know, we publish quite some of our research on this blog and our GitHub page. We believe in sharing. We believe that a more knowledgeable and equipped red teaming community will increase the security posture of organisations and their resilience against real threat actors on the long run. However, some techniques are just too dangerous to disclose to the public. This is one of them. That’s why we decided to release our implementation of weaponizing MSC files (and several other initial access techniques) to vetted members of our OST community only. Below is a screenshot of what this looks like to our customers.

One of our OST customers used the MSC file format in one of their red teaming operations. The blue team picked up this curious file and uploaded it to VirusTotal, where it was spotted by the Elastic team and they blogged about their discovery. Later on FalconForce blogged and provided MDE detection rules as well. Now that you know who the real GrimResource is, we publish this blog post with some additional technical details. Our weaponization in OST remains exclusively available to vetted OST customers and will not be published.

MMC Background

First of all: MMC is the console. MSC is the file format understood by MMC. MMC allows administrators to create consoles, which can manage all sorts of settings on either the local computer or remote computers. Within the console they can add “snap-ins” that provide specific management functionality, such as user account management, system services, device drivers, etc. The custom configuration of these consoles and their snap-ins can then be saved to an XML representation on disk, which is the MSC format.

In the MMC GUI above, we have the scope pane, the results pane, and the actions pane. Interacting with MMC, for our purposes, requires knowledge of a few basic building blocks that we can interact with programmatically:

  • Document: The loaded MMC console, which includes both the scope pane and the result pane.
  • Scope Nodes: Items in the hierarchical tree view on the left side of the MMC. It defines the structure and navigation within the console. There are also result nodes, but they are not relevant to us right now.
  • View: The content pane or result pane associated with nodes, which can display detailed information and management options. The Active View is the pane that displays detailed information about the Active Scope Node.
+----------------------------------------------------+
|                   Application                      |
|                (MMC Framework)                     |
|                                                    |
|   +---------------------------------------------+  |
|   |                Document                     |  |
|   |            (Loaded Console)                 |  |
|   |                                             |  |
|   |  +-------------------+   +----------------+ |  |
|   |  |   Scope Node 1    |   |     View 1     | |  |
|   |  |   (Tree Item)     |   | (Content Pane) | |  |
|   |  +-------------------+   +----------------+ |  |
|   |  |   Scope Node 2    |   |     View 2     | |  |
|   |  |   (Tree Item)     |   | (Content Pane) | |  |
|   |  +-------------------+   +----------------+ |  |
|   |  |   Scope Node 3    |   |     View 3     | |  |
|   |  |   (Tree Item)     |   | (Content Pane) | |  |
|   |  +-------------------+   +----------------+ |  |
|   +---------------------------------------------+  |
+----------------------------------------------------+

The MMC format offers a semi-known technique for executing commands via the ExecuteShellCommand method, which can be invoked from a View object. The View object serves as the external object when an MMC snap-in hosts Microsoft Internet Explorer browser components. This means that from an HTML page shown in MMC, you can execute commands by embedding a script tag like <script>external.ExecuteShellCommand(....)</script>. This was indepedently discovered by my colleagues Stan & Pieter many years ago, and also implemented in the UACME project’s Kamikaze.msc as a UAC bypass. The downside to this approach is that a subprocess will be launched.

In a Red Team operation some time ago we faced an environment with many security restrictions on the endpoints. They had AppLocker rules to block anything that wasn’t whitelisted, PowerShell with constrained language mode enabled, about 20 WDEG restrictions on applications, ASR rules deployed, … the works. However, we noticed MMC was allowed to run, so we decided to once more revisit the format and see if we could find others ways of executing code that wouldn’t require launching subprocesses.

Code execution within MMC

Spoiler alert if you hadn’t read Elastic’s blog post on our MSC payload: we found a way to stay within process and load shellcode! 🙂 With the background out of the way, let’s see how the MSC sample is actually able to execute code.

This technique is based off a few “happy accidents” that can be combined into code execution. On a high level, this is how the magic happens:

  • The “ActiveX Control” snap-in allows us to load ActiveX COM objects.
    • Also ActiveX controls that aren’t directly listed in the GUI.
  • The “Link to Web Address” snap-in allows us to load HTML documents.
    • We can get a reference to the control object in the active view. We use the browser object to load some JavaScript code that gets a reference to our COM object and call actions on it.

Let’s have a deeper look at these snap-ins, starting with the “Link to Web Address” snap-in.

The “Link to Web Address” snap-in

This snap-in pretty much does what you’d expect it to do: display a web address. Except it will load it in a prehistoric Internet Explorer browser object that is slightly reminiscent of the Geocities era. You can also embed JScript/VBScript in your HTML page and show Hello World message boxes.

Despite looking prehistoric, this browser component still has security controls in place and has received security patches over the years. Once you try to do anything slightly more spicy – like attempting to instantiate a WScript.Shell object, you are likely to run into pesky ActiveX security warnings. This depends also on Internet Explorer security settings, but is beyond the scope of this article.

So we have pretty straightforward way to execute JScript/VBScript code, but we are still sandboxed. As mentioned, via the browser object we also have access to the external object. Since this object is an instantiation of a View in the context of a browser object, we can call the methods of this object or retrieve properties. This means we can interact with other elements of the MMC console, and is a key element in getting this specific technique to work.

In the publicly shared MSC sample, you could see the following JavaScript code, which does exactly this. Via the external object, a reference is obtained to the Document. Then the code traverses the scope namespace to get references to nodes related to the loaded snap-ins.

var scopeNamespace = external.Document.ScopeNamespace;
var rootNode = scopeNamespace.GetRoot()
var mainNode = scopeNamespace.GetChild(rootNode)
var docNode = scopeNamespace.GetNext(mainNode)

You can see that through these exposed objects, we might get access to additional properties and methods that are outside of the standard browser sandbox. This is all we need to know about the “Link to Web Address” snap-in for now.

The “ActiveX Control” snap-in

The other interesting snap-in in MMC that is used by our MSC file is the “ActiveX Control” snap-in. When inserting the snap-in, we can select from a list of predefined controls in the GUI interface.

When saving the console to file, and open the created MSC file in a text editor, we can see that the ActiveX control we’d just added via the GUI is stored in the Strings table in the MSC file’s XML. Referenced by its CLSID.

Besides the list of controls selectable in the GUI, it turns out you can replace the CLSID with an arbitrary other ActiveX object’s CLSID. This means we can instantiate any ActiveX COM object we would like through this control, a very useful primitive.

Combining the pieces

Let’s start fitting the pieces together. The “Link to Web Address” snap-in’s browser object’s external interface allows us to get a reference to the ActiveX object loaded as a snap-in. external.Document.ActiveView.ControlObject gets us a reference to the object that is currently in the active view. We can use this to get a reference to the ActiveX object that was loaded by the ActiveX snap-in, and then call methods on that object.

While the “ActiveX Control” snap-in’s “Windows Mail Mime Editor” wasn’t hugely useful in triggering code execution, we instead opted to make use of a well-known trick that leverages MSXML (Microsoft.XMLDOM / {2933BF90-7B36-11D2-B20E-00C04F983E60}), which allows XSL transformations using JScript. This is the CLSID you can view in the public sample, as referenced in the Strings table.

    <String ID="23" Refs="2">...</String>
    <String ID="24" Refs="1">{2933BF90-7B36-11D2-B20E-00C04F983E60}</String>
    <String ID="38" Refs="2">Main</String>
    <String ID="39" Refs="1">...</String>

Because we are now referencing the MSXML object through the “ActiveX Control” snap-in, we are not bound to the same security restrictions as we are faced with within the browser object. Hence, no security warning is shown while executing more useful/harmful JScript code from this context.

To summarize:

  1. We load a useful ActiveX object into the “ActiveX Control” snap-in, e.g. MSXML.
  2. We load an HTML file into the “Link to Web Address” snap-in.
  3. From the HTML file, we interact using JavaScript with the loaded ActiveX object. Via MSXML methods we can trigger the XSL transformation to execute JScript code.
  4. From the JScript code we can now call system functions, or e.g. execute .NET code via DotNetToJScript.

This technique allows us to execute code within MMC via an MSC file while staying in-process. Yes, there are other ways to potentially execute code within MMC, but let’s keep those for another time 😺. (Yes, this emoji is a hint.)

MSC is fun

Honestly, MSC is probably one of the most fun file formats we ever played around with. Besides there being many gadgets to play with, there are some tidbits that make the whole format that much more interesting:

  • Custom icons: You can set custom icons for the MSC file, which are stored within the XML. The icon is visible in file explorer windows, but only after MOTW is accepted.
  • Hidden window: You can hide the MMC window by specifying SW_HIDE instead of SW_SHOW in the XML.
  • Dark mode: just kidding, but I wouldn’t be surprised.

About MOTW: the MSC file format does not magically bypass MOTW. You still get a warning dialog when double clicking an MSC file downloaded from the Internet.

Detection

For detection guidance, refer to:

Elastic’s detection guidance also includes a short analysis on the technique. A few notes on this:

  • The MSXML ‘transformNode’ call did not allow us to bypass ActiveX security. (At least not in our experience.)
  • The HTML page that we’re loading in the snap-in can be a file path or hosted online. Directly referring to a javascript: URI that executes code via the ActiveX object unfortunately does not work. As an alternative, we used a years old arbitrary redirect vulnerability built into apds.dll to redirect towards a JavaScript URI. The redirect in apds.dll is a fun gadget, and while useful as a way of invoking the JavaScript stage that triggers the code execution, it is not the key to this technique. You can just as well host the entire payload in a separate HTML file on disk, on an SMB share, on a website, anything really that the browser object understands.
  • We are still wondering why this was named GrimResource, but my colleague Max Grim approves!

Outflank Security Tooling

This initial access method has been part of our OST offering for some time now. Our toolkit includes many other initial access vectors, a C2 framework and dozens of tools for post exploitation and lateral movement in your red teaming operations. Moreover, the offering includes training sessions and a Slack community with all other OST users. If you’re interested in becoming a vetted member, make sure to sign up for one of our demo sessions or request a quote.