Land #8625, Remove OpenSSL from Windows Meterp, packet header changes, and TLV packet encryption

bug/bundler_fix
Brent Cook 2017-08-20 19:13:51 -05:00
commit f961495860
No known key found for this signature in database
GPG Key ID: 1FFAA0B24B708F96
49 changed files with 352 additions and 211 deletions

View File

@ -18,9 +18,9 @@ group :development do
gem 'pry'
# module documentation
gem 'octokit'
# metasploit-aggregator as a framework only option for now
# Metasploit::Aggregator external session proxy
gem 'metasploit-aggregator'
# Disabled for now for crypttlv updates
# gem 'metasploit-aggregator'
end
group :development, :test do

View File

@ -17,9 +17,9 @@ PATH
metasploit-concern
metasploit-credential
metasploit-model
metasploit-payloads (= 1.2.46)
metasploit-payloads (= 1.3.0)
metasploit_data_models
metasploit_payloads-mettle (= 0.1.14)
metasploit_payloads-mettle (= 0.2.0)
msgpack
nessus_rest
net-ssh
@ -126,35 +126,14 @@ GEM
ffi (1.9.18)
filesize (0.1.1)
fivemat (1.3.5)
google-protobuf (3.4.0.2)
googleauth (0.5.3)
faraday (~> 0.12)
jwt (~> 1.4)
logging (~> 2.0)
memoist (~> 0.12)
multi_json (~> 1.11)
os (~> 0.9)
signet (~> 0.7)
grpc (1.4.5)
google-protobuf (~> 3.1)
googleauth (~> 0.5.1)
hashery (2.1.2)
i18n (0.8.6)
jsobfu (0.4.2)
rkelly-remix
json (2.1.0)
jwt (1.5.6)
little-plugger (1.1.4)
logging (2.2.2)
little-plugger (~> 1.1)
multi_json (~> 1.10)
loofah (2.0.3)
nokogiri (>= 1.5.9)
memoist (0.16.0)
metasm (1.0.3)
metasploit-aggregator (0.2.1)
grpc
rex-arch
metasploit-concern (2.0.5)
activemodel (~> 4.2.6)
activesupport (~> 4.2.6)
@ -172,7 +151,7 @@ GEM
activemodel (~> 4.2.6)
activesupport (~> 4.2.6)
railties (~> 4.2.6)
metasploit-payloads (1.2.46)
metasploit-payloads (1.3.0)
metasploit_data_models (2.0.15)
activerecord (~> 4.2.6)
activesupport (~> 4.2.6)
@ -183,12 +162,11 @@ GEM
postgres_ext
railties (~> 4.2.6)
recog (~> 2.0)
metasploit_payloads-mettle (0.1.14)
metasploit_payloads-mettle (0.2.0)
method_source (0.8.2)
mini_portile2 (2.2.0)
minitest (5.10.3)
msgpack (1.1.0)
multi_json (1.12.1)
multipart-post (2.0.0)
nessus_rest (0.1.6)
net-ssh (4.1.0)
@ -200,7 +178,6 @@ GEM
sawyer (~> 0.8.0, >= 0.5.3)
openssl-ccm (1.2.1)
openvas-omp (0.0.4)
os (0.9.6)
packetfu (1.1.13)
pcaprub
patch_finder (1.0.2)
@ -328,11 +305,6 @@ GEM
sawyer (0.8.1)
addressable (>= 2.3.5, < 2.6)
faraday (~> 0.8, < 1.0)
signet (0.7.3)
addressable (~> 2.3)
faraday (~> 0.9)
jwt (~> 1.5)
multi_json (~> 1.10)
simplecov (0.15.0)
docile (~> 1.1.0)
json (>= 1.8, < 3)
@ -362,7 +334,6 @@ PLATFORMS
DEPENDENCIES
factory_girl_rails
fivemat
metasploit-aggregator
metasploit-framework!
octokit
pry

View File

