Module: Msf::Auxiliary::Report
- Extended by:
- Metasploit::Framework::Require
- Included in:
- Arista, Brocade, CNPILOT, Cisco, EPMP, F5, HttpCrawler, Juniper, Mikrotik, PasswordCracker, Redis, Ubiquiti, VYOS, Web, Evasion, Exploit::FILEFORMAT, Exploit::Remote::BrowserAutopwn, Exploit::Remote::DNS::Enumeration, Exploit::Remote::HttpClient, Exploit::Remote::HttpServer, Exploit::Remote::SMB::Server::HashCapture, Exploit::Remote::WDBRPC_Client, Module::External, PostMixin, 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, similiar to store_loot.
-
#store_loot(ltype, ctype, host, data, filename = nil, info = nil, service = nil) ⇒ 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
73 74 75 |
# File 'lib/msf/core/auxiliary/report.rb', line 73 def active_db? framework.db.active end |
#create_cracked_credential(opts = {}) ⇒ Object
27 28 29 30 31 32 33 34 |
# 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!') end end |
#create_credential(opts = {}) ⇒ Object
36 37 38 39 40 41 42 43 |
# File 'lib/msf/core/auxiliary/report.rb', line 36 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!') end end |
#create_credential_and_login(opts = {}) ⇒ Object
54 55 56 57 58 59 60 61 |
# File 'lib/msf/core/auxiliary/report.rb', line 54 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!') end end |
#create_credential_login(opts = {}) ⇒ Object
45 46 47 48 49 50 51 52 |
# File 'lib/msf/core/auxiliary/report.rb', line 45 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!') end end |
#db ⇒ Object
Shortcut method for detecting when the DB is active
78 79 80 |
# File 'lib/msf/core/auxiliary/report.rb', line 78 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
156 157 158 159 160 |
# File 'lib/msf/core/auxiliary/report.rb', line 156 def get_client(opts={}) return if not db opts = {:workspace => myworkspace}.merge(opts) framework.db.get_client(opts) end |
#get_host(opts) ⇒ Object
133 134 135 136 137 |
# File 'lib/msf/core/auxiliary/report.rb', line 133 def get_host(opts) return if not db opts = {:workspace => myworkspace}.merge(opts) framework.db.get_host(opts) end |
#inside_workspace_boundary?(ip) ⇒ Boolean
108 109 110 111 112 |
# File 'lib/msf/core/auxiliary/report.rb', line 108 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
63 64 65 66 67 68 69 70 |
# File 'lib/msf/core/auxiliary/report.rb', line 63 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!') end end |
#mytask ⇒ Object
98 99 100 101 102 103 104 105 106 |
# File 'lib/msf/core/auxiliary/report.rb', line 98 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
82 83 84 |
# File 'lib/msf/core/auxiliary/report.rb', line 82 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
90 91 92 93 94 95 96 |
# File 'lib/msf/core/auxiliary/report.rb', line 90 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.
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 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 |
# File 'lib/msf/core/auxiliary/report.rb', line 196 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://github.com/rapid7/metasploit-framework/wiki/Creating-Metasploit-Framework-LoginScanners') print_warning(' https://github.com/rapid7/metasploit-framework/wiki/How-to-write-a-HTTP-LoginScanner-Module') 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].kind_of?(::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].kind_of?(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
147 148 149 150 151 152 153 154 |
# File 'lib/msf/core/auxiliary/report.rb', line 147 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.
322 323 324 325 326 327 328 329 |
# File 'lib/msf/core/auxiliary/report.rb', line 322 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
124 125 126 127 128 129 130 131 |
# File 'lib/msf/core/auxiliary/report.rb', line 124 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
331 332 333 334 335 336 337 338 |
# File 'lib/msf/core/auxiliary/report.rb', line 331 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
174 175 176 177 178 179 180 181 |
# File 'lib/msf/core/auxiliary/report.rb', line 174 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
165 166 167 168 169 170 171 172 |
# File 'lib/msf/core/auxiliary/report.rb', line 165 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
287 288 289 290 291 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 |
# File 'lib/msf/core/auxiliary/report.rb', line 287 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
358 359 360 361 362 363 364 365 |
# File 'lib/msf/core/auxiliary/report.rb', line 358 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
349 350 351 352 353 354 355 356 |
# File 'lib/msf/core/auxiliary/report.rb', line 349 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
340 341 342 343 344 345 346 347 |
# File 'lib/msf/core/auxiliary/report.rb', line 340 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
367 368 369 370 371 372 373 374 |
# File 'lib/msf/core/auxiliary/report.rb', line 367 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
522 523 524 525 526 527 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 |
# File 'lib/msf/core/auxiliary/report.rb', line 522 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, similiar 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.
467 468 469 470 471 472 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 |
# File 'lib/msf/core/auxiliary/report.rb', line 467 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) ⇒ 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
393 394 395 396 397 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 |
# File 'lib/msf/core/auxiliary/report.rb', line 393 def store_loot(ltype, ctype, host, data, filename=nil, info=nil, service=nil) 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 <= 4 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 framework.db.report_loot(conf) end return full_path.dup end |