Land #9151, mettle extension support + sniffer module

MS-2855/keylogger-mettle-extension
Brent Cook 2017-12-18 21:49:40 -06:00
commit 9f144ce8d4
No known key found for this signature in database
GPG Key ID: 1FFAA0B24B708F96
50 changed files with 215 additions and 96 deletions

View File

@ -19,7 +19,7 @@ PATH
metasploit-model
metasploit-payloads (= 1.3.19)
metasploit_data_models
metasploit_payloads-mettle (= 0.2.8)
metasploit_payloads-mettle (= 0.3.2)
msgpack
nessus_rest
net-ssh
@ -188,7 +188,7 @@ GEM
postgres_ext
railties (~> 4.2.6)
recog (~> 2.0)
metasploit_payloads-mettle (0.2.8)
metasploit_payloads-mettle (0.3.2)
method_source (0.9.0)
mini_portile2 (2.3.0)
minitest (5.10.3)

View File

@ -635,24 +635,26 @@ class Meterpreter < Rex::Post::Meterpreter::Client
# Platform-agnostic archs go first
case self.arch
when 'java'
'jar'
['jar']
when 'php'
'php'
['php']
when 'python'
'py'
['py']
else
# otherwise we fall back to the platform
case self.platform
when 'windows'
"#{self.arch}.dll"
["#{self.arch}.dll"]
when 'linux' , 'aix' , 'hpux' , 'irix' , 'unix'
'lso'
['bin', 'elf']
when 'osx'
['elf']
when 'android', 'java'
'jar'
['jar']
when 'php'
'php'
['php']
when 'python'
'py'
['py']
else
nil
end

View File

