diff --git a/lib/msf/core/exploit/kerberos/client.rb b/lib/msf/core/exploit/kerberos/client.rb index b6e5432ae2..3a6e7d36fb 100644 --- a/lib/msf/core/exploit/kerberos/client.rb +++ b/lib/msf/core/exploit/kerberos/client.rb @@ -1,137 +1,143 @@ # -*- coding: binary -*- require 'rex/proto/kerberos' -module Msf::Exploit::Remote::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' +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 + 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 + # @!attribute client + # @return [Rex::Proto::Kerberos::Client] The kerberos client + attr_accessor :client - def initialize(info = {}) - super + 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 + 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 target host + # + # @return [String] + def rhost + datastore['RHOST'] + end - # Returns the remote port - # - # @return [Fixnum] - def rport - datastore['RPORT'] - 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 TCP timeout + # + # @return [Fixnum] + def timeout + datastore['Timeout'] + end - # Returns the kdc peer - # - # @return [String] - def peer - "#{rhost}:#{rport}" - 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' - ) + # 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 + disconnect if client + self.client = kerb_client - kerb_client - end + 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 + # 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 + 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 - - # 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 diff --git a/lib/msf/core/exploit/kerberos/client/as_request.rb b/lib/msf/core/exploit/kerberos/client/as_request.rb index 8d3a6ac8eb..62f2dc4593 100644 --- a/lib/msf/core/exploit/kerberos/client/as_request.rb +++ b/lib/msf/core/exploit/kerberos/client/as_request.rb @@ -1,108 +1,113 @@ # -*- coding: binary -*- require 'rex/proto/kerberos' -module Msf::Exploit::Remote::Kerberos - module Client - module AsRequest +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) - # 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 = 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 - 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] || '' - # 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 + ) - 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) + ) - 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 = Rex::Proto::Kerberos::Model::PreAuthData.new( - type: Rex::Proto::Kerberos::Model::PA_ENC_TIMESTAMP, - value: enc_time_stamp.encode - ) + pa_enc_time_stamp + end - 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) - # 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 = 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 + body + 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 index b954fd3329..3ebd852422 100644 --- a/lib/msf/core/exploit/kerberos/client/as_response.rb +++ b/lib/msf/core/exploit/kerberos/client/as_response.rb @@ -1,43 +1,48 @@ # -*- coding: binary -*- require 'rex/proto/kerberos' -module Msf::Exploit::Remote::Kerberos - module Client - module AsResponse +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) - # 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 - 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) - # 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 = enc_kdc_res.auth_time - - auth_time.to_i + auth_time.to_i + 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 index 41d46155e0..cb44a48507 100644 --- a/lib/msf/core/exploit/kerberos/client/base.rb +++ b/lib/msf/core/exploit/kerberos/client/base.rb @@ -1,41 +1,47 @@ # -*- coding: binary -*- -module Msf::Exploit::Remote::Kerberos - module Client - module Base +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 + # 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 + 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 + # 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('/') - ) + Rex::Proto::Kerberos::Model::PrincipalName.new( + name_type: name_type, + name_string: name.split('/') + ) + 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 index 5ff70f90fc..5c4eb96fa2 100644 --- a/lib/msf/core/exploit/kerberos/client/cache_credential.rb +++ b/lib/msf/core/exploit/kerberos/client/cache_credential.rb @@ -1,145 +1,151 @@ # -*- coding: binary -*- require 'rex/proto/kerberos' -module Msf::Exploit::Remote::Kerberos - module Client - module CacheCredential +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)] + # 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 = Rex::Proto::Kerberos::CredentialCache::Cache.new( + version: version, + headers: headers, + primary_principal: primary_principal, + credentials: credentials + ) - cache - end + 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] || [''] + # 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 = Rex::Proto::Kerberos::CredentialCache::Principal.new( + name_type: name_type, + realm: realm, + components:components + ) - principal - end + 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] || '' + # 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 = Rex::Proto::Kerberos::CredentialCache::KeyBlock.new( + key_type: key_type, + e_type: e_type, + key_value: key_value + ) - key_block - end + 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 + # 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 = 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 + 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] || '' + # 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 = 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 + cred + 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 index 5a06dfdcd0..03bf256513 100644 --- a/lib/msf/core/exploit/kerberos/client/pac.rb +++ b/lib/msf/core/exploit/kerberos/client/pac.rb @@ -1,109 +1,114 @@ # -*- coding: binary -*- require 'rex/proto/kerberos' -module Msf::Exploit::Remote::Kerberos - module Client - module Pac +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 - ) + # 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 + 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 - - # 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 diff --git a/lib/msf/core/exploit/kerberos/client/tgs_request.rb b/lib/msf/core/exploit/kerberos/client/tgs_request.rb index 5573136288..27670f4f10 100644 --- a/lib/msf/core/exploit/kerberos/client/tgs_request.rb +++ b/lib/msf/core/exploit/kerberos/client/tgs_request.rb @@ -1,270 +1,276 @@ # -*- coding: binary -*- require 'rex/proto/kerberos' -module Msf::Exploit::Remote::Kerberos - module Client - module TgsRequest +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) + # 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 + 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 - - 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 diff --git a/lib/msf/core/exploit/kerberos/client/tgs_response.rb b/lib/msf/core/exploit/kerberos/client/tgs_response.rb index 16d26f7e32..bc16bbc9e5 100644 --- a/lib/msf/core/exploit/kerberos/client/tgs_response.rb +++ b/lib/msf/core/exploit/kerberos/client/tgs_response.rb @@ -1,71 +1,77 @@ # -*- coding: binary -*- require 'rex/proto/kerberos' -module Msf::Exploit::Remote::Kerberos - module Client - module TgsResponse +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) + # 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 - ) + 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 - ) + 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 - ) + 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 - ) + 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 - ) + 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_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 = create_cache( + primary_principal: cache_principal, + credentials: [credential] + ) - cache + cache + end + end + end end end end diff --git a/spec/lib/msf/core/exploit/kerberos/client/as_request_spec.rb b/spec/lib/msf/core/exploit/kerberos/client/as_request_spec.rb index 0bb19abe6d..c1be46e24a 100644 --- a/spec/lib/msf/core/exploit/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/core/exploit/kerberos/client/as_response_spec.rb b/spec/lib/msf/core/exploit/kerberos/client/as_response_spec.rb index 68584e7156..cebe701d68 100644 --- a/spec/lib/msf/core/exploit/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/core/exploit/kerberos/client/base_spec.rb b/spec/lib/msf/core/exploit/kerberos/client/base_spec.rb index cb1f03a495..87fb9e42ca 100644 --- a/spec/lib/msf/core/exploit/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/core/exploit/kerberos/client/cache_credential_spec.rb b/spec/lib/msf/core/exploit/kerberos/client/cache_credential_spec.rb index 31688efa0f..159caf6b9d 100644 --- a/spec/lib/msf/core/exploit/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/core/exploit/kerberos/client/pac_spec.rb b/spec/lib/msf/core/exploit/kerberos/client/pac_spec.rb index 6251d30e46..698872fc5a 100644 --- a/spec/lib/msf/core/exploit/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/core/exploit/kerberos/client/tgs_request_spec.rb b/spec/lib/msf/core/exploit/kerberos/client/tgs_request_spec.rb index d05810c7a5..842ea2af51 100644 --- a/spec/lib/msf/core/exploit/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/core/exploit/kerberos/client/tgs_response_spec.rb b/spec/lib/msf/core/exploit/kerberos/client/tgs_response_spec.rb index fe60ddcd52..6f399b0f82 100644 --- a/spec/lib/msf/core/exploit/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