From bde2f71f9032262cce2c04be9c56473eb6f4996d Mon Sep 17 00:00:00 2001 From: Vincent Rose Date: Wed, 29 Nov 2023 19:02:43 -0700 Subject: [PATCH] remove name arg from listener start and shutdown (#734) --- CHANGELOG.md | 1 + empire/server/common/empire.py | 2 +- empire/server/core/listener_service.py | 6 +- empire/server/listeners/dbx.py | 41 +++----- empire/server/listeners/http.py | 41 +++----- empire/server/listeners/http_com.py | 41 +++----- empire/server/listeners/http_foreign.py | 6 +- empire/server/listeners/http_hop.py | 4 +- empire/server/listeners/http_malleable.py | 44 +++------ empire/server/listeners/onedrive.py | 41 +++----- empire/server/listeners/port_forward_pivot.py | 99 ++++++++++--------- empire/server/listeners/smb.py | 5 +- empire/server/listeners/template.py | 35 +++---- 13 files changed, 138 insertions(+), 228 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 59ad87e76..20020944f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Removed usages of deprecated `Credentials` and `Listeners` functions (@Vinnybod) - Remove usages of deprecated `Agents` functions (@Vinnybod) - Add typehinting for `MainMenu` object in modules (@Vinnybod) +- Removed `name` property from listener start and shutdown functions (@Vinnybod) ### Removed diff --git a/empire/server/common/empire.py b/empire/server/common/empire.py index fdfa03ab1..b904bd0de 100755 --- a/empire/server/common/empire.py +++ b/empire/server/common/empire.py @@ -107,7 +107,7 @@ def shutdown(self): """ log.info("Empire shutting down...") - # enumerate all active servers/listeners and shut them down + log.info("Shutting down listeners...") self.listenersv2.shutdown_listeners() log.info("Shutting down plugins...") diff --git a/empire/server/core/listener_service.py b/empire/server/core/listener_service.py index a57503b64..90d8b02be 100644 --- a/empire/server/core/listener_service.py +++ b/empire/server/core/listener_service.py @@ -112,7 +112,7 @@ def create_listener(self, db: Session, listener_req): def stop_listener(self, db_listener: models.Listener): if self._active_listeners.get(db_listener.id): - self._active_listeners[db_listener.id].shutdown(name=db_listener.name) + self._active_listeners[db_listener.id].shutdown() del self._active_listeners[db_listener.id] def delete_listener(self, db: Session, db_listener: models.Listener): @@ -135,7 +135,7 @@ def start_existing_listener(self, db: Session, listener: models.Listener): log.error(err) return None, err - success = template_instance.start(name=listener.name) + success = template_instance.start() db.flush() if success: @@ -160,7 +160,7 @@ def _start_listener(self, db: Session, template_instance, template_name): name = template_instance.options["Name"]["Value"] try: log.info(f"v2: Starting listener '{name}'") - success = template_instance.start(name=name) + success = template_instance.start() if success: listener_options = copy.deepcopy(template_instance.options) diff --git a/empire/server/listeners/dbx.py b/empire/server/listeners/dbx.py index 5f02cbf29..9983b0716 100755 --- a/empire/server/listeners/dbx.py +++ b/empire/server/listeners/dbx.py @@ -125,7 +125,7 @@ def __init__(self, mainMenu: MainMenu): # required: self.mainMenu = mainMenu - self.threads = {} + self.thread = None # optional/specific for this module @@ -1016,40 +1016,23 @@ def delete_file(dbx, path): stagingKey, responseData, listenerOptions ) - def start(self, name=""): + def start(self): """ Start a threaded instance of self.start_server() and store it in the - self.threads dictionary keyed by the listener name. + self.thread property. """ listenerOptions = self.options - if name and name != "": - self.threads[name] = helpers.KThread( - target=self.start_server, args=(listenerOptions,) - ) - self.threads[name].start() - time.sleep(3) - # returns True if the listener successfully started, false otherwise - return self.threads[name].is_alive() - else: - name = listenerOptions["Name"]["Value"] - self.threads[name] = helpers.KThread( - target=self.start_server, args=(listenerOptions,) - ) - self.threads[name].start() - time.sleep(3) - # returns True if the listener successfully started, false otherwise - return self.threads[name].is_alive() + self.thread = helpers.KThread(target=self.start_server, args=(listenerOptions,)) + self.thread.start() + time.sleep(3) + # returns True if the listener successfully started, false otherwise + return self.thread.is_alive() - def shutdown(self, name=""): + def shutdown(self): """ - Terminates the server thread stored in the self.threads dictionary, - keyed by the listener name. + Terminates the server thread stored in the self.thread property. """ - if name and name != "": - to_kill = name - else: - to_kill = self.options["Name"]["Value"] - + to_kill = self.options["Name"]["Value"] self.instance_log.info(f"{to_kill}: shutting down...") log.info(f"{to_kill}: shutting down...") - self.threads[to_kill].kill() + self.thread.kill() diff --git a/empire/server/listeners/http.py b/empire/server/listeners/http.py index fae7dacc7..5d32f885a 100755 --- a/empire/server/listeners/http.py +++ b/empire/server/listeners/http.py @@ -158,7 +158,7 @@ def __init__(self, mainMenu: MainMenu): # required: self.mainMenu = mainMenu - self.threads = {} + self.thread = None # optional/specific for this module self.app = None @@ -1251,40 +1251,23 @@ def handle_post(request_uri): exc_info=True, ) - def start(self, name=""): + def start(self): """ Start a threaded instance of self.start_server() and store it in the - self.threads dictionary keyed by the listener name. + self.thread property. """ listenerOptions = self.options - if name and name != "": - self.threads[name] = helpers.KThread( - target=self.start_server, args=(listenerOptions,) - ) - self.threads[name].start() - time.sleep(1) - # returns True if the listener successfully started, false otherwise - return self.threads[name].is_alive() - else: - name = listenerOptions["Name"]["Value"] - self.threads[name] = helpers.KThread( - target=self.start_server, args=(listenerOptions,) - ) - self.threads[name].start() - time.sleep(1) - # returns True if the listener successfully started, false otherwise - return self.threads[name].is_alive() + self.thread = helpers.KThread(target=self.start_server, args=(listenerOptions,)) + self.thread.start() + time.sleep(1) + # returns True if the listener successfully started, false otherwise + return self.thread.is_alive() - def shutdown(self, name=""): + def shutdown(self): """ - Terminates the server thread stored in the self.threads dictionary, - keyed by the listener name. + Terminates the server thread stored in the self.thread property. """ - if name and name != "": - to_kill = name - else: - to_kill = self.options["Name"]["Value"] - + to_kill = self.options["Name"]["Value"] self.instance_log.info(f"{to_kill}: shutting down...") log.info(f"{to_kill}: shutting down...") - self.threads[to_kill].kill() + self.thread.kill() diff --git a/empire/server/listeners/http_com.py b/empire/server/listeners/http_com.py index f7dd9ea43..ed3c72a22 100755 --- a/empire/server/listeners/http_com.py +++ b/empire/server/listeners/http_com.py @@ -137,7 +137,7 @@ def __init__(self, mainMenu: MainMenu): # required: self.mainMenu = mainMenu - self.threads = {} + self.thread = None # optional/specific for this module self.app = None @@ -849,40 +849,23 @@ def handle_post(request_uri): self.instance_log.error(message1, exc_info=True) self.instance_log.error(message2, exc_info=True) - def start(self, name=""): + def start(self): """ Start a threaded instance of self.start_server() and store it in the - self.threads dictionary keyed by the listener name. + self.thread property. """ listenerOptions = self.options - if name and name != "": - self.threads[name] = helpers.KThread( - target=self.start_server, args=(listenerOptions,) - ) - self.threads[name].start() - time.sleep(1) - # returns True if the listener successfully started, false otherwise - return self.threads[name].is_alive() - else: - name = listenerOptions["Name"]["Value"] - self.threads[name] = helpers.KThread( - target=self.start_server, args=(listenerOptions,) - ) - self.threads[name].start() - time.sleep(1) - # returns True if the listener successfully started, false otherwise - return self.threads[name].is_alive() + self.thread = helpers.KThread(target=self.start_server, args=(listenerOptions,)) + self.thread.start() + time.sleep(1) + # returns True if the listener successfully started, false otherwise + return self.thread.is_alive() - def shutdown(self, name=""): + def shutdown(self): """ - Terminates the server thread stored in the self.threads dictionary, - keyed by the listener name. + Terminates the server thread stored in the self.thread property. """ - if name and name != "": - to_kill = name - else: - to_kill = self.options["Name"]["Value"] - + to_kill = self.options["Name"]["Value"] self.instance_log.info(f"{to_kill}: shutting down...") log.info(f"{to_kill}: shutting down...") - self.threads[to_kill].kill() + self.thread.kill() diff --git a/empire/server/listeners/http_foreign.py b/empire/server/listeners/http_foreign.py index d129fe6f0..21b87a6b0 100755 --- a/empire/server/listeners/http_foreign.py +++ b/empire/server/listeners/http_foreign.py @@ -110,7 +110,7 @@ def __init__(self, mainMenu: MainMenu): # required: self.mainMenu = mainMenu - self.threads = {} + self.thread = None # optional/specific for this module self.app = None @@ -465,13 +465,13 @@ def generate_comms(self, listenerOptions, language=None): else: log.error("listeners/http_foreign generate_comms(): no language specified!") - def start(self, name=""): + def start(self): """ Nothing to actually start for a foreign listner. """ return True - def shutdown(self, name=""): + def shutdown(self): """ Nothing to actually shut down for a foreign listner. """ diff --git a/empire/server/listeners/http_hop.py b/empire/server/listeners/http_hop.py index 2c8f6301c..046ed8d50 100755 --- a/empire/server/listeners/http_hop.py +++ b/empire/server/listeners/http_hop.py @@ -87,7 +87,7 @@ def __init__(self, mainMenu: MainMenu): # required: self.mainMenu = mainMenu - self.threads = {} + self.thread = None self.instance_log = log @@ -540,7 +540,7 @@ def generate_comms(self, listenerOptions, language=None): else: log.error("listeners/http_hop generate_comms(): no language specified!") - def start(self, name=""): + def start(self): """ Nothing to actually start for a hop listner, but ensure the stagingKey is synced with the redirect listener. diff --git a/empire/server/listeners/http_malleable.py b/empire/server/listeners/http_malleable.py index 3237ce612..f30aeef78 100644 --- a/empire/server/listeners/http_malleable.py +++ b/empire/server/listeners/http_malleable.py @@ -139,7 +139,7 @@ def __init__(self, mainMenu: MainMenu): # required: self.mainMenu = mainMenu - self.threads = {} # used to keep track of any threaded instances of this server + self.thread = None # optional/specific for this module self.app = None @@ -1764,44 +1764,26 @@ def handle_request(request_uri="", tempListenerOptions=None): self.instance_log.error(message, exc_info=True) log.error(message, exc_info=True) - def start(self, name=""): + def start(self): """ - Start a threaded instance of self.start_server() and store it in - the self.threads dictionary keyed by the listener name. + Start a threaded instance of self.start_server() and store it in the + self.thread property. """ self.instance_log = log_util.get_listener_logger( LOG_NAME_PREFIX, self.options["Name"]["Value"] ) - listenerOptions = self.options - if name and name != "": - self.threads[name] = helpers.KThread( - target=self.start_server, args=(listenerOptions,) - ) - self.threads[name].start() - time.sleep(1) - # returns True if the listener successfully started, false otherwise - return self.threads[name].is_alive() - else: - name = listenerOptions["Name"]["Value"] - self.threads[name] = helpers.KThread( - target=self.start_server, args=(listenerOptions,) - ) - self.threads[name].start() - time.sleep(1) - # returns True if the listener successfully started, false otherwise - return self.threads[name].is_alive() + self.thread = helpers.KThread(target=self.start_server, args=(listenerOptions,)) + self.thread.start() + time.sleep(1) + # returns True if the listener successfully started, false otherwise + return self.thread.is_alive() - def shutdown(self, name=""): + def shutdown(self): """ - Terminates the server thread stored in the self.threads dictionary, - keyed by the listener name. + Terminates the server thread stored in the self.thread property. """ - if name and name != "": - to_kill = name - else: - to_kill = self.options["Name"]["Value"] - + to_kill = self.options["Name"]["Value"] self.instance_log.info(f"{to_kill}: shutting down...") log.info(f"{to_kill}: shutting down...") - self.threads[to_kill].kill() + self.thread.kill() diff --git a/empire/server/listeners/onedrive.py b/empire/server/listeners/onedrive.py index 5010fed85..efc02d680 100755 --- a/empire/server/listeners/onedrive.py +++ b/empire/server/listeners/onedrive.py @@ -146,7 +146,7 @@ def __init__(self, mainMenu: MainMenu): self.stager_url = "" self.mainMenu = mainMenu - self.threads = {} + self.thread = None self.options["StagingKey"]["Value"] = str( data_util.get_config("staging_key")[0] @@ -885,40 +885,23 @@ def upload_stager(): s.close() - def start(self, name=""): + def start(self): """ Start a threaded instance of self.start_server() and store it in the - self.threads dictionary keyed by the listener name. + self.thread property. """ listenerOptions = self.options - if name and name != "": - self.threads[name] = helpers.KThread( - target=self.start_server, args=(listenerOptions,) - ) - self.threads[name].start() - time.sleep(3) - # returns True if the listener successfully started, false otherwise - return self.threads[name].is_alive() - else: - name = listenerOptions["Name"]["Value"] - self.threads[name] = helpers.KThread( - target=self.start_server, args=(listenerOptions,) - ) - self.threads[name].start() - time.sleep(3) - # returns True if the listener successfully started, false otherwise - return self.threads[name].is_alive() + self.thread = helpers.KThread(target=self.start_server, args=(listenerOptions,)) + self.thread.start() + time.sleep(3) + # returns True if the listener successfully started, false otherwise + return self.thread.is_alive() - def shutdown(self, name=""): + def shutdown(self): """ - Terminates the server thread stored in the self.threads dictionary, - keyed by the listener name. + Terminates the server thread stored in the self.thread property. """ - if name and name != "": - to_kill = name - else: - to_kill = self.options["Name"]["Value"] - + to_kill = self.options["Name"]["Value"] self.instance_log.info(f"{to_kill}: shutting down...") log.info(f"{to_kill}: shutting down...") - self.threads[to_kill].kill() + self.thread.kill() diff --git a/empire/server/listeners/port_forward_pivot.py b/empire/server/listeners/port_forward_pivot.py index abf0ef59f..d1cfe280c 100755 --- a/empire/server/listeners/port_forward_pivot.py +++ b/empire/server/listeners/port_forward_pivot.py @@ -63,7 +63,7 @@ def __init__(self, mainMenu: MainMenu): # required: self.mainMenu = mainMenu - self.threads = {} # used to keep track of any threaded instances of this server + self.thread = None self.instance_log = log @@ -677,12 +677,13 @@ def generate_comms(self, listenerOptions, language=None): else: log.error("listeners/http generate_comms(): no language specified!") - def start(self, name=""): + def start(self): """ If a server component needs to be started, implement the kick off logic here and the actual server code in another function to facilitate threading (i.e. start_server() in the http listener). """ + name = self.options["Name"]["Value"] try: tempOptions = copy.deepcopy(self.options) with SessionLocal.begin() as db: @@ -853,53 +854,53 @@ def start(self, name=""): log.error(f'Listener "{name}" failed to start') return False - def shutdown(self, name=""): + def shutdown(self): """ If a server component was started, implement the logic that kills the particular named listener here. """ - if name and name != "": - self.instance_log.info(f"{name}: shutting down...") - log.info(f"{name}: shutting down...") - - with SessionLocal() as db: - agent = self.mainMenu.agentsv2.get_by_name(db, name) - - if not agent: - log.error("Agent is not present in the cache or not elevated") - return - - if agent.high_integrity: - if agent.language.startswith("po"): - script = """ - function Invoke-Redirector { - param($FirewallName, $ListenAddress, $ListenPort, $ConnectHost, [switch]$Reset, [switch]$ShowAll) - if($ShowAll){ - $out = netsh interface portproxy show all - if($out){ - $out - } - else{ - "[*] no redirectors currently configured" - } + name = self.options["Name"]["Value"] + self.instance_log.info(f"{name}: shutting down...") + log.info(f"{name}: shutting down...") + + with SessionLocal() as db: + agent = self.mainMenu.agentsv2.get_by_name(db, name) + + if not agent: + log.error("Agent is not present in the cache or not elevated") + return + + if agent.high_integrity: + if agent.language.startswith("po"): + script = """ + function Invoke-Redirector { + param($FirewallName, $ListenAddress, $ListenPort, $ConnectHost, [switch]$Reset, [switch]$ShowAll) + if($ShowAll){ + $out = netsh interface portproxy show all + if($out){ + $out } - elseif($Reset){ - Netsh.exe advfirewall firewall del rule name="$FirewallName" - $out = netsh interface portproxy reset - if($out){ - $out - } - else{ - "[+] successfully removed all redirectors" - } + else{ + "[*] no redirectors currently configured" + } + } + elseif($Reset){ + Netsh.exe advfirewall firewall del rule name="$FirewallName" + $out = netsh interface portproxy reset + if($out){ + $out } else{ - if((-not $ListenPort)){ - "[!] netsh error: required option not specified" - } - else{ - $ConnectAddress = "" - $ConnectPort = "" + "[+] successfully removed all redirectors" + } + } + else{ + if((-not $ListenPort)){ + "[!] netsh error: required option not specified" + } + else{ + $ConnectAddress = "" + $ConnectPort = "" $parts = $ConnectHost -split(":") if($parts.Length -eq 2){ @@ -941,12 +942,12 @@ def shutdown(self, name=""): } Invoke-Redirector""" - script += " -Reset" - script += f" -FirewallName {agent.session_id}" + script += " -Reset" + script += f" -FirewallName {agent.session_id}" - self.mainMenu.agenttasksv2.create_task_shell(db, agent, script) - msg = "Tasked agent to uninstall Pivot listener " - self.mainMenu.agents.save_agent_log(agent.session_id, msg) + self.mainMenu.agenttasksv2.create_task_shell(db, agent, script) + msg = "Tasked agent to uninstall Pivot listener " + self.mainMenu.agents.save_agent_log(agent.session_id, msg) - elif agent.language.startswith("py"): - log.error("Shutdown not implemented for python") + elif agent.language.startswith("py"): + log.error("Shutdown not implemented for python") diff --git a/empire/server/listeners/smb.py b/empire/server/listeners/smb.py index 781b2d5bc..d49b8b8fa 100755 --- a/empire/server/listeners/smb.py +++ b/empire/server/listeners/smb.py @@ -415,13 +415,14 @@ def generate_comms(self, listenerOptions, language=None): else: log.error("generate_comms(): no language specified!") - def start(self, name=""): + def start(self): """ If a server component needs to be started, implement the kick off logic here and the actual server code in another function to facilitate threading (i.e. start_server() in the http listener). """ try: + name = self.options["Name"]["Value"] tempOptions = copy.deepcopy(self.options) with SessionLocal() as db: @@ -480,7 +481,7 @@ def start(self, name=""): except Exception: return False - def shutdown(self, name=""): + def shutdown(self): """ If a server component was started, implement the logic that kills the particular named listener here. diff --git a/empire/server/listeners/template.py b/empire/server/listeners/template.py index 14523d851..7b654beb5 100644 --- a/empire/server/listeners/template.py +++ b/empire/server/listeners/template.py @@ -1,4 +1,5 @@ import random +import time # Empire imports from empire.server.common import helpers @@ -129,7 +130,7 @@ def __init__(self, mainMenu): # required: self.mainMenu = mainMenu - self.threads = {} # used to keep track of any threaded instances of this server + self.thread = None # optional/specific for this module @@ -305,31 +306,23 @@ def generate_comms(self, listenerOptions, language=None): ) ) - def start(self, name=""): + def start_server(self): + pass + + def start(self): """ If a server component needs to be started, implement the kick off logic here and the actual server code in another function to facilitate threading (i.e. start_server() in the http listener). """ - - # listenerOptions = self.options - # if name and name != '': - # self.threads[name] = helpers.KThread(target=self.start_server, args=(listenerOptions,)) - # self.threads[name].start() - # time.sleep(1) - # # returns True if the listener successfully started, false otherwise - # return self.threads[name].is_alive() - # else: - # name = listenerOptions['Name']['Value'] - # self.threads[name] = helpers.KThread(target=self.start_server, args=(listenerOptions,)) - # self.threads[name].start() - # time.sleep(1) - # # returns True if the listener successfully started, false otherwise - # return self.threads[name].is_alive() - - return True - - def shutdown(self, name=""): + listenerOptions = self.options + self.thread = helpers.KThread(target=self.start_server, args=(listenerOptions,)) + self.thread.start() + time.sleep(1) + # returns True if the listener successfully started, false otherwise + return self.thread.is_alive() + + def shutdown(self): """ If a server component was started, implement the logic that kills the particular named listener here.