@ -541,6 +541,7 @@ class ReadableText
columns << 'Id'
columns << 'Type'
columns << 'Checkin?' if show_extended
columns << 'Enc?' if show_extended
columns << 'Local URI' if show_extended
columns << 'Information'
columns << 'Connection'
@ -575,6 +576,12 @@ class ReadableText
row << '?'
end
if session.respond_to?(:tlv_enc_key) && session.tlv_enc_key && session.tlv_enc_key[:key]
row << "Y"
else
row << 'N'
end
if session.exploit_datastore.has_key?('LURI') && !session.exploit_datastore['LURI'].empty?
row << " (#{session.exploit_datastore['LURI']})"
else
@ -616,12 +623,16 @@ class ReadableText
sess_uuid = session.payload_uuid.to_s
sess_puid = session.payload_uuid.respond_to?(:puid_hex) ? session.payload_uuid.puid_hex : nil
sess_luri = session.exploit_datastore['LURI'] || ""
sess_enc = false
if session.respond_to?(:tlv_enc_key) && session.tlv_enc_key && session.tlv_enc_key[:key]
sess_enc = true
end
sess_checkin = "<none>"
sess_registration = "No"
if session.respond_to? :platform
sess_type << (" " + session.platform)
if session.respond_to?(:platform)
sess_type << " " + session.platform
end
if session.respond_to?(:last_checkin) && session.last_checkin
@ -640,6 +651,7 @@ class ReadableText
out << " Info: #{sess_info}\n"
out << " Tunnel: #{sess_tunnel}\n"
out << " Via: #{sess_via}\n"
out << " Encrypted: #{sess_enc}\n"
out << " UUID: #{sess_uuid}\n"
out << " CheckIn: #{sess_checkin}\n"
out << " Registered: #{sess_registration}\n"

View File

@ -43,6 +43,8 @@ module MeterpreterOptions
valid = true
session.tlv_enc_key = session.core.negotiate_tlv_encryption
if datastore['AutoVerifySession']
if not session.is_valid_session?(datastore['AutoVerifySessionTimeout'].to_i)
print_error("Meterpreter session #{session.sid} is not valid and will be closed")
@ -52,14 +54,13 @@ module MeterpreterOptions
if valid
# always make sure that the new session has a new guid if it's not already known
guid = session.core.get_session_guid
guid = session.session_guid
if guid == '00000000-0000-0000-0000-000000000000'
guid = SecureRandom.uuid
session.core.set_session_guid(guid)
session.guid = guid
session.session_guid = guid
# TODO: New statgeless session, do some account in the DB so we can track it later.
else
session.guid = guid
# TODO: This session was either staged or previously known, and so we shold do some accounting here!
end

View File

@ -21,6 +21,10 @@ class Meterpreter_x64_Win < Msf::Sessions::Meterpreter
def lookup_error(code)
Msf::WindowsError.description(code)
end
def supports_ssl?
false
end
end
end

View File

@ -21,6 +21,10 @@ class Meterpreter_x86_Win < Msf::Sessions::Meterpreter
def lookup_error(code)
Msf::WindowsError.description(code)
end
def supports_ssl?
false
end
end
end

View File

@ -79,9 +79,9 @@ module Payload::Python::MeterpreterLoader
met.sub!("PAYLOAD_UUID = \'\'", "PAYLOAD_UUID = \'#{uuid}\'")
if opts[:stageless] == true
session_guid = '\x00' * 16
session_guid = '00' * 16
else
session_guid = SecureRandom.uuid.gsub(/-/, '').gsub(/(..)/, '\\x\1')
session_guid = SecureRandom.uuid.gsub(/-/, '')
end
met.sub!("SESSION_GUID = \'\'", "SESSION_GUID = \'#{session_guid}\'")

View File

@ -386,10 +386,6 @@ module Session
#
attr_accessor :machine_id
#
# The guid that identifies an active Meterpreter session
#
attr_accessor :guid
#
# The actual exploit module instance that created this session
#
attr_accessor :exploit

View File

@ -77,7 +77,7 @@ class Client
# Initializes the client context with the supplied socket through
# which communication with the server will be performed.
#
def initialize(sock,opts={})
def initialize(sock, opts={})
init_meterpreter(sock, opts)
end
@ -130,6 +130,9 @@ class Client
# self.encode_unicode = opts.has_key?(:encode_unicode) ? opts[:encode_unicode] : true
self.encode_unicode = false
self.aes_key = nil
self.session_guid = '00000000-0000-0000-0000-000000000000'
# The SSL certificate is being passed down as a file path
if opts[:ssl_cert]
if ! ::File.exist? opts[:ssl_cert]

View File

