Added ability to enable/disable listeners, so they are still stored in the

database, but will not start automatically.
Also, listener options can now be edited without deleting the listener
and starting a new one from scratch.
php_fix
mr64bit 2018-01-18 22:45:53 -05:00
parent 8a27017d43
commit 3bff4e6ef2
4 changed files with 153 additions and 8 deletions

View File

@ -155,7 +155,9 @@ class MainMenu(cmd.Cmd):
# if we're displaying listeners/stagers or generating a stager
if self.args.listener:
if self.args.listener == 'list':
messages.display_active_listeners(self.listeners.activeListeners)
messages.display_listeners(self.listeners.activeListeners)
messages.display_listeners(self.listeners.get_inactive_listeners(), "Inactive")
else:
activeListeners = self.listeners.activeListeners
targetListener = [l for l in activeListeners if self.args.listener in l[1]]
@ -783,7 +785,8 @@ class MainMenu(cmd.Cmd):
elif parts[0].lower() == 'listeners':
messages.display_active_listeners(self.listeners.activeListeners)
messages.display_listeners(self.listeners.activeListeners)
messages.display_listeners(self.listeners.get_inactive_listeners(), "Inactive")
def do_interact(self, line):
@ -2912,7 +2915,8 @@ class ListenersMenu(SubMenu):
self.prompt = '(Empire: ' + helpers.color('listeners', color='blue') + ') > '
# display all active listeners on menu startup
messages.display_active_listeners(self.mainMenu.listeners.activeListeners)
messages.display_listeners(self.mainMenu.listeners.activeListeners)
messages.display_listeners(self.mainMenu.listeners.get_inactive_listeners(), "Inactive")
def do_back(self, line):
"Go back to the main menu."
@ -3027,6 +3031,48 @@ class ListenersMenu(SubMenu):
else:
print helpers.color("[!] Please enter a valid listenerName")
def do_enable(self, line):
"Enables and starts one or all listners."
listenerID = line.strip()
if listenerID == '':
print helpers.color("[!] Please provide a listener name")
elif listenerID.lower() == 'all':
try:
choice = raw_input(helpers.color('[>] Start all listeners? [y/N] ', 'red'))
if choice.lower() != '' and choice.lower()[0] == 'y':
self.mainMenu.listeners.enable_listener('all')
except KeyboardInterrupt:
print ''
else:
self.mainMenu.listeners.enable_listener(listenerID)
def do_disable(self, line):
"Disables (stops) one or all listeners. The listener(s) will not start automatically with Empire"
listenerID = line.strip()
if listenerID.lower() == 'all':
try:
choice = raw_input(helpers.color('[>] Stop all listeners? [y/N] ', 'red'))
if choice.lower() != '' and choice.lower()[0] == 'y':
self.mainMenu.listeners.shutdown_listener('all')
except KeyboardInterrupt:
print ''
else:
self.mainMenu.listeners.disable_listener(listenerID)
def do_edit(self,line):
"Change a listener option, will not take effect until the listener is restarted"
arguments = line.strip().split(" ")
if len(arguments) < 3:
print helpers.color("[!] edit <listener name> <option name> <option value>")
return
self.mainMenu.listeners.update_listener_options(arguments[0], arguments[1], arguments[2])
def complete_usestager(self, text, line, begidx, endidx):
"Tab-complete an Empire stager module path."

View File

