Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixing multiple bugs in credential generation + refactoring #19653

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
289 changes: 99 additions & 190 deletions lib/metasploit/framework/credential_collection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -212,23 +212,6 @@ class CredentialCollection < PrivateCredentialCollection
# @return [Boolean]
attr_accessor :anonymous_login

# @!attribute ignore_private
# Whether to ignore private (password). This is usually set when Kerberos
# or Schannel authentication is requested and the credentials are
# retrieved from cache or from a file. This attribute should be true in
# these scenarios, otherwise validation will fail since the password is not
# provided.
# @return [Boolean]
attr_accessor :ignore_private

# @!attribute ignore_public
# Whether to ignore public (username). This is usually set when Schannel
# authentication is requested and the credentials are retrieved from a
# file (certificate). This attribute should be true in this case,
# otherwise validation will fail since the password is not provided.
# @return [Boolean]
attr_accessor :ignore_public

# @option opts [Boolean] :blank_passwords See {#blank_passwords}
# @option opts [String] :pass_file See {#pass_file}
# @option opts [String] :password See {#password}
Expand Down Expand Up @@ -257,29 +240,29 @@ def add_public(public_str='')
# @yieldparam credential [Metasploit::Framework::Credential]
# @return [void]
def each_filtered
if ignore_private
if ignore_public
yield Metasploit::Framework::Credential.new(public: nil, private: nil, realm: realm)
else
yield Metasploit::Framework::Credential.new(public: username, private: nil, realm: realm)
end
elsif password_spray
each_unfiltered_password_first do |credential|
next unless self.filter.nil? || self.filter.call(credential)

yield credential
end
else
each_unfiltered_username_first do |credential|
next unless self.filter.nil? || self.filter.call(credential)
each_unfiltered do |credential|
next unless self.filter.nil? || self.filter.call(credential)

yield credential
end
yield credential
end
end

alias each each_filtered

def each_unfiltered(&block)
prepended_creds.each { |c| yield c }

if anonymous_login
yield Metasploit::Framework::Credential.new(public: '', private: '', realm: realm, private_type: :password)
end

cgranleese-r7 marked this conversation as resolved.
Show resolved Hide resolved
if password_spray
each_unfiltered_password_first(&block)
else
each_unfiltered_username_first(&block)
end
end

# When password spraying is enabled, do first passwords then usernames
# i.e.
# username1:password1
Expand All @@ -293,117 +276,72 @@ def each_filtered
# @yieldparam credential [Metasploit::Framework::Credential]
# @return [void]
def each_unfiltered_password_first
if user_file.present?
user_fd = File.open(user_file, 'r:binary')
end

prepended_creds.each { |c| yield c }

if anonymous_login
yield Metasploit::Framework::Credential.new(public: '', private: '', realm: realm, private_type: :password)
end

if user_as_pass
if user_fd
user_fd.each_line do |user_from_file|
user_from_file.chomp!
yield Metasploit::Framework::Credential.new(public: user_from_file, private: user_from_file, realm: realm, private_type: private_type(password))
end
user_fd.seek(0)
if nil_passwords
each_username do |username|
yield Metasploit::Framework::Credential.new(public: username, private: nil, realm: realm, private_type: :password)
end
end

if password.present?
if nil_passwords
yield Metasploit::Framework::Credential.new(public: username, private: nil, realm: realm, private_type: :password)
end
if username.present?
each_username do |username|
yield Metasploit::Framework::Credential.new(public: username, private: password, realm: realm, private_type: private_type(password))
end
if user_as_pass
end

if user_as_pass
each_username do |username|
yield Metasploit::Framework::Credential.new(public: username, private: username, realm: realm, private_type: :password)
end
if blank_passwords
end

if blank_passwords
each_username do |username|
yield Metasploit::Framework::Credential.new(public: username, private: "", realm: realm, private_type: :password)
end
if user_fd
user_fd.each_line do |user_from_file|
user_from_file.chomp!
yield Metasploit::Framework::Credential.new(public: user_from_file, private: password, realm: realm, private_type: private_type(password))
end
user_fd.seek(0)
end
end

if pass_file.present?
File.open(pass_file, 'r:binary') do |pass_fd|
pass_fd.each_line do |pass_from_file|
pass_from_file.chomp!
if username.present?
yield Metasploit::Framework::Credential.new(public: username, private: pass_from_file, realm: realm, private_type: :password)
end
next unless user_fd

