Module: Msf::Auxiliary::Report
- Extended by:
- Metasploit::Framework::Require
- Included in:
- Arista, Brocade, CNPILOT, Cisco, EPMP, F5, HttpCrawler, Juniper, Mikrotik, PasswordCracker, Prometheus, Redis, Ubiquiti, VYOS, Web, Evasion, Exploit::FILEFORMAT, Exploit::Remote::BrowserAutopwn, Exploit::Remote::DNS::Enumeration, Exploit::Remote::HttpClient, Exploit::Remote::HttpServer, Exploit::Remote::Kerberos::AuthBrute, Exploit::Remote::Kerberos::ServiceAuthenticator::Base, Exploit::Remote::Kerberos::Ticket::Storage::Base, Exploit::Remote::MsSamr::Computer, Exploit::Remote::SMB::Client::Ipc, Exploit::Remote::SMB::Server::HashCapture, Exploit::Remote::WDBRPC_Client, Module::External, SessionCompatibility, Rex::Post::HWBridge::Ui::Console::CommandDispatcher::Automotive, Rex::Post::HWBridge::Ui::Console::CommandDispatcher::CustomMethods, Rex::Post::HWBridge::Ui::Console::CommandDispatcher::RFtransceiver, Rex::Post::HWBridge::Ui::Console::CommandDispatcher::Zigbee, Rex::Post::Meterpreter::Ui::Console::CommandDispatcher::Android
- Defined in:
- lib/msf/core/auxiliary/report.rb
Overview
This module provides methods for reporting data to the DB
Instance Method Summary collapse
-
#active_db? ⇒ Boolean
This method overrides the method from Metasploit::Credential to check for an active db.
- #create_cracked_credential(opts = {}) ⇒ Object
- #create_credential(opts = {}) ⇒ Object
- #create_credential_and_login(opts = {}) ⇒ Object
- #create_credential_login(opts = {}) ⇒ Object
-
#db ⇒ Object
Shortcut method for detecting when the DB is active.
- #db_warning_given? ⇒ Boolean
- #get_client(opts = {}) ⇒ Object
- #get_host(opts) ⇒ Object
- #inside_workspace_boundary?(ip) ⇒ Boolean
- #invalidate_login(opts = {}) ⇒ Object
- #mytask ⇒ Object
- #myworkspace ⇒ Object
-
#myworkspace_id ⇒ NilClass, Integer
This method safely get the workspace ID.
-
#report_auth_info(opts = {}) ⇒ Object
This Legacy method is responsible for creating credentials from data supplied by a module.
-
#report_client(opts = {}) ⇒ Object
Report a client connection.
-
#report_exploit(opts = {}) ⇒ Object
This will simply log a deprecation warning, since report_exploit() is no longer implemented.
-
#report_host(opts) ⇒ Object
Report a host’s liveness and attributes such as operating system and service pack.
- #report_loot(opts = {}) ⇒ Object
- #report_note(opts = {}) ⇒ Object
-
#report_service(opts = {}) ⇒ Object
Report detection of a service.
- #report_vuln(opts = {}) ⇒ Object
- #report_web_form(opts = {}) ⇒ Object
- #report_web_page(opts = {}) ⇒ Object
- #report_web_site(opts = {}) ⇒ Object
- #report_web_vuln(opts = {}) ⇒ Object
-
#store_cred(opts = {}) ⇒ Object
Takes a credential from a script (shell or meterpreter), and sources it correctly to the originating user account or session.
-
#store_local(ltype = nil, ctype = nil, data = nil, filename = nil) ⇒ Object
Store some locally-generated data as a file, similar to store_loot.
-
#store_loot(ltype, ctype, host, data, filename = nil, info = nil, service = nil, &block) ⇒ Object
Store some data stolen from a session as a file.
Methods included from Metasploit::Framework::Require
optionally, optionally_active_record_railtie, optionally_include_metasploit_credential_creation, optionally_include_metasploit_credential_creation, optionally_require_metasploit_db_gem_engines
Instance Method Details
#active_db? ⇒ Boolean
This method overrides the method from Metasploit::Credential to check for an active db
78 79 80 |
# File 'lib/msf/core/auxiliary/report.rb', line 78 def active_db? framework.db.active end |
#create_cracked_credential(opts = {}) ⇒ Object
27 28 29 30 31 32 33 34 35 |
# File 'lib/msf/core/auxiliary/report.rb', line 27 def create_cracked_credential(opts={}) if active_db? opts = { :task_id => mytask.id }.merge(opts) if mytask framework.db.create_cracked_credential(opts) elsif !db_warning_given? vprint_warning('No active DB -- Credential data will not be saved!') nil end end |
#create_credential(opts = {}) ⇒ Object
37 38 39 40 41 42 43 44 45 |
# File 'lib/msf/core/auxiliary/report.rb', line 37 def create_credential(opts={}) if active_db? opts = { :task_id => mytask.id }.merge(opts) if mytask framework.db.create_credential(opts) elsif !db_warning_given? vprint_warning('No active DB -- Credential data will not be saved!') nil end end |
#create_credential_and_login(opts = {}) ⇒ Object
57 58 59 60 61 62 63 64 65 |
# File 'lib/msf/core/auxiliary/report.rb', line 57 def create_credential_and_login(opts={}) if active_db? opts = { :task_id => mytask.id }.merge(opts) if mytask framework.db.create_credential_and_login(opts) elsif !db_warning_given? vprint_warning('No active DB -- Credential data will not be saved!') nil end end |
#create_credential_login(opts = {}) ⇒ Object
47 48 49 50 51 52 53 54 55 |
# File 'lib/msf/core/auxiliary/report.rb', line 47 def create_credential_login(opts={}) if active_db? opts = { :task_id => mytask.id }.merge(opts) if mytask framework.db.create_credential_login(opts) elsif !db_warning_given? vprint_warning('No active DB -- Credential data will not be saved!') nil end end |
#db ⇒ Object
Shortcut method for detecting when the DB is active
83 84 85 |
# File 'lib/msf/core/auxiliary/report.rb', line 83 def db framework.db.active end |
#db_warning_given? ⇒ Boolean
18 19 20 21 22 23 24 25 |
# File 'lib/msf/core/auxiliary/report.rb', line 18 def db_warning_given? if @warning_issued true else @warning_issued = true false end end |
#get_client(opts = {}) ⇒ Object
161 162 163 164 165 |
# File 'lib/msf/core/auxiliary/report.rb', line 161 def get_client(opts={}) return if not db opts = {:workspace => myworkspace}.merge(opts) framework.db.get_client(opts) end |
#get_host(opts) ⇒ Object
138 139 140 141 142 |
# File 'lib/msf/core/auxiliary/report.rb', line 138 def get_host(opts) return if not db opts = {:workspace => myworkspace}.merge(opts) framework.db.get_host(opts) end |
#inside_workspace_boundary?(ip) ⇒ Boolean
113 114 115 116 117 |
# File 'lib/msf/core/auxiliary/report.rb', line 113 def inside_workspace_boundary?(ip) return true if not framework.db.active allowed = myworkspace.allow_actions_on?(ip) return allowed end |
#invalidate_login(opts = {}) ⇒ Object
67 68 69 70 71 72 73 74 75 |
# File 'lib/msf/core/auxiliary/report.rb', line 67 def invalidate_login(opts={}) if active_db? opts = { :task_id => mytask.id }.merge(opts) if mytask framework.db.invalidate_login(opts) elsif !db_warning_given? vprint_warning('No active DB -- Credential data will not be saved!') nil end end |
#mytask ⇒ Object
103 104 105 106 107 108 109 110 111 |
# File 'lib/msf/core/auxiliary/report.rb', line 103 def mytask if self.respond_to?(:[]) && self[:task] return self[:task].record elsif @task && @task.class == Mdm::Task return @task else return nil end end |
#myworkspace ⇒ Object
87 88 89 |
# File 'lib/msf/core/auxiliary/report.rb', line 87 def myworkspace @myworkspace = framework.db.find_workspace(self.workspace) end |
#myworkspace_id ⇒ NilClass, Integer
This method safely get the workspace ID. It handles if the db is not active
95 96 97 98 99 100 101 |
# File 'lib/msf/core/auxiliary/report.rb', line 95 def myworkspace_id if framework.db.active myworkspace.id else nil end end |
#report_auth_info(opts = {}) ⇒ Object
This Legacy method is responsible for creating credentials from data supplied by a module. This method is deprecated and the new Metasploit::Credential methods should be used directly instead.
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 236 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 282 283 284 285 286 287 288 289 290 |
# File 'lib/msf/core/auxiliary/report.rb', line 201 def report_auth_info(opts={}) print_warning("*** #{self.fullname} is still calling the deprecated report_auth_info method! This needs to be updated!") print_warning('*** For detailed information about LoginScanners and the Credentials objects see:') print_warning(' https://docs.metasploit.com/docs/development/developing-modules/guides/scanners/creating-metasploit-framework-loginscanners.html') print_warning(' https://docs.metasploit.com/docs/development/developing-modules/guides/scanners/how-to-write-a-http-loginscanner-module.html') print_warning('*** For examples of modules converted to just report credentials without report_auth_info, see:') print_warning(' https://github.com/rapid7/metasploit-framework/pull/5376') print_warning(' https://github.com/rapid7/metasploit-framework/pull/5377') return unless db 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 opts[:host].is_a?(::Mdm::Host) host = opts[:host].address else host = opts[:host] end type = :password case opts[:type] when "password" type = :password when "hash" type = :nonreplayable_hash when "ssh_key" type = :ssh_key end case opts[:proto] when "tcp" proto = "tcp" when "udp" proto = "udp" else proto = "tcp" end if opts[:service] && opts[:service].is_a?(Mdm::Service) port = opts[:service].port proto = opts[:service].proto service_name = opts[:service].name host = opts[:service].host.address else port = opts.fetch(:port) service_name = opts.fetch(:sname, nil) end username = opts.fetch(:user, nil) private = opts.fetch(:pass, nil) service_data = { address: host, port: port, service_name: service_name, protocol: proto, workspace_id: myworkspace_id } if self.type == "post" credential_data = { origin_type: :session, session_id: session_db_id, post_reference_name: self.refname } else credential_data = { origin_type: :service, module_fullname: self.fullname } credential_data.merge!(service_data) end unless private.nil? credential_data[:private_type] = type credential_data[:private_data] = private end unless username.nil? credential_data[:username] = username end credential_core = create_credential(credential_data) login_data ={ core: credential_core, status: Metasploit::Model::Login::Status::UNTRIED } login_data.merge!(service_data) create_credential_login(login_data) end |
#report_client(opts = {}) ⇒ Object
Report a client connection
152 153 154 155 156 157 158 159 |
# File 'lib/msf/core/auxiliary/report.rb', line 152 def report_client(opts={}) return if not db opts = { :workspace => myworkspace, :task => mytask }.merge(opts) framework.db.report_client(opts) end |
#report_exploit(opts = {}) ⇒ Object
This will simply log a deprecation warning, since report_exploit() is no longer implemented.
327 328 329 330 331 332 333 334 |
# File 'lib/msf/core/auxiliary/report.rb', line 327 def report_exploit(opts={}) return if not db opts = { :workspace => myworkspace, :task => mytask }.merge(opts) framework.db.report_exploit(opts) end |
#report_host(opts) ⇒ Object
Report a host’s liveness and attributes such as operating system and service pack
opts must contain :host, which is an IP address identifying the host you’re reporting about
See data/sql/*.sql and lib/msf/core/db.rb for more info
129 130 131 132 133 134 135 136 |
# File 'lib/msf/core/auxiliary/report.rb', line 129 def report_host(opts) return if not db opts = { :workspace => myworkspace, :task => mytask }.merge(opts) framework.db.report_host(opts) end |
#report_loot(opts = {}) ⇒ Object
336 337 338 339 340 341 342 343 |
# File 'lib/msf/core/auxiliary/report.rb', line 336 def report_loot(opts={}) return if not db opts = { :workspace => myworkspace, :task => mytask }.merge(opts) framework.db.report_loot(opts) end |
#report_note(opts = {}) ⇒ Object
179 180 181 182 183 184 185 186 |
# File 'lib/msf/core/auxiliary/report.rb', line 179 def report_note(opts={}) return if not db opts = { :workspace => myworkspace, :task => mytask }.merge(opts) framework.db.report_note(opts) end |
#report_service(opts = {}) ⇒ Object
Report detection of a service
170 171 172 173 174 175 176 177 |
# File 'lib/msf/core/auxiliary/report.rb', line 170 def report_service(opts={}) return if not db opts = { :workspace => myworkspace, :task => mytask }.merge(opts) framework.db.report_service(opts) end |
#report_vuln(opts = {}) ⇒ Object
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 |
# File 'lib/msf/core/auxiliary/report.rb', line 292 def report_vuln(opts={}) return if not db opts = { :workspace => myworkspace, :task => mytask }.merge(opts) vuln = framework.db.report_vuln(opts) raise Msf::ValidationError, "Failed to report vuln for #{opts[:host]}:#{opts[:port]} to the database" if vuln.nil? # add vuln attempt audit details here during report = opts[:timestamp] username = opts[:username] mname = self.fullname # use module name when reporting attempt for correlation # report_vuln is only called in an identified case, consider setting value reported here attempt_info = { :vuln_id => vuln.id, :attempted_at => || Time.now.utc, :exploited => false, :fail_detail => 'vulnerability identified', :fail_reason => 'Untried', # Mdm::VulnAttempt::Status::UNTRIED, avoiding direct dependency on Mdm, used elsewhere in this module :module => mname, :username => username || "unknown", } # TODO: figure out what opts are required and why the above logic doesn't match that of the db_manager method framework.db.report_vuln_attempt(vuln, attempt_info) vuln end |
#report_web_form(opts = {}) ⇒ Object
363 364 365 366 367 368 369 370 |
# File 'lib/msf/core/auxiliary/report.rb', line 363 def report_web_form(opts={}) return if not db opts = { :workspace => myworkspace, :task => mytask }.merge(opts) framework.db.report_web_form(opts) end |
#report_web_page(opts = {}) ⇒ Object
354 355 356 357 358 359 360 361 |
# File 'lib/msf/core/auxiliary/report.rb', line 354 def report_web_page(opts={}) return if not db opts = { :workspace => myworkspace, :task => mytask }.merge(opts) framework.db.report_web_page(opts) end |
#report_web_site(opts = {}) ⇒ Object
345 346 347 348 349 350 351 352 |
# File 'lib/msf/core/auxiliary/report.rb', line 345 def report_web_site(opts={}) return if not db opts = { :workspace => myworkspace, :task => mytask }.merge(opts) framework.db.report_web_site(opts) end |
#report_web_vuln(opts = {}) ⇒ Object
372 373 374 375 376 377 378 379 |
# File 'lib/msf/core/auxiliary/report.rb', line 372 def report_web_vuln(opts={}) return if not db opts = { :workspace => myworkspace, :task => mytask }.merge(opts) framework.db.report_web_vuln(opts) end |
#store_cred(opts = {}) ⇒ Object
Takes a credential from a script (shell or meterpreter), and sources it correctly to the originating user account or session. Note that the passed-in session ID should be the Session.local_id, which will be correlated with the Session.id
528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 |
# File 'lib/msf/core/auxiliary/report.rb', line 528 def store_cred(opts={}) if [opts[:port],opts[:sname]].compact.empty? raise ArgumentError, "Missing option: :sname or :port" end cred_opts = opts cred_opts = opts.merge(:workspace => myworkspace) cred_opts = { :task_id => mytask.id }.merge(cred_opts) if mytask cred_host = myworkspace.hosts.find_by_address(cred_opts[:host]) unless opts[:port] possible_services = myworkspace.services.where(host_id: cred_host[:id], name: cred_opts[:sname]) case possible_services.size when 0 case cred_opts[:sname].downcase when "smb" cred_opts[:port] = 445 when "ssh" cred_opts[:port] = 22 when "telnet" cred_opts[:port] = 23 when "snmp" cred_opts[:port] = 161 cred_opts[:proto] = "udp" else raise ArgumentError, "No matching :sname found to store this cred." end when 1 cred_opts[:port] = possible_services.first[:port] else # SMB should prefer 445. Everyone else, just take the first hit. if (cred_opts[:sname].downcase == "smb") && possible_services.map {|x| x[:port]}.include?(445) cred_opts[:port] = 445 elsif (cred_opts[:sname].downcase == "ssh") && possible_services.map {|x| x[:port]}.include?(22) cred_opts[:port] = 22 else cred_opts[:port] = possible_services.first[:port] end end end if opts[:collect_user] cred_service = cred_host.services.find_by_host_id(cred_host[:id]) myworkspace.creds.sort {|a,b| a.created_at.to_f}.each do |cred| if(cred.user.downcase == opts[:collect_user].downcase && cred.pass == opts[:collect_pass] ) cred_opts[:source_id] ||= cred.id cred_opts[:source_type] ||= cred_opts[:collect_type] break end end end if opts[:collect_session] session = myworkspace.sessions.where(local_id: opts[:collect_session]).last if !session.nil? cred_opts[:source_id] = session.id cred_opts[:source_type] = "exploit" end end print_status "Collecting #{cred_opts[:user]}:#{cred_opts[:pass]}" framework.db.report_auth_info(cred_opts) end |
#store_local(ltype = nil, ctype = nil, data = nil, filename = nil) ⇒ Object
Store some locally-generated data as a file, similar to store_loot. Sometimes useful for keeping artifacts of an exploit or auxiliary module, such as files from fileformat exploits. (TODO: actually implement this on file format modules.)
filename
is the local file name.
data
is the actual contents of the file
Also stores metadata about the file in the database when available. ltype
is an OID-style loot type, e.g. “cisco.ios.config”. Ignored when no database is connected.
ctype
is the Content-Type, e.g. “text/plain”. Ignored when no database is connected.
473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 |
# File 'lib/msf/core/auxiliary/report.rb', line 473 def store_local(ltype=nil, ctype=nil, data=nil, filename=nil) if ! ::File.directory?(Msf::Config.local_directory) FileUtils.mkdir_p(Msf::Config.local_directory) end # Split by fname an extension if filename and not filename.empty? if filename =~ /(.*)\.(.*)/ ext = $2 fname = $1 else fname = filename end else fname = ctype || "local_#{Time.now.utc.to_i}" end # Split by path separator fname = ::File.split(fname).last case ctype # Probably could use more cases when "text/plain" ext ||= "txt" when "text/xml" ext ||= "xml" when "text/html" ext ||= "html" when "application/pdf" ext ||= "pdf" else ext ||= "bin" end fname.gsub!(/[^a-z0-9\.\_\-]+/i, '') fname << ".#{ext}" ltype.gsub!(/[^a-z0-9\.\_\-]+/i, '') path = File.join(Msf::Config.local_directory, fname) full_path = ::File.(path) File.open(full_path, "wb") { |fd| fd.write(data) } # This will probably evolve into a new database table report_note( :data => full_path.dup, :type => "#{ltype}.localpath" ) return full_path.dup end |
#store_loot(ltype, ctype, host, data, filename = nil, info = nil, service = nil, &block) ⇒ Object
Store some data stolen from a session as a file
Also stores metadata about the file in the database when available ltype
is an OID-style loot type, e.g. “cisco.ios.config”. Ignored when no database is connected.
ctype
is the Content-Type, e.g. “text/plain”. Affects the extension the file will be saved with.
host
can be an String address or a Session object
data
is the actual contents of the file
filename
and info
are only stored as metadata, and therefore both are ignored if there is no database
398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 |
# File 'lib/msf/core/auxiliary/report.rb', line 398 def store_loot(ltype, ctype, host, data, filename=nil, info=nil, service=nil, &block) if ! ::File.directory?(Msf::Config.loot_directory) FileUtils.mkdir_p(Msf::Config.loot_directory) end ext = 'bin' if filename parts = filename.to_s.split('.') if parts.length > 1 and parts[-1].length <= 6 ext = parts[-1] end end case ctype when /^text\/[\w\.]+$/ ext = "txt" end # This method is available even if there is no database, don't bother checking host = Msf::Util::Host.normalize_host(host) ws = (db ? myworkspace.name[0,16] : 'default') name = Time.now.strftime("%Y%m%d%H%M%S") + "_" + ws + "_" + (host || 'unknown') + '_' + ltype[0,16] + '_' + Rex::Text.rand_text_numeric(6) + '.' + ext name.gsub!(/[^a-z0-9\.\_]+/i, '') path = File.join(Msf::Config.loot_directory, name) full_path = ::File.(path) File.open(full_path, "wb") do |fd| fd.write(data) end if (db) # If we have a database we need to store it with all the available # metadata. conf = {} conf[:host] = host if host conf[:type] = ltype conf[:content_type] = ctype conf[:path] = full_path conf[:workspace] = myworkspace conf[:name] = filename if filename conf[:info] = info if info conf[:data] = data unless data.nil? if service and service.kind_of?(::Mdm::Service) conf[:service] = service if service end loot = framework.db.report_loot(conf) yield loot if block_given? end return full_path.dup end |