Class: Metasploit::Credential::Importer::Pwdump
- Inherits:
-
Object
- Object
- Metasploit::Credential::Importer::Pwdump
- Defined in:
- lib/metasploit/credential/importer/pwdump.rb
Overview
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 Login objects, which is the legacy behavior of this export prior to the creation of this library.
Constant Summary collapse
- COMMENT_LINE_START_REGEX =
Matches a line starting with a ‘#’
/^[\s]*#/
- JTR_NO_PASSWORD_STRING =
The string that John the Ripper uses to designate a lack of password in a credentials entry
"NO PASSWORD"
- NONREPLAYABLE_REGEX =
Matches lines that contain usernames and non-SMB hashes
/^[\s]*([\x21-\x7f]+):([\x21-\x7f]+):::/n
- PLAINTEXT_REGEX =
Matches lines that contain usernames and plaintext passwords
/^[\s]*([\x21-\x7f]+)[\s]+([\x21-\x7f]+)?/n
- POSTGRES_REGEX =
Matches lines taht contain MD5 hashes for PostgreSQL
/^[\s]*([\x21-\x7f]+):md5([0-9a-f]{32})$/
- 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+
/^#[\s]*([0-9.]+):([0-9]+)(\x2f(tcp|udp))?[\s]*(\x28([^\x29]*)\x29)?/n
- SMB_WITH_JTR_BLANK_PASSWORD_REGEX =
Matches the way that John the Ripper exports SMB hashes with no password piece
/^[\s]*([^\s:]+):([0-9]+):NO PASSWORD\*+:NO PASSWORD\*+[^\s]*$/
- SMB_WITH_HASH_REGEX =
Matches LM/NTLM hash format
/^[\s]*([^\s:]+):[0-9]+:([A-Fa-f0-9]+:[A-Fa-f0-9]+):[^\s]*$/
- SMB_WITH_PLAINTEXT_REGEX =
Matches a line with free-form text - less restrictive than SMB_WITH_HASH_REGEX
/^[\s]*([^\s:]+):(.+):[A-Fa-f0-9]*:[A-Fa-f0-9]*:::$/
- WARNING_REGEX =
Matches warning lines in legacy pwdump files
/^[\s]*Warning:/
Constants included from Base
Base::LONG_FORM_ALLOWED_PRIVATE_TYPE_NAMES, Base::SHORT_FORM_ALLOWED_PRIVATE_TYPE_NAMES
Instance Method Summary collapse
-
#blank_or_string(check_string, dehex = false) ⇒ String
Checks a string for matching Exporter::Pwdump::BLANK_CRED_STRING and returns blank string if it matches that constant.
-
#import! ⇒ void
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.
-
#initialize(args = {}) ⇒ Pwdump
constructor
A new instance of Pwdump.
-
#parsed_regex_results(username, private, dehex = false) ⇒ Hash
Break a line into user, hash.
-
#service_info_from_comment_string(comment_string) ⇒ Hash
Take an msfpwdump comment string and parse it into information necessary for creating ‘Mdm::Host` and `Mdm::Service` objects.
Methods included from Creation
#active_db?, #create_cracked_credential, #create_credential, #create_credential_and_login, #create_credential_core, #create_credential_login, #create_credential_origin, #create_credential_origin_cracked_password, #create_credential_origin_import, #create_credential_origin_manual, #create_credential_origin_service, #create_credential_origin_session, #create_credential_private, #create_credential_public, #create_credential_realm, #create_credential_service, #invalidate_login
Constructor Details
#initialize(args = {}) ⇒ Pwdump
Returns a new instance of Pwdump.
145 146 147 |
# File 'lib/metasploit/credential/importer/pwdump.rb', line 145 def initialize(args={}) super args end |
Instance Method Details
#blank_or_string(check_string, dehex = false) ⇒ String
Checks a string for matching Exporter::Pwdump::BLANK_CRED_STRING and returns blank string if it matches that constant.
62 63 64 65 66 67 68 69 70 71 72 |
# 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 |
#import! ⇒ void
This method returns an undefined value.
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.
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
# 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 |
#parsed_regex_results(username, private, dehex = false) ⇒ Hash
Break a line into user, hash
154 155 156 157 158 159 160 |
# 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 |
#service_info_from_comment_string(comment_string) ⇒ Hash
Take an msfpwdump comment string and parse it into information necessary for creating ‘Mdm::Host` and `Mdm::Service` objects.
166 167 168 169 170 171 172 173 174 175 176 177 |
# 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 |