@ -17,6 +17,8 @@ require 'rex/payloads/meterpreter/uri_checksum'
# certificate hash checking
require 'rex/socket/x509_certificate'
require 'openssl'
module Rex
module Post
module Meterpreter
@ -210,7 +212,7 @@ class ClientCore < Extension
image = f.read
}
if !image.nil?
if image
request.add_tlv(TLV_TYPE_DATA, image, false, client.capabilities[:zlib])
else
raise RuntimeError, "Failed to serialize library #{library_path}.", caller
@ -601,7 +603,12 @@ class ClientCore < Extension
# Send the migration request. Timeout can be specified by the caller, or set to a min
# of 60 seconds.
timeout = [(opts[:timeout] || 0), 60].max
client.send_request(request, timeout)
response = client.send_request(request, timeout)
# Post-migration the session doesn't have encryption any more.
# Set the TLV key to nil to make sure that the old key isn't used
# at all.
client.tlv_enc_key = nil
if client.passive_service
# Sleep for 5 seconds to allow the full handoff, this prevents
@ -617,28 +624,34 @@ class ClientCore < Extension
# Now communicating with the new process
###
# If renegotiation takes longer than a minute, it's a pretty
# good bet that migration failed and the remote side is hung.
# Since we have the comm_mutex here, we *must* release it to
# keep from hanging the packet dispatcher thread, which results
# in blocking the entire process.
begin
Timeout.timeout(timeout) do
# Renegotiate SSL over this socket
client.swap_sock_ssl_to_plain()
client.swap_sock_plain_to_ssl()
# only renegotiate SSL if the session had support for it in the
# first place!
if client.supports_ssl?
# If renegotiation takes longer than a minute, it's a pretty
# good bet that migration failed and the remote side is hung.
# Since we have the comm_mutex here, we *must* release it to
# keep from hanging the packet dispatcher thread, which results
# in blocking the entire process.
begin
Timeout.timeout(timeout) do
# Renegotiate SSL over this socket
client.swap_sock_ssl_to_plain()
client.swap_sock_plain_to_ssl()
end
rescue TimeoutError
client.alive = false
return false
end
rescue TimeoutError
client.alive = false
return false
end
# Restart the socket monitor
client.monitor_socket
end
end
# Renegotiate TLV encryption on the migrated session
client.tlv_enc_key = negotiate_tlv_encryption
# Load all the extensions that were loaded in the previous instance (using the correct platform/binary_suffix)
client.ext.aliases.keys.each { |e|
client.core.use(e)
@ -680,6 +693,38 @@ class ClientCore < Extension
end
end
#
# Negotiates the use of encryption at the TLV level
#
def negotiate_tlv_encryption
sym_key = nil
rsa_key = OpenSSL::PKey::RSA.new(2048)
rsa_pub_key = rsa_key.public_key
request = Packet.create_request('core_negotiate_tlv_encryption')
request.add_tlv(TLV_TYPE_RSA_PUB_KEY, rsa_pub_key.to_pem)
begin
response = client.send_request(request)
key_enc = response.get_tlv_value(TLV_TYPE_ENC_SYM_KEY)
key_type = response.get_tlv_value(TLV_TYPE_SYM_KEY_TYPE)
if key_enc
sym_key = rsa_key.private_decrypt(key_enc, OpenSSL::PKey::RSA::PKCS1_PADDING)
else
sym_key = response.get_tlv_value(TLV_TYPE_SYM_KEY)
end
rescue OpenSSL::PKey::RSAError, Rex::Post::Meterpreter::RequestError
# 1) OpenSSL error may be due to padding issues (or something else)
# 2) Request error probably means the request isn't supported, so fallback to plain
end
{
key: sym_key,
type: key_type
}
end
private
#

View File

@ -1,4 +1,5 @@
# -*- coding: binary -*-
require 'openssl'
module Rex
module Post
@ -107,6 +108,11 @@ TLV_TYPE_MACHINE_ID = TLV_META_TYPE_STRING | 460
TLV_TYPE_UUID = TLV_META_TYPE_RAW | 461
TLV_TYPE_SESSION_GUID = TLV_META_TYPE_RAW | 462
TLV_TYPE_RSA_PUB_KEY = TLV_META_TYPE_STRING | 550
TLV_TYPE_SYM_KEY_TYPE = TLV_META_TYPE_UINT | 551
TLV_TYPE_SYM_KEY = TLV_META_TYPE_RAW | 552
TLV_TYPE_ENC_SYM_KEY = TLV_META_TYPE_RAW | 553
#
# Core flags
#
@ -122,6 +128,8 @@ LOAD_LIBRARY_FLAG_LOCAL = (1 << 2)
class Tlv
attr_accessor :type, :value, :compress
HEADER_SIZE = 8
##
#
# Constructor
@ -214,6 +222,10 @@ class Tlv
when TLV_TYPE_MACHINE_ID; "MACHINE-ID"
when TLV_TYPE_UUID; "UUID"
when TLV_TYPE_SESSION_GUID; "SESSION-GUID"
when TLV_TYPE_RSA_PUB_KEY; "RSA-PUB-KEY"
when TLV_TYPE_SYM_KEY_TYPE; "SYM-KEY-TYPE"
when TLV_TYPE_SYM_KEY; "SYM-KEY"
when TLV_TYPE_ENC_SYM_KEY; "ENC-SYM-KEY"
#when Extensions::Stdapi::TLV_TYPE_NETWORK_INTERFACE; 'network-interface'
#when Extensions::Stdapi::TLV_TYPE_IP; 'ip-address'
@ -299,7 +311,7 @@ class Tlv
end
# check if the tlv is to be compressed...
if( @compress )
if @compress
raw_uncompressed = raw
# compress the raw data
raw_compressed = Rex::Text.zlib_deflate( raw_uncompressed )
@ -315,7 +327,7 @@ class Tlv
end
end
return [raw.length + 8, self.type].pack("NN") + raw
[raw.length + HEADER_SIZE, self.type].pack("NN") + raw
end
#
@ -334,16 +346,16 @@ class Tlv
# tlv type to its origional, allowing for transparent data compression.
self.type = self.type ^ TLV_META_TYPE_COMPRESSED
# decompress the compressed data (skipping the length and type DWORD's)
raw_decompressed = Rex::Text.zlib_inflate( raw[8..length-1] )
# update the length to reflect the decompressed data length (+8 for the length and type DWORD's)
length = raw_decompressed.length + 8
raw_decompressed = Rex::Text.zlib_inflate( raw[HEADER_SIZE..length-1] )
# update the length to reflect the decompressed data length (+HEADER_SIZE for the length and type DWORD's)
length = raw_decompressed.length + HEADER_SIZE
# update the raw buffer with the new length, decompressed data and updated type.
raw = [length, self.type].pack("NN") + raw_decompressed
end
if (self.type & TLV_META_TYPE_STRING == TLV_META_TYPE_STRING)
if (raw.length > 0)
self.value = raw[8..length-2]
self.value = raw[HEADER_SIZE..length-2]
else
self.value = nil
end
@ -361,23 +373,24 @@ class Tlv
self.value = false
end
else
self.value = raw[8..length-1]
self.value = raw[HEADER_SIZE..length-1]
end
return length;
length
end
protected
def htonq( value )
if( [1].pack( 's' ) == [1].pack( 'n' ) )
def htonq(value)
if [1].pack( 's' ) == [1].pack('n')
return value
else
[value].pack('Q<').reverse.unpack('Q<').first
end
return [ value ].pack( 'Q<' ).reverse.unpack( 'Q<' ).first
end
def ntohq( value )
return htonq( value )
def ntohq(value)
htonq(value)
end
end
@ -403,7 +416,7 @@ class GroupTlv < Tlv
def initialize(type)
super(type)
self.tlvs = [ ]
self.tlvs = []
end
##
@ -444,8 +457,8 @@ class GroupTlv < Tlv
# Returns an array of TLVs for the given type.
#
def get_tlvs(type)
if (type == TLV_TYPE_ANY)
return self.tlvs
if type == TLV_TYPE_ANY
self.tlvs
else
type_tlvs = []
@ -455,7 +468,7 @@ class GroupTlv < Tlv
end
}
return type_tlvs
type_tlvs
end
end
@ -471,7 +484,7 @@ class GroupTlv < Tlv
def add_tlv(type, value = nil, replace = false, compress=false)
# If we should replace any TLVs with the same type...remove them first
if (replace)
if replace
each(type) { |tlv|
if (tlv.type == type)
self.tlvs.delete(tlv)
@ -487,14 +500,14 @@ class GroupTlv < Tlv
self.tlvs << tlv
return tlv
tlv
end
#
# Adds zero or more TLVs to the packet.
#
def add_tlvs(tlvs)
if (tlvs != nil)
if tlvs
tlvs.each { |tlv|
add_tlv(tlv['type'], tlv['value'])
}
@ -507,11 +520,12 @@ class GroupTlv < Tlv
def get_tlv(type, index = 0)
type_tlvs = get_tlvs(type)
if (type_tlvs.length > index)
return type_tlvs[index]
if type_tlvs.length > index
type_tlvs[index]
else
nil
end
return nil
end
#
@ -520,7 +534,7 @@ class GroupTlv < Tlv
def get_tlv_value(type, index = 0)
tlv = get_tlv(type, index)
return (tlv != nil) ? tlv.value : nil
(tlv != nil) ? tlv.value : nil
end
#
@ -534,7 +548,7 @@ class GroupTlv < Tlv
# Checks to see if the container has a TLV of a given type.
#
def has_tlv?(type)
return get_tlv(type) != nil
get_tlv(type) != nil
end
#
@ -561,7 +575,7 @@ class GroupTlv < Tlv
raw << tlv.to_r
}
return [raw.length + 8, self.type].pack("NN") + raw
[raw.length + HEADER_SIZE, self.type].pack("NN") + raw
end
#
@ -569,19 +583,19 @@ class GroupTlv < Tlv
# TLVs.
#
def from_r(raw)
offset = 8
offset = HEADER_SIZE
# Reset the TLVs array
self.tlvs = []
self.type = raw.unpack("NN")[1]
# Enumerate all of the TLVs
while (offset < raw.length-1)
while offset < raw.length-1
tlv = nil
# Get the length and type
length, type = raw[offset..offset+8].unpack("NN")
length, type = raw[offset..offset+HEADER_SIZE].unpack("NN")
if (type & TLV_META_TYPE_GROUP == TLV_META_TYPE_GROUP)
tlv = GroupTlv.new(type)
@ -608,6 +622,48 @@ end
###
class Packet < GroupTlv
attr_accessor :created_at
attr_accessor :raw
attr_accessor :session_guid
##
#
# The Packet container itself has a custom header that is slightly different to the
# typical TLV packets. The header contains the following:
#
# XOR KEY - 4 bytes
# Session GUID - 16 bytes
# Encrypt flags - 4 bytes
# Packet length - 4 bytes
# Packet type - 4 bytes
# Packet data - X bytes
#
# If the encrypt flags are zero, then the Packet data is just straight TLV values as
# per the normal TLV packet structure.
#
# If the encrypt flags are non-zer, then the Packet data is encrypted based on the scheme.
#
# Flag == 1 (AES256)
# IV - 16 bytes
# Encrypted data - X bytes
#
# The key that is required to decrypt the data is stored alongside the session data,
# and hence when the packet is initially parsed, only the header is accessed. The
# packet itself will need to be decrypted on the fly at the point that it is required
# and at that point the decryption key needs to be provided.
#
###
XOR_KEY_SIZE = 4
SESSION_GUID_SIZE = 16
ENCRYPTED_FLAGS_SIZE = 4
PACKET_LENGTH_SIZE = 4
PACKET_TYPE_SIZE = 4
PACKET_HEADER_SIZE = XOR_KEY_SIZE + SESSION_GUID_SIZE + ENCRYPTED_FLAGS_SIZE + PACKET_LENGTH_SIZE + PACKET_TYPE_SIZE
AES_IV_SIZE = 16
ENC_FLAG_NONE = 0x0
ENC_FLAG_AES256 = 0x1
##
#
@ -619,7 +675,7 @@ class Packet < GroupTlv
# Creates a request with the supplied method.
#
def Packet.create_request(method = nil)
return Packet.new(PACKET_TYPE_REQUEST, method)
Packet.new(PACKET_TYPE_REQUEST, method)
end
#
@ -637,7 +693,7 @@ class Packet < GroupTlv
method = request.method
end
return Packet.new(response_type, method)
Packet.new(response_type, method)
end
##
@ -654,11 +710,12 @@ class Packet < GroupTlv
def initialize(type = nil, method = nil)
super(type)
if (method)
if method
self.method = method
end
self.created_at = ::Time.now
self.raw = ''
# If it's a request, generate a random request identifier
if ((type == PACKET_TYPE_REQUEST) ||
@ -671,20 +728,93 @@ class Packet < GroupTlv
end
end
def add_raw(bytes)
self.raw << bytes
end
def raw_bytes_required
# if we have the xor bytes and length ...
if self.raw.length >= PACKET_HEADER_SIZE
# return a value based on the length of the data indicated by
# the header
xor_key = self.raw.unpack('a4')[0]
decoded_bytes = xor_bytes(xor_key, raw[0, PACKET_HEADER_SIZE])
_, _, _, length, _ = decoded_bytes.unpack('a4a16NNN')
length + PACKET_HEADER_SIZE - HEADER_SIZE - self.raw.length
else
# Otherwise ask for the remaining bytes for the metadata to get the packet length
# So we can do the rest of the calculation next time
PACKET_HEADER_SIZE - self.raw.length
end
end
def aes_encrypt(key, data)
# Create the required cipher instance
aes = OpenSSL::Cipher.new('AES-256-CBC')
# Generate a truly random IV
iv = aes.random_iv
# set up the encryption
aes.encrypt
aes.key = key
aes.iv = iv
# encrypt and return the IV along with the result
return iv, aes.update(data) + aes.final
end
def aes_decrypt(key, iv, data)
# Create the required cipher instance
aes = OpenSSL::Cipher.new('AES-256-CBC')
# Generate a truly random IV
# set up the encryption
aes.decrypt
aes.key = key
aes.iv = iv
# decrypt!
aes.update(data) + aes.final
end
#
# Override the function that creates the raw byte stream for
# sending so that it generates an XOR key, uses it to scramble
# the serialized TLV content, and then returns the key plus the
# scrambled data as the payload.
#
def to_r
raw = super
xor_key = rand(254) + 1
xor_key |= (rand(254) + 1) << 8
xor_key |= (rand(254) + 1) << 16
xor_key |= (rand(254) + 1) << 24
result = [xor_key].pack('N') + xor_bytes(xor_key, raw)
result
def to_r(session_guid=nil, key=nil)
xor_key = (rand(254) + 1).chr + (rand(254) + 1).chr + (rand(254) + 1).chr + (rand(254) + 1).chr
raw = [(session_guid || "0"*32).gsub(/-/, '')].pack('H*')
tlv_data = GroupTlv.instance_method(:to_r).bind(self).call
if key && key[:key] && key[:type] == ENC_FLAG_AES256
# encrypt the data, but not include the length and type
iv, ciphertext = aes_encrypt(key[:key], tlv_data[HEADER_SIZE..-1])
# now manually add the length/type/iv/ciphertext
raw << [ENC_FLAG_AES256, iv.length + ciphertext.length + HEADER_SIZE, self.type, iv, ciphertext].pack('NNNA*A*')
else
raw << [ENC_FLAG_NONE, tlv_data].pack('NA*')
end
# return the xor'd result with the key
xor_key + xor_bytes(xor_key, raw)
end
#
# Decrypt the packet based on the content of the encryption flags.
#
def decrypt_packet(key, encrypt_flags, data)
# TODO: throw an error if the expected encryption isn't the same as the given
# as this could be an indication of hijacking or side-channel packet addition
# as highlighted by Justin Steven on github.
if key && key[:key] && key[:type] && encrypt_flags == ENC_FLAG_AES256 && encrypt_flags == key[:type]
iv = data[0, AES_IV_SIZE]
aes_decrypt(key[:key], iv, data[iv.length..-1])
else
data
end
end
#
@ -693,17 +823,20 @@ class Packet < GroupTlv
# passing it on to the default functionality that can parse
# the TLV values.
#
def from_r(bytes)
xor_key = bytes[0,4].unpack('N')[0]
super(xor_bytes(xor_key, bytes[4, bytes.length]))
def from_r(key=nil)
xor_key = self.raw.unpack('a4')[0]
data = xor_bytes(xor_key, self.raw)
_, self.session_guid, encrypt_flags, length, type = data.unpack('a4a16NNN')
raw = decrypt_packet(key, encrypt_flags, data[PACKET_HEADER_SIZE..-1])
super([length, type, raw].pack('NNA*'))
end
#
# Xor a set of bytes with a given DWORD xor key.
# Xor a set of bytes with a given XOR key.
#
def xor_bytes(xor_key, bytes)
result = ''
bytes.bytes.zip([xor_key].pack('V').bytes.cycle).each do |b|
bytes.bytes.zip(xor_key.bytes.cycle).each do |b|
result << (b[0].ord ^ b[1].ord).chr
end
result

View File

@ -57,6 +57,11 @@ module PacketDispatcher
# active migration. Unused if this is a passive dispatcher
attr_accessor :comm_mutex
# The guid that identifies an active Meterpreter session
attr_accessor :session_guid
# This contains the key material used for TLV encryption
attr_accessor :tlv_enc_key
# Passive Dispatching
#
@ -71,10 +76,10 @@ module PacketDispatcher
attr_accessor :recv_queue
def initialize_passive_dispatcher
self.send_queue = []
self.recv_queue = []
self.waiters = []
self.alive = true
self.send_queue = []
self.recv_queue = []
self.waiters = []
self.alive = true
# Ensure that there is only one leading and trailing slash on the URI
resource_uri = "/" + self.conn_id.to_s.gsub(/(^\/|\/$)/, '') + "/"
@ -131,7 +136,8 @@ module PacketDispatcher
resp.body = ""
if req.body and req.body.length > 0
packet = Packet.new(0)
packet.from_r(req.body)
packet.add_raw(req.body)
packet.from_r(self.tlv_enc_key)
dispatch_inbound_packet(packet)
end
cli.send_response(resp)
@ -157,7 +163,7 @@ module PacketDispatcher
end
bytes = 0
raw = packet.to_r
raw = packet.to_r(self.session_guid, self.tlv_enc_key)
err = nil
# Short-circuit send when using a passive dispatcher
@ -166,8 +172,7 @@ module PacketDispatcher
return raw.size # Lie!
end
if (raw)
if raw
self.comm_mutex.synchronize do
begin
bytes = self.sock.write(raw)
@ -420,7 +425,15 @@ module PacketDispatcher
# once a full packet has been received.
#
def receive_packet
return parser.recv(self.sock)
packet = parser.recv(self.sock)
if packet
packet.from_r(self.tlv_enc_key)
if self.session_guid == '00000000-0000-0000-0000-000000000000'
parts = packet.session_guid.unpack('H*')[0]
self.session_guid = [parts[0, 8], parts[8, 4], parts[12, 4], parts[16, 4], parts[20, 12]].join('-')
end
end
packet
end
#

View File

@ -12,17 +12,10 @@ module Meterpreter
###
class PacketParser
# 4 byte xor
# 4 byte length
# 4 byte type
HEADER_SIZE = 12
#
# Initializes the packet parser context with an optional cipher.
# Initializes the packet parser context.
#
def initialize(cipher = nil)
self.cipher = cipher
def initialize
reset
end
@ -30,71 +23,35 @@ class PacketParser
# Resets the parser state so that a new packet can begin being parsed.
#
def reset
self.raw = ''
self.hdr_length_left = HEADER_SIZE
self.payload_length_left = 0
self.packet = Packet.new(0)
end
#
# Reads data from the wire and parse as much of the packet as possible.
#
def recv(sock)
# Create a typeless packet
packet = Packet.new(0)
bytes_left = self.packet.raw_bytes_required
if (self.hdr_length_left > 0)
buf = sock.read(self.hdr_length_left)
if (buf)
self.raw << buf
self.hdr_length_left -= buf.length
else
raise EOFError
end
# If we've finished reading the header, set the
# payload length left to the number of bytes
# specified in the length
if (self.hdr_length_left == 0)
xor_key = raw[0, 4].unpack('N')[0]
length_bytes = packet.xor_bytes(xor_key, raw[4, 4])
# header size doesn't include the xor key, which is always tacked on the front
self.payload_length_left = length_bytes.unpack("N")[0] - (HEADER_SIZE - 4)
end
end
if (self.payload_length_left > 0)
buf = sock.read(self.payload_length_left)
if (buf)
self.raw << buf
self.payload_length_left -= buf.length
if bytes_left > 0
raw = sock.read(bytes_left)
if raw
self.packet.add_raw(raw)
else
raise EOFError
end
end
# If we've finished reading the entire packet
if ((self.hdr_length_left == 0) &&
(self.payload_length_left == 0))
# TODO: cipher decryption
if (cipher)
end
# Deserialize the packet from the raw buffer
packet.from_r(self.raw)
# Reset our state
if self.packet.raw_bytes_required == 0
packet = self.packet
reset
return packet
end
nil
end
protected
attr_accessor :cipher, :raw, :hdr_length_left, :payload_length_left # :nodoc:
attr_accessor :cipher, :packet # :nodoc:
end

View File

@ -469,8 +469,9 @@ class Console::CommandDispatcher::Core
# Get the session GUID
#
def cmd_guid(*args)
client.guid = client.core.get_session_guid unless client.guid
print_good("Session GUID: #{client.guid}")
parts = client.session_guid.unpack('H*')[0]
guid = [parts[0, 8], parts[8, 4], parts[12, 4], parts[16, 4], parts[20, 12]].join('-')
print_good("Session GUID: #{guid}")
end
#

View File

@ -70,9 +70,9 @@ 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.46'
spec.add_runtime_dependency 'metasploit-payloads', '1.3.0'
# Needed for the next-generation POSIX Meterpreter
spec.add_runtime_dependency 'metasploit_payloads-mettle', '0.1.14'
spec.add_runtime_dependency 'metasploit_payloads-mettle', '0.2.0'
# 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_armle_linux'
module MetasploitModule
CachedSize = 666624
CachedSize = 666552
include Msf::Payload::Single
include Msf::Sessions::MeterpreterOptions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_options'
module MetasploitModule
CachedSize = 27735
CachedSize = 30038
include Msf::Payload::Single
include Msf::Payload::Php::ReverseTcp

View File

@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_python'
module MetasploitModule
CachedSize = 54590
CachedSize = 56570
include Msf::Payload::Single
include Msf::Payload::Python

View File

@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_python'
module MetasploitModule
CachedSize = 54554
CachedSize = 56530
include Msf::Payload::Single
include Msf::Payload::Python

View File

@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_python'
module MetasploitModule
CachedSize = 54554
CachedSize = 56534
include Msf::Payload::Single
include Msf::Payload::Python

View File

@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_python'
module MetasploitModule
CachedSize = 54506
CachedSize = 56486
include Msf::Payload::Single
include Msf::Payload::Python

View File

@ -12,7 +12,7 @@ require 'rex/payloads/meterpreter/config'
module MetasploitModule
CachedSize = 956991
CachedSize = 171583
include Msf::Payload::TransportConfig
include Msf::Payload::Windows

View File

@ -12,7 +12,7 @@ require 'rex/payloads/meterpreter/config'
module MetasploitModule
CachedSize = 958035
CachedSize = 172627
include Msf::Payload::TransportConfig
include Msf::Payload::Windows

View File

@ -12,7 +12,7 @@ require 'rex/payloads/meterpreter/config'
module MetasploitModule
CachedSize = 958035
CachedSize = 172627
include Msf::Payload::TransportConfig
include Msf::Payload::Windows

View File

@ -12,7 +12,7 @@ require 'rex/payloads/meterpreter/config'
module MetasploitModule
CachedSize = 956991
CachedSize = 171583
include Msf::Payload::TransportConfig
include Msf::Payload::Windows

View File

@ -12,7 +12,7 @@ require 'rex/payloads/meterpreter/config'
module MetasploitModule
CachedSize = 956991
CachedSize = 171583
include Msf::Payload::TransportConfig
include Msf::Payload::Windows

View File

@ -12,7 +12,7 @@ require 'rex/payloads/meterpreter/config'
module MetasploitModule
CachedSize = 1188415
CachedSize = 194623
include Msf::Payload::TransportConfig
include Msf::Payload::Windows

View File

@ -12,7 +12,7 @@ require 'rex/payloads/meterpreter/config'
module MetasploitModule
CachedSize = 1189459
CachedSize = 195667
include Msf::Payload::TransportConfig
include Msf::Payload::Windows

View File

@ -12,7 +12,7 @@ require 'rex/payloads/meterpreter/config'
module MetasploitModule
CachedSize = 1189459
CachedSize = 195667
include Msf::Payload::TransportConfig
include Msf::Payload::Windows

View File

@ -12,7 +12,7 @@ require 'rex/payloads/meterpreter/config'
module MetasploitModule
CachedSize = 1188415
CachedSize = 194623
include Msf::Payload::TransportConfig
include Msf::Payload::Windows

View File

@ -12,7 +12,7 @@ require 'rex/payloads/meterpreter/config'
module MetasploitModule
CachedSize = 1188415
CachedSize = 194623
include Msf::Payload::TransportConfig
include Msf::Payload::Windows

View File

@ -462,7 +462,8 @@ RSpec.describe Rex::Post::Meterpreter::Packet do
rid = packet.rid
meth = packet.method
raw = packet.to_r
packet.from_r(raw)
packet.add_raw(raw)
packet.from_r
expect(packet.rid).to eq rid
expect(packet.method).to eq meth
end