Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improves UX for scanner/login modules #19199

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
147 changes: 147 additions & 0 deletions lib/msf/core/auxiliary/report_summary.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
# -*- coding: binary -*-

##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# https://metasploit.com/framework/
##

module Msf
class Auxiliary
###
#
# This module provides a means to report module summaries
#
###
module ReportSummary
def initialize(info = {})
super(info)

if framework.features.enabled?(Msf::FeatureManager::SHOW_SUCCESSFUL_LOGINS)
register_options(
[
OptBool.new('ShowSuccessfulLogins', [false, 'Outputs a table of successful logins', true]),
]
)
end
end

def run
cgranleese-r7 marked this conversation as resolved.
Show resolved Hide resolved
return super unless framework.features.enabled?(Msf::FeatureManager::SHOW_SUCCESSFUL_LOGINS) && datastore['ShowSuccessfulLogins']

@report = {}
@report.extend(::Rex::Ref)
rhost_walker = Msf::RhostsWalker.new(datastore['RHOSTS'], datastore).to_enum
conditional_verbose_output(rhost_walker.count)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a blocker; This might still need opt out functionality, were folk do want a quiet scanner still for 1 target

result = super
print_report_summary
cgranleese-r7 marked this conversation as resolved.
Show resolved Hide resolved
result
end

# Creates a credential and adds to to the DB if one is present
#
# @param [Hash] credential_data
# @return [Metasploit::Credential::Login]
def create_credential_login(credential_data)
cgranleese-r7 marked this conversation as resolved.
Show resolved Hide resolved
return super unless framework.features.enabled?(Msf::FeatureManager::SHOW_SUCCESSFUL_LOGINS) && datastore['ShowSuccessfulLogins']

credential = {
public: credential_data[:username],
private_data: credential_data[:private_data]
}
@report[rhost] = { successful_logins: [] }
@report[rhost][:successful_logins] << credential
super
end

# Framework is notified that we have a new session opened
#
# @param [MetasploitModule] obj
# @param [Object] info
# @param [Hash] ds_merge
# @param [FalseClass] crlf
# @param [Socket] sock
# @param [Msf::Sessions::<SESSION_CLASS>] sess
# @return [Msf::Sessions::<SESSION_CLASS>]
def start_session(obj, info, ds_merge, crlf = false, sock = nil, sess = nil)
cgranleese-r7 marked this conversation as resolved.
Show resolved Hide resolved
return super unless framework.features.enabled?(Msf::FeatureManager::SHOW_SUCCESSFUL_LOGINS) && datastore['ShowSuccessfulLogins']

result = super
@report[rhost].merge!({ successful_sessions: [] })
@report[rhost][:successful_sessions] << result
result
end

private

# Prints a summary of successful logins
# Returns a ::Rex::Text::Table with the following data: host, public and private credentials for each
# successful login per host
#
# @return [Hash] Rhost keys mapped to successful logins and sessions for each host
def print_report_summary
report = @report

logins = report.flat_map { |_k, v| v[:successful_logins] }.compact
sessions = report.flat_map { |_k, v| v[:successful_sessions] }.compact

print_status("Scan completed, #{logins.size} #{logins.size == 1 ? 'credential was' : 'credentials were'} successful.")
print_successful_logins(report)

if datastore['CreateSession']
print_status("#{sessions.size} #{sessions.size == 1 ? 'session was' : 'sessions were'} opened successfully.")
end

report
end

# Logic to detect if the ShowSuccessLogins datastore option has been set
#
# @param [Hash] report Host mapped to successful logins and sessions
# @return [String] Rex::Text::Table containing successful logins
def print_successful_logins(report)
if datastore['ShowSuccessfulLogins'] == true && !report.empty?
table = successful_logins_to_table(report)
print_line("\n" + table.to_s + "\n")
end
end

# The idea here is to add a hybrid approach for scanner modules
# If only one host is scanned a more verbose output is useful to the user
# If scanning multiple hosts we would want more lightweight information
#
# @param [Object] host_count The number of hosts
def conditional_verbose_output(host_count)
cgranleese-r7 marked this conversation as resolved.
Show resolved Hide resolved
if host_count == 1
datastore['Verbose'] = true
end
end

# Takes the login/session results and converts them into a Rex::Text::Table format
#
# @param report [Hash{String => [Metasploit::Framework::LoginScanner::Result, Msf::Sessions]}]
# @return [Rex::Text::WrappedTable] Rex::Text::Table containing successful logins
def successful_logins_to_table(report)
cgranleese-r7 marked this conversation as resolved.
Show resolved Hide resolved
field_headers = %w[Host Public Private]

markdown_fields = report.flat_map do |host, result|
if result[:successful_logins].nil?
next
end

result[:successful_logins].map do |credential|
[host, credential[:public], credential[:private_data]]
end
end

::Rex::Text::Table.new(
'Header' => 'Successful logins',
'Indent' => 4,
'Columns' => field_headers,
'Rows' => markdown_fields.compact
)
end
end
end
end
8 changes: 8 additions & 0 deletions lib/msf/core/feature_manager.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class FeatureManager
MYSQL_SESSION_TYPE = 'mysql_session_type'
MSSQL_SESSION_TYPE = 'mssql_session_type'
LDAP_SESSION_TYPE = 'ldap_session_type'
SHOW_SUCCESSFUL_LOGINS = 'show_successful_logins'

