Locating a Target
To begin, let’s discuss the com- ponents of an AppLocker bypass.
Our ultimate goal is to execute arbitrary C# code via
a whitelisted application, which means our target application
must either accept a pre-compiled executable as an
argument and load it into memory or compile it itself.
In addition, the target application
must obviously execute our code.
Either way, the whitelisted application must load unsigned
managed code into memory.
This is typically done through APIs like Load,
LoadFile or LoadFrom.
The first step in this process is therefore to locate native
compiled managed code that performs these actions.
While it may seem logical to simply scan each assembly for
one of these loading methods, the compilation and loading
processes are typically performed by nested
method calls inside core DLLs.
Still, we could scan a compiled assembly for references to
either of the previously mentioned methods through the
dnlib external library or with the LoadMethodScanner developed
by security researcher Matt Graeber.
Although this approach automates the search process & scales well
developing the test harness requires significant preparation
Alternatively, we could reverse engineer assemblies which reside
in whitelisted locations in search of the code segments
that either load precompiled managed code or use source code
which is compiled as part of the processing.
Once identified, these code segments must execute the code
we provide after it is loaded into memory.
In the following sections, we’ll leverage this second approach,
focussing on the System. Workflow.ComponentModel.dll
assembly which is vulnerable to a relatively new
AppLocker bypass.
This assembly is located in a Windows sub directory which is
whitelisted by AppLocker’s default path rules.
Additionally the assembly is signed by Microsoft,
so it is whitelisted through a default publisher rule.
Let’s reverse engineer the assembly, locate the specific
logic we will use to bypass AppLocker
and finally, weaponize it.