def check_root(self): """ Check if Empire has been run as root, and alert user. """ try: if os.geteuid() != 0: if self.isroot: messages.title(VERSION) print( "[!] Warning: Running Empire as non-root, after running as root will likely fail to access prior agents!" ) while True: a = input( helpers.color( "[>] Are you sure you want to continue (y) or (n): " )) if a.startswith("y"): return if a.startswith("n"): self.shutdown() sys.exit() else: pass if os.geteuid() == 0: if self.isroot: pass if not self.isroot: config = Session().query(models.Config).all() config.rootuser = True Session().commit() except Exception as e: print(e)
def add_credential_note(self, credential_id, note): """ Update a note to a credential in the database. """ results = Session().query(models.Agent).filter(models.Credential.id == credential_id).first() results.notes = note Session().commit()
def add_credential(self, credtype, domain, username, password, host, os="", sid="", notes=""): """ Add a credential with the specified information to the database. """ results = (Session().query(models.Credential).filter( and_( models.Credential.credtype.like(credtype), models.Credential.domain.like(domain), models.Credential.username.like(username), models.Credential.password.like(password), )).all()) if len(results) == 0: credential = models.Credential( credtype=credtype, domain=domain, username=username, password=password, host=host, os=os, sid=sid, notes=notes, ) Session().add(credential) Session().commit() return credential
def add_new_user(self, user_name, password): """ Add new user to cache """ success = Session().add( models.User(username=user_name, password=self.get_hashed_password(password), enabled=True, admin=False)) Session().commit() if success: # dispatch the event signal = json.dumps({ 'print': True, 'message': "Added {} to Users".format(user_name) }) dispatcher.send(signal, sender="Users") message = True else: message = False return message
def delete_listener(self, listener_name): """ Delete listener(s) from database. """ try: listeners = Session().query(models.Listener).all() db_names = [x['name'] for x in listeners] 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 list(self.activeListeners.keys()): self.shutdown_listener(name) listener = Session().query(models.Listener).filter( models.Listener.name == name).first() Session().delete(listener) Session().commit() except Exception as e: print(helpers.color("[!] Error deleting listener '%s'" % name))
def kill_listener(self, listener_name): """ Shut down the server associated with a listenerName and delete the listener from the database. To kill all listeners, use listenerName == 'all' """ if listener_name.lower() == 'all': listener_names = list(self.activeListeners.keys()) else: listener_names = [listener_name] for listener_name in listener_names: if listener_name not in self.activeListeners: print( helpers.color("[!] Listener '%s' not active!" % (listener_name))) return False listener = Session().query(models.Listener).filter( models.Listener.name == listener_name).first() # shut down the listener and remove it from the cache if self.mainMenu.listeners.get_listener_module( listener_name) == 'redirector': del self.activeListeners[listener_name] Session().delete(listener) continue self.shutdown_listener(listener_name) # remove the listener from the database Session().delete(listener) Session().commit()
def disable_listener(self, listener_name): """ Wrapper for shutdown_listener(), also marks listener as 'disabled' so it won't autostart """ active_listener_module_name = self.activeListeners[listener_name][ "moduleName"] listener = (Session().query(models.Listener).filter( and_( models.Listener.name == listener_name.lower(), models.Listener.module != "redirector", )).first()) listener.enabled = False self.shutdown_listener(listener_name) Session().commit() # dispatch this event message = "[*] Listener {} disabled".format(listener_name) signal = json.dumps({"print": True, "message": message}) dispatcher.send( signal, sender="listeners/{}/{}".format(active_listener_module_name, listener_name), )
def ps_hook(tasking: models.Tasking): """ This hook watches for the 'ps' command and writes the processes into the processes table. For Powershell Agents, the data comes back (as of 4.1) as JSON. For Python Agents, the data comes back in the typical 'ls' format. For C# Agents, no support yet. AFAIK, it is not easy to convert the shell tables into JSON, but I found this jq wizardry on StackOverflow, so that's what we'll stick with for now for the python results, even though it is imperfect. https://unix.stackexchange.com/a/243485 """ if (tasking.input.strip() not in ["ps", "tasklist"] or tasking.agent.language == "csharp"): return if tasking.agent.language == "python": output = (jq.compile( """[sub("\n$";"") | splits("\n") | sub("^ +";"") | [splits(" +")]] | .[0] as $header | .[1:] | [.[] | [. as $x | range($header | length) | {"key": $header[.], "value": $x[.]}] | from_entries]""" ).input( tasking.output.decode("utf-8").split( "\r\n ..Command execution completed.")[0]).first()) else: output = json.loads(tasking.output) existing_processes = (Session().query( models.HostProcess.process_id).filter( models.HostProcess.host_id == tasking.agent.host_id).all()) existing_processes = list(map(lambda p: p[0], existing_processes)) for process in output: process_name = process.get("CMD") or process.get("ProcessName") or "" process_id = process.get("PID") arch = process.get("Arch") user = process.get("UserName") if process_id: # and process_id.isnumeric(): if int(process_id) not in existing_processes: Session().add( models.HostProcess( host_id=tasking.agent.host_id, process_id=process_id, process_name=process_name, architecture=arch, user=user, )) elif int(process_id) in existing_processes: db_process: models.HostProcess = (Session().query( models.HostProcess).filter( and_( models.HostProcess.host_id == tasking.agent.host_id, models.HostProcess.process_id == process_id, )).first()) if not db_process.agent: db_process.architecture = arch db_process.process_name = process_name Session().commit()
def remove_all_credentials(self): """ Remove all credentials from the database. """ creds = Session().query(models.Credential).all() for cred in creds: Session().delete(cred) Session().commit()
def remove_credentials(self, credIDs): """ Removes a list of IDs from the database """ for credID in credIDs: cred_entry = Session().query(models.Credential).filter(models.Credential.id == credID).first() Session().delete(cred_entry) Session().commit()
def load_malleable_profiles(self): """ Load Malleable C2 Profiles to the database """ malleable_path = self.installPath + "/data/profiles" print( helpers.color( "[*] Loading malleable profiles from: {}".format(malleable_path) ) ) malleable_directories = os.listdir(malleable_path) for malleable_directory in malleable_directories: for root, dirs, files in os.walk( malleable_path + "/" + malleable_directory ): for filename in files: if not filename.lower().endswith(".profile"): continue file_path = os.path.join(root, filename) # don't load up any of the templates if fnmatch.fnmatch(filename, "*template.profile"): continue malleable_split = file_path.split(malleable_path)[-1].split("/") profile_category = malleable_split[1] profile_name = malleable_split[2] # Check if module is in database and load new profiles profile = ( Session() .query(models.Profile) .filter(models.Profile.name == profile_name) .first() ) if not profile: message = "[*] Loading malleable profile {}".format( profile_name ) signal = json.dumps({"print": False, "message": message}) dispatcher.send(signal, sender="empire") with open(file_path, "r") as stream: profile_data = stream.read() Session().add( models.Profile( file_path=file_path, name=profile_name, category=profile_category, data=profile_data, ) ) Session().commit()
def change_module_state(main, module_list: list, module_state: bool): for module_name in module_list: try: module = Session().query(models.Module).filter(models.Module.name == module_name).first() module.enabled = module_state main.modules.modules[module_name].enabled = module_state except: # skip if module name is not found pass Session().commit()
def enable_listener(self, listener_name): """ Starts an existing listener and sets it to enabled """ if listener_name in list(self.activeListeners.keys()): print(helpers.color("[!] Listener already running!")) return False result = (Session().query(models.Listener).filter( models.Listener.name == listener_name).first()) if not result: print( helpers.color("[!] Listener %s doesn't exist!" % listener_name)) return False module_name = result["module"] options = result["options"] try: listener_module = self.loadedListeners[module_name] for option, value in options.items(): listener_module.options[option]["Value"] = value["Value"] print(helpers.color("[*] Starting listener '%s'" % listener_name)) if module_name == "redirector": success = True else: success = listener_module.start(name=listener_name) if success: print(helpers.color("[+] Listener successfully started!")) listener_options = copy.deepcopy(listener_module.options) self.activeListeners[listener_name] = { "moduleName": module_name, "options": listener_options, } listener = (Session().query(models.Listener).filter( and_( models.Listener.name == listener_name, models.Listener.module != "redirector", )).first()) listener.enabled = True Session().commit() else: print(helpers.color("[!] Listener failed to start!")) except Exception as e: traceback.print_exc() if listener_name in self.activeListeners: del self.activeListeners[listener_name] print(helpers.color("[!] Error starting listener: %s" % e))
def run_report_query(self): reporting_sub_query = ( Session() .query( models.Reporting, self.substring(Session(), models.Reporting.name, "/").label( "agent_name" ), ) .filter( and_( models.Reporting.name.ilike("agent%"), or_( models.Reporting.event_type == "task", models.Reporting.event_type == "checkin", ), ) ) .subquery() ) return ( Session() .query( reporting_sub_query.c.timestamp, reporting_sub_query.c.event_type, reporting_sub_query.c.agent_name, reporting_sub_query.c.taskID, models.Agent.hostname, models.User.username, models.Tasking.input.label("task"), models.Tasking.output.label("results"), ) .join( models.Tasking, and_( models.Tasking.id == reporting_sub_query.c.taskID, models.Tasking.agent_id == reporting_sub_query.c.agent_name, ), isouter=True, ) .join(models.User, models.User.id == models.Tasking.user_id, isouter=True) .join( models.Agent, models.Agent.session_id == reporting_sub_query.c.agent_name, isouter=True, ) .all() )
def _load_module(self, yaml_module, root_path, file_path: str): # extract just the module name from the full path module_name = file_path.split(root_path)[-1][0:-5] # if root_path != f"{self.main_menu.installPath}/modules/": # module_name = f"external/{module_name}" if file_path.lower().endswith(".covenant.yaml"): my_model = PydanticModule( **_convert_covenant_to_empire(yaml_module, file_path)) module_name = f"{module_name[:-9]}/{my_model.name}" else: my_model = PydanticModule(**yaml_module) if my_model.advanced.custom_generate: if not path.exists(file_path[:-4] + "py"): raise Exception("No File to use for custom generate.") spec = importlib.util.spec_from_file_location( module_name + ".py", file_path[:-5] + ".py") imp_mod = importlib.util.module_from_spec(spec) spec.loader.exec_module(imp_mod) my_model.advanced.generate_class = imp_mod.Module() elif my_model.script_path: if not path.exists( os.path.join( empire_config.yaml.get("directories", {})["module_source"], my_model.script_path, )): raise Exception( f"File provided in script_path does not exist: { module_name }" ) elif my_model.script: pass else: raise Exception( "Must provide a valid script, script_path, or custom generate function" ) mod = (Session().query( models.Module).filter(models.Module.name == module_name).first()) if not mod: mod = models.Module(name=module_name, enabled=True) Session().add(mod) self.modules[module_name] = my_model self.modules[module_name].enabled = mod.enabled
def generate_launcher(self, listenerName, language=None, encode=True, obfuscate=False, obfuscationCommand="", userAgent='default', proxy='default', proxyCreds='default', stagerRetries='0', safeChecks='true', bypasses: str = ''): """ Abstracted functionality that invokes the generate_launcher() method for a given listener, if it exists. """ bypasses_parsed = [] for bypass in bypasses.split(' '): b = Session().query( models.Bypass).filter(models.Bypass.name == bypass).first() if b: bypasses_parsed.append(b.code) 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, obfuscate=obfuscate, obfuscationCommand=obfuscationCommand, userAgent=userAgent, proxy=proxy, proxyCreds=proxyCreds, stagerRetries=stagerRetries, language=language, listenerName=listenerName, safeChecks=safeChecks, bypasses=bypasses_parsed) if launcherCode: return launcherCode
def keyword_obfuscation(data): functions = Session().query(models.Function).all() for function in functions: data = data.replace(function.keyword, function.replacement) return data
def is_credential_valid(self, credentialID): """ Check if this credential ID is valid. """ results = (Session().query(models.Credential).filter( models.Credential.id == credentialID).all()) return len(results) > 0
def disable_user(self, uid, disable): """ Disable user """ user = Session().query( models.User).filter(models.User.id == uid).first() if not self.user_exists(uid): message = False elif self.is_admin(uid): signal = json.dumps({ 'print': True, 'message': "Cannot disable admin account" }) message = False else: user.enabled = not (disable) Session.commit() signal = json.dumps({ 'print': True, 'message': 'User {}'.format('disabled' if disable else 'enabled') }) message = True dispatcher.send(signal, sender="Users") return message
def user_logout(self, uid): user = Session().query( models.User).filter(models.User.id == uid).first() user.api_token = '' Session.commit() # dispatch the event signal = json.dumps({'print': True, 'message': "User disconnected"}) dispatcher.send(signal, sender="Users")
def log_event(name, event_type, message, task_id=None): """ Log arbitrary events name - the sender string from the dispatched event event_type - the category of the event - agent_result, agent_task, agent_rename, etc. Ideally a succinct description of what the event actually is. message - the body of the event, WHICH MUST BE JSON, describing any pertinent details of the event task_id - the ID of the task this event is in relation to. Enables quick queries of an agent's task and its result together. """ Session().add( models.Reporting(name=name, event_type=event_type, message=message, taskID=task_id)) Session().commit()
def user_exists(self, uid): """ Return whether a user exists or not """ user = Session().query( models.User).filter(models.User.id == uid).first() if user: return True else: return False
def update_listener_options(self, listener_name, option_name, option_value): """ Updates a listener option in the database """ listener = Session().query(models.Listener).filter( models.Listener.name == listener_name).first() if not listener: print(helpers.color("[!] Listener %s not found" % listener_name)) return False if option_name not in list(listener.options.keys()): print( helpers.color("[!] Listener %s does not have the option %s" % (listener_name, option_name))) return False listener.options[option_name]['Value'] = option_value flag_modified(listener, 'options') Session().commit() return True
def get_listener_module(self, listener_name): """ Resolve a listener name to the module used to instantiate it. """ results = Session().query(models.Listener.module).filter( models.Listener.name == listener_name).first() if results: return results[0] else: return None
def is_admin(self, uid): """ Returns whether a user is an admin or not. """ admin = Session().query( models.User.admin).filter(models.User.id == uid).first() if admin[0] == True: return True return False
def get_listener_options(listener_name): """ Returns the options for a specified listenername from the database outside of the normal menu execution. """ try: listener_options = Session().query(models.Listener.options).filter( models.Listener.name == listener_name).first() return listener_options except Exception: return None
def get_listener_name(self, listener_id): """ Resolve a listener ID to a name. """ results = Session().query(models.Listener.name).filter( or_(models.Listener.name == listener_id, models.Listener.id == listener_id)).first() if results: return results[0] else: return None
def get_listener_id(self, name): """ Resolve a name to listener ID. """ results = Session().query(models.Listener.id).filter( or_(models.Listener.name == name, models.Listener.id == name)).first() if results: return results[0] else: return None
def run_report_query(self): reporting_sub_query = Session() \ .query(models.Reporting, self.substring(Session(), models.Reporting.name, '/').label('agent_name')) \ .filter(and_(models.Reporting.name.ilike('agent%'), or_(models.Reporting.event_type == 'task', models.Reporting.event_type == 'checkin'))) \ .subquery() return Session() \ .query(reporting_sub_query.c.timestamp, reporting_sub_query.c.event_type, reporting_sub_query.c.agent_name, reporting_sub_query.c.taskID, models.Agent.hostname, models.User.username, models.Tasking.input.label('task'), models.Tasking.output.label('results')) \ .join(models.Tasking, and_(models.Tasking.id == reporting_sub_query.c.taskID, models.Tasking.agent == reporting_sub_query.c.agent_name), isouter=True) \ .join(models.User, models.User.id == models.Tasking.user_id, isouter=True) \ .join(models.Agent, models.Agent.session_id == reporting_sub_query.c.agent_name, isouter=True) \ .all()
def get_listener_for_socket(self, name): listener = Session().query( models.Listener).filter(models.Listener.name == name).first() return { 'ID': listener.id, 'name': listener.name, 'module': listener.module, 'listener_type': listener.listener_type, 'listener_category': listener.listener_category, 'options': listener.options, 'created_at': listener.created_at }