DEFAULTS = [
{
Expand Down Expand Up @@ -103,6 +104,13 @@ class FeatureManager
default_value: false,
developer_notes: 'To be enabled by default after appropriate testing'
}.freeze,
{
name: SHOW_SUCCESSFUL_LOGINS,
description: 'When enabled scanners/login modules will return a table off successful logins once the module completes',
requires_restart: false,
default_value: false,
developer_notes: 'To be enabled after appropriate testing'
}.freeze,
{
name: DNS,
description: 'When enabled allows configuration of DNS resolution behaviour in Metasploit',
Expand Down
1 change: 1 addition & 0 deletions modules/auxiliary/cloud/aws/enum_ssm.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::Report
include Msf::Auxiliary::CommandShell
include Msf::Sessions::CreateSessionOptions
include Msf::Auxiliary::ReportSummary

def initialize(info = {})
super(
Expand Down
1 change: 1 addition & 0 deletions modules/auxiliary/scanner/ldap/ldap_login.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::LDAP
include Msf::Sessions::CreateSessionOptions
include Msf::Auxiliary::CommandShell
include Msf::Auxiliary::ReportSummary

def initialize(info = {})
super(
Expand Down
1 change: 1 addition & 0 deletions modules/auxiliary/scanner/mssql/mssql_login.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::CommandShell
include Msf::Auxiliary::Scanner
include Msf::Sessions::CreateSessionOptions
include Msf::Auxiliary::ReportSummary

def initialize
super(
Expand Down
1 change: 1 addition & 0 deletions modules/auxiliary/scanner/mysql/mysql_login.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::Scanner
include Msf::Sessions::CreateSessionOptions
include Msf::Auxiliary::CommandShell
include Msf::Auxiliary::ReportSummary

def initialize(info = {})
super(update_info(info,
Expand Down
1 change: 1 addition & 0 deletions modules/auxiliary/scanner/postgres/postgres_login.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::Report
include Msf::Auxiliary::CommandShell
include Msf::Sessions::CreateSessionOptions
include Msf::Auxiliary::ReportSummary

# Creates an instance of this module.
def initialize(info = {})
Expand Down
1 change: 1 addition & 0 deletions modules/auxiliary/scanner/rservices/rexec_login.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::Scanner
include Msf::Auxiliary::CommandShell
include Msf::Sessions::CreateSessionOptions
include Msf::Auxiliary::ReportSummary

def initialize
super(
Expand Down
1 change: 1 addition & 0 deletions modules/auxiliary/scanner/rservices/rlogin_login.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::Login
include Msf::Auxiliary::CommandShell
include Msf::Sessions::CreateSessionOptions
include Msf::Auxiliary::ReportSummary

def initialize
super(
Expand Down
1 change: 1 addition & 0 deletions modules/auxiliary/scanner/rservices/rsh_login.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::Scanner
include Msf::Auxiliary::CommandShell
include Msf::Sessions::CreateSessionOptions
include Msf::Auxiliary::ReportSummary

def initialize
super(
Expand Down
1 change: 1 addition & 0 deletions modules/auxiliary/scanner/smb/smb_login.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::AuthBrute
include Msf::Auxiliary::CommandShell
include Msf::Sessions::CreateSessionOptions
include Msf::Auxiliary::ReportSummary

Aliases = [
'auxiliary/scanner/smb/login'
Expand Down
1 change: 1 addition & 0 deletions modules/auxiliary/scanner/ssh/eaton_xpert_backdoor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::CommandShell
include Msf::Auxiliary::Report
include Msf::Sessions::CreateSessionOptions
include Msf::Auxiliary::ReportSummary

def initialize(info = {})
super(update_info(info,
Expand Down
1 change: 1 addition & 0 deletions modules/auxiliary/scanner/ssh/fortinet_backdoor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::CommandShell
include Msf::Sessions::CreateSessionOptions
include Msf::Auxiliary::Report
include Msf::Auxiliary::ReportSummary

def initialize(info = {})
super(update_info(info,
Expand Down
1 change: 1 addition & 0 deletions modules/auxiliary/scanner/ssh/libssh_auth_bypass.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::CommandShell
include Msf::Auxiliary::Report
include Msf::Sessions::CreateSessionOptions
include Msf::Auxiliary::ReportSummary

def initialize(info = {})
super(update_info(info,
Expand Down
1 change: 1 addition & 0 deletions modules/auxiliary/scanner/ssh/ssh_login.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::Scanner
include Msf::Exploit::Remote::SSH::Options
include Msf::Sessions::CreateSessionOptions
include Msf::Auxiliary::ReportSummary

def initialize
super(
Expand Down
1 change: 1 addition & 0 deletions modules/auxiliary/scanner/ssh/ssh_login_pubkey.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::Scanner
include Msf::Exploit::Remote::SSH::Options
include Msf::Sessions::CreateSessionOptions
include Msf::Auxiliary::ReportSummary

attr_accessor :ssh_socket, :good_key

Expand Down
1 change: 1 addition & 0 deletions modules/auxiliary/scanner/telnet/brocade_enable_login.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::Scanner
include Msf::Auxiliary::CommandShell
include Msf::Sessions::CreateSessionOptions
include Msf::Auxiliary::ReportSummary

def initialize
super(
Expand Down
1 change: 1 addition & 0 deletions modules/auxiliary/scanner/telnet/telnet_login.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::Scanner
include Msf::Auxiliary::CommandShell
include Msf::Sessions::CreateSessionOptions
include Msf::Auxiliary::ReportSummary

def initialize
super(
Expand Down
1 change: 1 addition & 0 deletions modules/auxiliary/scanner/winrm/winrm_login.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::Scanner
include Msf::Exploit::Remote::Kerberos::Ticket::Storage
include Msf::Sessions::CreateSessionOptions
include Msf::Auxiliary::ReportSummary

def initialize
super(
Expand Down