Merge pull request #157 from PowerShellEmpire/restful_api

RESTful API
1.6
HarmJ0y 2016-03-22 14:15:25 -07:00
commit 446a004cc1
9 changed files with 844 additions and 234 deletions

648
empire
View File

@ -1,13 +1,637 @@
#!/usr/bin/python
import sqlite3, argparse
import sqlite3, argparse, sys, argparse, logging, json, string, os, re, time, signal
from flask import Flask, request, jsonify, make_response, abort
from time import localtime, strftime
from OpenSSL import SSL
from Crypto.Random import random
# Empire imports
from lib.common import empire
from lib.common import listeners
from lib.common import http
from lib.common import packets
from lib.common import messages
#####################################################
#
# Database interaction methods for the RESTful API
#
#####################################################
def database_connect():
"""
Connect with the backend ./empire.db sqlite database and return the
connection object.
"""
try:
# set the database connectiont to autocommit w/ isolation level
conn = sqlite3.connect('./data/empire.db', check_same_thread=False)
conn.text_factory = str
conn.isolation_level = None
return conn
except Exception as e:
print helpers.color("[!] Could not connect to database")
print helpers.color("[!] Please run database_setup.py")
sys.exit()
def execute_db_query(conn, query, args=None):
"""
Execute the supplied query on the provided db conn object
with optional args for a paramaterized query.
"""
cur = conn.cursor()
if(args):
cur.execute(query, args)
else:
cur.execute(query)
results = cur.fetchall()
cur.close()
return results
def refresh_api_token(conn):
"""
Generates a randomized RESTful API token and updates the value
in the config stored in the backend database.
"""
# generate a randomized API token
apiToken = ''.join(random.choice(string.ascii_lowercase + string.digits) for x in range(40))
execute_db_query(conn, "UPDATE config SET api_token=?", [apiToken])
return apiToken
####################################################################
#
# The Empire RESTful API.
#
# Adapted from http://blog.miguelgrinberg.com/post/designing-a-restful-api-with-python-and-flask
# example code at https://gist.github.com/miguelgrinberg/5614326
#
# Verb URI Action
# ---- --- ------
# GET http://localhost:1337/empire/api/version return the current Empire version
#
# GET http://localhost:1337/empire/api/config return the current default config
#
# GET http://localhost:1337/empire/api/stagers return all current stagers
# GET http://localhost:1337/empire/api/stagers/X return the stager with name X
# POST http://localhost:1337/empire/api/stagers generate a stager given supplied options (need to implement)
#
# GET http://localhost:1337/empire/api/modules return all current modules
#
# GET http://localhost:1337/empire/api/listeners return all current listeners
# GET http://localhost:1337/empire/api/listeners/Y return the listener with id Y
# GET http://localhost:1337/empire/api/listeners/options return all listener options
# POST http://localhost:1337/empire/api/listeners starts a new listener with the specified options
# DELETE http://localhost:1337/empire/api/listeners/Y kills listener Y
#
# GET http://localhost:1337/empire/api/agents return all current agents
# GET http://localhost:1337/empire/api/agents/Y return the agent with name Y
# GET http://localhost:1337/empire/api/agents/Y/results return tasking results for the agent with name Y
# POST http://localhost:1337/empire/api/agents/Y modify or task agent with Y
# DELETE http://localhost:1337/empire/api/agents/Y removes agent Y from the database
# DELETE http://localhost:1337/empire/api/agents/stale removes stale agents from the database
#
# GET http://localhost:1337/empire/api/reporting return all logged events
# GET http://localhost:1337/empire/api/reporting/agent/X return all logged events for the given agent name X
# GET http://localhost:1337/empire/api/reporting/type/Y return all logged events of type Y (checkin, task, result, rename)
# GET http://localhost:1337/empire/api/reporting/msg/Z return all logged events matching message Z, wildcards accepted
#
# GET http://localhost:1337/empire/api/admin/shutdown shutdown the RESTful API
#
####################################################################
def start_restful_api(startEmpire=False, suppress=False, port=1337):
'''
'''
app = Flask(__name__)
class Namespace:
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
# instantiate an Empire instance in case we need to interact with stagers or listeners
args = Namespace(debug=None, listener=None, stager=None, stager_options=None, version=False)
print ""
if startEmpire:
# if we want to start a full-running empire instance
print " * Starting a full Empire instance"
main = empire.MainMenu(args=args)
else:
# if we just want the RESTful API, i.e. no listener/etc. startup
main = empire.MainMenu(args=args, restAPI=True)
conn = database_connect()
print " * Starting Empire RESTful API on port: %s" %(port)
# refresh the token for the RESTful API
apiToken = refresh_api_token(conn)
print " * RESTful API token: %s" %(apiToken)
tokenAllowed = re.compile("^[0-9a-z]{40}")
oldStdout = sys.stdout
if suppress:
# suppress the normal Flask output
log = logging.getLogger('werkzeug')
log.setLevel(logging.ERROR)
# suppress all stdout and don't initiate the main cmdloop
sys.stdout = open(os.devnull, 'w')
# validate API token before every request
@app.before_request
def check_token():
token = request.args.get('token')
if (not token) or (not tokenAllowed.match(token)):
return make_response('', 403)
if token != apiToken:
return make_response('', 403)
@app.errorhandler(Exception)
def exception_handler(error):
return repr(error)
@app.errorhandler(404)
def not_found(error):
return make_response(jsonify( { 'error': 'Not found' } ), 404)
@app.route('/empire/api/version', methods=['GET'])
def get_version():
"""
Returns the current Empire version.
"""
return jsonify({'version': empire.VERSION})
@app.route('/empire/api/config', methods=['GET'])
def get_config():
"""
Returns JSON of the current Empire config.
"""
configRaw = execute_db_query(conn, 'SELECT * FROM config')
[staging_key, stage0_uri, stage1_uri, stage2_uri, default_delay, default_jitter, default_profile, default_cert_path, default_port, install_path, server_version, ip_whitelist, ip_blacklist, default_lost_limit, autorun_command, autorun_data, api_token] = configRaw[0]
config = {"version":empire.VERSION, "staging_key":staging_key, "stage0_uri":stage0_uri, "stage1_uri":stage1_uri, "stage2_uri":stage2_uri, "default_delay":default_delay, "default_jitter":default_jitter, "default_profile":default_profile, "default_cert_path":default_cert_path, "default_port":default_port, "install_path":install_path, "server_version":server_version, "ip_whitelist":ip_whitelist, "ip_blacklist":ip_blacklist, "default_lost_limit":default_lost_limit, "autorun_command":autorun_command, "autorun_data":autorun_data, "api_token":api_token}
return jsonify({'config': config})
@app.route('/empire/api/stagers', methods=['GET'])
def get_stagers():
"""
Returns JSON describing all stagers.
"""
stagerInfo = {}
for stagerName,stager in main.stagers.stagers.iteritems():
info = stager.info
info['options'] = stager.options
stagerInfo[stagerName] = info
return jsonify({'stagers': stagerInfo})
@app.route('/empire/api/stagers/<string:stager_name>', methods=['GET'])
def get_stagers_name(stager_name):
"""
Returns JSON describing the specified stager_name passed.
"""
stagerInfo = {}
for stagerName,stager in main.stagers.stagers.iteritems():
if(stagerName == stager_name):
info = stager.info
info['options'] = stager.options
stagerInfo[stagerName] = info
return jsonify({'stagers': stagerInfo})
@app.route('/empire/api/stagers', methods=['POST'])
def generate_stager():
"""
Generates a stager with the supplied config and returns JSON information
describing the generated stager, with 'Output' being the stager output.
Required JSON args:
StagerName - the stager name to generate
Listener - the Listener name to use for the stager
"""
if not request.json or not 'StagerName' in request.json or not 'Listener' in request.json:
abort(400)
stagerName = request.json['StagerName']
listener = request.json['Listener']
if stagerName not in main.stagers.stagers:
return jsonify({'error': 'StagerName invalid'})
if not main.listeners.is_listener_valid(listener):
return jsonify({'error': 'invalid listener ID or name'})
stager = main.stagers.stagers[stagerName]
# set all passed options
for option,values in request.json.iteritems():
if option != 'StagerName':
if(option not in stager.options):
return jsonify({'error': 'Invalid option %s, check capitalization.' %(option)})
stager.options[option]['Value'] = values
# validate stager options
for option,values in stager.options.iteritems():
if values['Required'] and ((not values['Value']) or (values['Value'] == '')):
return jsonify({'error': 'required stager options missing'})
stagerOut = stager.options
stagerOut['Output'] = stager.generate()
return jsonify({stagerName: stagerOut})
@app.route('/empire/api/modules', methods=['GET'])
def get_modules():
"""
Returns JSON describing all currently loaded modules.
"""
moduleInfo = {}
for moduleName,module in main.modules.modules.iteritems():
info = module.info
info['options'] = module.options
moduleInfo[moduleName] = info
return jsonify({'modules': moduleInfo})
@app.route('/empire/api/listeners', methods=['GET'])
def get_listeners():
"""
Returns JSON describing all currently registered listeners.
"""
activeListenersRaw = execute_db_query(conn, 'SELECT * FROM listeners')
activeListeners = {}
for activeListener in activeListenersRaw:
[ID,name,host,port,cert_path,staging_key,default_delay,default_jitter,default_profile,kill_date,working_hours,listener_type,redirect_target,default_lost_limit] = activeListener
activeListeners[name] = {'ID':ID, 'name':name, 'host':host, 'port':port, 'cert_path':cert_path, 'staging_key':staging_key, 'default_delay':default_delay, 'default_jitter':default_jitter, 'default_profile':default_profile, 'kill_date':kill_date, 'working_hours':working_hours, 'listener_type':listener_type, 'redirect_target':redirect_target, 'default_lost_limit':default_lost_limit}
return jsonify({'listeners' : activeListeners})
@app.route('/empire/api/listeners/<string:listener_name>', methods=['GET'])
def get_listener_name(listener_name):
"""
Returns JSON describing the listener specified by listener_name.
"""
activeListenersRaw = execute_db_query(conn, 'SELECT * FROM listeners')
activeListeners = {}
for activeListener in activeListenersRaw:
[ID,name,host,port,cert_path,staging_key,default_delay,default_jitter,default_profile,kill_date,working_hours,listener_type,redirect_target,default_lost_limit] = activeListener
if name == listener_name:
activeListeners[name] = {'ID':ID, 'name':name, 'host':host, 'port':port, 'cert_path':cert_path, 'staging_key':staging_key, 'default_delay':default_delay, 'default_jitter':default_jitter, 'default_profile':default_profile, 'kill_date':kill_date, 'working_hours':working_hours, 'listener_type':listener_type, 'redirect_target':redirect_target, 'default_lost_limit':default_lost_limit}
return jsonify({'listeners' : activeListeners})
@app.route('/empire/api/listeners/<string:listener_name>', methods=['DELETE'])
def kill_listener(listener_name):
"""
Kills the listener specified by listener_name.
"""
if listener_name.lower() == "all":
activeListenersRaw = execute_db_query(conn, 'SELECT * FROM listeners')
for activeListener in activeListenersRaw:
[ID,name,host,port,cert_path,staging_key,default_delay,default_jitter,default_profile,kill_date,working_hours,listener_type,redirect_target,default_lost_limit] = activeListener
main.listeners.shutdown_listener(name)
main.listeners.delete_listener(name)
return jsonify({'result': True})
else:
if listener_name != "" and main.listeners.is_listener_valid(listener_name):
main.listeners.shutdown_listener(listener_name)
main.listeners.delete_listener(listener_name)
return jsonify({'result': True})
else:
return jsonify({'error': 'invalid listener name: %s' %(listener_name)})
@app.route('/empire/api/listeners/options', methods=['GET'])
def get_listener_options():
"""
Returns JSON describing the current listener options.
"""
return jsonify({'ListenerOptions' : main.listeners.options})
@app.route('/empire/api/listeners', methods=['POST'])
def start_listener():
"""
Starts a listener with options supplied in the POST.
"""
# set all passed options
for option,values in request.json.iteritems():
returnVal = main.listeners.set_listener_option(option, values)
if not returnVal:
return jsonify({'error': 'Error setting listener value %s with option %s' %(option, values)})
valid = main.listeners.validate_listener_options()
if not valid:
return jsonify({'error': 'Error validating listener options'})
main.listeners.add_listener_from_config()
return jsonify({'result': True})
@app.route('/empire/api/agents', methods=['GET'])
def get_agents():
"""
Returns JSON describing all currently registered agents.
"""
activeAgentsRaw = execute_db_query(conn, 'SELECT * FROM agents')
activeAgents = {}
for activeAgent in activeAgentsRaw:
[ID, sessionID, listener, name, delay, jitter, external_ip, internal_ip, username, high_integrity, process_name, process_id, hostname, os_details, session_key, checkin_time, lastseen_time, parent, children, servers, uris, old_uris, user_agent, headers, functions, kill_date, working_hours, ps_version, lost_limit, taskings, results] = activeAgent
activeAgents[name] = {"ID":ID, "sessionID":sessionID, "listener":listener, "name":name, "delay":delay, "jitter":jitter, "external_ip":external_ip, "internal_ip":internal_ip, "username":username, "high_integrity":high_integrity, "process_name":process_name, "process_id":process_id, "hostname":hostname, "os_details":os_details, "session_key":session_key, "checkin_time":checkin_time, "lastseen_time":lastseen_time, "parent":parent, "children":children, "servers":servers, "uris":uris, "old_uris":old_uris, "user_agent":user_agent, "headers":headers, "functions":functions, "kill_date":kill_date, "working_hours":working_hours, "ps_version":ps_version, "lost_limit":lost_limit, "taskings":taskings, "results":results}
return jsonify({'agents' : activeAgents})
@app.route('/empire/api/agents/<string:agent_name>', methods=['GET'])
def get_agents_name(agent_name):
"""
Returns JSON describing the agent specified by agent_name.
"""
activeAgentsRaw = execute_db_query(conn, 'SELECT * FROM agents WHERE name=? OR session_id=?', [agent_name, agent_name])
activeAgents = {}
for activeAgent in activeAgentsRaw:
[ID, sessionID, listener, name, delay, jitter, external_ip, internal_ip, username, high_integrity, process_name, process_id, hostname, os_details, session_key, checkin_time, lastseen_time, parent, children, servers, uris, old_uris, user_agent, headers, functions, kill_date, working_hours, ps_version, lost_limit, taskings, results] = activeAgent
activeAgents[name] = {"ID":ID, "sessionID":sessionID, "listener":listener, "name":name, "delay":delay, "jitter":jitter, "external_ip":external_ip, "internal_ip":internal_ip, "username":username, "high_integrity":high_integrity, "process_name":process_name, "process_id":process_id, "hostname":hostname, "os_details":os_details, "session_key":session_key, "checkin_time":checkin_time, "lastseen_time":lastseen_time, "parent":parent, "children":children, "servers":servers, "uris":uris, "old_uris":old_uris, "user_agent":user_agent, "headers":headers, "functions":functions, "kill_date":kill_date, "working_hours":working_hours, "ps_version":ps_version, "lost_limit":lost_limit, "taskings":taskings, "results":results}
return jsonify({'agents' : activeAgents})
@app.route('/empire/api/agents/<string:agent_name>/results', methods=['GET'])
def get_agent_results(agent_name):
"""
Returns JSON describing the agent's results and removes the result field
from the backend database.
"""
agentResults = execute_db_query(conn, 'SELECT results FROM agents WHERE name=? OR session_id=?', [agent_name, agent_name])[0]
if agentResults and agentResults[0] and agentResults[0] != '':
out = json.loads(agentResults[0])
if(out):
agentResults = "\n".join(out)
else:
agentResults = ''
else:
agentResults = ''
execute_db_query(conn, 'UPDATE agents SET results=? WHERE name=? OR session_id=?', ['', agent_name, agent_name])
return jsonify({agent_name : {'Results': agentResults}})
# TODO: add get /name/results to get/clear results from DB
@app.route('/empire/api/agents/<string:agent_name>', methods=['POST'])
def modify_agent(agent_name):
"""
Modifies an agent with name agent_name.
Used for tasking, clearing tasking, setting sleep, renaming, and killing.
"""
if 'Task' in request.json.keys():
if agent_name.lower() == "all":
agent_name = '%'
taskName = request.json['Task']['TaskName']
task = request.json['Task']['Task']
# get existing agent taskings
agentTasks = execute_db_query(conn, 'SELECT taskings FROM agents WHERE name like ? OR session_id like ?', [agent_name, agent_name])[0]
if(agentTasks and agentTasks[0]):
agentTasks = json.loads(agentTasks[0])
else:
agentTasks = []
# append our new json-ified task and update the backend
agentTasks.append([taskName, task])
execute_db_query(conn, "UPDATE agents SET taskings=? WHERE name=? OR session_id=?", [json.dumps(agentTasks), agent_name, agent_name])
timeStamp = strftime("%Y-%m-%d %H:%M:%S", localtime())
execute_db_query(conn, "INSERT INTO reporting (name,event_type,message,time_stamp) VALUES (?,?,?,?)", (agent_name,"task",taskName + " - " + task[0:50], timeStamp ))
return jsonify({'AgentName':agent_name, 'TaskType':'Task', 'TaskName':taskName, 'Task':task})
elif 'Clear' in request.json.keys():
if agent_name.lower() == "all":
agent_name = '%'
execute_db_query(conn, "UPDATE agents SET taskings=? WHERE name like ? OR session_id like ?", ['', agent_name, agent_name])
return jsonify({'AgentName':agent_name, 'TaskType':'Clear', 'TaskName':'', 'Task':''})
elif 'Rename' in request.json.keys():
oldName = request.json['Rename']['OldName']
newName = request.json['Rename']['NewName']
try:
main.agents.rename_agent(oldName, newName)
return jsonify({'result': True})
except:
return jsonify({'error': 'error in renaming %s to %s' %(oldName, newName)})
return jsonify({'error':'error in tasking agent %s' % (agent_name)})
@app.route('/empire/api/agents/<string:agent_name>', methods=['DELETE'])
def remove_agent(agent_name):
"""
Removes an agent from the controller specified by agent_name.
WARNING: doesn't kill the agent first! Ensure the agent is dead.
"""
if agent_name.lower() == "all":
agent_name = '%'
agentsRaw = execute_db_query(conn, 'SELECT * FROM agents WHERE name like ? OR session_id like ?', [agent_name, agent_name])
removedAgents = {}
for agent in agentsRaw:
[ID, sessionID, listener, name, delay, jitter, external_ip, internal_ip, username, high_integrity, process_name, process_id, hostname, os_details, session_key, checkin_time, lastseen_time, parent, children, servers, uris, old_uris, user_agent, headers, functions, kill_date, working_hours, ps_version, lost_limit, taskings, results] = agent
execute_db_query(conn, "DELETE FROM agents WHERE session_id LIKE ?", [sessionID])
removedAgents[name] = {"ID":ID, "sessionID":sessionID, "listener":listener, "name":name, "delay":delay, "jitter":jitter, "external_ip":external_ip, "internal_ip":internal_ip, "username":username, "high_integrity":high_integrity, "process_name":process_name, "process_id":process_id, "hostname":hostname, "os_details":os_details, "session_key":session_key, "checkin_time":checkin_time, "lastseen_time":lastseen_time, "parent":parent, "children":children, "servers":servers, "uris":uris, "old_uris":old_uris, "user_agent":user_agent, "headers":headers, "functions":functions, "kill_date":kill_date, "working_hours":working_hours, "ps_version":ps_version, "lost_limit":lost_limit, "taskings":taskings, "results":results}
return jsonify({'RemovedAgents': removedAgents})
@app.route('/empire/api/agents/stale', methods=['DELETE'])
def remove_stale_agent():
"""
Removes stale agents from the controller.
WARNING: doesn't kill the agent first! Ensure the agent is dead.
"""
agentsRaw = execute_db_query(conn, 'SELECT * FROM agents')
removedAgents = {}
for agent in agentsRaw:
[ID, sessionID, listener, name, delay, jitter, external_ip, internal_ip, username, high_integrity, process_name, process_id, hostname, os_details, session_key, checkin_time, lastseen_time, parent, children, servers, uris, old_uris, user_agent, headers, functions, kill_date, working_hours, ps_version, lost_limit, taskings, results] = agent
intervalMax = (delay + delay * jitter)+30
# get the agent last check in time
agentTime = time.mktime(time.strptime(lastseen_time, "%Y-%m-%d %H:%M:%S"))
if agentTime < time.mktime(time.localtime()) - intervalMax:
execute_db_query(conn, "DELETE FROM agents WHERE session_id LIKE ?", [sessionID])
removedAgents[name] = {"ID":ID, "sessionID":sessionID, "listener":listener, "name":name, "delay":delay, "jitter":jitter, "external_ip":external_ip, "internal_ip":internal_ip, "username":username, "high_integrity":high_integrity, "process_name":process_name, "process_id":process_id, "hostname":hostname, "os_details":os_details, "session_key":session_key, "checkin_time":checkin_time, "lastseen_time":lastseen_time, "parent":parent, "children":children, "servers":servers, "uris":uris, "old_uris":old_uris, "user_agent":user_agent, "headers":headers, "functions":functions, "kill_date":kill_date, "working_hours":working_hours, "ps_version":ps_version, "lost_limit":lost_limit, "taskings":taskings, "results":results}
return jsonify({'RemovedAgents': removedAgents})
@app.route('/empire/api/reporting', methods=['GET'])
def get_reporting():
"""
Returns JSON describing the reporting events from the backend database.
"""
reportingRaw = execute_db_query(conn, 'SELECT * FROM reporting')
reportingEvents = {}
for reportingEvent in reportingRaw:
[ID, name, eventType, message, timestamp] = reportingEvent
reportingEvents[ID] = {"ID":ID, "name":name, "event_type":eventType, "message":message, "timestamp":timestamp}
return jsonify({'reporting' : reportingEvents})
@app.route('/empire/api/reporting/agent/<string:reporting_agent>', methods=['GET'])
def get_reporting_agent(reporting_agent):
"""
Returns JSON describing the reporting events from the backend database for
the agent specified by reporting_agent.
"""
# first resolve the supplied name to a sessionID
results = execute_db_query(conn, 'SELECT session_id FROM agents WHERE name=?', [reporting_agent])
if(results):
sessionID = results[0][0]
else:
return jsonify({'reporting' : ''})
reportingRaw = execute_db_query(conn, 'SELECT * FROM reporting WHERE name=?', [sessionID])
reportingEvents = {}
for reportingEvent in reportingRaw:
[ID, name, eventType, message, timestamp] = reportingEvent
reportingEvents[ID] = {"ID":ID, "name":name, "event_type":eventType, "message":message, "timestamp":timestamp}
return jsonify({'reporting' : reportingEvents})
@app.route('/empire/api/reporting/type/<string:event_type>', methods=['GET'])
def get_reporting_type(event_type):
"""
Returns JSON describing the reporting events from the backend database for
the event type specified by event_type.
"""
reportingRaw = execute_db_query(conn, 'SELECT * FROM reporting WHERE event_type=?', [event_type])
reportingEvents = {}
for reportingEvent in reportingRaw:
[ID, name, eventType, message, timestamp] = reportingEvent
reportingEvents[ID] = {"ID":ID, "name":name, "event_type":eventType, "message":message, "timestamp":timestamp}
return jsonify({'reporting' : reportingEvents})
@app.route('/empire/api/reporting/msg/<string:msg>', methods=['GET'])
def get_reporting_msg(msg):
"""
Returns JSON describing the reporting events from the backend database for
the any messages with *msg* specified by msg.
"""
reportingRaw = execute_db_query(conn, "SELECT * FROM reporting WHERE message like ?", ['%'+msg+'%'])
reportingEvents = {}
for reportingEvent in reportingRaw:
[ID, name, eventType, message, timestamp] = reportingEvent
reportingEvents[ID] = {"ID":ID, "name":name, "event_type":eventType, "message":message, "timestamp":timestamp}
return jsonify({'reporting' : reportingEvents})
@app.route('/empire/api/admin/shutdown', methods=['GET', 'POST', 'PUT'])
def shutdown_server():
"""
Signal a shutdown for the Flask server and any Empire server.
"""
shutdown_server()
return jsonify({'result': True})
if not os.path.exists('./data/empire.pem'):
print "[!] Error: cannot find certificate ./data/empire.pem"
sys.exit()
def shutdown_server():
"""
Shut down the Flask server and any Empire server gracefully.
"""
if suppress:
# repair stdout
sys.stdout.close()
sys.stdout = oldStdout
print "\n[*]Shutting down Empire RESTful API"
func = request.environ.get('werkzeug.server.shutdown')
if func is not None:
func()
if conn: conn.close()
if startEmpire:
print "Shutting down the Empire instance"
main.shutdown()
# override the keyboardinterrupt signal handler so we can gracefully shut everything down
def signal_handler(signal, frame):
with app.test_request_context():
shutdown_server()
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
# wrap the Flask connection in SSL and start it
context = ('./data/empire.pem', './data/empire.pem')
app.run(host='0.0.0.0', port=port, ssl_context=context, threaded=True)
if __name__ == '__main__':
@ -19,11 +643,25 @@ if __name__ == '__main__':
parser.add_argument('-o', '--stager-options', nargs='*', help="Supply options to set for a stager in OPTION=VALUE format. Lists options if nothing is specified.")
parser.add_argument('-l', '--listener', nargs='?', const="list", help='Display listener options. Displays all listeners if nothing is specified.')
parser.add_argument('-v', '--version', action='store_true', help='Display current Empire version.')
parser.add_argument('--rest', action='store_true', help='Run the Empire RESTful API.')
parser.add_argument('--headless', action='store_true', help='Run Empire and the RESTful API headless without the usual interface.')
args = parser.parse_args()
if args.version:
print empire.VERSION
elif args.rest:
# start just the RESTful API
start_restful_api(startEmpire=False, suppress=False, port=1337)
elif args.headless:
# start an Empire instance and RESTful API and suppress output
start_restful_api(startEmpire=True, suppress=True, port=1337)
else:
# normal execution
main = empire.MainMenu(args=args)
main.cmdloop()
sys.exit()

