From 67b1a19aa1272f40724615a0b464dfeaf2c1f160 Mon Sep 17 00:00:00 2001 From: OJ Date: Sun, 25 Jun 2017 10:24:00 +1000 Subject: [PATCH] Finalised MSF-side of AES key negotiation over RSA --- lib/msf/base/sessions/meterpreter_options.rb | 1 - lib/rex/post/meterpreter/client_core.rb | 27 +++++++++++++++---- lib/rex/post/meterpreter/packet.rb | 17 +++--------- lib/rex/post/meterpreter/packet_dispatcher.rb | 4 --- lib/rex/post/meterpreter/packet_parser.rb | 2 -- 5 files changed, 26 insertions(+), 25 deletions(-) diff --git a/lib/msf/base/sessions/meterpreter_options.rb b/lib/msf/base/sessions/meterpreter_options.rb index 65d2697761..8208a34446 100644 --- a/lib/msf/base/sessions/meterpreter_options.rb +++ b/lib/msf/base/sessions/meterpreter_options.rb @@ -55,7 +55,6 @@ module MeterpreterOptions if valid # always make sure that the new session has a new guid if it's not already known guid = session.session_guid - STDERR.puts("Session GUID is #{guid}\n") if guid == '00000000-0000-0000-0000-000000000000' guid = SecureRandom.uuid session.core.set_session_guid(guid) diff --git a/lib/rex/post/meterpreter/client_core.rb b/lib/rex/post/meterpreter/client_core.rb index a181f52acf..fb784701be 100644 --- a/lib/rex/post/meterpreter/client_core.rb +++ b/lib/rex/post/meterpreter/client_core.rb @@ -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 @@ -75,7 +77,6 @@ class ClientCore < Extension begin response = self.client.send_packet_wait_response(request, self.client.response_timeout) rescue - STDERR.puts("Getting ext commands for #{extension_name} failed with an exception\n") # In the case where orphaned shells call back with OLD copies of the meterpreter # binaries, we end up with a case where this fails. So here we just return the # empty list of supported commands. @@ -212,7 +213,6 @@ class ClientCore < Extension } if image - STDERR.puts("Capabilities zlib: #{client.capabilities[:zlib]}\n") request.add_tlv(TLV_TYPE_DATA, image, false, client.capabilities[:zlib]) else raise RuntimeError, "Failed to serialize library #{library_path}.", caller @@ -289,8 +289,6 @@ class ClientCore < Extension raise RuntimeError, "No module of the name #{modname}.#{client.binary_suffix} found", caller end - STDERR.puts("Going to try to load #{mod} from #{path}\n") - # Load the extension DLL commands = load_library( 'LibraryFilePath' => path, @@ -688,9 +686,28 @@ class ClientCore < Extension # Negotiates the use of AES256 encryption over the TLV packets. # def negotiate_aes + aes_key = nil + rsa_key = OpenSSL::PKey::RSA.new(2048) + rsa_pub_key = rsa_key.public_key + request = Packet.create_request('core_negotiate_aes') + request.add_tlv(TLV_TYPE_RSA_PUB_KEY, rsa_pub_key.to_pem) + response = client.send_request(request) - response.get_tlv_value(TLV_TYPE_AES_KEY) + aes_key_enc = response.get_tlv_value(TLV_TYPE_ENC_AES_KEY) + + if aes_key_enc + begin + aes_key = rsa_key.private_decrypt(aes_key_enc, OpenSSL::PKey::RSA::PKCS1_PADDING) + rescue OpenSSL::PKey::RSAError + # probably failed due to padding, everything else can be bubbled up, but + # we'll stick with a blank key + end + else + aes_key = response.get_tlv_value(TLV_TYPE_AES_KEY) + end + + aes_key end private diff --git a/lib/rex/post/meterpreter/packet.rb b/lib/rex/post/meterpreter/packet.rb index 91cfcab6e0..5235d481d7 100644 --- a/lib/rex/post/meterpreter/packet.rb +++ b/lib/rex/post/meterpreter/packet.rb @@ -111,6 +111,8 @@ TLV_TYPE_SESSION_GUID = TLV_META_TYPE_RAW | 462 TLV_TYPE_CIPHER_NAME = TLV_META_TYPE_STRING | 500 TLV_TYPE_CIPHER_PARAMETERS = TLV_META_TYPE_GROUP | 501 TLV_TYPE_AES_KEY = TLV_META_TYPE_RAW | 550 +TLV_TYPE_ENC_AES_KEY = TLV_META_TYPE_RAW | 551 +TLV_TYPE_RSA_PUB_KEY = TLV_META_TYPE_STRING | 552 # # Core flags @@ -222,6 +224,8 @@ class Tlv when TLV_TYPE_UUID; "UUID" when TLV_TYPE_SESSION_GUID; "SESSION-GUID" when TLV_TYPE_AES_KEY; "AES-KEY" + when TLV_TYPE_ENC_AES_KEY; "ENC-AES-KEY" + when TLV_TYPE_RSA_PUB_KEY; "RSA-PUB-KEY" #when Extensions::Stdapi::TLV_TYPE_NETWORK_INTERFACE; 'network-interface' #when Extensions::Stdapi::TLV_TYPE_IP; 'ip-address' @@ -740,12 +744,6 @@ class Packet < GroupTlv def raw_bytes_required # if we have the xor bytes and length ... if self.raw.length >= REQUIRED_PREFIX_SIZE - p = [ self.raw[0,4].unpack('H*')[0], - self.raw[4,16].unpack('H*')[0], - self.raw[20].unpack('H*')[0], - self.raw[21,4].unpack('H*')[0] ].join('-') - STDERR.puts("Incoming packet: #{p}\n") - # return a value based on the length of the data indicated by # the header xor_key = self.raw[XOR_KEY_OFF, XOR_KEY_SIZE] @@ -795,7 +793,6 @@ class Packet < GroupTlv # scrambled data as the payload. # def to_r(session_guid, aes_key=nil) - STDERR.puts("AES key: #{aes_key.inspect}\n") xor_key = (rand(254) + 1).chr + (rand(254) + 1).chr + (rand(254) + 1).chr + (rand(254) + 1).chr raw = [session_guid.gsub(/-/, '')].pack('H*') @@ -803,12 +800,9 @@ class Packet < GroupTlv if aes_key raw << "\x01" - STDERR.puts("Doing the encryption!\n") # encrypt the data, but not include the length and type iv, ciphertext = aes_encrypt(aes_key, tlv_data[HEADER_SIZE, tlv_data.length - HEADER_SIZE]) - STDERR.puts("Encryption done! IV is #{iv.unpack('H*')[0]}\n") # now manually add the length/type/iv/ciphertext - STDERR.puts("len/type: #{[iv.length + ciphertext.length + HEADER_SIZE, self.type].inspect}\n") raw << [iv.length + ciphertext.length + HEADER_SIZE, self.type].pack('NN') raw << iv raw << ciphertext @@ -836,17 +830,14 @@ class Packet < GroupTlv packet_type = data[PACKET_TYPE_OFF, PACKET_TYPE_SIZE] self.type = packet_type.unpack('N')[0] if encrypted_flag - STDERR.puts("Packet is encrypted\n") # TODO error when there's no aes key iv = data[PACKET_DATA_OFF, AES_IV_SIZE] raw = aes_decrypt(aes_key, iv, data[PACKET_DATA_OFF + AES_IV_SIZE, data.length - PACKET_DATA_OFF - AES_IV_SIZE]) else - STDERR.puts("Packet isn't encrypted\n") raw = data[PACKET_DATA_OFF, data.length - PACKET_DATA_OFF] end super(packet_length + packet_type + raw) - STDERR.puts("Received packet: #{self.inspect}\n") end # diff --git a/lib/rex/post/meterpreter/packet_dispatcher.rb b/lib/rex/post/meterpreter/packet_dispatcher.rb index 7c06abf097..2ba6de6549 100644 --- a/lib/rex/post/meterpreter/packet_dispatcher.rb +++ b/lib/rex/post/meterpreter/packet_dispatcher.rb @@ -162,8 +162,6 @@ module PacketDispatcher add_response_waiter(packet, completion_routine, completion_param) end - STDERR.puts("Sending packet: #{packet.inspect}\n") - bytes = 0 raw = packet.to_r(self.session_guid, self.aes_key) err = nil @@ -430,9 +428,7 @@ module PacketDispatcher packet = parser.recv(self.sock) if packet packet.from_r(self.aes_key) - STDERR.puts("Current GUID in packet dispatcher: #{self.session_guid}\n") if self.session_guid == '00000000-0000-0000-0000-000000000000' - STDERR.puts("Packet Session GUID : #{packet.session_guid.inspect}\n") 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 diff --git a/lib/rex/post/meterpreter/packet_parser.rb b/lib/rex/post/meterpreter/packet_parser.rb index 0575fd11bc..28bd1ef584 100644 --- a/lib/rex/post/meterpreter/packet_parser.rb +++ b/lib/rex/post/meterpreter/packet_parser.rb @@ -31,7 +31,6 @@ class PacketParser # def recv(sock) bytes_left = self.packet.raw_bytes_required - STDERR.puts("Waiting for bytes: #{bytes_left}\n") if bytes_left > 0 raw = sock.read(bytes_left) @@ -43,7 +42,6 @@ class PacketParser end if self.packet.raw_bytes_required == 0 - STDERR.puts("Packet is ready ...\n") packet = self.packet reset return packet