Re-renamespace error handling, and validate rhost schemas

This commit is contained in:
adfoster-r7 2021-08-26 18:19:08 +01:00
parent 3b23951d62
commit f3ad3e8292
No known key found for this signature in database
GPG Key ID: 3BD4FA3818818F04
14 changed files with 68 additions and 44 deletions

View File

@ -206,7 +206,8 @@ protected
end
return
rescue ::Msf::OptionValidateError => e
::Msf::Simple::Exception.print_option_validate_error(mod, e)
mod.error = e
::Msf::Ui::Formatter::OptionValidateError.print_error(mod, e)
rescue ::Exception => e
mod.error = e
mod.print_error("Auxiliary failed: #{e.class} #{e}")

View File

@ -92,7 +92,8 @@ module Evasion
evasion.error = $!
raise $!
rescue ::Msf::OptionValidateError => e
::Msf::Simple::Exception.print_option_validate_error(mod, e)
evasion.error = e
::Msf::Ui::Formatter::OptionValidateError.print_error(mod, e)
rescue ::Exception => e
evasion.error = e
evasion.print_error("evasion failed: #{e}")

View File

@ -1,28 +0,0 @@
# -*- coding: binary -*-
module Msf
module Simple
module Exception
#
# Print the `Msf::OptionValidateError` error in a human readable format
#
# @param error [::Msf::Framework, ::Msf::Simple::Framework] The error to print
# @param error [::Msf::OptionValidateError] The error to print
def self.print_option_validate_error(mod, error)
if error.reasons.empty?
mod.print_error("#{error.class} The following options failed to validate: #{error.options.join(', ')}")
else
mod.print_error("#{error.class} The following options failed to validate:")
error.options.sort.each do |option_name|
reasons = error.reasons[option_name]
if reasons
mod.print_error("Invalid option #{option_name}: #{reasons.join(', ')}")
else
mod.print_error("Invalid option #{option_name}")
end
end
end
end
end
end
end

View File

@ -153,7 +153,7 @@ module Exploit
raise $!
rescue ::Msf::OptionValidateError => e
exploit.error = e
::Msf::Simple::Exception.print_option_validate_error(oexploit, e)
::Msf::Ui::Formatter::OptionValidateError.print_error(oexploit, e)
rescue ::Exception => e
exploit.error = e
exploit.print_error("Exploit failed: #{e}")

View File

@ -134,7 +134,8 @@ protected
mod.cleanup
return
rescue ::Msf::OptionValidateError => e
::Msf::Simple::Exception.print_option_validate_error(mod, e)
mod.error = e
::Msf::Ui::Formatter::OptionValidateError.print_error(mod, e)
rescue ::Exception => e
mod.error = e
mod.print_error("Post failed: #{e.class} #{e}")

View File

@ -1392,7 +1392,7 @@ class Exploit < Msf::Module
when Msf::OptionValidateError
self.fail_reason = Msf::Exploit::Failure::BadConfig
::Msf::Simple::Exception.print_option_validate_error(self, e)
::Msf::Ui::Formatter::OptionValidateError.print_error(self, e)
elog("Exploit failed (#{self.refname}): #{msg}", error: e)
when Msf::Exploit::Failed

View File

@ -40,11 +40,11 @@ module Msf
end
# @return [OptRhosts]
def self.RHOSTS(default= nil, required=true, desc="The target host(s) of format 10.10.10.10, cidr identifier 10.10.10.10/24, 'http:<url>' which overrides the RPORT/SSL/TARGETURI values, combine cidr and http with 'cidr:/24:http://<url>', or host file 'file:<path>'")
def self.RHOSTS(default= nil, required=true, desc="The target host(s), see https://github.com/rapid7/metasploit-framework/wiki/Using-Metasploit")
Msf::OptRhosts.new('RHOSTS', [ required, desc, default ], aliases: [ 'RHOST' ])
end
def self.RHOST(default=nil, required=true, desc="The target host(s) of format 10.10.10.10, cidr identifier 10.10.10.10/24, 'http:<url>' which overrides the RPORT/SSL/TARGETURI values, combine cidr and http with 'cidr:/24:http://<url>', or host file 'file:<path>'")
def self.RHOST(default=nil, required=true, desc="The target host(s), see https://github.com/rapid7/metasploit-framework/wiki/Using-Metasploit")
Msf::OptRhosts.new('RHOSTS', [ required, desc, default ], aliases: [ 'RHOST' ])
end

View File