View File

@ -12,12 +12,7 @@ the response types are handled as appropriate.
"""
from pydispatch import dispatcher
import sqlite3
import pickle
import base64
import string
import os
import iptools
import sqlite3, pickle, base64, string, os, iptools, json
# Empire imports
import encryption
@ -40,31 +35,28 @@ class Agents:
self.installPath = self.mainMenu.installPath
self.args = args
# internal agent dictionary for the client's session key and tasking/result sets
# self.agents[sessionID] = [ clientSessionKey,
# [tasking1, tasking2, ...],
# [results1, results2, ...],
# [tab-completable function names for a script-import],
# current URIs,
# old URIs
# ]
# internal agent dictionary for the client's session key, funcions, and URI sets
# this is done to prevent database reads for extremely common tasks (like checking tasking URI existence)
# self.agents[sessionID] = { 'sessionKey' : clientSessionKey,
# 'functions' : [tab-completable function names for a script-import],
# 'currentURIs' : [current URIs used by the client],
# 'oldURIs' : [old URIs used by the client]
# }
self.agents = {}
# reinitialize any agents that already exist in the database
agentIDs = self.get_agent_ids()
for agentID in agentIDs:
sessionKey = self.get_agent_session_key(agentID)
functions = self.get_agent_functions_database(agentID)
self.agents[agentID] = {}
self.agents[agentID]['sessionKey'] = self.get_agent_session_key(agentID)
self.agents[agentID]['functions'] = self.get_agent_functions_database(agentID)
# get the current and previous URIs for tasking
uris,old_uris = self.get_agent_uris(agentID)
if not old_uris:
old_uris = ""
# [sessionKey, taskings, results, stored_functions, tasking uris, old uris]
self.agents[agentID] = [sessionKey, [], [], functions, uris, old_uris]
currentURIs,oldURIs = self.get_agent_uris(agentID)
if not oldURIs: oldURIs = ''
self.agents[agentID]['currentURIs'] = currentURIs
self.agents[agentID]['oldURIs'] = oldURIs
# pull out common configs from the main menu object in empire.py
self.ipWhiteList = self.mainMenu.ipWhiteList
@ -92,13 +84,13 @@ class Agents:
# remove the agent from the internal cache
self.agents.pop(sessionID, None)
# remove an agent from the database
# remove the agent from the database
cur = self.conn.cursor()
cur.execute("DELETE FROM agents WHERE session_id like ?", [sessionID])
cur.execute("DELETE FROM agents WHERE session_id LIKE ?", [sessionID])
cur.close()
def add_agent(self, sessionID, externalIP, delay, jitter, profile, killDate, workingHours,lostLimit):
def add_agent(self, sessionID, externalIP, delay, jitter, profile, killDate, workingHours, lostLimit):
"""
Add an agent to the internal cache and database.
"""
@ -133,7 +125,8 @@ class Agents:
# initialize the tasking/result buffers along with the client session key
sessionKey = self.get_agent_session_key(sessionID)
self.agents[sessionID] = [sessionKey, [],[],[], requestUris, ""]
# TODO: should oldURIs be a string or list?
self.agents[sessionID] = {'sessionKey':sessionKey, 'functions':[], 'currentURIs':requestUris, 'oldURIs': ''}
# report the initial checkin in the reporting database
cur = self.conn.cursor()
@ -159,7 +152,7 @@ class Agents:
"""
for option,values in self.agents.iteritems():
if resource in values[-1] or resource in values [-2]:
if resource in values['currentURIs'] or resource in values['oldURIs']:
return True
return False
@ -283,7 +276,6 @@ class Agents:
#
###############################################################
def get_agents(self):
"""
Return all active agents from the database.
@ -388,7 +380,7 @@ class Agents:
if ps_version and ps_version != None:
if type(ps_version) is str:
return sessionKey
return ps_version
else:
return ps_version[0]
@ -416,7 +408,7 @@ class Agents:
def get_agent_results(self, sessionID):
"""
Get the agent's results buffer.
Return agent results from the backend database.
"""
agentName = sessionID
@ -426,11 +418,21 @@ class Agents:
if nameid : sessionID = nameid
if sessionID not in self.agents:
print helpers.color("[!] Agent " + str(agentName) + " not active.")
print helpers.color("[!] Agent %s not active." %(agentName))
else:
results = self.agents[sessionID][2]
self.agents[sessionID][2] = []
return "\n".join(results)
cur = self.conn.cursor()
cur.execute("SELECT results FROM agents WHERE session_id=?", [sessionID])
results = cur.fetchone()
cur.execute("UPDATE agents SET results = ? WHERE session_id=?", ['',sessionID])
if results and results[0] and results[0] != '':
out = json.loads(results[0])
if(out):
return "\n".join(out)
else:
return ''
cur.close()
def get_agent_id(self, name):
@ -474,6 +476,7 @@ class Agents:
else:
return None
def get_agent_functions(self, sessionID):
"""
Get the tab-completable functions for an agent.
@ -484,7 +487,7 @@ class Agents:
if nameid : sessionID = nameid
if sessionID in self.agents:
return self.agents[sessionID][3]
return self.agents[sessionID]['functions']
else:
return []
@ -552,6 +555,7 @@ class Agents:
except:
pass
###############################################################
#
# Methods to update agent information fields.
@ -568,7 +572,21 @@ class Agents:
if nameid : sessionID = nameid
if sessionID in self.agents:
self.agents[sessionID][2].append(results)
cur = self.conn.cursor()
# get existing agent results
cur.execute("SELECT results FROM agents WHERE session_id LIKE ?", [sessionID])
agentResults = cur.fetchone()
if(agentResults and agentResults[0]):
agentResults = json.loads(agentResults[0])
else:
agentResults = []
agentResults.append(results)
cur.execute("UPDATE agents SET results = ? WHERE session_id=?", [json.dumps(agentResults),sessionID])
cur.close()
else:
dispatcher.send("[!] Non-existent agent " + str(sessionID) + " returned results", sender="Agents")
@ -615,8 +633,8 @@ class Agents:
cur = self.conn.cursor()
# get the existing URIs from the agent and save them to
# the old_uris field, so we can ensure that it can check in
# to get the new URI tasking... bootstrapping problem :)
# the old_uris field, so we can ensure that it can check in
# to get the new URI tasking... bootstrapping problem :)
cur.execute("SELECT uris FROM agents WHERE session_id=?", [sessionID])
oldURIs = cur.fetchone()[0]
@ -624,9 +642,8 @@ class Agents:
print helpers.color("[!] Agent " + agentName + " not active.")
else:
# update the URIs in the cache
self.agents[sessionID][-1] = oldURIs
# new URIs
self.agents[sessionID][-2] = parts[0]
self.agents[sessionID]['oldURIs'] = oldURIs
self.agents[sessionID]['currentURIs'] = parts[0]
# if no additional headers
if len(parts) == 2:
@ -696,7 +713,7 @@ class Agents:
if nameid : sessionID = nameid
if sessionID in self.agents:
self.agents[sessionID][3] = functions
self.agents[sessionID]['functions'] = functions
functions = ",".join(functions)
@ -756,8 +773,22 @@ class Agents:
print helpers.color("[!] Agent " + str(agentName) + " not active.")
else:
if sessionID:
dispatcher.send("[*] Tasked " + str(sessionID) + " to run " + str(taskName), sender="Agents")
self.agents[sessionID][1].append([taskName, task])
# get existing agent taskings
cur = self.conn.cursor()
cur.execute("SELECT taskings FROM agents WHERE session_id=?", [sessionID])
agentTasks = cur.fetchone()
if(agentTasks and agentTasks[0]):
agentTasks = json.loads(agentTasks[0])
else:
agentTasks = []
# append our new json-ified task and update the backend
agentTasks.append([taskName, task])
cur.execute("UPDATE agents SET taskings=? WHERE session_id=?", [json.dumps(agentTasks),sessionID])
# write out the last tasked script to "LastTask.ps1" if in debug mode
if self.args and self.args.debug:
@ -766,8 +797,7 @@ class Agents:
f.close()
# report the agent tasking in the reporting database
cur = self.conn.cursor()
cur.execute("INSERT INTO reporting (name,event_type,message,time_stamp) VALUES (?,?,?,?)", (sessionID,"task",taskName + " - " + task[0:30],helpers.get_datetime()))
cur.execute("INSERT INTO reporting (name,event_type,message,time_stamp) VALUES (?,?,?,?)", (sessionID,"task",taskName + " - " + task[0:50],helpers.get_datetime()))
cur.close()
@ -786,47 +816,37 @@ class Agents:
print helpers.color("[!] Agent " + str(agentName) + " not active.")
return []
else:
tasks = self.agents[sessionID][1]
# clear the taskings out
self.agents[sessionID][1] = []
cur = self.conn.cursor()
cur.execute("SELECT taskings FROM agents WHERE session_id=?", [sessionID])
tasks = cur.fetchone()
if(tasks and tasks[0]):
tasks = json.loads(tasks[0])
# clear the taskings out
cur.execute("UPDATE agents SET taskings=? WHERE session_id=?", ['', sessionID])
else:
tasks = []
cur.close()
return tasks
def get_agent_task(self, sessionID):
"""
Pop off the agent's top task.
"""
# see if we were passed a name instead of an ID
nameid = self.get_agent_id(sessionID)
if nameid : sessionID = nameid
try:
# pop the first task off the front of the stack
return self.agents[sessionID][1].pop(0)
except:
[]
def clear_agent_tasks(self, sessionID):
"""
Clear out the agent's task buffer.
Clear out one (or all) agent's task buffer.
"""
agentName = sessionID
if sessionID.lower() == "all":
for option,values in self.agents.iteritems():
self.agents[option][1] = []
else:
# see if we were passed a name instead of an ID
nameid = self.get_agent_id(sessionID)
if nameid : sessionID = nameid
sessionID = '%'
if sessionID not in self.agents:
print helpers.color("[!] Agent " + agentName + " not active.")
else:
self.agents[sessionID][1] = []
cur = self.conn.cursor()
cur.execute("UPDATE agents SET taskings=? WHERE session_id LIKE ?", ['', sessionID])
cur.close()
def handle_agent_response(self, sessionID, responseName, data):
@ -1122,7 +1142,7 @@ class Agents:
allTaskPackets += taskPacket
# get the session key for the agent
sessionKey = self.agents[sessionID][0]
sessionKey = self.agents[sessionID]['sessionKey']
# encrypt the tasking packets with the agent's session key
encryptedData = encryption.aes_encrypt_then_mac(sessionKey, allTaskPackets)
@ -1199,7 +1219,7 @@ class Agents:
else:
# extract the agent's session key
sessionKey = self.agents[sessionID][0]
sessionKey = self.agents[sessionID]['sessionKey']
try:
# verify, decrypt and depad the packet
@ -1241,7 +1261,7 @@ class Agents:
return (404, "")
except Exception as e:
dispatcher.send("[!] Error processing result packet from "+str(sessionID), sender="Agents")
dispatcher.send("[!] Error processing result packet from %s : %s" %(str(sessionID),e), sender="Agents")
return (404, "")
@ -1330,7 +1350,7 @@ class Agents:
lostLimit = config[11]
# get the session key for the agent
sessionKey = self.agents[sessionID][0]
sessionKey = self.agents[sessionID]['sessionKey']
try:
# decrypt and parse the agent's sysinfo checkin

