def Connect6Download(self, url): ''' Downloads raw source of Connects6 page. ''' NameList = [] try: if url.startswith('http') or url.startswith('https'): r = requests.get(url, headers=self.UserAgent) else: url = 'http://' + str(url) r = requests.get(url, headers=self.UserAgent) except Exception as e: error = " [!] Major issue with Downloading Connect6 source:" + str(e) print helpers.color(error, warning=True) try: if r: RawHtml = r.content soup = BeautifulSoup(RawHtml) try: for utag in soup.findAll("ul", { "class" : "directoryList" }): for litag in utag.findAll('li'): NameList.append(litag.text) except: pass return NameList #for a in soup.findAll('a', href=True): except Exception as e: print e
def Connect6AutoUrl(self): # Using startpage to attempt to get the URL # https://www.google.com/search?q=site:connect6.com+domain.com try: # This returns a JSON object urllist = [] url = "https://www.google.com/search?q=site:connect6.com+%22" + self.domain + '%22' r = requests.get(url, headers=self.UserAgent) except Exception as e: error = "[!] Major issue with Google Search: for Connect6 URL" + str(e) print helpers.color(error, warning=True) try: RawHtml = r.content soup = BeautifulSoup(RawHtml) for a in soup.findAll('a', href=True): try: l = urlparse.parse_qs(urlparse.urlparse(a['href']).query)['q'] if 'site:connect6.com' not in l[0]: l = l[0].split(":") urllist.append(l[2]) except: pass return urllist except Exception as e: print e
def display_agents(agents): """ Take a dictionary of agents and build the display for the main menu. """ if len(agents) > 0: print '' print helpers.color("[*] Active agents:\n") print " Name Lang Internal IP Machine Name Username Process Delay Last Seen" print " --------- ---- ----------- ------------ --------- ------- ----- --------------------" for agent in agents: if str(agent['high_integrity']) == '1': # add a * to the username if it's high integrity agent['username'] = '******' + str(agent['username']) if not agent['language'] or agent['language'] == '': agent['language'] = 'X' elif agent['language'].lower() == 'powershell': agent['language'] = 'ps' elif agent['language'].lower() == 'python': agent['language'] = 'py' else: agent['language'] = 'X' print " %.16s%.6s%.16s%.16s%.20s%.20s%.9s%.20s" % ('{0: <16}'.format(agent['name']), '{0: <6}'.format(agent['language']), '{0: <16}'.format(agent['internal_ip']), '{0: <16}'.format(agent['hostname']), '{0: <20}'.format(agent['username']), '{0: <20}'.format(str(agent['process_name']) + "/" + str(agent['process_id'])), '{0: <9}'.format(str(agent['delay']) + "/" +str(agent['jitter'])), agent['lastseen_time']) print '' else: print helpers.color('[!] No agents currently registered')
def shutdown_listener(self, listenerId): """ Shut down the server associated with a listenerId/name, but DON'T delete it from the database. If the listener is a pivot, task the associated agent to kill the redirector. """ try: # get the listener information [ID,name,host,port,cert_path,staging_key,default_delay,default_jitter,default_profile,kill_date,working_hours,listener_type,redirect_target] = self.get_listener(listenerId) listenerId = int(ID) if listenerId in self.listeners: # can't shut down hop, foreign, or meter listeners if listener_type == "hop" or listener_type == "foreign" or listener_type == "meter": pass # if this listener is a pivot, task the associated agent to shut it down elif listener_type == "pivot": print helpers.color("[*] Tasking pivot listener to shut down on agent " + name) killCmd = "netsh interface portproxy reset" self.agents.add_agent_task(name, "TASK_SHELL", killCmd) else: # otherwise get the server object associated with this listener and shut it down self.listeners[listenerId].shutdown() # remove the listener object from the internal cache del self.listeners[listenerId] except Exception as e: dispatcher.send("[!] Error shutting down listener " + str(listenerId), sender="Listeners")
def module_info(self, module, showInfo=True, showTitle=True): if showTitle == True: messages.title() if showInfo: # extract the payload class name from the instantiated object, then chop off the load folder prefix #modulename = "/".join(str(str(module.__class__)[str(module.__class__).find("ClassName"):]).split(".")[0].split("/")[1:]) print helpers.color(" Module information:\n", blue=True) print "\tName:\t\t" + module.name print "\tLanguage:\t" + module.language # format this all nice-like print helpers.formatLong("Description:", module.description) # if required options were specified, output them if hasattr(module, 'required_options'): print helpers.color("\n Required Options:\n", blue=True) 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()): print " %s\t%s\t%s" % ('{0: <16}'.format(key), '{0: <8}'.format(module.required_options[key][0]), module.required_options[key][1]) print ""
def Connect6AutoUrl(self): # Using startpage to attempt to get the URL # https://www.google.com/search?q=site:connect6.com+domain.com try: # This returns a JSON object urllist = [] url = "https://www.google.com/search?q=site:connect6.com+%22" + self.domain + "%22" r = requests.get(url, headers=self.UserAgent) except Exception as e: error = "[!] Major issue with Google Search: for Connect6 URL" + str(e) print helpers.color(error, warning=True) try: RawHtml = r.content soup = BeautifulSoup(RawHtml) for a in soup.findAll("a", href=True): try: l = urlparse.parse_qs(urlparse.urlparse(a["href"]).query)["q"] if "site:connect6.com" not in l[0]: l = l[0].split(":") urllist.append(l[2]) except: pass return urllist except Exception as e: print e
def generate_dll(self, poshCode, arch): """ Generate a PowerPick Reflective DLL to inject with base64-encoded stager code. """ #read in original DLL and patch the bytes based on arch if arch.lower() == "x86": origPath = self.installPath + "/data/misc/ReflectivePick_x86_orig.dll" else: origPath = self.installPath + "/data/misc/ReflectivePick_x64_orig.dll" if os.path.isfile(origPath): dllRaw = '' with open(origPath, 'rb') as f: dllRaw = f.read() replacementCode = helpers.decode_base64(poshCode) # patch the dll with the new PowerShell code searchString = (("Invoke-Replace").encode("UTF-16"))[2:] index = dllRaw.find(searchString) dllPatched = dllRaw[:index]+replacementCode+dllRaw[(index+len(replacementCode)):] return dllPatched else: print helpers.color("[!] Original .dll for arch "+arch+" does not exist!")
def kill_listener(self, listenerName): """ Shut down the server associated with a listenerName and delete the listener from the database. To kill all listeners, use listenerName == 'all' """ if listenerName.lower() == 'all': listenerNames = self.activeListeners.keys() else: listenerNames = [listenerName] for listenerName in listenerNames: if listenerName not in self.activeListeners: print helpers.color("[!] Listener '%s' not active!" % (listenerName)) return False # shut down the listener and remove it from the cache self.shutdown_listener(listenerName) # remove the listener from the database self.conn.row_factory = None cur = self.conn.cursor() cur.execute("DELETE FROM listeners WHERE name=?", [listenerName]) cur.close()
def generate_shellcode(self, poshCode, arch): """ Generate shellcode using monogas's sRDI python module and the PowerPick reflective DLL """ if arch.lower() == 'x86': origPath = "{}/data/misc/x86_slim.dll".format( self.mainMenu.installPath) else: origPath = "{}/data/misc/x64_slim.dll".format( self.mainMenu.installPath) if os.path.isfile(origPath): dllRaw = '' with open(origPath, 'rb') as f: dllRaw = f.read() replacementCode = helpers.decode_base64(poshCode) # patch the dll with the new PowerShell code searchString = (("Invoke-Replace").encode("UTF-16"))[2:] index = dllRaw.find(searchString) dllPatched = dllRaw[:index] + replacementCode + dllRaw[ (index + len(replacementCode)):] flags = 0 flags |= 0x1 sc = ConvertToShellcode(dllPatched) return sc else: print helpers.color( "[!] Original .dll for arch {} does not exist!".format(arch))
def generate_launcher(self, listenerName, language=None, encode=True, userAgent='default', proxy='default', proxyCreds='default', stagerRetries='0', safeChecks='true'): """ Abstracted functionality that invokes the generate_launcher() method for a given listener, if it exists. """ if not listenerName in self.mainMenu.listeners.activeListeners: print helpers.color("[!] Invalid listener: %s" % (listenerName)) return '' activeListener = self.mainMenu.listeners.activeListeners[listenerName] launcherCode = self.mainMenu.listeners.loadedListeners[ activeListener['moduleName']].generate_launcher( encode=encode, userAgent=userAgent, proxy=proxy, proxyCreds=proxyCreds, stagerRetries=stagerRetries, language=language, listenerName=listenerName, safeChecks=safeChecks) if launcherCode: return launcherCode
def EmailHunterDetect(self): ''' A function to use EmailHunter to use their JSON API to detect the email format. ''' try: # This returns a JSON object url = "https://emailhunter.co/trial/v1/search?offset=0&domain=" + \ self.domain + "&format=json" r = requests.get(url) except Exception as e: error = "[!] Major issue with EmailHunter Search:" + str(e) print helpers.color(error, warning=True) try: results = r.json() # pprint(results) # Check to make sure we got data back from the API if results['status'] == "success": if results['pattern']: pattern = results['pattern'] if pattern: return pattern else: if self.verbose: e = ' [!] No pattern dettected via EmailHunter API' print helpers.color(e, firewall=True) return False except: pass
def Connect6AutoUrl(self): # Using startpage to attempt to get the URL # https://www.google.com/search?q=site:connect6.com+domain.com try: # This returns a JSON object urllist = [] domain = self.domain.split('.') url = "https://www.google.com/search?q=site:connect6.com+%22" + domain[0] + '%22' r = requests.get(url, headers=self.UserAgent) except Exception as e: error = "[!] Major issue with Google Search: for Connect6 URL" + str(e) print helpers.color(error, warning=True) try: RawHtml = r.content soup = BeautifulSoup(RawHtml) for a in soup.findAll('a', href=True): try: l = urlparse.parse_qs(urlparse.urlparse(a['href']).query)['q'] if 'site:connect6.com' not in l[0]: l = l[0].split(":") urllist.append(l[2]) except: pass if urllist: y = 0 s = 0 for x in urllist: if "/c" in x: urllist.insert(s, urllist.pop(y)) s += 1 y += 1 return urllist except Exception as e: print e return urllist
def reload_module(self, moduleToReload): """ Reload a specific module from the install + "/lib/modules/*" path """ rootPath = self.installPath + "lib/modules/" pattern = "*.py" for root, dirs, files in os.walk(rootPath): for filename in fnmatch.filter(files, pattern): filePath = os.path.join(root, filename) # don't load up the template if filename == "template.py" or filename == "jobs-template.py": continue # extract just the module name from the full path moduleName = filePath.split("/lib/modules/")[-1][0:-3] # check to make sure we've found the specific module if moduleName.lower() == moduleToReload.lower(): # instantiate the module and save it to the internal cache try: self.modules[moduleName] = imp.load_source(moduleName, filePath).Module(self.mainMenu, []) except Exception as e: print helpers.color("[!] Error: Failed to reload module, not instantiate new module!") print helpers.color("[!] Module Error:" + str(e), color="yellow")
def load_modules(self, rootPath=""): """ Load modules from the install + "/lib/modules/*" path """ if rootPath == "": rootPath = self.installPath + "lib/modules/" pattern = "*.py" print helpers.color("[*] Loading modules from: %s" % (rootPath)) for root, dirs, files in os.walk(rootPath): for filename in fnmatch.filter(files, pattern): filePath = os.path.join(root, filename) # don't load up the template if filename == "template.py" or filename == "jobs-template.py": continue # extract just the module name from the full path moduleName = filePath.split(rootPath)[-1][0:-3] if rootPath != self.installPath + "lib/modules/": moduleName = "external/%s" % (moduleName) # instantiate the module and save it to the internal cache self.modules[moduleName] = imp.load_source(moduleName, filePath).Module(self.mainMenu, [])
def title(): """ Print the framework title, with version. """ if settings.TERMINAL_CLEAR != "false": os.system(settings.TERMINAL_CLEAR) print '=========================================================================' print ' %s | [Version]: %s' % (helpers.color( 'ByWaf', status=False, bold=True), version) print '=========================================================================' print ' [Web]: https://www.owasp.org/index.php/OWASP_Bywaf_Project ' print '=========================================================================\n' # if settings.OPERATING_SYSTEM != "Kali": # print helpers.color(' [!] WARNING: Official support for Kali Linux (x86) only at this time!', warning=True) # print helpers.color(' [!] WARNING: Continue at your own risk!\n', warning=True) # check to make sure the current OS is supported, # print a warning message if it's not and exit if settings.OPERATING_SYSTEM == "Windows" or settings.OPERATING_SYSTEM == "Unsupported": print helpers.color( ' [!] ERROR: Your operating system is not currently supported...\n', warning=True) print helpers.color( ' [!] ERROR: Request your distribution at the GitHub repository...\n', warning=True) sys.exit()
def display_listeners(listeners): """ Take a listeners list and display everything nicely. """ if len(listeners) > 0: print "" print helpers.color("[*] Active listeners:\n") print " ID Name Host Type Delay/Jitter KillDate Redirect Target" print " -- ---- ---- ------- ------------ -------- ---------------" for listener in listeners: [ID,name,host,port,cert_path,staging_key,default_delay,default_jitter,default_profile,kill_date,working_hours,listener_type,redirect_target,default_lost_limit] = listener if not host.startswith("http"): if cert_path and cert_path != "": host = "https://" + host else: host = "http://" + host host += ":" + str(port) print " %s%s%s%s%s%s%s" % ('{0: <6}'.format(ID), '{0: <18}'.format(name), '{0: <37}'.format(host), '{0: <10}'.format(listener_type), '{0: <15}'.format(str(default_delay)+"/"+str(default_jitter)), '{0: <12}'.format(kill_date), redirect_target) print "" else: print helpers.color("[!] No listeners currently active ")
def shutdown_listener(self, listenerId): """ Shut down the server associated with a listenerId/name, but DON'T delete it from the database. If the listener is a pivot, task the associated agent to kill the redirector. """ try: # get the listener information [ID,name,host,port,cert_path,staging_key,default_delay,default_jitter,default_profile,kill_date,working_hours,listener_type,redirect_target,default_lost_limit] = self.get_listener(listenerId) listenerId = int(ID) if listenerId in self.listeners: # can't shut down hop, foreign, or meter listeners if listener_type == "hop" or listener_type == "foreign" or listener_type == "meter": pass # if this listener is a pivot, task the associated agent to shut it down elif listener_type == "pivot": print helpers.color("[*] Tasking pivot listener to shut down on agent " + name) killCmd = "netsh interface portproxy reset" self.agents.add_agent_task(name, "TASK_SHELL", killCmd) else: # otherwise get the server object associated with this listener and shut it down self.listeners[listenerId].shutdown() # remove the listener object from the internal cache del self.listeners[listenerId] except Exception as e: dispatcher.send("[!] Error shutting down listener " + str(listenerId), sender="Listeners")
def load_modules(self, rootPath=''): """ Load modules from the install + "/lib/modules/*" path """ if rootPath == '': rootPath = self.installPath + 'lib/modules/' pattern = '*.py' print helpers.color("[*] Loading modules from: %s" % (rootPath)) for root, dirs, files in os.walk(rootPath): for filename in fnmatch.filter(files, pattern): filePath = os.path.join(root, filename) # don't load up the template if filename == "template.py" or filename == "jobs-template.py": continue # extract just the module name from the full path moduleName = filePath.split(rootPath)[-1][0:-3] if rootPath != self.installPath + 'lib/modules/': moduleName = "external/%s" % (moduleName) # instantiate the module and save it to the internal cache self.modules[moduleName] = imp.load_source( moduleName, filePath).Module(self.mainMenu, [])
def Connect6Download(self, url): """ Downloads raw source of Connects6 page. """ NameList = [] try: if url.startswith("http") or url.startswith("https"): r = requests.get(url, headers=self.UserAgent) else: url = "http://" + str(url) r = requests.get(url, headers=self.UserAgent) except Exception as e: error = " [!] Major issue with Downloading Connect6 source:" + str(e) print helpers.color(error, warning=True) try: if r: RawHtml = r.content soup = BeautifulSoup(RawHtml) try: for utag in soup.findAll("ul", {"class": "directoryList"}): for litag in utag.findAll("li"): NameList.append(litag.text) except: pass return NameList # for a in soup.findAll('a', href=True): except Exception as e: print e
def load_modules(self, rootPath=''): """ Load Empire modules from a specified path, default to installPath + "/lib/modules/*" """ if rootPath == '': rootPath = "%s/lib/modules/" % (self.mainMenu.installPath) pattern = '*.py' print helpers.color("[*] Loading modules from: %s" % (rootPath)) for root, dirs, files in os.walk(rootPath): for filename in fnmatch.filter(files, pattern): filePath = os.path.join(root, filename) # don't load up any of the templates if fnmatch.fnmatch(filename, '*template.py'): continue # extract just the module name from the full path moduleName = filePath.split(rootPath)[-1][0:-3] if rootPath != "%s/lib/modules/" % (self.mainMenu.installPath): moduleName = "external/%s" %(moduleName) # instantiate the module and save it to the internal cache self.modules[moduleName] = imp.load_source(moduleName, filePath).Module(self.mainMenu, [])
def title(): """ Print the framework title, with version. """ if settings.TERMINAL_CLEAR != "false": os.system(settings.TERMINAL_CLEAR) print '=========================================================================' print ' Veil-Evasion | [Version]: ' + version print '=========================================================================' print ' [Web]: https://www.veil-framework.com/ | [Twitter]: @VeilFramework' print '=========================================================================\n' # if settings.OPERATING_SYSTEM != "Kali": # print helpers.color(' [!] WARNING: Official support for Kali Linux (x86) only at this time!', warning=True) # print helpers.color(' [!] WARNING: Continue at your own risk!\n', warning=True) # check to make sure the current OS is supported, # print a warning message if it's not and exit if settings.OPERATING_SYSTEM == "Windows" or settings.OPERATING_SYSTEM == "Unsupported": print helpers.color( ' [!] ERROR: Your operating system is not currently supported...\n', warning=True) print helpers.color( ' [!] ERROR: Request your distribution at the GitHub repository...\n', warning=True) sys.exit()
def generate_shellcode(self, poshCode, arch): """ Generate shellcode using monogas's sRDI python module and the PowerPick reflective DLL """ if arch.lower() == 'x86': origPath = "{}/data/misc/x86_slim.dll".format(self.mainMenu.installPath) else: origPath = "{}/data/misc/x64_slim.dll".format(self.mainMenu.installPath) if os.path.isfile(origPath): dllRaw = '' with open(origPath, 'rb') as f: dllRaw = f.read() replacementCode = helpers.decode_base64(poshCode) # patch the dll with the new PowerShell code searchString = (("Invoke-Replace").encode("UTF-16"))[2:] index = dllRaw.find(searchString) dllPatched = dllRaw[:index]+replacementCode+dllRaw[(index+len(replacementCode)):] flags = 0 flags |= 0x1 sc = ConvertToShellcode(dllPatched) return sc else: print helpers.color("[!] Original .dll for arch {} does not exist!".format(arch))
def generate_dylib(self, launcherCode, arch, hijacker): """ Generates a dylib with an embedded python interpreter and runs launcher code when loaded into an application. """ import macholib.MachO MH_DYLIB = 6 if hijacker.lower() == 'true': if arch == 'x86': f = open( "%s/data/misc/hijackers/template.dylib" % (self.mainMenu.installPath), 'rb') else: f = open( "%s/data/misc/hijackers/template64.dylib" % (self.mainMenu.installPath), 'rb') else: if arch == 'x86': f = open( "%s/data/misc/templateLauncher.dylib" % (self.mainMenu.installPath), 'rb') else: f = open( "%s/data/misc/templateLauncher64.dylib" % (self.mainMenu.installPath), 'rb') macho = macholib.MachO.MachO(f.name) if int(macho.headers[0].header.filetype) != MH_DYLIB: print helpers.color( "[!] Dylib template is not the correct filetype") return "" cmds = macho.headers[0].commands for cmd in cmds: count = 0 if int(cmd[count].cmd) == macholib.MachO.LC_SEGMENT_64 or int( cmd[count].cmd) == macholib.MachO.LC_SEGMENT: count += 1 if cmd[count].segname.strip( '\x00') == '__TEXT' and cmd[count].nsects > 0: count += 1 for section in cmd[count]: if section.sectname.strip('\x00') == '__cstring': offset = int(section.offset) placeHolderSz = int(section.size) - 52 template = f.read() f.close() if placeHolderSz and offset: launcher = launcherCode + "\x00" * (placeHolderSz - len(launcherCode)) patchedDylib = template[:offset] + launcher + template[ (offset + len(launcher)):] return patchedDylib else: print helpers.color("[!] Unable to patch dylib")
def shutdown_listener(self, listenerName): """ Shut down the server associated with a listenerName, but DON'T delete it from the database. """ if listenerName.lower() == 'all': listenerNames = self.activeListeners.keys() else: listenerNames = [listenerName] for listenerName in listenerNames: if listenerName not in self.activeListeners: print helpers.color("[!] Listener '%s' doesn't exist!" % (listenerName)) return False # retrieve the listener module for this listener name activeListenerModuleName = self.activeListeners[listenerName][ 'moduleName'] activeListenerModule = self.loadedListeners[ activeListenerModuleName] if activeListenerModuleName == 'redirector': print helpers.color( "[!] skipping redirector listener %s. Start/Stop actions can only initiated by the user." % (listenerName)) continue # signal the listener module to shut down the thread for this particular listener instance activeListenerModule.shutdown(name=listenerName) # remove the listener object from the internal cache del self.activeListeners[listenerName]
def validate_listener_options(self): """ Validate all currently set listener options. """ # make sure all options are set for option, values in self.options.iteritems(): if values['Required'] and (values['Value'] == ''): return False # make sure the name isn't already taken if self.is_listener_valid(self.options['Name']['Value']): for x in xrange(1, 20): self.options['Name'][ 'Value'] = self.options['Name']['Value'] + str(x) if not self.is_listener_valid(self.options['Name']['Value']): break if self.is_listener_valid(self.options['Name']['Value']): print helpers.color("[!] Listener name already used.") return False # if this is a pivot or hop listener, make sure we have a redirect listener target if self.options['Type']['Value'] == "pivot" or self.options['Type'][ 'Value'] == "hop": if self.options['RedirectTarget']['Value'] == '': return False return True
def delete_listener(self, listener_name): """ Delete listener(s) from database. """ try: old_factory = self.conn.row_factory self.conn.row_factory = helpers.dict_factory cur = self.conn.cursor() cur.execute("SELECT name FROM listeners") db_names = map(lambda x: x['name'], cur.fetchall()) if listener_name.lower() == "all": names = db_names else: names = [listener_name] for name in names: if not name in db_names: print helpers.color("[!] Listener '%s' does not exist!" % name) return False if name in self.activeListeners.keys(): self.shutdown_listener(name) cur.execute("DELETE FROM listeners WHERE name=?", [name]) except Exception, e: print helpers.color("[!] Error deleting listener '%s'" % name)
def rename_agent(self, oldname, newname): """ Update the agent's last seen timestamp. """ # rename the logging/downloads folder oldPath = self.installPath + "/downloads/"+str(oldname)+"/" newPath = self.installPath + "/downloads/"+str(newname)+"/" # check if the folder is already used if os.path.exists(newPath): print helpers.color("[!] Name already used by current or past agent.") return False else: # signal in the log that we've renamed the agent self.save_agent_log(oldname, "[*] Agent renamed from " + str(oldname) + " to " + str(newname)) # move the old folder path to the new one if os.path.exists(oldPath): os.rename(oldPath, newPath) # rename the agent in the database cur = self.conn.cursor() cur.execute("UPDATE agents SET name=? WHERE name=?", [newname, oldname]) cur.close() # report the agent rename in the reporting database cur = self.conn.cursor() cur.execute("INSERT INTO reporting (name,event_type,message,time_stamp) VALUES (?,?,?,?)", (oldname,"rename",newname,helpers.get_datetime())) cur.close() return True
def update_agent_profile(self, sessionID, profile): """ Update the agent's "uri1,uri2,...|useragent|headers" profile. """ # see if we were passed a name instead of an ID nameid = self.get_agent_id(sessionID) if nameid : sessionID = nameid parts = profile.strip("\"").split("|") cur = self.conn.cursor() # get the existing URIs from the agent and save them to # the old_uris field, so we can ensure that it can check in # to get the new URI tasking... bootstrapping problem :) cur.execute("SELECT uris FROM agents WHERE session_id=?", [sessionID]) oldURIs = cur.fetchone()[0] if sessionID not in self.agents: print helpers.color("[!] Agent " + agentName + " not active.") else: # update the URIs in the cache self.agents[sessionID][-1] = oldURIs # new URIs self.agents[sessionID][-2] = parts[0] # if no additional headers if len(parts) == 2: cur.execute("UPDATE agents SET uris=?, user_agent=?, old_uris=? WHERE session_id=?", [parts[0], parts[1], oldURIs, sessionID]) else: # if additional headers cur.execute("UPDATE agents SET uris=?, user_agent=?, headers=?, old_uris=? WHERE session_id=?", [parts[0], parts[1], parts[2], oldURIs, sessionID]) cur.close()
def validate_listener_options(self): """ Validate all currently set listener options. """ # make sure all options are set for option,values in self.options.iteritems(): if values['Required'] and (values['Value'] == ''): return False # make sure the name isn't already taken if self.is_listener_valid(self.options['Name']['Value']): for x in xrange(1,20): self.options['Name']['Value'] = self.options['Name']['Value'] + str(x) if not self.is_listener_valid(self.options['Name']['Value']): break if self.is_listener_valid(self.options['Name']['Value']): print helpers.color("[!] Listener name already used.") return False # if this is a pivot or hop listener, make sure we have a redirect listener target if self.options['Type']['Value'] == "pivot" or self.options['Type']['Value'] == "hop": if self.options['RedirectTarget']['Value'] == '': return False return True
def generate_dll(self, poshCode, arch): """ Generate a PowerPick Reflective DLL to inject with base64-encoded stager code. """ #read in original DLL and patch the bytes based on arch if arch.lower() == 'x86': origPath = "%s/data/misc/ReflectivePick_x86_orig.dll" % (self.mainMenu.installPath) else: origPath = "%s/data/misc/ReflectivePick_x64_orig.dll" % (self.mainMenu.installPath) if os.path.isfile(origPath): dllRaw = '' with open(origPath, 'rb') as f: dllRaw = f.read() replacementCode = helpers.decode_base64(poshCode) # patch the dll with the new PowerShell code searchString = (("Invoke-Replace").encode("UTF-16"))[2:] index = dllRaw.find(searchString) dllPatched = dllRaw[:index]+replacementCode+dllRaw[(index+len(replacementCode)):] return dllPatched else: print helpers.color("[!] Original .dll for arch %s does not exist!" % (arch))
def load_modules(self, rootPath=''): """ Load Invader modules from a specified path, default to installPath + "/lib/modules/*" """ if rootPath == '': rootPath = "%s/lib/modules/" % (self.mainMenu.installPath) pattern = '*.py' print helpers.color("[*] Loading modules from: %s" % (rootPath)) for root, dirs, files in os.walk(rootPath): for filename in fnmatch.filter(files, pattern): filePath = os.path.join(root, filename) # don't load up any of the templates if fnmatch.fnmatch(filename, '*template.py'): continue # extract just the module name from the full path moduleName = filePath.split(rootPath)[-1][0:-3] if rootPath != "%s/lib/modules/" % (self.mainMenu.installPath): moduleName = "external/%s" % (moduleName) # instantiate the module and save it to the internal cache self.modules[moduleName] = imp.load_source( moduleName, filePath).Module(self.mainMenu, [])
def VerifyEmail(self, email, email2): ''' Takes one email and checks if it is valid. ''' # Idea from: # https://www.scottbrady91.com/Email-Verification/Python-Email-Verification-Script hostname = socket.gethostname() socket.setdefaulttimeout(10) server = smtplib.SMTP(timeout=10) server.set_debuglevel(0) try: if self.verbose: e = " [*] Checking for valid email: " + str(email) print helpers.color(e, firewall=True) server.connect(self.mxhost['Host']) server.helo(hostname) server.mail('*****@*****.**') code, message = server.rcpt(str(email)) server.quit() except Exception as e: print e if code == 250: return True else: return False
def module_info(self, module, showInfo=True, showTitle=True): if showTitle == True: messages.title() if showInfo: # extract the payload class name from the instantiated object, then chop off the load folder prefix #modulename = "/".join(str(str(module.__class__)[str(module.__class__).find("ClassName"):]).split(".")[0].split("/")[1:]) print helpers.color(" Module information:\n", blue=True) print "\tName:\t\t" + module.name print "\tLanguage:\t" + module.language # format this all nice-like print helpers.formatLong("Description:", module.description) # if required options were specified, output them if hasattr(module, 'required_options'): print helpers.color("\n Required Options:\n", blue=True) 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()): print " %s\t%s\t%s" % ('{0: <16}'.format(key), '{0: <8}'.format( module.required_options[key][0]), module.required_options[key][1]) print ""
def shutdown_listener(self, listenerName): """ Shut down the server associated with a listenerName, but DON'T delete it from the database. """ if listenerName.lower() == 'all': listenerNames = self.activeListeners.keys() else: listenerNames = [listenerName] for listenerName in listenerNames: if listenerName not in self.activeListeners: print helpers.color("[!] Listener '%s' doesn't exist!" % (listenerName)) return False # retrieve the listener module for this listener name activeListenerModuleName = self.activeListeners[listenerName]['moduleName'] activeListenerModule = self.loadedListeners[activeListenerModuleName] # signal the listener module to shut down the thread for this particular listener instance activeListenerModule.shutdown(name=listenerName) # remove the listener object from the internal cache del self.activeListeners[listenerName]
def reload_module(self, moduleToReload): """ Reload a specific module from the install + "/lib/modules/*" path """ rootPath = self.installPath + 'lib/modules/' pattern = '*.py' for root, dirs, files in os.walk(rootPath): for filename in fnmatch.filter(files, pattern): filePath = os.path.join(root, filename) # don't load up the template if filename == "template.py" or filename == "jobs-template.py": continue # extract just the module name from the full path moduleName = filePath.split("/lib/modules/")[-1][0:-3] # check to make sure we've found the specific module if moduleName.lower() == moduleToReload.lower(): # instantiate the module and save it to the internal cache try: self.modules[moduleName] = imp.load_source( moduleName, filePath).Module(self.mainMenu, []) except Exception as e: print helpers.color( "[!] Error: Failed to reload module, not instantiate new module!" ) print helpers.color("[!] Module Error:" + str(e), color="yellow")
def agent_print(agents): """ Take an agent dictionary and display everything nicely. """ print "" print helpers.color("[*] Active agents:\n") print " Name Internal IP Machine Name Username Process Delay Last Seen" print " --------- ----------- ------------ --------- ------- ----- --------------------" for agent in agents: [ ID, sessionID, listener, name, delay, jitter, external_ip, internal_ip, username, high_integrity, process_name, process_id, hostname, os_details, session_key, checkin_time, lastseen_time, parent, children, servers, uris, old_uris, user_agent, headers, functions, kill_date, working_hours, ps_version, lost_limit, taskings, results ] = agent if str(high_integrity) == "1": # add a * to the username if it's high integrity username = "******" + username print " %.19s%.16s%.16s%.20s%.20s%.9s%.20s" % ( '{0: <19}'.format(name), '{0: <16}'.format(internal_ip), '{0: <16}'.format(hostname), '{0: <20}'.format(username), '{0: <20}'.format(str(process_name) + "/" + str(process_id)), '{0: <9}'.format(str(delay) + "/" + str(jitter)), lastseen_time) print ""
def display_agent(agent): """ Display an agent all nice-like. Takes in the tuple of the raw agent database results. """ # extract out database fields. keys = [ "ID", "sessionID", "listener", "name", "delay", "jitter", "external_ip", "internal_ip", "username", "high_integrity", "process_name", "process_id", "hostname", "os_details", "session_key", "checkin_time", "lastseen_time", "parent", "children", "servers", "uris", "old_uris", "user_agent", "headers", "functions", "kill_date", "working_hours", "ps_version", "lost_limit", "takings", "results" ] print helpers.color("\n[*] Agent info:\n") # turn the agent into a keyed dictionary agentInfo = dict(zip(keys, agent)) for key in agentInfo: if key != "functions" and key != "takings" and key != "results": print "\t%s\t%s" % (helpers.color('{0: <16}'.format(key), "blue"), wrap_string(agentInfo[key], width=70)) print ""
def add_agent_task(self, sessionID, taskName, task=""): """ Add a task to the specified agent's buffer. """ agentName = sessionID # see if we were passed a name instead of an ID nameid = self.get_agent_id(sessionID) if nameid : sessionID = nameid if sessionID not in self.agents: print helpers.color("[!] Agent " + str(agentName) + " not active.") else: if sessionID: dispatcher.send("[*] Tasked " + str(sessionID) + " to run " + str(taskName), sender="Agents") self.agents[sessionID][1].append([taskName, task]) # write out the last tasked script to "LastTask.ps1" if in debug mode if self.args and self.args.debug: f = open(self.installPath + '/LastTask.ps1', 'w') f.write(task) f.close() # report the agent tasking in the reporting database cur = self.conn.cursor() cur.execute("INSERT INTO reporting (name,event_type,message,time_stamp) VALUES (?,?,?,?)", (sessionID,"task",taskName + " - " + task[0:30],helpers.get_datetime())) cur.close()
def endmsg(): """ Print the exit message. """ print " [*] Your payload files have been generated, don't get caught!" print helpers.color( " [!] And don't submit samples to any online scanner! ;)\n", yellow=True)
def display_staleagents(agents): """ Take a stale agent dictionary and display everything nicely. """ if len(agents) > 0: agent_print(agents) else: print helpers.color("[!] No stale agents currently registered ")
def GoogleCaptchaDetection(self, RawHtml, Url): soup = BeautifulSoup(RawHtml, "lxml") if "Our systems have detected unusual traffic" in soup.text: p = " [!] Google Captcha was detected! (For best results stop/resolve/restart)" print helpers.color(p, warning=True) return True else: return False
def GoogleCaptchaDetection(self, RawHtml): soup = BeautifulSoup(RawHtml, "lxml") if "Our systems have detected unusual traffic" in soup.text: p = " [!] Google Captcha was detected! (For best results stop/resolve/restart)" self.logger.warning("Google Captcha was detected!") print helpers.color(p, warning=True) return True else: return False
def item_check(ns): if not host_regex.match(ns): raise ValueError( '{0} does not look like a valid host name'.format( item['ns'])) if item.get('disable', None): return False # Extend lifetime if we are running a test extra_params = dict() if "pytest" in sys.modules: extra_params['lifetime'] = 15 try: try: addr = dns.resolver.resolve(ns, 'a', search=True, **extra_params) # Outputing for every resolved entry makes it harder to find the actual error, # due to being swamped with data in the error output. # log('debug', '{0} resolved to {1}'.format( # ns, ','.join(x.to_text() for x in addr))) except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer): if not item.get('pass', None): soa = dns.resolver.resolve(ns, 'soa', search=True, **extra_params) log( 'debug', '{0} has no A record; SOA is {1}'.format( ns, ';'.join(s.to_text() for s in soa))) except dns.resolver.NoNameservers: if not item.get('pass', None): log( 'warn', '{0} has no available servers to service DNS ' 'request.'.format(ns)) except dns.resolver.Timeout: log('warn', '{0}: DNS lookup timed out.'.format(ns)) except Exception: log_current_exception() log('error', '{}'.format( color('-' * 41 + 'v' * len(ns), 'red', attrs=['bold'])), no_exception=True) log('error', ('validate YAML: Failed NS validation for:' ' {} in {}'.format(color(ns, 'white', attrs=['bold']), self._filename)), no_exception=True) log('error', '{}'.format( color('-' * 41 + '^' * len(ns), 'red', attrs=['bold'])), no_exception=True) raise return True
def GoogleCaptchaDetection(self, RawHtml): soup = BeautifulSoup(RawHtml, "lxml") if "Our systems have detected unusual traffic" in soup.text: p = " [!] Google Captcha was detected! (For best results resolve/restart -- Increase sleep/jitter in SimplyEmail.ini)" self.logger.warning("Google Captcha was detected!") print helpers.color(p, warning=True) return True else: return False
def add_target(self, target=None, port=None, access=None, username=None, password=None, domain=None): """ Add a target with the specified information to the database. """ print helpers.color("[+] Adding target: {}".format(target)) cur = self.conn.cursor() cur.execute("INSERT INTO targets (target, port, access, username, password, domain) VALUES (?,?,?,?,?,?)", [target, port,access, username, password, domain] ) cur.close()
def do_usemodule(self,line): name=line.strip() if name not in self.modules.modules: print helpers.color('[!] Error: invalid module') else: try: exp=modules.Exploit(self,name) exp.cmdloop() except: pass
def LinkedInClean(self, raw): ''' This function simply uses clean names. ''' try: if raw: FirstName = raw[0] Lastname = raw[1] try: if "'" in FirstName: FirstName = FirstName.replace("'", "") if "-" in FirstName: FirstName = FirstName.replace("-", "") if " " in FirstName: FirstName = FirstName.replace(" ", "") if "," in FirstName: FirstName = FirstName.replace(",", "") if "(" in FirstName: FirstName = FirstName.replace("(", "") if ")" in FirstName: FirstName = FirstName.replace(")", "") if "'" in Lastname: Lastname = Lastname.replace("'", "") if "-" in Lastname: Lastname = Lastname.replace("-", "") if " " in Lastname: Lastname = Lastname.replace(" ", "") if "," in Lastname: Lastname = Lastname.replace(",", "") if "(" in Lastname: Lastname = Lastname.replace("(", "") if ")" in Lastname: Lastname = Lastname.replace(")", "") if ("@" in FirstName) or ("@" in Lastname): return None except Exception as e: pass try: if raw[3]: FirstName = raw[0] Lastname = raw[3] return [FirstName, Lastname] except Exception as e: pass if self.verbose: e = ' [*] Name Cleaned: ' + str([FirstName, Lastname]) print helpers.color(e, firewall=True) return [FirstName, Lastname] except Exception as e: if self.verbose: h = " [!] Error during name building: " + str(e) print helpers.color(h, warning=True) return None
def connect_to_db(): try: # set the database connectiont to autocommit w/ isolation level conn = sqlite3.connect('./data/empire.db', check_same_thread=False) conn.text_factory = str conn.isolation_level = None return conn except Exception: print helpers.color("[!] Could not connect to database") print helpers.color("[!] Please run database_setup.py") sys.exit()
def VersionRequest(self): if self.Start == "Yes": try: r = requests.get(self.RepoLocation, headers=self.UserAgent) results = r.content results = results.rstrip('\n') if str(results) != str(self.version): p = " [!] Newer Version Available, Re-Run Setup.sh to update!" print helpers.color(p, warning=True,bold=False) except Exception as e: error = "[!] Fail during Request to Update/Version Check (Check Connection)" print helpers.color(error, warning=True)
def main_menu(self, showMessage=True): cmd = "" try: while cmd == "": if showMessage: # print the title, where we are, and number of payloads loaded messages.main_menu(self.modules) messages.help_msg(self.commands) cmd = raw_input(helpers.color(' OFF -> ', blue=True)).strip() # handle our tab completed commands if cmd.startswith("help"): messages.title() messages.help_msg(self.commands) cmd = "" showMessage=False elif cmd.startswith("use"): messages.title() self.call_handler(cmd) cmd = "" elif cmd.startswith("list"): if len(cmd.split()) == 1: messages.title() self.list_modules() cmd = "" showMessage=False elif cmd.startswith("update"): if len(cmd.split()) == 1: messages.title() self.list_modules() cmd = "" showMessage=False # catch any ctrl + c interrupts except KeyboardInterrupt: if self.oneRun: # if we're being invoked from external code, just return # an empty string on an exit/quit instead of killing everything return "" else: print helpers.color("\n\n [!] Exiting...\n", warning=True) sys.exit()
def delete_file(self, local_filename): # Deletes a file from local path try: if os.path.isfile(local_filename): os.remove(local_filename) self.logger.debug("File deleted: " + str(local_filename)) else: if self.verbose: p = ' [*] File not found to remove : ' + local_filename print helpers.color(p, firewall=True) except Exception as e: self.logger.error("Failed to delete file: " + str(e)) if self.verbose: print e
def LinkedInNames(self): # This function simply uses # Bing to scrape for names and # returns a list of list names. try: br = mechanize.Browser() br.set_handle_robots(False) self.domain = self.domain.split('.') self.domain = self.domain[0] r = br.open('http://www.bing.com/search?q=(site%3A%22www.linkedin.com%2Fin%2F%22%20OR%20site%3A%22www.linkedin.com%2Fpub%2F%22)%20%26%26%20(NOT%20site%3A%22www.linkedin.com%2Fpub%2Fdir%2F%22)%20%26%26%20%22' + self.domain + '%22&qs=n&form=QBRE&pq=(site%3A%22www.linkedin.com%2Fin%2F%22%20or%20site%3A%22www.linkedin.com%2Fpub%2F%22)%20%26%26%20(not%20site%3A%22www.linkedin.com%2Fpub%2Fdir%2F%22)%20%26%26%20%22'+self.domain+'%22') soup = BeautifulSoup(r, 'lxml') if soup: link_list = [] namelist = [] more_records = True Round = False while more_records: if Round: response = br.follow_link(text="Next") soup = BeautifulSoup(response) # enter this loop to parse all results # also follow any seondary links for definition in soup.findAll('h2'): definition = definition.renderContents() if "LinkedIn" in definition: name = (((((definition.replace('<strong>', '')).replace( '</strong>', '')).split('>')[1]).split('|')[0]).rstrip()).split(',')[0] name = name.split(' ') if self.verbose: e = ' [*] LinkedIn Name Found: ' + str(name) print helpers.color(e, firewall=True) namelist.append(name) for link in br.links(): link_list.append(link.text) if "Next" in link_list: more_records = True Round = True else: more_records = False if namelist: return namelist except Exception as e: error = " [!] Major issue with Downloading LinkedIn source:" + \ str(e) print helpers.color(error, warning=True) if namelist: return namelist