class Metasploit::Credential::Importer::Pwdump
Implements importation behavior for pwdump files exported by Metasploit
as well as files from the John the Ripper hash cracking suite: www.openwall.com/john/
Please note that in the case of data exported from Metasploit
, the dataset will contain information on the ‘Mdm::Host` and `Mdm::Service` objects that are related to the credential. This means that Metasploit
exports will be limited to containing {Metasploit::Credential::Login} objects, which is the legacy behavior of this export prior to the creation of this library.
Constants
- COMMENT_LINE_START_REGEX
Matches a line starting with a ‘#’
- JTR_NO_PASSWORD_STRING
The string that John the Ripper uses to designate a lack of password in a credentials entry
- NONREPLAYABLE_REGEX
Matches lines that contain usernames and non-SMB hashes
- PLAINTEXT_REGEX
Matches lines that contain usernames and plaintext passwords
- POSTGRES_REGEX
Matches lines taht contain MD5 hashes for PostgreSQL
- SERVICE_COMMENT_REGEX
Matches a line that we use to get information for creating ‘Mdm::Host` and `Mdm::Service` objects TODO: change to use named groups from 1.9+
- SMB_WITH_HASH_REGEX
Matches LM/NTLM hash format
- SMB_WITH_JTR_BLANK_PASSWORD_REGEX
Matches the way that John the Ripper exports SMB hashes with no password piece
- SMB_WITH_PLAINTEXT_REGEX
Matches a line with free-form text - less restrictive than {SMB_WITH_HASH_REGEX}
- WARNING_REGEX
Matches warning lines in legacy pwdump files
Public Class Methods
Metasploit::Credential::Importer::Base::new
# File lib/metasploit/credential/importer/pwdump.rb, line 145 def initialize(args={}) super args end
Public Instance Methods
Checks a string for matching {Metasploit::Credential::Exporter::Pwdump::BLANK_CRED_STRING} and returns blank string if it matches that constant. @param check_string [String] the string to check @param dehex [Boolean] convert hex to char if true @return [String]
# File lib/metasploit/credential/importer/pwdump.rb, line 62 def blank_or_string(check_string, dehex=false) if check_string.blank? || check_string == Metasploit::Credential::Exporter::Pwdump::BLANK_CRED_STRING || check_string == JTR_NO_PASSWORD_STRING "" else if dehex Metasploit::Credential::Text.dehex check_string else check_string end end end
Perform the import of the credential data, creating ‘Mdm::Host` and `Mdm::Service` objects as needed, parsing out data by matching against regex constants that match the various kinds of valid lines found in the file. Ignore lines which match none of the REGEX constants. @return [void]
# File lib/metasploit/credential/importer/pwdump.rb, line 78 def import! service_info = nil Metasploit::Credential::Core.transaction do input.each_line do |line| case line when WARNING_REGEX next when COMMENT_LINE_START_REGEX service_info = service_info_from_comment_string(line) when SMB_WITH_HASH_REGEX info = parsed_regex_results($1, $2) username, private = info[:username], info[:private] creds_class = Metasploit::Credential::NTLMHash when SMB_WITH_JTR_BLANK_PASSWORD_REGEX info = parsed_regex_results($1, $2) username, private = info[:username], info[:private] creds_class = Metasploit::Credential::NTLMHash when SMB_WITH_PLAINTEXT_REGEX info = parsed_regex_results($1, $2) username, private = info[:username], info[:private] creds_class = Metasploit::Credential::NTLMHash when NONREPLAYABLE_REGEX info = parsed_regex_results($1, $2) username, private = info[:username], info[:private] creds_class = Metasploit::Credential::NonreplayableHash when POSTGRES_REGEX info = parsed_regex_results($1,"md5#{$2}") username, private = info[:username], info[:private] creds_class = Metasploit::Credential::PostgresMD5 when PLAINTEXT_REGEX info = parsed_regex_results($1, $2, true) username, private = info[:username], info[:private] creds_class = Metasploit::Credential::Password else next end # Skip unless we have enough to make a Login if service_info.present? if [service_info[:host_address], service_info[:port], username, private].compact.size != 4 next end else next end public_obj = create_credential_public(username: username) private_obj = creds_class.where(data: private).first_or_create core = create_credential_core(origin: origin, private: private_obj, public: public_obj, workspace_id: workspace.id) login_opts = { address: service_info[:host_address], port: service_info[:port], protocol: service_info[:protocol], service_name: service_info[:name], workspace_id: workspace.id, core: core, status: Metasploit::Model::Login::Status::UNTRIED } create_credential_login(login_opts) end end end
Break a line into user, hash @param username [String] @param private [String] @param dehex [Boolean] convert hex to char if true @return [Hash]
# File lib/metasploit/credential/importer/pwdump.rb, line 154 def parsed_regex_results(username, private, dehex=false) results = {} results[:username] = blank_or_string(username, dehex) results[:private] = blank_or_string(private, dehex) results end
Take an msfpwdump comment string and parse it into information necessary for creating ‘Mdm::Host` and `Mdm::Service` objects. @param comment_string [String] a string starting with a ’#‘ that conforms to {SERVICE_COMMENT_REGEX} @return [Hash]
# File lib/metasploit/credential/importer/pwdump.rb, line 166 def service_info_from_comment_string(comment_string) service_info = {} if comment_string[SERVICE_COMMENT_REGEX] service_info[:host_address] = $1 service_info[:port] = $2 service_info[:protocol] = $4.present? ? $4 : "tcp" service_info[:name] = $6 service_info else nil end end