user_fd.each_line do |user_from_file|
user_from_file.chomp!
yield Metasploit::Framework::Credential.new(public: user_from_file, private: pass_from_file, realm: realm, private_type: private_type(pass_from_file))
each_username do |username|
yield Metasploit::Framework::Credential.new(public: username, private: pass_from_file, realm: realm, private_type: private_type(pass_from_file))
end
user_fd.seek(0)
end
end
end

if userpass_file.present?
File.open(userpass_file, 'r:binary') do |userpass_fd|
userpass_fd.each_line do |line|
user, pass = line.split(" ", 2)
if pass.blank?
pass = ''
else
pass.chomp!
end
yield Metasploit::Framework::Credential.new(public: user, private: pass, realm: realm)
end
end
each_user_pass_from_userpass_file do |user, pass|
yield Metasploit::Framework::Credential.new(public: user, private: pass, realm: realm)
end

additional_privates.each do |add_private|
if username.present?
each_username do |username|
yield Metasploit::Framework::Credential.new(public: username, private: add_private, realm: realm, private_type: private_type(add_private))
end
user_fd.each_line do |user_from_file|
user_from_file.chomp!
yield Metasploit::Framework::Credential.new(public: user_from_file, private: add_private, realm: realm, private_type: private_type(add_private))
end
user_fd.seek(0)
end
end

additional_publics.each do |add_public|
if password.present?
yield Metasploit::Framework::Credential.new(public: add_public, private: password, realm: realm, private_type: private_type(password) )
end
if user_as_pass
yield Metasploit::Framework::Credential.new(public: add_public, private: user_from_file, realm: realm, private_type: :password)
end
if blank_passwords
yield Metasploit::Framework::Credential.new(public: add_public, private: "", realm: realm, private_type: :password)
end
if nil_passwords
yield Metasploit::Framework::Credential.new(public: add_public, private: nil, realm: realm, private_type: :password)
end
if user_fd
# Iterates over all possible usernames
def each_username
if username.present?
yield username
end

if user_file.present?
File.open(user_file, 'r:binary') do |user_fd|
user_fd.each_line do |user_from_file|
user_from_file.chomp!
yield Metasploit::Framework::Credential.new(public: add_public, private: user_from_file, realm: realm, private_type: private_type(user_from_file))
yield user_from_file
end
user_fd.seek(0)
end
additional_privates.each do |add_private|
yield Metasploit::Framework::Credential.new(public: add_public, private: add_private, realm: realm, private_type: private_type(add_private))
end
end
ensure
user_fd.close if user_fd && !user_fd.closed?

additional_publics.each do |add_public|
yield add_public
end
end

# When password spraying is not enabled, do first usernames then passwords
Expand All @@ -418,108 +356,79 @@ def each_unfiltered_password_first
# @yieldparam credential [Metasploit::Framework::Credential]
# @return [void]
def each_unfiltered_username_first
if pass_file.present?
pass_fd = File.open(pass_file, 'r:binary')
end

prepended_creds.each { |c| yield c }

if anonymous_login
yield Metasploit::Framework::Credential.new(public: '', private: '', realm: realm, private_type: :password)
end

if username.present?
if nil_passwords
yield Metasploit::Framework::Credential.new(public: username, private: nil, realm: realm, private_type: :password)
end
if password.present?
yield Metasploit::Framework::Credential.new(public: username, private: password, realm: realm, private_type: private_type(password))
end
if user_as_pass
yield Metasploit::Framework::Credential.new(public: username, private: username, realm: realm, private_type: :password)
end
if blank_passwords
yield Metasploit::Framework::Credential.new(public: username, private: "", realm: realm, private_type: :password)
end
if pass_fd
pass_fd.each_line do |pass_from_file|
pass_from_file.chomp!
yield Metasploit::Framework::Credential.new(public: username, private: pass_from_file, realm: realm, private_type: private_type(pass_from_file))
end
pass_fd.seek(0)
end
additional_privates.each do |add_private|
yield Metasploit::Framework::Credential.new(public: username, private: add_private, realm: realm, private_type: private_type(add_private))
each_password(username) do |password, private_type|
yield Metasploit::Framework::Credential.new(public: username, private: password, realm: realm, private_type: private_type)
end
end

