Bypass Technique Description

Microsoft.Workflow.Compiler.exe, a utility included by default in the .NET framework, permits the execution of arbitrary, unsigned code by supplying a serialized workflow in the form of a XOML workflow file (don’t worry. I had no clue what that was either) and an XML file consisting of serialized compiler arguments. This bypass is similar in its mechanics to Casey Smith’s msbuild.exe bypass.

Microsoft.Workflow.Compiler.exe requires two command-line arguments. The first argument must be the path to an XML file consisting of a serialized CompilerInput object. The second argument expected is a file path to which the utility writes serialized compilation results.

The root of the execution vector is that Microsoft.Workflow.Compiler.exe calls Assembly.Load(byte[]) (which is not code integrity aware) on an attacker-supplied .NET assembly. Loading an assembly will not achieve code execution by itself, though. When C# (or VB.Net) code is supplied via a XOML file, a code path is reached where a class constructor is called for the loaded assembly. The only constraint is that to achieve code execution, the class constructor must be derived from the System.Workflow.ComponentModel.Activity class.

This technique bypasses code integrity enforcement in Windows Defender Application Control (including Windows 10S), AppLocker, and likely any other app whitelisting product. These days though, I tend to care less about the fact that something bypasses application whitelisting and instead focus on the fact that arbitrary, unsigned code execution can be achieved through a signed, high-reputation, in-box binary. Bypassing application whitelisting (w/ DLL enforcement) just happens to be the bar I tend to set for myself when researching new post-exploitation tradecraft.

The following video demonstrates the bypass on a fully-patched Windows 10S system. The purpose of the video is to show that code integrity enforcement is bypassed — not that of demonstrating an end-to-end remote delivery vector on 10S: