diff --git a/lib/metasploit/framework/credential.rb b/lib/metasploit/framework/credential.rb index 800a526344..c78af1baf5 100644 --- a/lib/metasploit/framework/credential.rb +++ b/lib/metasploit/framework/credential.rb @@ -12,6 +12,9 @@ module Metasploit # @return [Boolean] Whether BOTH a public and private are required # (defaults to `true`) attr_accessor :paired + # @!attribute parent + # @return [Object] the parent object that had .to_credential called on it to create this object + attr_accessor :parent # @!attribute private # The private credential component (e.g. username) # diff --git a/lib/metasploit/framework/login_scanner/base.rb b/lib/metasploit/framework/login_scanner/base.rb index d34db46aba..a69bed242d 100644 --- a/lib/metasploit/framework/login_scanner/base.rb +++ b/lib/metasploit/framework/login_scanner/base.rb @@ -83,6 +83,7 @@ module Metasploit # This could be a Credential object, or a Credential Core, or an Attempt object # so make sure that whatever it is, we end up with a Credential. credential = raw_cred.to_credential + credential.parent = raw_cred if credential.realm.present? && self.class::REALM_KEY.present? credential.realm_key = self.class::REALM_KEY @@ -129,7 +130,14 @@ module Metasploit successful_users = Set.new each_credential do |credential| - next if successful_users.include?(credential.public) + # For Pro bruteforce Reuse and Guess we need to note that we skipped an attempt. + if successful_users.include?(credential.public) + if credential.parent.respond_to?(:skipped) + credential.parent.skipped = true + credential.parent.save! + end + next + end result = attempt_login(credential) result.freeze