@ -198,7 +198,7 @@ class Listeners:
self.activeListeners[name] = {'moduleName': moduleName, 'options':listenerOptions}
pickledOptions = pickle.dumps(listenerObject.options)
cur = self.conn.cursor()
cur.execute("INSERT INTO listeners (name, module, listener_category, options) VALUES (?,?,?,?)", [name, moduleName, category, pickledOptions])
cur.execute("INSERT INTO listeners (name, module, listener_category, enabled, options) VALUES (?,?,?,?,?)", [name, moduleName, category, True, pickledOptions])
cur.close()
else:
print helpers.color('[!] Listener failed to start!')
@ -216,7 +216,7 @@ class Listeners:
oldFactory = self.conn.row_factory
self.conn.row_factory = helpers.dict_factory
cur = self.conn.cursor()
cur.execute("SELECT id,name,module,listener_type,listener_category,options FROM listeners")
cur.execute("SELECT id,name,module,listener_type,listener_category,options FROM listeners WHERE enabled=?", [True])
results = cur.fetchall()
cur.close()
@ -259,6 +259,50 @@ class Listeners:
self.conn.row_factory = oldFactory
def enable_listener(self, listenerName):
"Starts an existing listener and sets it to enabled"
if listenerName in self.activeListeners.keys():
print helpers.color("[!] Listener already running!")
return False
oldFactory = self.conn.row_factory
self.conn.row_factory = helpers.dict_factory
cur = self.conn.cursor()
cur.execute("SELECT id,name,module,listener_type,listener_category,options FROM listeners WHERE name=?", [listenerName])
result = cur.fetchone()
if not result:
print helpers.color("[!] Listener %s doesn't exist!" % listenerName)
return False
moduleName = result['module']
options = pickle.loads(result['options'])
try:
listenerModule = self.loadedListeners[moduleName]
for option, value in options.iteritems():
listenerModule.options[option] = value
print helpers.color("[*] Starting listener '%s'" % (listenerName))
if moduleName == 'redirector':
success = True
else:
success = listenerModule.start(name=listenerName)
if success:
print helpers.color('[+] Listener successfully started!')
listenerOptions = copy.deepcopy(listenerModule.options)
self.activeListeners[listenerName] = {'moduleName': moduleName, 'options': listenerOptions}
cur.execute("UPDATE listeners SET enabled=? WHERE name=? AND NOT module=?", [True, listenerName, 'redirector'])
else:
print helpers.color('[!] Listener failed to start!')
except Exception as e:
traceback.print_exc()
if listenerName in self.activeListeners:
del self.activeListeners[listenerName]
print helpers.color("[!] Error starting listener: %s" % (e))
cur.close()
self.conn.row_factory = oldFactory
def kill_listener(self, listenerName):
"""
@ -327,6 +371,17 @@ class Listeners:
# remove the listener object from the internal cache
del self.activeListeners[listenerName]
def disable_listener(self, listenerName):
"Wrapper for shutdown_listener(), also marks listener as 'disabled' so it won't autostart"
cur = self.conn.cursor()
if listenerName.lower() == "all":
cur.execute("UPDATE listeners SET enabled=? WHERE NOT module=?", [False, "redirector"])
else:
cur.execute("UPDATE listeners SET enabled=? WHERE name=? AND NOT module=?", [False, listenerName.lower(), "redirector"])
cur.close()
cur.close()
self.shutdown_listener(listenerName)
def is_listener_valid(self, name):
return name in self.activeListeners
@ -399,3 +454,45 @@ class Listeners:
Return all current listener names.
"""
return self.activeListeners.keys()
def get_inactive_listeners(self):
"""
Returns any listeners that are not currently running
"""
oldFactory = self.conn.row_factory
self.conn.row_factory = helpers.dict_factory
cur = self.conn.cursor()
cur.execute("SELECT name,module,options FROM listeners")
db_listeners = cur.fetchall()
inactive_listeners = {}
for listener in filter((lambda x: x['name'] not in self.activeListeners.keys()), db_listeners):
inactive_listeners[listener['name']] = {'moduleName': listener['module'],
'options': pickle.loads(listener['options'])}
cur.close()
self.conn.row_factory = oldFactory
return inactive_listeners
def update_listener_options(self, listener_name, option_name, option_value):
"Updates a listener option in the database"
try:
cur = self.conn.cursor()
cur.execute('SELECT id,options FROM listeners WHERE name=?', [listener_name])
listener_id, result = cur.fetchone()
options = pickle.loads(result)
if not option_name in options.keys():
print helpers.color("[!] Listener %s does not have the option %s" % (listener_name, option_name))
return
options[option_name]['Value'] = option_value
pickled_options = pickle.dumps(options)
cur.execute('UPDATE listeners SET options=? WHERE id=?', [pickled_options, listener_id])
if listener_name in self.activeListeners.keys():
print helpers.color("[*] This change will not take effect until the listener is restarted")
except ValueError:
print helpers.color("[!] Listener %s not found" % listenerName)
cur.close()

View File

@ -220,14 +220,14 @@ def display_agent(agent, returnAsString=False):
print ''
def display_active_listeners(listeners):
def display_listeners(listeners, type = "Active"):
"""
Take an active listeners list and display everything nicely.
"""
if len(listeners) > 0:
print ''
print helpers.color("[*] Active listeners:\n")
print helpers.color("[*] %s listeners:\n" % type)
print " Name Module Host Delay/Jitter KillDate"
print " ---- ------ ---- ------------ --------"
@ -265,7 +265,8 @@ def display_active_listeners(listeners):
print ''
else:
print helpers.color("[!] No listeners currently active ")
if(type.lower() != "inactive"):
print helpers.color("[!] No listeners currently %s " % type.lower())
def display_active_listener(listener):

View File

@ -127,6 +127,7 @@ c.execute('''CREATE TABLE "listeners" (
"module" text,
"listener_type" text,
"listener_category" text,
"enabled" boolean,
"options" blob
)''')