Module: Msf::DBManager::Cred
- Included in:
- Msf::DBManager
- Defined in:
- lib/msf/core/db_manager/cred.rb
Instance Method Summary collapse
-
#creds(opts) ⇒ Object
This methods returns a list of all credentials in the database.
- #delete_credentials(opts) ⇒ Object
-
#each_cred(wspace = framework.db.workspace, &block) ⇒ Object
This method iterates the creds table calling the supplied block with the cred instance of each entry.
-
#find_or_create_cred(opts) ⇒ Object
Find or create a credential matching this type/data.
-
#report_auth_info(opts = {}) ⇒ Object
(also: #report_auth, #report_cred)
Store a set of credentials in the database.
- #update_credential(opts) ⇒ Object
Instance Method Details
#creds(opts) ⇒ Object
This methods returns a list of all credentials in the database
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
# File 'lib/msf/core/db_manager/cred.rb', line 3 def creds(opts) query = nil ::ApplicationRecord.connection_pool.with_connection { # If :id exists we're looking for a specific record, skip the other stuff if opts[:id] && !opts[:id].to_s.empty? return Array.wrap(Metasploit::Credential::Core.find(opts[:id])) end wspace = Msf::Util::DBManager.process_opts_workspace(opts, framework) search_term = opts[:search_term] query = Metasploit::Credential::Core.where( workspace_id: wspace.id ) query = query.includes(:private, :public, :logins, :realm).references(:private, :public, :logins, :realm) query = query.includes(logins: [ :service, { service: :host } ]) if opts[:type].present? query = query.where('"metasploit_credential_privates"."type" = ?', opts[:type]) end if opts[:jtr_format].present? query = query.where('"metasploit_credential_privates"."jtr_format" = ?', opts[:jtr_format]) end if opts[:svcs].present? query = query.where(Mdm::Service[:name].in(opts[:svcs])) end if opts[:ports].present? query = query.where(Mdm::Service[:port].in(opts[:ports])) end if opts.key?(:realm) if opts[:realm].nil? query = query.where( realm: nil ) else query = query.where('"metasploit_credential_realms"."value" = ?', opts[:realm]) end end if opts[:user].present? query = query.where('"metasploit_credential_publics"."username" = ?', opts[:user]) end if opts[:pass].present? query = query.where('"metasploit_credential_privates"."data" = ?', opts[:pass]) end if opts[:host_ranges] || opts[:ports] || opts[:svcs] # Only find Cores that have non-zero Logins if the user specified a # filter based on host, port, or service name query = query.where(Metasploit::Credential::Login[:id].not_eq(nil)) end if search_term && !search_term.empty? core_search_conditions = Msf::Util::DBManager.create_all_column_search_conditions(Metasploit::Credential::Core, search_term, ['created_at', 'updated_at']) public_search_conditions = Msf::Util::DBManager.create_all_column_search_conditions(Metasploit::Credential::Public, search_term, ['created_at', 'updated_at']) private_search_conditions = Msf::Util::DBManager.create_all_column_search_conditions(Metasploit::Credential::Private, search_term, ['created_at', 'updated_at']) realm_search_conditions = Msf::Util::DBManager.create_all_column_search_conditions(Metasploit::Credential::Realm, search_term, ['created_at', 'updated_at']) column_search_conditions = core_search_conditions.or(public_search_conditions).or(private_search_conditions).or(realm_search_conditions) query = query.where(column_search_conditions) end } query end |
#delete_credentials(opts) ⇒ Object
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 |
# File 'lib/msf/core/db_manager/cred.rb', line 283 def delete_credentials(opts) raise ArgumentError.new("The following options are required: :ids") if opts[:ids].nil? ::ApplicationRecord.connection_pool.with_connection { deleted = [] opts[:ids].each do |cred_id| cred = Metasploit::Credential::Core.find(cred_id) begin deleted << cred.destroy rescue # refs suck elog("Forcibly deleting #{cred}") deleted << cred.delete end end return deleted } end |
#each_cred(wspace = framework.db.workspace, &block) ⇒ Object
This method iterates the creds table calling the supplied block with the cred instance of each entry.
70 71 72 73 74 75 76 |
# File 'lib/msf/core/db_manager/cred.rb', line 70 def each_cred(wspace=framework.db.workspace,&block) ::ApplicationRecord.connection_pool.with_connection { wspace.creds.each do |cred| block.call(cred) end } end |
#find_or_create_cred(opts) ⇒ Object
Find or create a credential matching this type/data
79 80 81 |
# File 'lib/msf/core/db_manager/cred.rb', line 79 def find_or_create_cred(opts) report_auth_info(opts) end |
#report_auth_info(opts = {}) ⇒ Object Also known as: report_auth, report_cred
Store a set of credentials in the database.
report_auth_info used to create a note, now it creates an entry in the creds table. It’s much more akin to report_vuln() now.
opts MUST contain
:host
-
an IP address or Host object reference
:port
-
a port number
opts can contain
:user
-
the username
:pass
-
the password, or path to ssh_key
:ptype
-
the type of password (password(ish), hash, or ssh_key)
:proto
-
a transport name for the port
:sname
-
service name
:active
-
by default, a cred is active, unless explicitly false
:proof
-
data used to prove the account is actually active.
Sources: Credentials can be sourced from another credential, or from a vulnerability. For example, if an exploit was used to dump the smb_hashes, and this credential comes from there, the source_id would be the Vuln id (as reported by report_vuln) and the type would be “Vuln”.
:source_id
-
The Vuln or Cred id of the source of this cred.
:source_type
-
Either Vuln or Cred
TODO: This is written somewhat host-centric, when really the Service is the thing. Need to revisit someday.
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 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 |
# File 'lib/msf/core/db_manager/cred.rb', line 113 def report_auth_info(opts={}) return if not active raise ArgumentError.new("Missing required option :host") if opts[:host].nil? raise ArgumentError.new("Missing required option :port") if (opts[:port].nil? and opts[:service].nil?) if (not opts[:host].kind_of?(::Mdm::Host)) and (not validate_ips(opts[:host])) raise ArgumentError.new("Invalid address or object for :host (#{opts[:host].inspect})") end ::ApplicationRecord.connection_pool.with_connection { host = opts[:host] ptype = opts[:type] || "password" token = [opts[:user], opts[:pass]] sname = opts[:sname] port = opts[:port] proto = opts[:proto] || "tcp" proof = opts[:proof] source_id = opts[:source_id] source_type = opts[:source_type] duplicate_ok = opts[:duplicate_ok] # Nil is true for active. active = (opts[:active] || opts[:active].nil?) ? true : false wspace = Msf::Util::DBManager.process_opts_workspace(opts, framework) # Service management; assume the user knows what # he's talking about. service = opts[:service] || report_service(:host => host, :port => port, :proto => proto, :name => sname, :workspace => wspace) # Non-US-ASCII usernames are tripping up the database at the moment, this is a temporary fix until we update the tables if (token[0]) # convert the token to US-ASCII from UTF-8 to prevent an error token[0] = token[0].unpack("C*").pack("C*") token[0] = token[0].gsub(/[\x00-\x1f\x7f-\xff]/n){|m| "\\x%.2x" % m.unpack("C")[0] } end if (token[1]) token[1] = token[1].unpack("C*").pack("C*") token[1] = token[1].gsub(/[\x00-\x1f\x7f-\xff]/n){|m| "\\x%.2x" % m.unpack("C")[0] } end ret = {} # Check to see if the creds already exist. We look also for a downcased username with the # same password because we can fairly safely assume they are not in fact two separate creds. # this allows us to hedge against duplication of creds in the DB. if duplicate_ok # If duplicate usernames are okay, find by both user and password (allows # for actual duplicates to get modified updated_at, sources, etc) if token[0].nil? or token[0].empty? cred = service.creds.where(user: token[0] || "", ptype: ptype, pass: token[1] || "").first_or_initialize else cred = service.creds.find_by_user_and_ptype_and_pass(token[0] || "", ptype, token[1] || "") unless cred dcu = token[0].downcase cred = service.creds.find_by_user_and_ptype_and_pass( dcu || "", ptype, token[1] || "") unless cred cred = service.creds.where(user: token[0] || "", ptype: ptype, pass: token[1] || "").first_or_initialize end end end else # Create the cred by username only (so we can change passwords) if token[0].nil? or token[0].empty? cred = service.creds.where(user: token[0] || "", ptype: ptype).first_or_initialize else cred = service.creds.find_by_user_and_ptype(token[0] || "", ptype) unless cred dcu = token[0].downcase cred = service.creds.find_by_user_and_ptype_and_pass( dcu || "", ptype, token[1] || "") unless cred cred = service.creds.where(user: token[0] || "", ptype: ptype).first_or_initialize end end end end # Update with the password cred.pass = (token[1] || "") # Annotate the credential cred.ptype = ptype cred.active = active # Update the source ID only if there wasn't already one. if source_id and !cred.source_id cred.source_id = source_id cred.source_type = source_type if source_type end # Safe proof (lazy way) -- doesn't chop expanded # characters correctly, but shouldn't ever be a problem. unless proof.nil? proof = Rex::Text.to_hex_ascii(proof) proof = proof[0,4096] end cred.proof = proof # Update the timestamp if cred.changed? (opts, cred) cred.save! end # Ensure the updated_at is touched any time report_auth_info is called # except when it's set explicitly (as it is for imports) unless opts[:updated_at] || opts["updated_at"] cred.updated_at = Time.now.utc cred.save! end if opts[:task] Mdm::TaskCred.create( :task => opts[:task], :cred => cred ) end ret[:cred] = cred } end |
#update_credential(opts) ⇒ Object
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 |
# File 'lib/msf/core/db_manager/cred.rb', line 237 def update_credential(opts) ::ApplicationRecord.connection_pool.with_connection { # process workspace string for update if included in opts wspace = Msf::Util::DBManager.process_opts_workspace(opts, framework, false) opts = opts.clone() opts.delete(:workspace) opts[:workspace] = wspace if wspace if opts[:public] if opts[:public][:id] public_id = opts[:public].delete(:id) public = Metasploit::Credential::Public.find(public_id) public.update_attributes(opts[:public]) else public = Metasploit::Credential::Public.where(opts[:public]).first_or_initialize end opts[:public] = public end if opts[:private] if opts[:private][:id] private_id = opts[:private].delete(:id) private = Metasploit::Credential::Private.find(private_id) private.update_attributes(opts[:private]) else private = Metasploit::Credential::Private.where(opts[:private]).first_or_initialize end opts[:private] = private end if opts[:origin] if opts[:origin][:id] origin_id = opts[:origin].delete(:id) origin = Metasploit::Credential::Origin.find(origin_id) origin.update_attributes(opts[:origin]) else origin = Metasploit::Credential::Origin.where(opts[:origin]).first_or_initialize end opts[:origin] = origin end id = opts.delete(:id) cred = Metasploit::Credential::Core.find(id) cred.update!(opts) return cred } end |