Skip to content

Commit

Permalink
Show session/rhost options separate from each other
Browse files Browse the repository at this point in the history
Add ability to group options for display
  • Loading branch information
dwelch-r7 committed Feb 15, 2024
1 parent e49c6a7 commit 88f9283
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 54 deletions.
100 changes: 57 additions & 43 deletions lib/msf/base/serializer/readable_text.rb
Original file line number Diff line number Diff line change
Expand Up @@ -569,53 +569,18 @@ def self.dump_generic_module(mod, indent = '')
# @param missing [Boolean] dump only empty required options.
# @return [String] the string form of the information.
def self.dump_options(mod, indent = '', missing = false)
options = mod.options.map { |_name, option| option }
options_grouped_by_conditions = options.group_by(&:conditions)
all_options = mod.options.map { |_name, option| option }

conditional_options, option_groups = all_options.partition { |option| option.group.nil? }
options_grouped_by_conditions = conditional_options.group_by(&:conditions)
options_by_group = option_groups.group_by { |option| option.group if mod.options.keys.include?(option.name) }

options_with_conditions = ''.dup
options_without_conditions = ''.dup
options_group = ''.dup

options_grouped_by_conditions.each do |conditions, options|
tbl = Rex::Text::Table.new(
'Indent' => indent.length,
'Columns' =>
[
'Name',
'Current Setting',
'Required',
'Description'
])

options.sort_by(&:name).each do |opt|
name = opt.name
if mod.datastore.is_a?(Msf::DataStoreWithFallbacks)
val = mod.datastore[name]
else
val = mod.datastore[name].nil? ? opt.default : mod.datastore[name]
end

next if (opt.advanced?)
next if (opt.evasion?)
next if (missing && opt.valid?(val))

desc = opt.desc.dup

# Hint at RPORT proto by regexing mixins
if name == 'RPORT' && opt.kind_of?(Msf::OptPort)
mod.class.included_modules.each do |m|
case m.name
when /tcp/i, /HttpClient$/
desc << ' (TCP)'
break
when /udp/i
desc << ' (UDP)'
break
end
end
end

tbl << [ name, opt.display_value(val), opt.required? ? "yes" : "no", desc ]
end
tbl = options_table(missing, mod, options, indent)

next if conditions.any? && tbl.rows.empty?

Expand All @@ -627,10 +592,59 @@ def self.dump_options(mod, indent = '', missing = false)
end
end

result = "#{options_without_conditions}#{options_with_conditions}"
options_by_group.each do |group, options|
tbl = options_table(missing, mod, options, indent)
options_group << "\n\n#{indent}#{group.description}:\n\n"
options_group << tbl.to_s
end

result = "#{options_without_conditions}#{options_with_conditions}#{options_group}"
result
end

def self.options_table(missing, mod, options, indent)
tbl = Rex::Text::Table.new(
'Indent' => indent.length,
'Columns' =>
[
'Name',
'Current Setting',
'Required',
'Description'
])
options.sort_by(&:name).each do |opt|
# Skip over advanced or evasion options
next if (opt.advanced? || opt.evasion?)

name = opt.name
if mod.datastore.is_a?(Msf::DataStoreWithFallbacks)
val = mod.datastore[name]
else
val = mod.datastore[name].nil? ? opt.default : mod.datastore[name]
end
next if (missing && opt.valid?(val))

desc = opt.desc.dup

# Hint at RPORT proto by regexing mixins
if name == 'RPORT' && opt.kind_of?(Msf::OptPort)
mod.class.included_modules.each do |m|
case m.name
when /tcp/i, /HttpClient$/
desc << ' (TCP)'
break
when /udp/i
desc << ' (UDP)'
break
end
end
end

tbl << [name, opt.display_value(val), opt.required? ? "yes" : "no", desc]
end
tbl
end