View File

@ -9,7 +9,7 @@ menu loops.
"""
# make version for Empire
VERSION = "1.4.4"
VERSION = "1.4.6"
from pydispatch import dispatcher
@ -39,7 +39,7 @@ class NavListeners(Exception): pass
class MainMenu(cmd.Cmd):
def __init__(self, args=None):
def __init__(self, args=None, restAPI=False):
cmd.Cmd.__init__(self)
@ -49,42 +49,8 @@ class MainMenu(cmd.Cmd):
# empty database object
self.conn = self.database_connect()
# grab the universal install path
# TODO: combine these into one query
cur = self.conn.cursor()
cur.execute("SELECT install_path FROM config")
self.installPath = cur.fetchone()[0]
cur.close()
# pull out the stage0 uri
cur = self.conn.cursor()
cur.execute("SELECT stage0_uri FROM config")
self.stage0 = cur.fetchone()[0]
cur.close()
# pull out the stage1 uri
cur = self.conn.cursor()
cur.execute("SELECT stage1_uri FROM config")
self.stage1 = cur.fetchone()[0]
cur.close()
# pull out the stage2 uri
cur = self.conn.cursor()
cur.execute("SELECT stage2_uri FROM config")
self.stage2 = cur.fetchone()[0]
cur.close()
# pull out the IP whitelist and create it, if applicable
cur = self.conn.cursor()
cur.execute("SELECT ip_whitelist FROM config")
self.ipWhiteList = helpers.generate_ip_list(cur.fetchone()[0])
cur.close()
# pull out the IP blacklist and create it, if applicable
cur = self.conn.cursor()
cur.execute("SELECT ip_blacklist FROM config")
self.ipBlackList = helpers.generate_ip_list(cur.fetchone()[0])
cur.close()
# pull out some common configuration information
(self.installPath, self.stage0, self.stage1, self.stage2, self.ipWhiteList, self.ipBlackList) = helpers.get_config('install_path,stage0_uri,stage1_uri,stage2_uri,ip_whitelist,ip_blacklist')
# instantiate the agents, listeners, and stagers objects
self.agents = agents.Agents(self, args=args)
@ -94,7 +60,6 @@ class MainMenu(cmd.Cmd):
self.credentials = credentials.Credentials(self, args=args)
# make sure all the references are passed after instantiation
# TODO: replace these with self?
self.agents.listeners = self.listeners
self.agents.modules = self.modules
self.agents.stagers = self.stagers
@ -116,8 +81,9 @@ class MainMenu(cmd.Cmd):
self.args = args
self.handle_args()
# start everything up normally
self.startup()
# start everything up normally if the RESTful API isn't being launched
if not restAPI:
self.startup()
def handle_args(self):
@ -252,7 +218,7 @@ class MainMenu(cmd.Cmd):
else:
num_modules = 0
num_listeners = self.listeners.listeners
num_listeners = self.listeners.get_listeners()
if(num_listeners):
num_listeners = len(num_listeners)
else:
@ -407,6 +373,7 @@ class MainMenu(cmd.Cmd):
except Exception as e:
raise e
def do_usemodule(self, line):
"Use an Empire module."
if line not in self.modules.modules:
@ -418,6 +385,7 @@ class MainMenu(cmd.Cmd):
except Exception as e:
raise e
def do_searchmodule(self, line):
"Search Empire module names/descriptions."
self.modules.search_modules(line.strip())
@ -748,7 +716,7 @@ class AgentsMenu(cmd.Cmd):
# traceback.print_stack()
# print a nicely formatted help menu
# stolen/adapted from recon-ng
# stolen/adapted from recon-ng
def print_topics(self, header, cmds, cmdlen, maxcol):
if cmds:
self.stdout.write("%s\n"%str(header))
@ -763,8 +731,13 @@ class AgentsMenu(cmd.Cmd):
def do_back(self, line):
"Return back a menu."
return True
"Go back to the main menu."
raise NavMain()
def do_listeners(self, line):
"Jump to the listeners menu."
raise NavListeners()
def do_main(self, line):
@ -796,8 +769,6 @@ class AgentsMenu(cmd.Cmd):
# 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
oldname = parts[0]
newname = parts[1]
self.mainMenu.agents.rename_agent(parts[0], parts[1])
else:
print helpers.color("[!] Please enter an agent name and new name")
@ -1107,11 +1078,6 @@ class AgentsMenu(cmd.Cmd):
print helpers.color("[!] Invalid agent name")
def do_listeners(self, line):
"Jump to the listeners menu."
raise NavListeners()
def do_usestager(self, line):
"Use an Empire stager."
@ -1334,9 +1300,9 @@ class AgentMenu(cmd.Cmd):
return True
def do_main(self, line):
"Go back to the main menu."
raise NavMain()
def do_agents(self, line):
"Jump to the Agents menu."
raise NavAgents()
def do_listeners(self, line):
@ -1344,9 +1310,9 @@ class AgentMenu(cmd.Cmd):
raise NavListeners()
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_help(self, *args):
@ -1538,7 +1504,6 @@ class AgentMenu(cmd.Cmd):
self.mainMenu.agents.save_agent_log(self.sessionID, msg)
def do_shell(self, line):
"Task an agent to use a shell command."
@ -2042,11 +2007,6 @@ class ListenerMenu(cmd.Cmd):
def emptyline(self): pass
def do_exit(self, line):
"Exit Empire."
raise KeyboardInterrupt
def do_list(self, line):
"List all active listeners (or agents)."
@ -2059,8 +2019,13 @@ class ListenerMenu(cmd.Cmd):
def do_back(self, line):
"Go back a menu."
return True
"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):
@ -2068,6 +2033,11 @@ class ListenerMenu(cmd.Cmd):
raise NavMain()
def do_exit(self, line):
"Exit Empire."
raise KeyboardInterrupt
def do_set(self, line):
"Set a listener option."
parts = line.split(" ")
@ -2158,11 +2128,6 @@ class ListenerMenu(cmd.Cmd):
self.do_execute(line)
def do_agents(self, line):
"Jump to the Agents menu."
raise NavAgents()
def do_usestager(self, line):
"Use an Empire stager."
@ -2370,6 +2335,11 @@ class ModuleMenu(cmd.Cmd):
self.stdout.write("\n")
def do_back(self, line):
"Go back a menu."
return True
def do_agents(self, line):
"Jump to the Agents menu."
raise NavAgents()
@ -2380,16 +2350,16 @@ class ModuleMenu(cmd.Cmd):
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_main(self, line):
"Return to the main menu."
return True
def do_list(self, line):
"Lists all active agents (or listeners)."
@ -2422,16 +2392,6 @@ class ModuleMenu(cmd.Cmd):
messages.display_module(self.moduleName, self.module)
def do_back(self, line):
"Return to the main menu."
return True
def do_main(self, line):
"Go back to the main menu."
raise NavMain()
def do_set(self, line):
"Set a module option."
@ -2703,14 +2663,29 @@ class StagerMenu(cmd.Cmd):
self.stdout.write("\n")
def do_exit(self, line):
"Exit Empire."
raise KeyboardInterrupt
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):
"Return to the main menu."
return True
"Go back to the main menu."
raise NavMain()
def do_exit(self, line):
"Exit Empire."
raise KeyboardInterrupt
def do_list(self, line):
@ -2734,16 +2709,6 @@ class StagerMenu(cmd.Cmd):
messages.display_stager(self.stagerName, self.stager)
def do_back(self, line):
"Return to the main menu."
return True
def do_main(self, line):
"Go back to the main menu."
raise NavMain()
def do_set(self, line):
"Set a stager option."
@ -2826,7 +2791,6 @@ class StagerMenu(cmd.Cmd):
def do_execute(self, line):
"Generate/execute the given Empire stager."
self.do_generate(line)
@ -2862,13 +2826,3 @@ class StagerMenu(cmd.Cmd):
mline = line.partition(' ')[2]
offs = len(mline) - len(text)
return [s[offs:] for s in options if s.startswith(mline)]
def do_agents(self, line):
"Jump to the Agents menu."
raise NavAgents()
def do_listeners(self, line):
"Jump to the listeners menu."
raise NavListeners()

View File

@ -7,18 +7,9 @@ randomized stagers.
"""
import re, string, commands, base64, binascii, sys, os, socket, sqlite3, iptools
from time import localtime, strftime
from Crypto.Random import random
import re
import string
import commands
import base64
import binascii
import sys
import os
import socket
import sqlite3
import iptools
###############################################################
@ -501,7 +492,7 @@ def get_config(fields):
conn.isolation_level = None
cur = conn.cursor()
cur.execute("SELECT "+fields+" FROM config")
cur.execute("SELECT %s FROM config" %(fields))
results = cur.fetchone()
cur.close()
conn.close()
@ -622,14 +613,6 @@ def uniquify_tuples(tuples):
return [item for item in tuples if "%s%s%s%s"%(item[0],item[1],item[2],item[3]) not in seen and not seen.add("%s%s%s%s"%(item[0],item[1],item[2],item[3]))]
def urldecode(url):
"""
URL decode a string.
"""
rex=re.compile('%([0-9a-hA-H][0-9a-hA-H])',re.M)
return rex.sub(htc,url)
def decode_base64(data):
"""
Try to decode a base64 string.

View File

@ -111,17 +111,18 @@ class RequestHandler(BaseHTTPRequestHandler):
dispatcher.send("[*] Post to "+resource+" from "+str(sessionID)+" at "+clientIP, sender="HttpHandler")
# read in the length of the POST data
length = int(self.headers.getheader('content-length'))
postData = self.rfile.read(length)
if self.headers.getheader('content-length'):
length = int(self.headers.getheader('content-length'))
postData = self.rfile.read(length)
# get the appropriate response for this agent
(code, responsedata) = self.server.agents.process_post(self.server.server_port, clientIP, sessionID, resource, postData)
# get the appropriate response for this agent
(code, responsedata) = self.server.agents.process_post(self.server.server_port, clientIP, sessionID, resource, postData)
# write the response out
self.send_response(code)
self.end_headers()
self.wfile.write(responsedata)
self.wfile.flush()
# write the response out
self.send_response(code)
self.end_headers()
self.wfile.write(responsedata)
self.wfile.flush()
# self.wfile.close() # causes an error with HTTP comms
# supress all the stupid default stdout/stderr output

View File

@ -200,12 +200,15 @@ class Listeners:
else:
self.options['Port']['Value'] = "80"
return True
elif option == "CertPath":
self.options[option]['Value'] = value
host = self.options["Host"]['Value']
# if we're setting a SSL cert path, but the host is specific at http
if host.startswith("http:"):
self.options["Host"]['Value'] = self.options["Host"]['Value'].replace("http:", "https:")
return True
elif option == "Port":
self.options[option]['Value'] = value
@ -214,11 +217,13 @@ class Listeners:
parts = host.split(":")
if len(parts) == 2 or len(parts) == 3:
self.options["Host"]['Value'] = parts[0] + ":" + parts[1] + ":" + str(value)
return True
elif option == "StagingKey":
# if the staging key isn't 32 characters, assume we're md5 hashing it
if len(value) != 32:
self.options[option]['Value'] = hashlib.md5(value).hexdigest()
return True
elif option in self.options:
@ -228,9 +233,11 @@ class Listeners:
# set the profile for hop.php for hop
parts = self.options['DefaultProfile']['Value'].split("|")
self.options['DefaultProfile']['Value'] = "/hop.php|" + "|".join(parts[1:])
return True
else:
print helpers.color("[!] Error: invalid option name")
return False
def get_listener_options(self):
"""
@ -404,7 +411,7 @@ class Listeners:
if(listenerId):
cur = self.conn.cursor()
cur.execute('SELECT host,port,cert_path,staging_key,default_delay,default_jitter,default_profile,kill_date,working_hours,listener_type,redirect_target,default_lost_limit FROM listeners WHERE id=? or name=? limit 1', [listenerID, listenerID])
cur.execute('SELECT host,port,cert_path,staging_key,default_delay,default_jitter,default_profile,kill_date,working_hours,listener_type,redirect_target,default_lost_limit FROM listeners WHERE id=? or name=? limit 1', [listenerId, listenerId])
stagingInformation = cur.fetchone()
cur.close()