@ -37,7 +37,10 @@ module Msf
end
end
class InvalidCIDRURIError < StandardError
class InvalidSchemaError < StandardError
end
class InvalidCIDRError < StandardError
end
def initialize(value = '', datastore = Msf::ModuleDataStore.new(nil))
@ -118,7 +121,7 @@ module Msf
elsif value =~ /^cidr:(.*)/
cidr, child_value = Regexp.last_match(1).split(':', 2)
# Validate cidr syntax matches ipv6 '%scope_id/mask_part' or ipv4 '/mask_part'
raise InvalidCIDRURIError unless cidr =~ %r{^(%\w+)?/\d{1,3}$}
raise InvalidCIDRError unless cidr =~ %r{^(%\w+)?/\d{1,3}$}
# Parse the values, then apply range walker over the result
parse(child_value, datastore).each do |result|
@ -127,8 +130,11 @@ module Msf
results << result.merge('RHOSTS' => rhost, 'UNPARSED_RHOSTS' => value)
end
end
elsif value =~ /^(?<schema>\w+):.*/ && SUPPORTED_SCHEMAS.include?(Regexp.last_match(:schema))
parse_method = "parse_#{Regexp.last_match(:schema)}_uri"
elsif value =~ /^(?<schema>\w+):.*/
schema = Regexp.last_match(:schema)
raise InvalidSchemaError unless SUPPORTED_SCHEMAS.include?(schema)
parse_method = "parse_#{schema}_uri"
parsed_options = send(parse_method, value, datastore)
Rex::Socket::RangeWalker.new(parsed_options['RHOSTS']).each_ip do |ip|
results << datastore.merge(

View File

@ -59,7 +59,7 @@ class Auxiliary
begin
mod_with_opts.validate
rescue ::Msf::OptionValidateError => e
::Msf::Simple::Exception.print_option_validate_error(mod_with_opts, e)
::Msf::Ui::Formatter::OptionValidateError.print_error(mod_with_opts, e)
return false
end
@ -98,7 +98,7 @@ class Auxiliary
rescue ::Interrupt
print_error("Auxiliary interrupted by the console user")
rescue ::Msf::OptionValidateError => e
::Msf::Simple::Exception.print_option_validate_error(running_mod, e)
::Msf::Ui::Formatter::OptionValidateError.print_error(running_mod, e)
rescue ::Exception => e
print_error("Auxiliary failed: #{e.class} #{e}")
if(e.class.to_s != 'Msf::OptionValidateError')

View File

@ -46,7 +46,7 @@ class Exploit
rescue ::Interrupt
raise $!
rescue ::Msf::OptionValidateError => e
::Msf::Simple::Exception.print_option_validate_error(mod, e)
::Msf::Ui::Formatter::OptionValidateError.print_error(mod, e)
rescue ::Exception => e
print_error("Exploit exception (#{mod.refname}): #{e.class} #{e}")
if e.class.to_s != 'Msf::OptionValidateError'
@ -130,7 +130,7 @@ class Exploit
begin
mod_with_opts.validate
rescue ::Msf::OptionValidateError => e
::Msf::Simple::Exception.print_option_validate_error(mod_with_opts, e)
::Msf::Ui::Formatter::OptionValidateError.print_error(mod_with_opts, e)
return false
end

View File

@ -143,7 +143,7 @@ module ModuleCommandDispatcher
begin
mod_with_opts.validate
rescue ::Msf::OptionValidateError => e
::Msf::Simple::Exception.print_option_validate_error(mod_with_opts, e)
::Msf::Ui::Formatter::OptionValidateError.print_error(mod_with_opts, e)
return false
end

8
lib/msf/ui/formatter.rb Normal file
View File

@ -0,0 +1,8 @@
# -*- coding: binary -*-
module Msf
module Ui
module Formatter
end
end
end

View File

@ -0,0 +1,32 @@
# -*- coding: binary -*-
module Msf
module Ui
module Formatter
class OptionValidateError
#
# Print the `Msf::OptionValidateError` error in a human readable format
#
# @param mod [::Msf::Framework, ::Msf::Simple::Framework] The mod
# @param error [::Msf::OptionValidateError] The error to print
def self.print_error(mod, error)
raise ArgumentError, "invalid error type #{error.class}, expected ::Msf::OptionValidateError" unless error.is_a?(::Msf::OptionValidateError)
if error.reasons.empty?
mod.print_error("#{error.class} The following options failed to validate: #{error.options.join(', ')}")
else
mod.print_error("#{error.class} The following options failed to validate:")
error.options.sort.each do |option_name|
reasons = error.reasons[option_name]
if reasons
mod.print_error("Invalid option #{option_name}: #{reasons.join(', ')}")
else
mod.print_error("Invalid option #{option_name}")
end
end
end
end
end
end
end
end

View File

@ -306,6 +306,7 @@ RSpec.describe Msf::RhostsWalker do
{ 'RHOSTS' => '127.0.0.1 http:' },
{ 'RHOSTS' => '127.0.0.1 http: 127.0.0.1' },
{ 'RHOSTS' => '"http://127.0.0.1' },
{ 'RHOSTS' => 'unknown_protocol://127.0.0.1' },
].each do |test|
it "validates #{test['RHOSTS']} as being invalid" do
expect(described_class.new(test['RHOSTS']).valid?).to be false
@ -331,6 +332,7 @@ RSpec.describe Msf::RhostsWalker do
{ 'RHOSTS' => 'http:|', 'expected' => 0 },
{ 'RHOSTS' => '127.0.0.1 http:|', 'expected' => 1 },
{ 'RHOSTS' => '127.0.0.1 http:| 127.0.0.1', 'expected' => 2 },
{ 'RHOSTS' => '127.0.0.1 unknown_protocol://127.0.0.1 ftpz://127.0.0.1', 'expected' => 1 },
].each do |test|
it "counts #{test['RHOSTS'].inspect} as being #{test['expected']}" do
expect(described_class.new(test['RHOSTS'], aux_mod.datastore).count).to eq(test['expected'])
@ -354,6 +356,7 @@ RSpec.describe Msf::RhostsWalker do
{ 'RHOSTS' => 'http:', 'expected' => [Msf::RhostsWalker::Error.new('http:')] },
{ 'RHOSTS' => '127.0.0.1 http:', 'expected' => [Msf::RhostsWalker::Error.new('http:')] },
{ 'RHOSTS' => '127.0.0.1 http: 127.0.0.1 https:', 'expected' => [Msf::RhostsWalker::Error.new('http:'), Msf::RhostsWalker::Error.new('https:')] },
{ 'RHOSTS' => 'unknown_protocol://127.0.0.1 127.0.0.1', 'expected' => [ Msf::RhostsWalker::Error.new('unknown_protocol://127.0.0.1')] },
# cidr validation
{ 'RHOSTS' => 'cidr:127.0.0.1', 'expected' => [Msf::RhostsWalker::Error.new('cidr:127.0.0.1')] },