2014-06-04 18:01:09 +00:00
|
|
|
require 'metasploit/framework/credential'
|
|
|
|
|
|
|
|
class Metasploit::Framework::CredentialCollection
|
|
|
|
|
2015-01-07 17:30:39 +00:00
|
|
|
# @!attribute additional_privates
|
|
|
|
# Additional privates to be combined
|
|
|
|
#
|
|
|
|
# @return [Array<String>]
|
|
|
|
attr_accessor :additional_privates
|
|
|
|
|
|
|
|
# @!attribute additional_publics
|
|
|
|
# Additional public to be combined
|
|
|
|
#
|
|
|
|
# @return [Array<String>]
|
|
|
|
attr_accessor :additional_publics
|
|
|
|
|
2014-06-04 19:44:53 +00:00
|
|
|
# @!attribute blank_passwords
|
|
|
|
# Whether each username should be tried with a blank password
|
|
|
|
# @return [Boolean]
|
2014-06-04 18:01:09 +00:00
|
|
|
attr_accessor :blank_passwords
|
2014-06-11 19:30:45 +00:00
|
|
|
|
2014-06-04 19:44:53 +00:00
|
|
|
# @!attribute pass_file
|
|
|
|
# Path to a file containing passwords, one per line
|
|
|
|
# @return [String]
|
2014-06-04 18:01:09 +00:00
|
|
|
attr_accessor :pass_file
|
2014-06-11 19:30:45 +00:00
|
|
|
|
2014-06-04 19:44:53 +00:00
|
|
|
# @!attribute password
|
|
|
|
# @return [String]
|
2014-06-04 18:01:09 +00:00
|
|
|
attr_accessor :password
|
2014-06-11 19:30:45 +00:00
|
|
|
|
|
|
|
# @!attribute prepended_creds
|
|
|
|
# List of credentials to be tried before any others
|
|
|
|
#
|
|
|
|
# @see #prepend_cred
|
|
|
|
# @return [Array<Credential>]
|
|
|
|
attr_accessor :prepended_creds
|
|
|
|
|
2014-06-06 17:12:32 +00:00
|
|
|
# @!attribute realm
|
|
|
|
# @return [String]
|
|
|
|
attr_accessor :realm
|
2014-06-11 21:21:59 +00:00
|
|
|
|
2014-06-04 19:44:53 +00:00
|
|
|
# @!attribute user_as_pass
|
|
|
|
# Whether each username should be tried as a password for that user
|
|
|
|
# @return [Boolean]
|
2014-06-04 18:01:09 +00:00
|
|
|
attr_accessor :user_as_pass
|
2014-06-11 19:30:45 +00:00
|
|
|
|
2014-06-04 19:44:53 +00:00
|
|
|
# @!attribute user_file
|
|
|
|
# Path to a file containing usernames, one per line
|
|
|
|
# @return [String]
|
2014-06-04 18:01:09 +00:00
|
|
|
attr_accessor :user_file
|
2014-06-11 19:30:45 +00:00
|
|
|
|
2014-06-04 19:44:53 +00:00
|
|
|
# @!attribute username
|
|
|
|
# @return [String]
|
2014-06-04 18:01:09 +00:00
|
|
|
attr_accessor :username
|
2014-06-11 19:30:45 +00:00
|
|
|
|
2014-06-06 17:12:32 +00:00
|
|
|
# @!attribute userpass_file
|
2014-06-12 21:03:02 +00:00
|
|
|
# Path to a file containing usernames and passwords separated by a space,
|
2014-06-04 19:44:53 +00:00
|
|
|
# one pair per line
|
|
|
|
# @return [String]
|
2014-06-04 18:01:09 +00:00
|
|
|
attr_accessor :userpass_file
|
|
|
|
|
2014-06-04 19:44:53 +00:00
|
|
|
# @option opts [Boolean] :blank_passwords See {#blank_passwords}
|
|
|
|
# @option opts [String] :pass_file See {#pass_file}
|
|
|
|
# @option opts [String] :password See {#password}
|
2014-06-11 19:30:45 +00:00
|
|
|
# @option opts [Array<Credential>] :prepended_creds ([]) See {#prepended_creds}
|
2014-06-04 19:44:53 +00:00
|
|
|
# @option opts [Boolean] :user_as_pass See {#user_as_pass}
|
|
|
|
# @option opts [String] :user_file See {#user_file}
|
|
|
|
# @option opts [String] :username See {#username}
|
|
|
|
# @option opts [String] :userpass_file See {#userpass_file}
|
2014-06-04 18:01:09 +00:00
|
|
|
def initialize(opts = {})
|
|
|
|
opts.each do |attribute, value|
|
|
|
|
public_send("#{attribute}=", value)
|
|
|
|
end
|
2015-01-07 17:41:41 +00:00
|
|
|
self.prepended_creds ||= []
|
|
|
|
self.additional_privates ||= []
|
|
|
|
self.additional_publics ||= []
|
2014-06-11 19:30:45 +00:00
|
|
|
end
|
2015-01-07 17:30:39 +00:00
|
|
|
|
|
|
|
# Adds a string as an addition private credential
|
|
|
|
# to be combined in the collection.
|
|
|
|
#
|
2015-04-02 11:14:25 +00:00
|
|
|
# @param [String] private_str the string to use as a private
|
2015-01-07 17:30:39 +00:00
|
|
|
# @return [void]
|
|
|
|
def add_private(private_str='')
|
|
|
|
additional_privates << private_str
|
|
|
|
end
|
|
|
|
|
|
|
|
# Adds a string as an addition public credential
|
|
|
|
# to be combined in the collection.
|
|
|
|
#
|
2015-04-02 11:14:25 +00:00
|
|
|
# @param [String] public_str the string to use as a public
|
2015-01-07 17:30:39 +00:00
|
|
|
# @return [void]
|
|
|
|
def add_public(public_str='')
|
|
|
|
additional_publics << public_str
|
|
|
|
end
|
2014-06-11 19:30:45 +00:00
|
|
|
|
|
|
|
# Add {Credential credentials} that will be yielded by {#each}
|
|
|
|
#
|
|
|
|
# @see prepended_creds
|
|
|
|
# @param cred [Credential]
|
|
|
|
# @return [self]
|
|
|
|
def prepend_cred(cred)
|
|
|
|
prepended_creds.unshift cred
|
|
|
|
self
|
2014-06-04 18:01:09 +00:00
|
|
|
end
|
|
|
|
|
2014-06-04 22:03:52 +00:00
|
|
|
# Combines all the provided credential sources into a stream of {Credential}
|
|
|
|
# objects, yielding them one at a time
|
|
|
|
#
|
2014-06-04 18:01:09 +00:00
|
|
|
# @yieldparam credential [Metasploit::Framework::Credential]
|
|
|
|
# @return [void]
|
|
|
|
def each
|
2014-07-07 23:05:04 +00:00
|
|
|
if pass_file.present?
|
2014-06-04 18:01:09 +00:00
|
|
|
pass_fd = File.open(pass_file, 'r:binary')
|
|
|
|
end
|
|
|
|
|
2014-06-11 19:30:45 +00:00
|
|
|
prepended_creds.each { |c| yield c }
|
|
|
|
|
2014-06-19 20:45:24 +00:00
|
|
|
if username.present?
|
|
|
|
if password.present?
|
2014-08-01 16:57:35 +00:00
|
|
|
yield Metasploit::Framework::Credential.new(public: username, private: password, realm: realm, private_type: private_type(password))
|
2014-06-04 18:01:09 +00:00
|
|
|
end
|
|
|
|
if user_as_pass
|
2014-08-01 16:57:35 +00:00
|
|
|
yield Metasploit::Framework::Credential.new(public: username, private: username, realm: realm, private_type: :password)
|
2014-06-04 18:01:09 +00:00
|
|
|
end
|
|
|
|
if blank_passwords
|
2014-08-01 16:57:35 +00:00
|
|
|
yield Metasploit::Framework::Credential.new(public: username, private: "", realm: realm, private_type: :password)
|
2014-06-04 18:01:09 +00:00
|
|
|
end
|
|
|
|
if pass_fd
|
|
|
|
pass_fd.each_line do |pass_from_file|
|
2014-06-04 19:44:53 +00:00
|
|
|
pass_from_file.chomp!
|
2014-08-01 16:57:35 +00:00
|
|
|
yield Metasploit::Framework::Credential.new(public: username, private: pass_from_file, realm: realm, private_type: private_type(pass_from_file))
|
2014-06-04 18:01:09 +00:00
|
|
|
end
|
|
|
|
pass_fd.seek(0)
|
|
|
|
end
|
2015-01-07 17:41:41 +00:00
|
|
|
additional_privates.each do |add_private|
|
|
|
|
yield Metasploit::Framework::Credential.new(public: username, private: add_private, realm: realm, private_type: private_type(add_private))
|
|
|
|
end
|
2014-06-04 18:01:09 +00:00
|
|
|
end
|
|
|
|
|
2014-06-19 20:45:24 +00:00
|
|
|
if user_file.present?
|
2014-06-04 18:01:09 +00:00
|
|
|
File.open(user_file, 'r:binary') do |user_fd|
|
|
|
|
user_fd.each_line do |user_from_file|
|
2014-06-04 22:03:52 +00:00
|
|
|
user_from_file.chomp!
|
2014-12-04 18:59:51 +00:00
|
|
|
if password.present?
|
2014-08-01 16:57:35 +00:00
|
|
|
yield Metasploit::Framework::Credential.new(public: user_from_file, private: password, realm: realm, private_type: private_type(password) )
|
2014-06-04 18:01:09 +00:00
|
|
|
end
|
|
|
|
if user_as_pass
|
2014-08-01 16:57:35 +00:00
|
|
|
yield Metasploit::Framework::Credential.new(public: user_from_file, private: user_from_file, realm: realm, private_type: :password)
|
2014-06-04 18:01:09 +00:00
|
|
|
end
|
|
|
|
if blank_passwords
|
2014-08-01 16:57:35 +00:00
|
|
|
yield Metasploit::Framework::Credential.new(public: user_from_file, private: "", realm: realm, private_type: :password)
|
2014-06-04 18:01:09 +00:00
|
|
|
end
|
|
|
|
if pass_fd
|
|
|
|
pass_fd.each_line do |pass_from_file|
|
2014-06-04 19:44:53 +00:00
|
|
|
pass_from_file.chomp!
|
2014-08-01 16:57:35 +00:00
|
|
|
yield Metasploit::Framework::Credential.new(public: user_from_file, private: pass_from_file, realm: realm, private_type: private_type(pass_from_file))
|
2014-06-04 18:01:09 +00:00
|
|
|
end
|
|
|
|
pass_fd.seek(0)
|
|
|
|
end
|
2015-01-07 17:41:41 +00:00
|
|
|
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))
|
|
|
|
end
|
2014-06-04 18:01:09 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2014-06-04 22:03:52 +00:00
|
|
|
|
2014-06-19 20:45:24 +00:00
|
|
|
if userpass_file.present?
|
2014-06-04 22:03:52 +00:00
|
|
|
File.open(userpass_file, 'r:binary') do |userpass_fd|
|
|
|
|
userpass_fd.each_line do |line|
|
|
|
|
user, pass = line.split(" ", 2)
|
2014-06-12 17:39:36 +00:00
|
|
|
if pass.blank?
|
|
|
|
pass = ''
|
|
|
|
else
|
|
|
|
pass.chomp!
|
|
|
|
end
|
2014-06-04 22:03:52 +00:00
|
|
|
yield Metasploit::Framework::Credential.new(public: user, private: pass, realm: realm)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2015-01-07 17:41:41 +00:00
|
|
|
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 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))
|
|
|
|
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
|
|
|
|
end
|
|
|
|
|
2014-06-04 19:44:53 +00:00
|
|
|
ensure
|
|
|
|
pass_fd.close if pass_fd && !pass_fd.closed?
|
2014-06-04 18:01:09 +00:00
|
|
|
end
|
|
|
|
|
2017-01-31 18:10:17 +00:00
|
|
|
# Returns true when #each will have no results to iterate
|
|
|
|
def empty?
|
2017-02-09 20:57:20 +00:00
|
|
|
prepended_creds.empty? && !has_users? || (has_users? && !has_privates?)
|
|
|
|
end
|
|
|
|
|
|
|
|
def has_users?
|
|
|
|
username.present? || user_file.present? || userpass_file.present? || !additional_publics.empty?
|
|
|
|
end
|
|
|
|
|
|
|
|
def has_privates?
|
2017-02-15 21:05:49 +00:00
|
|
|
password.present? || pass_file.present? || userpass_file.present? || !additional_privates.empty? || blank_passwords || user_as_pass
|
2017-01-31 18:10:17 +00:00
|
|
|
end
|
|
|
|
|
2014-08-01 16:57:35 +00:00
|
|
|
private
|
|
|
|
|
|
|
|
def private_type(private)
|
|
|
|
if private =~ /[0-9a-f]{32}:[0-9a-f]{32}/
|
|
|
|
:ntlm_hash
|
2015-03-04 01:15:29 +00:00
|
|
|
elsif private =~ /^md5([a-f0-9]{32})$/
|
2015-03-03 22:43:52 +00:00
|
|
|
:postgres_md5
|
2014-08-01 16:57:35 +00:00
|
|
|
else
|
|
|
|
:password
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2014-06-04 18:01:09 +00:00
|
|
|
end
|