# Dumps the advanced options associated with the supplied module.
#
# @param mod [Msf::Module] the module.
Expand Down
4 changes: 2 additions & 2 deletions lib/msf/core/opt.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ def self.RHOSTS(default= nil, required=true, desc="The target host(s), see https
Msf::OptRhosts.new('RHOSTS', [ required, desc, default ], aliases: [ 'RHOST' ])
end

def self.RHOST(default=nil, required=true, desc="The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html")
Msf::OptRhosts.new('RHOSTS', [ required, desc, default ], aliases: [ 'RHOST' ])
def self.RHOST(default=nil, required=true, desc="The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html", **kwargs)
Msf::OptRhosts.new('RHOSTS', [ required, desc, default ], aliases: [ 'RHOST' ], **kwargs)
end

# @return [OptPort]
Expand Down
6 changes: 5 additions & 1 deletion lib/msf/core/opt_base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,15 @@ class OptBase
#
def initialize(in_name, attrs = [],
required: false, desc: nil, default: nil, conditions: [], enums: [], regex: nil, aliases: [], max_length: nil,
fallbacks: [])
fallbacks: [], group: nil)
self.name = in_name
self.advanced = false
self.evasion = false
self.aliases = aliases
self.max_length = max_length
self.conditions = conditions
self.fallbacks = fallbacks
self.group = group

if attrs.is_a?(String) || attrs.length == 0
self.required = required
Expand Down Expand Up @@ -230,6 +231,9 @@ def invalid_value_length?(value)
#
attr_accessor :max_length

# @return [Msf::OptionGroup, nil] The option group that this option belongs to if any
attr_accessor :group

protected

attr_writer :required, :desc, :default # :nodoc:
Expand Down
9 changes: 6 additions & 3 deletions lib/msf/core/opt_condition.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
module Msf
module OptCondition
# Check a condition's result
# @param [Msf::Module] mod The module module
# @param [Msf::OptBase] opt the option which has conditions present
# @return [String]
# @param [String] left_value The left hand side of the condition
# @param [String] operator The conditions comparison operator
# @param [String] right_value The right hand side of the condition
# @return [Boolean]
def self.eval_condition(left_value, operator, right_value)
case operator.to_sym
when :==
Expand All @@ -16,6 +17,8 @@ def self.eval_condition(left_value, operator, right_value)
right_value.include?(left_value)
when :nin
!right_value.include?(left_value)
else
raise ArgumentError("Operator: #{operator} is invalid")
end
end

Expand Down
13 changes: 13 additions & 0 deletions lib/msf/core/option_group.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# -*- coding: binary -*-

module Msf
class OptionGroup

attr_accessor :name, :description

def initialize(name:, description:)
self.name = name
self.description = description
end
end
end
4 changes: 4 additions & 0 deletions lib/msf/core/optional_session.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,9 @@
module Msf
module OptionalSession
include Msf::SessionCompatibility

def session_enabled?(session_feature_name)
framework.features.enabled?(session_feature_name)
end
end
end
25 changes: 20 additions & 5 deletions lib/msf/core/optional_session/smb.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ module OptionalSession
module SMB
include Msf::OptionalSession

FEATURE_NAME = Msf::FeatureManager::SMB_SESSION_TYPE
RHOST_GROUP_OPTIONS = %w[RHOSTS RPORT SMBDomain SMBUser SMBPass THREADS]

def initialize(info = {})
super(
update_info(
Expand All @@ -13,24 +16,36 @@ def initialize(info = {})
)
)


if framework.features.enabled?(Msf::FeatureManager::SMB_SESSION_TYPE)
if session_enabled?
session_group = Msf::OptionGroup.new(name: 'SESSION', description: 'Used when connecting via an existing SESSION')
rhost_group = Msf::OptionGroup.new(name: 'RHOST', description: 'Used when making a new connection via RHOSTS')
register_options(
[
Msf::OptInt.new('SESSION', [ false, 'The session to run this module on' ]),
Msf::OptInt.new('SESSION', [ false, 'The session to run this module on' ], group: session_group),
Msf::Opt::RHOST(nil, false),
Msf::Opt::RPORT(443, false)
Msf::Opt::RPORT(445, false),
]
)

RHOST_GROUP_OPTIONS.each do |option_name|
if options[option_name]
options[option_name].group = rhost_group
end
end

add_info('New in Metasploit 6.4 - This module can target a %grnSESSION%clr or an %grnRHOST%clr')
end
end

def session
return nil unless framework.features.enabled?(Msf::FeatureManager::SMB_SESSION_TYPE)
return nil unless session_enabled?

super
end

def session_enabled?
super(FEATURE_NAME)
end
end
end
end

0 comments on commit 88f9283

Please sign in to comment.