CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/lib/metasploit/framework/login_scanner/smb.rb
Views: 1904
require 'metasploit/framework'1require 'metasploit/framework/tcp/client'2require 'metasploit/framework/login_scanner/base'3require 'metasploit/framework/login_scanner/rex_socket'4require 'metasploit/framework/login_scanner/kerberos'5require 'ruby_smb'67module Metasploit8module Framework9module LoginScanner10# This is the LoginScanner class for dealing with the Server Messaging11# Block protocol.12class SMB13include Metasploit::Framework::Tcp::Client14include Metasploit::Framework::LoginScanner::Base15include Metasploit::Framework::LoginScanner::RexSocket1617# Constants to be used in {Result#access_level}18module AccessLevels19# Administrative access. For SMB, this is defined as being20# able to successfully Tree Connect to the `ADMIN$` share.21# This definition is not without its problems, but suffices to22# conclude that such a user will most likely be able to use23# psexec.24ADMINISTRATOR = 'Administrator'.freeze25# Guest access means our creds were accepted but the logon26# session is not associated with a real user account.27GUEST = 'Guest'.freeze28end2930CAN_GET_SESSION = true31DEFAULT_REALM = 'WORKSTATION'.freeze32LIKELY_PORTS = [ 445 ].freeze33LIKELY_SERVICE_NAMES = [ 'smb' ].freeze34PRIVATE_TYPES = %i[password ntlm_hash].freeze35REALM_KEY = Metasploit::Model::Realm::Key::ACTIVE_DIRECTORY_DOMAIN3637module StatusCodes38CORRECT_CREDENTIAL_STATUS_CODES = [39WindowsError::NTStatus::STATUS_ACCOUNT_DISABLED,40WindowsError::NTStatus::STATUS_ACCOUNT_EXPIRED,41WindowsError::NTStatus::STATUS_ACCOUNT_RESTRICTION,42WindowsError::NTStatus::STATUS_INVALID_LOGON_HOURS,43WindowsError::NTStatus::STATUS_INVALID_WORKSTATION,44WindowsError::NTStatus::STATUS_LOGON_TYPE_NOT_GRANTED,45WindowsError::NTStatus::STATUS_PASSWORD_EXPIRED,46WindowsError::NTStatus::STATUS_PASSWORD_MUST_CHANGE,47].freeze48end4950# @returns [Array[Integer]] The SMB versions to negotiate51attr_accessor :versions5253# @returns [Boolean] By default the client uses encryption even if it is not required by the server. Disable this by setting always_encrypt to false54attr_accessor :always_encrypt5556# @!attribute dispatcher57# @return [RubySMB::Dispatcher::Socket]58attr_accessor :dispatcher5960# @!attribute kerberos_authenticator_factory61# @return [Func<username, password, realm> : Msf::Exploit::Remote::Kerberos::ServiceAuthenticator::SMB]62# A factory method for creating a kerberos authenticator63attr_accessor :kerberos_authenticator_factory6465# @returns [Boolean] If a login is successful and this attribute is true - a RubySMB::Client instance is used as proof,66# and the socket is not immediately closed67attr_accessor :use_client_as_proof6869# If login is successful and {Result#access_level} is not set70# then arbitrary credentials are accepted. If it is set to71# Guest, then arbitrary credentials are accepted, but given72# Guest permissions.73#74# @param domain [String] Domain to authenticate against. Use an75# empty string for local accounts.76# @return [Result]77def attempt_bogus_login(domain)78if defined?(@attempt_bogus_login)79return @attempt_bogus_login80end8182cred = Credential.new(83public: Rex::Text.rand_text_alpha(8),84private: Rex::Text.rand_text_alpha(8),85realm: domain86)87@attempt_bogus_login = attempt_login(cred)88end8990# (see Base#attempt_login)91def attempt_login(credential)92begin93connect94rescue ::Rex::ConnectionError => e95result = Result.new(96credential: credential,97status: Metasploit::Model::Login::Status::UNABLE_TO_CONNECT,98proof: e,99host: host,100port: port,101protocol: 'tcp',102service_name: 'smb'103)104return result105end106proof = nil107108begin109realm = (credential.realm || '').dup.force_encoding('UTF-8')110username = (credential.public || '').dup.force_encoding('UTF-8')111password = (credential.private || '').dup.force_encoding('UTF-8')112client = RubySMB::Client.new(113dispatcher,114username: username,115password: password,116domain: realm,117smb1: versions.include?(1),118smb2: versions.include?(2),119smb3: versions.include?(3),120always_encrypt: always_encrypt121)122123if kerberos_authenticator_factory124client.extend(Msf::Exploit::Remote::SMB::Client::KerberosAuthentication)125client.kerberos_authenticator = kerberos_authenticator_factory.call(username, password, realm)126end127128status_code = client.login129130if status_code == WindowsError::NTStatus::STATUS_SUCCESS131# Windows SMB will return an error code during Session132# Setup, but nix Samba requires a Tree Connect. Try admin$133# first, since that will tell us if this user has local134# admin access. Fall back to IPC$ which should be accessible135# to any user with valid creds.136begin137tree = client.tree_connect("\\\\#{host}\\admin$")138# Check to make sure we can write a file to this dir139if tree.permissions.add_file == 1140access_level = AccessLevels::ADMINISTRATOR141end142rescue StandardError => _e143client.tree_connect("\\\\#{host}\\IPC$")144end145end146147case status_code148when WindowsError::NTStatus::STATUS_SUCCESS, WindowsError::NTStatus::STATUS_PASSWORD_MUST_CHANGE, WindowsError::NTStatus::STATUS_PASSWORD_EXPIRED149status = Metasploit::Model::Login::Status::SUCCESSFUL150# This module no long owns the socket, return it as proof so the calling context can perform additional operations151# Additionally assign values to nil to avoid closing the socket etc automatically152if use_client_as_proof153proof = client154connection = self.sock155client = nil156self.sock = nil157self.dispatcher = nil158end159when WindowsError::NTStatus::STATUS_ACCOUNT_LOCKED_OUT160status = Metasploit::Model::Login::Status::LOCKED_OUT161when WindowsError::NTStatus::STATUS_LOGON_FAILURE, WindowsError::NTStatus::STATUS_ACCESS_DENIED162status = Metasploit::Model::Login::Status::INCORRECT163when *StatusCodes::CORRECT_CREDENTIAL_STATUS_CODES164status = Metasploit::Model::Login::Status::DENIED_ACCESS165else166status = Metasploit::Model::Login::Status::INCORRECT167end168rescue ::Rex::ConnectionError, Errno::EINVAL, RubySMB::Error::NetBiosSessionService, RubySMB::Error::NegotiationFailure, RubySMB::Error::CommunicationError => e169status = Metasploit::Model::Login::Status::UNABLE_TO_CONNECT170proof = e171rescue RubySMB::Error::UnexpectedStatusCode => _e172status = Metasploit::Model::Login::Status::INCORRECT173rescue Rex::Proto::Kerberos::Model::Error::KerberosError => e174status = Metasploit::Framework::LoginScanner::Kerberos.login_status_for_kerberos_error(e)175proof = e176rescue RubySMB::Error::RubySMBError => _e177status = Metasploit::Model::Login::Status::UNABLE_TO_CONNECT178proof = e179ensure180client.disconnect! if client181end182183if status == Metasploit::Model::Login::Status::SUCCESSFUL && credential.public.empty?184access_level ||= AccessLevels::GUEST185end186187result = Result.new(credential: credential,188status: status,189proof: proof,190access_level: access_level,191connection: connection)192result.host = host193result.port = port194result.protocol = 'tcp'195result.service_name = 'smb'196result197end198199def connect200disconnect201self.sock = super202self.dispatcher = RubySMB::Dispatcher::Socket.new(sock)203end204205def set_sane_defaults206self.connection_timeout = 10 if connection_timeout.nil?207self.max_send_size = 0 if max_send_size.nil?208self.send_delay = 0 if send_delay.nil?209self.always_encrypt = true if always_encrypt.nil?210self.versions = ::Rex::Proto::SMB::SimpleClient::DEFAULT_VERSIONS if versions.nil?211end212213end214end215end216end217218219