View File

@ -124,7 +124,7 @@ def agent_print (agents):
print " --------- ----------- ------------ --------- ------- ----- --------------------"
for agent in agents:
[ID, sessionID, listener, name, delay, jitter, external_ip, internal_ip, username, high_integrity, process_name, process_id, hostname, os_details, session_key, checkin_time, lastseen_time, parent, children, servers, uris, old_uris, user_agent, headers, functions, kill_date, working_hours, ps_version, lost_limit] = agent
[ID, sessionID, listener, name, delay, jitter, external_ip, internal_ip, username, high_integrity, process_name, process_id, hostname, os_details, session_key, checkin_time, lastseen_time, parent, children, servers, uris, old_uris, user_agent, headers, functions, kill_date, working_hours, ps_version, lost_limit, taskings, results] = agent
if str(high_integrity) == "1":
# add a * to the username if it's high integrity
username = "*" + username
@ -160,7 +160,7 @@ def display_agent(agent):
"""
# extract out database fields.
keys = ["ID", "sessionID", "listener", "name", "delay", "jitter", "external_ip", "internal_ip", "username", "high_integrity", "process_name", "process_id", "hostname", "os_details", "session_key", "checkin_time", "lastseen_time", "parent", "children", "servers", "uris", "old_uris", "user_agent", "headers", "functions", "kill_date", "working_hours", "ps_version", "lost_limit"]
keys = ["ID", "sessionID", "listener", "name", "delay", "jitter", "external_ip", "internal_ip", "username", "high_integrity", "process_name", "process_id", "hostname", "os_details", "session_key", "checkin_time", "lastseen_time", "parent", "children", "servers", "uris", "old_uris", "user_agent", "headers", "functions", "kill_date", "working_hours", "ps_version", "lost_limit", "takings", "results"]
print helpers.color("\n[*] Agent info:\n")
@ -168,7 +168,7 @@ def display_agent(agent):
agentInfo = dict(zip(keys, agent))
for key in agentInfo:
if key != "functions":
if key != "functions" and key != "takings" and key != "results":
print "\t%s\t%s" % (helpers.color('{0: <16}'.format(key), "blue"), wrap_string(agentInfo[key], width=70))
print ""

View File

@ -14,6 +14,7 @@ if lsb_release -d | grep -q "Fedora"; then
pip install pycrypto
pip install iptools
pip install pydispatcher
pip install flask
elif lsb_release -d | grep -q "Kali"; then
Release=Kali
apt-get install python-dev
@ -23,6 +24,7 @@ elif lsb_release -d | grep -q "Kali"; then
pip install pycrypto
pip install iptools
pip install pydispatcher
pip install flask
elif lsb_release -d | grep -q "Ubuntu"; then
Release=Ubuntu
apt-get install python-dev
@ -31,6 +33,7 @@ elif lsb_release -d | grep -q "Ubuntu"; then
pip install pycrypto
pip install iptools
pip install pydispatcher
pip install flask
else
echo "Unknown distro - Debian/Ubuntu Fallback"
apt-get install python-dev
@ -39,6 +42,7 @@ else
pip install pycrypto
pip install iptools
pip install pydispatcher
pip install flask
fi
# set up the database schema

View File

@ -104,11 +104,12 @@ c.execute('''CREATE TABLE config (
"ip_blacklist" text,
"default_lost_limit" integer,
"autorun_command" text,
"autorun_data" text
"autorun_data" text,
"api_token" text
)''')
# kick off the config component of the database
c.execute("INSERT INTO config VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", (STAGING_KEY,STAGE0_URI,STAGE1_URI,STAGE2_URI,DEFAULT_DELAY,DEFAULT_JITTER,DEFAULT_PROFILE,DEFAULT_CERT_PATH,DEFAULT_PORT,INSTALL_PATH,SERVER_VERSION,IP_WHITELIST,IP_BLACKLIST, DEFAULT_LOST_LIMIT, "", ""))
c.execute("INSERT INTO config VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?, ?)", (STAGING_KEY,STAGE0_URI,STAGE1_URI,STAGE2_URI,DEFAULT_DELAY,DEFAULT_JITTER,DEFAULT_PROFILE,DEFAULT_CERT_PATH,DEFAULT_PORT,INSTALL_PATH,SERVER_VERSION,IP_WHITELIST,IP_BLACKLIST, DEFAULT_LOST_LIMIT, "", "", ""))
c.execute('''CREATE TABLE "agents" (
"id" integer PRIMARY KEY,
@ -139,7 +140,9 @@ c.execute('''CREATE TABLE "agents" (
"kill_date" text,
"working_hours" text,
"ps_version" text,
"lost_limit" integer
"lost_limit" integer,
"taskings" text,
"results" text
)''')
c.execute('''CREATE TABLE "listeners" (