@ -195,6 +195,10 @@ class ClientCore < Extension
# LibraryFilePath
# The path to the library that is to be loaded
#
# LibraryFileImage
# Binary object containing the library to be loaded
# (can be used instead of LibraryFilePath)
#
# TargetFilePath
# The target library path when uploading
#
@ -210,12 +214,13 @@ class ClientCore < Extension
#
def load_library(opts)
library_path = opts['LibraryFilePath']
library_image = opts['LibraryFileImage']
target_path = opts['TargetFilePath']
load_flags = LOAD_LIBRARY_FLAG_LOCAL
# No library path, no cookie.
if library_path.nil?
raise ArgumentError, 'No library file path was supplied', caller
if library_path.nil? && library_image.nil?
raise ArgumentError, 'No library file path or image was supplied', caller
end
# Set up the proper loading flags
@ -234,14 +239,17 @@ class ClientCore < Extension
# If we must upload the library, do so now
if (load_flags & LOAD_LIBRARY_FLAG_LOCAL) != LOAD_LIBRARY_FLAG_LOCAL
image = ''
if library_image.nil?
# Caller did not provide the image, load it from the path
library_image = ''
::File.open(library_path, 'rb') { |f|
image = f.read
}
::File.open(library_path, 'rb') { |f|
library_image = f.read
}
end
if image
request.add_tlv(TLV_TYPE_DATA, image, false, client.capabilities[:zlib])
if library_image
request.add_tlv(TLV_TYPE_DATA, library_image, false, client.capabilities[:zlib])
else
raise RuntimeError, "Failed to serialize library #{library_path}.", caller
end
@ -250,8 +258,17 @@ class ClientCore < Extension
# path of the local and target so that it gets loaded with a random
# name
if opts['Extension']
library_path = "ext#{rand(1000000)}.#{client.binary_suffix}"
target_path = library_path
if client.binary_suffix and client.binary_suffix.size > 1
m = /(.*)\.(.*)/.match(library_path)
suffix = $2
elsif client.binary_suffix.size == 1
suffix = client.binary_suffix[0]
else
suffix = client.binary_suffix
end
library_path = "ext#{rand(1000000)}.#{suffix}"
target_path = "/tmp/#{library_path}"
end
end
@ -297,6 +314,22 @@ class ClientCore < Extension
raise RuntimeError, "No modules were specified", caller
end
modnameprovided = mod
suffix = nil
if not client.binary_suffix
suffix = ''
elsif client.binary_suffix.size > 1
client.binary_suffix.each { |s|
if (mod =~ /(.*)\.#{s}/ )
mod = $1
suffix = s
break
end
}
else
suffix = client.binary_suffix.first
end
# Query the remote instance to see if commands for the extension are
# already loaded
commands = get_loaded_extension_commands(mod.downcase)
@ -304,22 +337,31 @@ class ClientCore < Extension
# if there are existing commands for the given extension, then we can use
# what's already there
unless commands.length > 0
# Get us to the installation root and then into data/meterpreter, where
# the file is expected to be
modname = "ext_server_#{mod.downcase}"
path = MetasploitPayloads.meterpreter_path(modname, client.binary_suffix)
image = nil
path = nil
# If client.sys isn't setup, it's a Windows meterpreter
if client.respond_to?(:sys) && !client.sys.config.sysinfo['BuildTuple'].blank?
# Query the payload gem directly for the extension image
image = MetasploitPayloads::Mettle.load_extension(client.sys.config.sysinfo['BuildTuple'], mod.downcase, suffix)
else
# Get us to the installation root and then into data/meterpreter, where
# the file is expected to be
modname = "ext_server_#{mod.downcase}"
path = MetasploitPayloads.meterpreter_path(modname, suffix)
if opts['ExtensionPath']
path = ::File.expand_path(opts['ExtensionPath'])
if opts['ExtensionPath']
path = ::File.expand_path(opts['ExtensionPath'])
end
end
if path.nil?
raise RuntimeError, "No module of the name #{modname}.#{client.binary_suffix} found", caller
if path.nil? and image.nil?
raise RuntimeError, "No module of the name #{modnameprovided} found", caller
end
# Load the extension DLL
commands = load_library(
'LibraryFilePath' => path,
'LibraryFileImage' => image,
'UploadLibrary' => true,
'Extension' => true,
'SaveToDisk' => opts['LoadFromDisk'])

View File

@ -45,9 +45,19 @@ class Priv < Extension
elevator_name = Rex::Text.rand_text_alpha_lower( 6 )
elevator_path = MetasploitPayloads.meterpreter_path('elevator', client.binary_suffix)
elevator_path = nil
client.binary_suffix.each { |s|
elevator_path = MetasploitPayloads.meterpreter_path('elevator', s)
if !elevator_path.nil?
break
end
}
if elevator_path.nil?
raise RuntimeError, "elevator.#{binary_suffix} not found", caller
elevators = ""
client.binary_suffix.each { |s|
elevators << "elevator.#{s}, "
}
raise RuntimeError, "#{elevators.chomp(', ')} not found", caller
end
elevator_data = ""

View File

@ -39,7 +39,13 @@ class Sniffer < Extension
response.each(TLV_TYPE_SNIFFER_INTERFACES) { |p|
vals = p.tlvs.map{|x| x.value }
iface = { }
ikeys = %W{idx name description type mtu wireless usable dhcp}
if vals.length == 8
# Windows
ikeys = %W{idx name description type mtu wireless usable dhcp}
else
# Mettle
ikeys = %W{idx name description usable}
end
ikeys.each_index { |i| iface[ikeys[i]] = vals[i] }
ifaces << iface
}

View File

@ -122,6 +122,7 @@ class Config
'Computer' => response.get_tlv_value(TLV_TYPE_COMPUTER_NAME),
'OS' => response.get_tlv_value(TLV_TYPE_OS_NAME),
'Architecture' => response.get_tlv_value(TLV_TYPE_ARCHITECTURE),
'BuildTuple' => response.get_tlv_value(TLV_TYPE_BUILD_TUPLE),
'System Language' => response.get_tlv_value(TLV_TYPE_LANG_SYSTEM),
'Domain' => response.get_tlv_value(TLV_TYPE_DOMAIN),
'Logged On Users' => response.get_tlv_value(TLV_TYPE_LOGGED_ON_USER_COUNT)

View File

@ -130,6 +130,7 @@ TLV_TYPE_SID = TLV_META_TYPE_STRING | 1045
TLV_TYPE_DOMAIN = TLV_META_TYPE_STRING | 1046
TLV_TYPE_LOGGED_ON_USER_COUNT = TLV_META_TYPE_UINT | 1047
TLV_TYPE_LOCAL_DATETIME = TLV_META_TYPE_STRING | 1048
TLV_TYPE_BUILD_TUPLE = TLV_META_TYPE_STRING | 1049
# Environment
TLV_TYPE_ENV_VARIABLE = TLV_META_TYPE_STRING | 1100

View File

@ -1147,14 +1147,27 @@ class Console::CommandDispatcher::Core
case opt
when '-l'
exts = SortedSet.new
msf_path = MetasploitPayloads.msf_meterpreter_dir
gem_path = MetasploitPayloads.local_meterpreter_dir
[msf_path, gem_path].each do |path|
::Dir.entries(path).each { |f|
if (::File.file?(::File.join(path, f)) && f =~ /ext_server_(.*)\.#{client.binary_suffix}/ )
exts.add($1)
end
}
if !client.sys.config.sysinfo['BuildTuple'].blank?
# Use API to get list of extensions from the gem
exts.merge(MetasploitPayloads::Mettle.available_extensions(client.sys.config.sysinfo['BuildTuple']))
else
msf_path = MetasploitPayloads.msf_meterpreter_dir
gem_path = MetasploitPayloads.local_meterpreter_dir
[msf_path, gem_path].each do |path|
::Dir.entries(path).each { |f|
if (::File.file?(::File.join(path, f)))
client.binary_suffix.each { |s|
if (f =~ /ext_server_(.*)\.#{s}/ )
if (client.binary_suffix.size > 1)
exts.add($1 + ".#{s}")
else
exts.add($1)
end
end
}
end
}
end
end
print(exts.to_a.join("\n") + "\n")
@ -1168,7 +1181,16 @@ class Console::CommandDispatcher::Core
# Load each of the modules
args.each { |m|
md = m.downcase
modulenameprovided = md
if client.binary_suffix and client.binary_suffix.size > 1
client.binary_suffix.each { |s|
if (md =~ /(.*)\.#{s}/ )
md = $1
break
end
}
end
if (extensions.include?(md))
print_error("The '#{md}' extension has already been loaded.")
next
@ -1178,7 +1200,7 @@ class Console::CommandDispatcher::Core
begin
# Use the remote side, then load the client-side
if (client.core.use(md) == true)
if (client.core.use(modulenameprovided) == true)
add_extension_client(md)
end
rescue
@ -1195,16 +1217,31 @@ class Console::CommandDispatcher::Core
def cmd_load_tabs(str, words)
tabs = SortedSet.new
msf_path = MetasploitPayloads.msf_meterpreter_dir
gem_path = MetasploitPayloads.local_meterpreter_dir
[msf_path, gem_path].each do |path|
::Dir.entries(path).each { |f|
if (::File.file?(::File.join(path, f)) && f =~ /ext_server_(.*)\.#{client.binary_suffix}/ )
if (not extensions.include?($1))
tabs.add($1)
if !client.sys.config.sysinfo['BuildTuple'].blank?
# Use API to get list of extensions from the gem
MetasploitPayloads::Mettle.available_extensions(client.sys.config.sysinfo['BuildTuple']).each { |f|
if !extensions.include?(f.split('.').first)
tabs.add(f)
end
}
else
msf_path = MetasploitPayloads.msf_meterpreter_dir
gem_path = MetasploitPayloads.local_meterpreter_dir
[msf_path, gem_path].each do |path|
::Dir.entries(path).each { |f|
if (::File.file?(::File.join(path, f)))
client.binary_suffix.each { |s|
if (f =~ /ext_server_(.*)\.#{s}/ )
if (client.binary_suffix.size > 1 && !extensions.include?($1 + ".#{s}"))
tabs.add($1 + ".#{s}")
elsif (!extensions.include?($1))
tabs.add($1)
end
end
}
end
}
end
}
end
return tabs.to_a
end

View File

@ -28,14 +28,26 @@ class Console::CommandDispatcher::Sniffer
# List of supported commands.
#
def commands
#all = {
{
"sniffer_interfaces" => "Enumerate all sniffable network interfaces",
"sniffer_start" => "Start packet capture on a specific interface",
"sniffer_stop" => "Stop packet capture on a specific interface",
"sniffer_stats" => "View statistics of an active capture",
"sniffer_dump" => "Retrieve captured packet data to PCAP file",
"sniffer_release" => "Free captured packets on a specific interface instead of downloading them",
"sniffer_release" => "Free captured packets on a specific interface instead of downloading them"
}
#reqs = {
# "sniffer_interfaces" => ['sniffer_interfaces'],
# "sniffer_start" => ['sniffer_capture_start'],
# "sniffer_stop" => ['sniffer_capture_stop'],
# "sniffer_stats" => ['sniffer_capture_stats'],
# "sniffer_dump" => ['sniffer_capture_dump'],
# "sniffer_release" => ['sniffer_capture_release']
#}
#filter_commands(all, reqs)
end
@ -46,10 +58,18 @@ class Console::CommandDispatcher::Sniffer
print_line()
ifaces.each do |i|
print_line(sprintf("%d - '%s' ( type:%d mtu:%d usable:%s dhcp:%s wifi:%s )",
i['idx'], i['description'],
i['type'], i['mtu'], i['usable'], i['dhcp'], i['wireless'])
)
if i.length == 8
# Windows
print_line(sprintf("%d - '%s' ( type:%d mtu:%d usable:%s dhcp:%s wifi:%s )",
i['idx'], i['description'],
i['type'], i['mtu'], i['usable'], i['dhcp'], i['wireless'])
)
else
# Mettle
print_line(sprintf("%d - '%s' ( usable:%s )",
i['idx'], i['description'], i['usable'])
)
end
end
print_line()
@ -167,10 +187,10 @@ class Console::CommandDispatcher::Sniffer
# TODO: reorder packets based on the ID (only an issue if the buffer wraps)
while(true)
buf = od.read(20)
break if not buf
break unless buf
idh,idl,thi,tlo,len = buf.unpack('N5')
break if not len
break unless len
if(len > 10000)
print_error("Corrupted packet data (length:#{len})")
break

View File

@ -72,7 +72,7 @@ Gem::Specification.new do |spec|
# Needed for Meterpreter
spec.add_runtime_dependency 'metasploit-payloads', '1.3.19'
# Needed for the next-generation POSIX Meterpreter
spec.add_runtime_dependency 'metasploit_payloads-mettle', '0.2.8'
spec.add_runtime_dependency 'metasploit_payloads-mettle', '0.3.2'
# Needed by msfgui and other rpc components
spec.add_runtime_dependency 'msgpack'
# get list of network interfaces, like eth* from OS.

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/meterpreter_aarch64_linux'
module MetasploitModule
CachedSize = 693880
CachedSize = 966280
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/meterpreter_aarch64_linux'
module MetasploitModule
CachedSize = 693880
CachedSize = 966280
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/meterpreter_aarch64_linux'
module MetasploitModule
CachedSize = 693880
CachedSize = 966280
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/meterpreter_armbe_linux'
module MetasploitModule
CachedSize = 682608
CachedSize = 902524
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/meterpreter_armbe_linux'
module MetasploitModule
CachedSize = 682608
CachedSize = 902524
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/meterpreter_armbe_linux'
module MetasploitModule
CachedSize = 682608
CachedSize = 902524
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/meterpreter_armle_linux'
module MetasploitModule
CachedSize = 682608
CachedSize = 898776
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/meterpreter_armle_linux'
module MetasploitModule
CachedSize = 682608
CachedSize = 898776
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/meterpreter_armle_linux'
module MetasploitModule
CachedSize = 682608
CachedSize = 898776
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/meterpreter_mips64_linux'
module MetasploitModule
CachedSize = 1081096
CachedSize = 1384552
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/meterpreter_mips64_linux'
module MetasploitModule
CachedSize = 1081096
CachedSize = 1384552
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/meterpreter_mips64_linux'
module MetasploitModule
CachedSize = 1081096
CachedSize = 1384552
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/meterpreter_mipsbe_linux'
module MetasploitModule
CachedSize = 1058488
CachedSize = 1280872
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/meterpreter_mipsbe_linux'
module MetasploitModule
CachedSize = 1058488
CachedSize = 1280872
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/meterpreter_mipsbe_linux'
module MetasploitModule
CachedSize = 1058488
CachedSize = 1280872
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/meterpreter_mipsle_linux'
module MetasploitModule
CachedSize = 1058584
CachedSize = 1281916
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/meterpreter_mipsle_linux'
module MetasploitModule
CachedSize = 1058584
CachedSize = 1281916
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/meterpreter_mipsle_linux'
module MetasploitModule
CachedSize = 1058584
CachedSize = 1281916
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/meterpreter_ppc_linux'
module MetasploitModule
CachedSize = 856196
CachedSize = 1060624
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/meterpreter_ppc_linux'
module MetasploitModule
CachedSize = 856196
CachedSize = 1060624
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/meterpreter_ppc_linux'
module MetasploitModule
CachedSize = 856196
CachedSize = 1060624
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/meterpreter_ppc64le_linux'
module MetasploitModule
CachedSize = 857808
CachedSize = 1014112
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/meterpreter_ppc64le_linux'
module MetasploitModule
CachedSize = 857808
CachedSize = 1014112
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/meterpreter_ppc64le_linux'
module MetasploitModule
CachedSize = 857808
CachedSize = 1014112
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/meterpreter_ppce500v2_linux'
module MetasploitModule
CachedSize = 856196
CachedSize = 1013304
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/meterpreter_ppce500v2_linux'
module MetasploitModule
CachedSize = 856196
CachedSize = 1013304
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/meterpreter_ppce500v2_linux'
module MetasploitModule
CachedSize = 856196
CachedSize = 1013304
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/meterpreter_x64_linux'
module MetasploitModule
CachedSize = 746944
CachedSize = 905984
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/meterpreter_x64_linux'
module MetasploitModule
CachedSize = 746944
CachedSize = 905984
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/meterpreter_x64_linux'
module MetasploitModule
CachedSize = 746944
CachedSize = 905984
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/meterpreter_x86_linux'
module MetasploitModule
CachedSize = 794800
CachedSize = 956868
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/meterpreter_x86_linux'
module MetasploitModule
CachedSize = 794800
CachedSize = 956868
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/meterpreter_x86_linux'
module MetasploitModule
CachedSize = 794800
CachedSize = 956868
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/meterpreter_zarch_linux'
module MetasploitModule
CachedSize = 907360
CachedSize = 1071464
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/meterpreter_zarch_linux'
module MetasploitModule
CachedSize = 907360
CachedSize = 1071464
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/meterpreter_zarch_linux'
module MetasploitModule
CachedSize = 907360
CachedSize = 1071464
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/meterpreter_x64_osx'
module MetasploitModule
CachedSize = 793284
CachedSize = 802564
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/meterpreter_x64_osx'
module MetasploitModule
CachedSize = 793284
CachedSize = 802564
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/meterpreter_x64_osx'
module MetasploitModule
CachedSize = 793284
CachedSize = 802564
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions

View File

@ -14,7 +14,7 @@ RSpec.describe Rex::Post::Meterpreter::ClientCore do
allow(@response).to receive(:result) { 0 }
allow(@response).to receive(:each) { [:help] }
@client = double("client")
allow(@client).to receive(:binary_suffix) { "x64.dll" }
allow(@client).to receive(:binary_suffix) { ["x64.dll"] }
allow(@client).to receive(:capabilities) { {:ssl => false, :zlib => false } }
allow(@client).to receive(:response_timeout) { 1 }
allow(@client).to receive(:send_packet_wait_response) { @response }