Path: blob/master/lib/metasploit/framework/login_scanner/kerberos.rb
32979 views
require 'metasploit/framework/login_scanner/base'12module Metasploit3module Framework4module LoginScanner56# Kerberos User scanner7class Kerberos8include Metasploit::Framework::LoginScanner::Base9include Msf::Exploit::Remote::Kerberos::Client1011DEFAULT_PORT = 8812REALM_KEY = Metasploit::Model::Realm::Key::ACTIVE_DIRECTORY_DOMAIN13DEFAULT_REALM = nil14LIKELY_PORTS = [ DEFAULT_PORT ].freeze15LIKELY_SERVICE_NAMES = [ 'kerberos', 'kerberos5', 'krb5', 'kerberos-sec' ].freeze16PRIVATE_TYPES = %i[ password ].freeze17CAN_GET_SESSION = true1819def attempt_login(credential)20result_options = {21credential: credential,22host: host,23port: port,24protocol: 'tcp',25service_name: 'kerberos'26}2728begin29self.kerberos_clock_skew = clock_skew if clock_skew30res = send_request_tgt(31server_name: server_name,32client_name: credential.public,33password: credential.private,34realm: credential.realm35)36unless res.preauth_required37# Pre-auth not required - let's get an RC4-HMAC ticket, since it's more easily crackable38begin39res = send_request_tgt(40server_name: server_name,41client_name: credential.public,42password: credential.private,43realm: credential.realm,44offered_etypes: [Rex::Proto::Kerberos::Crypto::Encryption::RC4_HMAC]45)46rescue Rex::Proto::Kerberos::Model::Error::KerberosEncryptionNotSupported => e47# RC4 likely disabled - let's just use the initial response48end49end5051result_options = result_options.merge(52{53status: Metasploit::Model::Login::Status::SUCCESSFUL,54proof: res55}56)57return Metasploit::Framework::LoginScanner::Result.new(result_options)58rescue ::EOFError => e59result_options = result_options.merge({ status: Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: e })60return Metasploit::Framework::LoginScanner::Result.new(result_options)61rescue Rex::Proto::Kerberos::Model::Error::KerberosError => e62status = self.class.login_status_for_kerberos_error(e)63result_options = result_options.merge({ status: status, proof: e })64return Metasploit::Framework::LoginScanner::Result.new(result_options)65end66end6768attr_accessor :server_name69attr_accessor :clock_skew7071# Override the kerberos client's methods with the login scanner implementations72alias rhost host73alias rport port74alias timeout connection_timeout7576# @param [Rex::Proto::Kerberos::Model::Error::KerberosError] krb_err The kerberos error77def self.login_status_for_kerberos_error(krb_err)78error_code = krb_err.error_code79case error_code80when Rex::Proto::Kerberos::Model::Error::ErrorCodes::KDC_ERR_KEY_EXPIRED, Rex::Proto::Kerberos::Model::Error::ErrorCodes::KRB_AP_ERR_SKEW81# Correct password, but either password needs resetting or clock is skewed82begin83pa_data_entry = krb_err.res.e_data_as_pa_data.find do |pa_data|84pa_data.type == Rex::Proto::Kerberos::Model::PreAuthType::PA_PW_SALT85end8687if pa_data_entry88pw_salt = pa_data_entry.decoded_value89if pw_salt.nt_status90case pw_salt.nt_status.value91when ::WindowsError::NTStatus::STATUS_PASSWORD_EXPIRED92# Windows Server 2019 Build 17763 (possibly others) replies with STATUS_PASSWORD_EXPIRED even when the password is incorrect93Metasploit::Model::Login::Status::INCORRECT94else95Metasploit::Model::Login::Status::SUCCESSFUL96end97else98Metasploit::Model::Login::Status::SUCCESSFUL99end100else101Metasploit::Model::Login::Status::SUCCESSFUL102end103rescue Rex::Proto::Kerberos::Model::Error::KerberosDecodingError104Metasploit::Model::Login::Status::SUCCESSFUL105end106when Rex::Proto::Kerberos::Model::Error::ErrorCodes::KDC_ERR_C_PRINCIPAL_UNKNOWN107# The username doesn't exist108Metasploit::Model::Login::Status::INVALID_PUBLIC_PART109when Rex::Proto::Kerberos::Model::Error::ErrorCodes::KDC_ERR_CLIENT_REVOKED110# Locked out, disabled or expired111# It doesn't appear to be documented anywhere, but Microsoft gives us a bit112# of extra information in the e-data section113begin114pa_data_entry = krb_err.res.e_data_as_pa_data.find do |pa_data|115pa_data.type == Rex::Proto::Kerberos::Model::PreAuthType::PA_PW_SALT116end117118if pa_data_entry119pw_salt = pa_data_entry.decoded_value120if pw_salt.nt_status121case pw_salt.nt_status.value122when ::WindowsError::NTStatus::STATUS_ACCOUNT_LOCKED_OUT123Metasploit::Model::Login::Status::LOCKED_OUT124when ::WindowsError::NTStatus::STATUS_ACCOUNT_DISABLED125Metasploit::Model::Login::Status::DISABLED126when ::WindowsError::NTStatus::STATUS_ACCOUNT_EXPIRED127# Actually expired, which is effectively Disabled128Metasploit::Model::Login::Status::DISABLED129else130# Unknown - maintain existing behaviour131Metasploit::Model::Login::Status::DISABLED132end133else134Metasploit::Model::Login::Status::DISABLED135end136else137Metasploit::Model::Login::Status::DISABLED138end139rescue Rex::Proto::Kerberos::Model::Error::KerberosDecodingError140# Could be a non-MS implementation?141Metasploit::Model::Login::Status::DISABLED142end143else144Metasploit::Model::Login::Status::INCORRECT145end146end147148private149150def set_sane_defaults151self.connection_timeout = 10 if self.connection_timeout.nil?152self.port = DEFAULT_PORT unless self.port153end154155def print_status(*args)156framework_module.print_status(*args) if framework_module157end158159def print_good(*args)160framework_module.print_good(*args) if framework_module161end162163def vprint_status(*args)164framework_module.vprint_status(*args) if framework_module165end166end167end168end169end170171172