if user_file.present?
File.open(user_file, 'r:binary') do |user_fd|
user_fd.each_line do |user_from_file|
user_from_file.chomp!
if nil_passwords
yield Metasploit::Framework::Credential.new(public: user_from_file, private: nil, realm: realm, private_type: :password)
end
if password.present?
yield Metasploit::Framework::Credential.new(public: user_from_file, private: password, realm: realm, private_type: private_type(password) )
end
if user_as_pass
yield Metasploit::Framework::Credential.new(public: user_from_file, private: user_from_file, realm: realm, private_type: :password)
end
if blank_passwords
yield Metasploit::Framework::Credential.new(public: user_from_file, private: "", realm: realm, private_type: :password)
end
if pass_fd
pass_fd.each_line do |pass_from_file|
pass_from_file.chomp!
yield Metasploit::Framework::Credential.new(public: user_from_file, private: pass_from_file, realm: realm, private_type: private_type(pass_from_file))
end
pass_fd.seek(0)
end
additional_privates.each do |add_private|
yield Metasploit::Framework::Credential.new(public: user_from_file, private: add_private, realm: realm, private_type: private_type(add_private))
each_password(user_from_file) do |password, private_type|
yield Metasploit::Framework::Credential.new(public: user_from_file, private: password, realm: realm, private_type: private_type)
end
end
end
end

if userpass_file.present?
File.open(userpass_file, 'r:binary') do |userpass_fd|
userpass_fd.each_line do |line|
user, pass = line.split(" ", 2)
if pass.blank?
pass = ''
else
pass.chomp!
end
yield Metasploit::Framework::Credential.new(public: user, private: pass, realm: realm)
end
end
each_user_pass_from_userpass_file do |user, pass|
yield Metasploit::Framework::Credential.new(public: user, private: pass, realm: realm)
end

additional_publics.each do |add_public|
if password.present?
yield Metasploit::Framework::Credential.new(public: add_public, private: password, realm: realm, private_type: private_type(password) )
each_password(add_public) do |password, private_type|
yield Metasploit::Framework::Credential.new(public: add_public, private: password, realm: realm, private_type: private_type)
end
if user_as_pass
yield Metasploit::Framework::Credential.new(public: add_public, private: user_from_file, realm: realm, private_type: :password)
end
if blank_passwords
yield Metasploit::Framework::Credential.new(public: add_public, private: "", realm: realm, private_type: :password)
end
if pass_fd
end
end

# Iterates over all possible passwords
def each_password(user)
if nil_passwords
yield [nil, :password]
end

if password.present?
yield [password, private_type(password)]
end

if user_as_pass
yield [user, :password]
end

if blank_passwords
yield ["", :password]
end

if pass_file
File.open(pass_file, 'r:binary') do |pass_fd|
pass_fd.each_line do |pass_from_file|
pass_from_file.chomp!
yield Metasploit::Framework::Credential.new(public: add_public, private: pass_from_file, realm: realm, private_type: private_type(pass_from_file))
yield [pass_from_file, private_type(pass_from_file)]
end
pass_fd.seek(0)
end
additional_privates.each do |add_private|
yield Metasploit::Framework::Credential.new(public: add_public, private: add_private, realm: realm, private_type: private_type(add_private))
end

additional_privates.each do |add_private|
yield [add_private, private_type(add_private)]
end
end

# Iterates on userpass file if present
def each_user_pass_from_userpass_file
return unless userpass_file.present?

File.open(userpass_file, 'r:binary') do |userpass_fd|
userpass_fd.each_line do |line|
user, pass = line.split(" ", 2)
pass = pass.blank? ? '' : pass.chomp!

yield [user, pass]
end
end
ensure
pass_fd.close if pass_fd && !pass_fd.closed?
end

# Returns true when #each will have no results to iterate
Expand All @@ -533,14 +442,14 @@ def empty?
#
# @return [Boolean]
def has_users?
username.present? || user_file.present? || userpass_file.present? || !additional_publics.empty? || !!ignore_public
username.present? || user_file.present? || userpass_file.present? || !additional_publics.empty?
end

# Returns true when there are any private values set
#
# @return [Boolean]
def has_privates?
super || userpass_file.present? || user_as_pass || !!ignore_private
super || userpass_file.present? || user_as_pass
end

end
Expand Down
Loading
Loading