Split all the option classes into their own files
parent
aa4489dd21
commit
3a5af3939d
|
@ -3,6 +3,8 @@ require 'msf/core'
|
|||
|
||||
module Msf
|
||||
|
||||
autoload :OptionContainer, 'msf/core/option_container'
|
||||
|
||||
###
|
||||
#
|
||||
# The module base class is responsible for providing the common interface
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
module Msf
|
||||
|
||||
###
|
||||
#
|
||||
# The core supported option types are:
|
||||
#
|
||||
# OptString - Multi-byte character string
|
||||
# OptRaw - Multi-byte raw string
|
||||
# OptBool - Boolean true or false indication
|
||||
# OptPort - TCP/UDP service port
|
||||
# OptAddress - IP address or hostname
|
||||
# OptPath - Path name on disk or an Object ID
|
||||
# OptInt - An integer value
|
||||
# OptEnum - Select from a set of valid values
|
||||
# OptAddressRange - A subnet or range of addresses
|
||||
# OptSession - A session identifier
|
||||
# OptRegexp - Valid Ruby regular expression
|
||||
#
|
||||
###
|
||||
|
||||
#
|
||||
# Builtin framework options with shortcut methods
|
||||
#
|
||||
module Opt
|
||||
|
||||
@@builtin_opts =
|
||||
{
|
||||
'RHOST' => [ Msf::OptAddress, 'nil', true, '"The target address"' ],
|
||||
'RPORT' => [ Msf::OptPort, 'nil', true, '"The target port"' ],
|
||||
'LHOST' => [ Msf::OptAddress, 'nil', true, '"The listen address"' ],
|
||||
'LPORT' => [ Msf::OptPort, 'nil', true, '"The listen port"' ],
|
||||
'CPORT' => [ Msf::OptPort, 'nil', false, '"The local client port"' ],
|
||||
'CHOST' => [ Msf::OptAddress, 'nil', false, '"The local client address"' ],
|
||||
'Proxies' => [ Msf::OptString, 'nil', 'false', '"A proxy chain of format type:host:port[,type:host:port][...]"']
|
||||
}
|
||||
|
||||
#
|
||||
# Build the builtin_xyz methods on the fly using the type information for each
|
||||
# of the builtin framework options, such as RHOST.
|
||||
#
|
||||
class <<self
|
||||
@@builtin_opts.each_pair { |opt, info|
|
||||
eval(
|
||||
"
|
||||
def builtin_#{opt.downcase}(default = #{info[1]}, required = #{info[2]}, desc = #{info[3]})
|
||||
#{info[0]}.new('#{opt}', [ required, desc, default ])
|
||||
end
|
||||
|
||||
alias #{opt} builtin_#{opt.downcase}
|
||||
")
|
||||
}
|
||||
end
|
||||
|
||||
#
|
||||
# Define the constant versions of the options which are merely redirections to
|
||||
# the class methods.
|
||||
#
|
||||
@@builtin_opts.each_pair { |opt, info|
|
||||
eval("#{opt} = Msf::Opt::builtin_#{opt.downcase}")
|
||||
}
|
||||
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,37 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
module Msf
|
||||
|
||||
###
|
||||
#
|
||||
# Network address option.
|
||||
#
|
||||
###
|
||||
class OptAddress < OptBase
|
||||
def type
|
||||
return 'address'
|
||||
end
|
||||
|
||||
def valid?(value)
|
||||
return false if empty_required_value?(value)
|
||||
return false unless value.kind_of?(String) or value.kind_of?(NilClass)
|
||||
|
||||
if (value != nil and value.empty? == false)
|
||||
begin
|
||||
getaddr_result = ::Rex::Socket.getaddress(value, true)
|
||||
# Covers a wierdcase where an incomplete ipv4 address will have it's
|
||||
# missing octets filled in with 0's. (e.g 192.168 become 192.0.0.168)
|
||||
# which does not feel like a legit behaviour
|
||||
if value =~ /^\d{1,3}(\.\d{1,3}){1,3}$/
|
||||
return false unless value =~ Rex::Socket::MATCH_IPV4
|
||||
end
|
||||
rescue
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
return super
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,51 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
module Msf
|
||||
|
||||
###
|
||||
#
|
||||
# Network address range option.
|
||||
#
|
||||
###
|
||||
class OptAddressRange < OptBase
|
||||
def type
|
||||
return 'addressrange'
|
||||
end
|
||||
|
||||
def normalize(value)
|
||||
return nil unless value.kind_of?(String)
|
||||
if (value =~ /^file:(.*)/)
|
||||
path = $1
|
||||
return false if not File.exists?(path) or File.directory?(path)
|
||||
return File.readlines(path).map{ |s| s.strip}.join(" ")
|
||||
elsif (value =~ /^rand:(.*)/)
|
||||
count = $1.to_i
|
||||
return false if count < 1
|
||||
ret = ''
|
||||
count.times {
|
||||
ret << " " if not ret.empty?
|
||||
ret << [ rand(0x100000000) ].pack("N").unpack("C*").map{|x| x.to_s }.join(".")
|
||||
}
|
||||
return ret
|
||||
end
|
||||
return value
|
||||
end
|
||||
|
||||
def valid?(value)
|
||||
return false if empty_required_value?(value)
|
||||
return false unless value.kind_of?(String) or value.kind_of?(NilClass)
|
||||
|
||||
if (value != nil and value.empty? == false)
|
||||
normalized = normalize(value)
|
||||
return false if normalized.nil?
|
||||
walker = Rex::Socket::RangeWalker.new(normalized)
|
||||
if (not walker or not walker.valid?)
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
return super
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,179 @@
|
|||
# -*- coding: binary -*-
|
||||
require 'resolv'
|
||||
require 'msf/core'
|
||||
require 'rex/socket'
|
||||
|
||||
module Msf
|
||||
|
||||
autoload :Opt, 'msf/core/opt'
|
||||
|
||||
autoload :OptAddress, 'msf/core/opt_address'
|
||||
autoload :OptAddressRange, 'msf/core/opt_address_range'
|
||||
autoload :OptBool, 'msf/core/opt_bool'
|
||||
autoload :OptEnum, 'msf/core/opt_enum'
|
||||
autoload :OptInt, 'msf/core/opt_int'
|
||||
autoload :OptPath, 'msf/core/opt_path'
|
||||
autoload :OptPort, 'msf/core/opt_port'
|
||||
autoload :OptRaw, 'msf/core/opt_raw'
|
||||
autoload :OptRegexp, 'msf/core/opt_regexp'
|
||||
autoload :OptString, 'msf/core/opt_string'
|
||||
|
||||
###
|
||||
#
|
||||
# The base class for all options.
|
||||
#
|
||||
###
|
||||
class OptBase
|
||||
|
||||
#
|
||||
# Initializes a named option with the supplied attribute array.
|
||||
# The array is composed of three values.
|
||||
#
|
||||
# attrs[0] = required (boolean type)
|
||||
# attrs[1] = description (string)
|
||||
# attrs[2] = default value
|
||||
# attrs[3] = possible enum values
|
||||
# attrs[4] = Regex to validate the option
|
||||
#
|
||||
def initialize(in_name, attrs = [])
|
||||
self.name = in_name
|
||||
self.advanced = false
|
||||
self.evasion = false
|
||||
self.required = attrs[0] || false
|
||||
self.desc = attrs[1]
|
||||
self.default = attrs[2]
|
||||
self.enums = [ *(attrs[3]) ].map { |x| x.to_s }
|
||||
regex_temp = attrs[4] || nil
|
||||
if regex_temp
|
||||
# convert to string
|
||||
regex_temp = regex_temp.to_s if regex_temp.is_a? Regexp
|
||||
# remove start and end character, they will be added later
|
||||
regex_temp = regex_temp.sub(/^\^/, '').sub(/\$$/, '')
|
||||
# Add start and end marker to match the whole regex
|
||||
regex_temp = "^#{regex_temp}$"
|
||||
begin
|
||||
Regexp.compile(regex_temp)
|
||||
self.regex = regex_temp
|
||||
rescue RegexpError, TypeError => e
|
||||
raise("Invalid Regex #{regex_temp}: #{e}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Returns true if this is a required option.
|
||||
#
|
||||
def required?
|
||||
return required
|
||||
end
|
||||
|
||||
#
|
||||
# Returns true if this is an advanced option.
|
||||
#
|
||||
def advanced?
|
||||
return advanced
|
||||
end
|
||||
|
||||
#
|
||||
# Returns true if this is an evasion option.
|
||||
#
|
||||
def evasion?
|
||||
return evasion
|
||||
end
|
||||
|
||||
#
|
||||
# Returns true if the supplied type is equivalent to this option's type.
|
||||
#
|
||||
def type?(in_type)
|
||||
return (type == in_type)
|
||||
end
|
||||
|
||||
#
|
||||
# If it's required and the value is nil or empty, then it's not valid.
|
||||
#
|
||||
def valid?(value)
|
||||
if required?
|
||||
# required variable not set
|
||||
return false if (value == nil or value.to_s.empty?)
|
||||
end
|
||||
if regex
|
||||
if value.match(regex)
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
#
|
||||
# Returns true if the value supplied is nil and it's required to be
|
||||
# a valid value
|
||||
#
|
||||
def empty_required_value?(value)
|
||||
return (required? and value.nil?)
|
||||
end
|
||||
|
||||
#
|
||||
# Normalizes the supplied value to conform with the type that the option is
|
||||
# conveying.
|
||||
#
|
||||
def normalize(value)
|
||||
value
|
||||
end
|
||||
|
||||
#
|
||||
# Returns a string representing a user-friendly display of the chosen value
|
||||
#
|
||||
def display_value(value)
|
||||
value.to_s
|
||||
end
|
||||
|
||||
#
|
||||
# The name of the option.
|
||||
#
|
||||
attr_reader :name
|
||||
#
|
||||
# Whether or not the option is required.
|
||||
#
|
||||
attr_reader :required
|
||||
#
|
||||
# The description of the option.
|
||||
#
|
||||
attr_reader :desc
|
||||
#
|
||||
# The default value of the option.
|
||||
#
|
||||
attr_reader :default
|
||||
#
|
||||
# Storing the name of the option.
|
||||
#
|
||||
attr_writer :name
|
||||
#
|
||||
# Whether or not this is an advanced option.
|
||||
#
|
||||
attr_accessor :advanced
|
||||
#
|
||||
# Whether or not this is an evasion option.
|
||||
#
|
||||
attr_accessor :evasion
|
||||
#
|
||||
# The module or entity that owns this option.
|
||||
#
|
||||
attr_accessor :owner
|
||||
#
|
||||
# The list of potential valid values
|
||||
#
|
||||
attr_accessor :enums
|
||||
#
|
||||
# A optional regex to validate the option value
|
||||
#
|
||||
attr_accessor :regex
|
||||
|
||||
protected
|
||||
|
||||
attr_writer :required, :desc, :default # :nodoc:
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
module Msf
|
||||
|
||||
###
|
||||
#
|
||||
# Boolean option.
|
||||
#
|
||||
###
|
||||
class OptBool < OptBase
|
||||
|
||||
TrueRegex = /^(y|yes|t|1|true)$/i
|
||||
|
||||
def type
|
||||
return 'bool'
|
||||
end
|
||||
|
||||
def valid?(value)
|
||||
return false if empty_required_value?(value)
|
||||
|
||||
if ((value != nil and
|
||||
(value.to_s.empty? == false) and
|
||||
(value.to_s.match(/^(y|yes|n|no|t|f|0|1|true|false)$/i) == nil)))
|
||||
return false
|
||||
end
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
def normalize(value)
|
||||
if(value.nil? or value.to_s.match(TrueRegex).nil?)
|
||||
false
|
||||
else
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
def is_true?(value)
|
||||
return normalize(value)
|
||||
end
|
||||
|
||||
def is_false?(value)
|
||||
return !is_true?(value)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,48 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
module Msf
|
||||
|
||||
###
|
||||
#
|
||||
# Enum option.
|
||||
#
|
||||
###
|
||||
class OptEnum < OptBase
|
||||
|
||||
def type
|
||||
return 'enum'
|
||||
end
|
||||
|
||||
def valid?(value=self.value)
|
||||
return false if empty_required_value?(value)
|
||||
return true if value.nil? and !required?
|
||||
|
||||
(value and self.enums.include?(value.to_s))
|
||||
end
|
||||
|
||||
def normalize(value=self.value)
|
||||
return nil if not self.valid?(value)
|
||||
return value.to_s
|
||||
end
|
||||
|
||||
def desc=(value)
|
||||
self.desc_string = value
|
||||
|
||||
self.desc
|
||||
end
|
||||
|
||||
def desc
|
||||
if self.enums
|
||||
str = self.enums.join(', ')
|
||||
end
|
||||
"#{self.desc_string || ''} (accepted: #{str})"
|
||||
end
|
||||
|
||||
|
||||
protected
|
||||
|
||||
attr_accessor :desc_string # :nodoc:
|
||||
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,35 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
module Msf
|
||||
|
||||
###
|
||||
#
|
||||
# Integer option.
|
||||
#
|
||||
###
|
||||
class OptInt < OptBase
|
||||
def type
|
||||
return 'integer'
|
||||
end
|
||||
|
||||
def normalize(value)
|
||||
if (value.to_s.match(/^0x[a-fA-F\d]+$/))
|
||||
value.to_i(16)
|
||||
else
|
||||
value.to_i
|
||||
end
|
||||
end
|
||||
|
||||
def valid?(value)
|
||||
return super if !required? and value.to_s.empty?
|
||||
return false if empty_required_value?(value)
|
||||
|
||||
if value and not value.to_s.match(/^0x[0-9a-fA-F]+$|^-?\d+$/)
|
||||
return false
|
||||
end
|
||||
|
||||
return super
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,44 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
module Msf
|
||||
|
||||
###
|
||||
#
|
||||
# File system path option.
|
||||
#
|
||||
###
|
||||
class OptPath < OptBase
|
||||
def type
|
||||
return 'path'
|
||||
end
|
||||
|
||||
# Generally, 'value' should be a file that exists.
|
||||
def valid?(value)
|
||||
return false if empty_required_value?(value)
|
||||
if value and !value.empty?
|
||||
if value =~ /^memory:\s*([0-9]+)/i
|
||||
return false unless check_memory_location($1)
|
||||
else
|
||||
unless File.exists?(value)
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
return super
|
||||
end
|
||||
|
||||
# The AuthBrute mixin can take a memory address as well --
|
||||
# currently, no other OptFile can make use of these objects.
|
||||
# TODO: Implement memory:xxx to be more generally useful so
|
||||
# the validator on OptFile isn't lying for non-AuthBrute.
|
||||
def check_memory_location(id)
|
||||
return false unless self.class.const_defined?(:ObjectSpace)
|
||||
obj = ObjectSpace._id2ref(id.to_i) rescue nil
|
||||
return false unless obj.respond_to? :acts_as_file?
|
||||
return false unless obj.acts_as_file? # redundant?
|
||||
return !!obj
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,31 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
module Msf
|
||||
|
||||
###
|
||||
#
|
||||
# Network port option.
|
||||
#
|
||||
###
|
||||
class OptPort < OptBase
|
||||
def type
|
||||
return 'port'
|
||||
end
|
||||
|
||||
def normalize(value)
|
||||
value.to_i
|
||||
end
|
||||
|
||||
def valid?(value)
|
||||
return false if empty_required_value?(value)
|
||||
|
||||
if ((value != nil and value.to_s.empty? == false) and
|
||||
((value.to_s.match(/^\d+$/) == nil or value.to_i < 0 or value.to_i > 65535)))
|
||||
return false
|
||||
end
|
||||
|
||||
return super
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,34 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
module Msf
|
||||
|
||||
###
|
||||
#
|
||||
# Raw, arbitrary data option.
|
||||
#
|
||||
###
|
||||
class OptRaw < OptBase
|
||||
def type
|
||||
return 'raw'
|
||||
end
|
||||
|
||||
def normalize(value)
|
||||
if (value =~ /^file:(.*)/)
|
||||
path = $1
|
||||
begin
|
||||
value = File.read(path)
|
||||
rescue ::Errno::ENOENT, ::Errno::EISDIR
|
||||
value = nil
|
||||
end
|
||||
end
|
||||
value
|
||||
end
|
||||
|
||||
def valid?(value=self.value)
|
||||
value = normalize(value)
|
||||
return false if empty_required_value?(value)
|
||||
return super
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,46 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
module Msf
|
||||
|
||||
###
|
||||
#
|
||||
# Regexp option
|
||||
#
|
||||
###
|
||||
class OptRegexp < OptBase
|
||||
def type
|
||||
return 'regexp'
|
||||
end
|
||||
|
||||
def valid?(value)
|
||||
unless super
|
||||
return false
|
||||
end
|
||||
return true if (not required? and value.nil?)
|
||||
|
||||
begin
|
||||
Regexp.compile(value)
|
||||
|
||||
return true
|
||||
rescue RegexpError, TypeError
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
def normalize(value)
|
||||
return nil if value.nil?
|
||||
return Regexp.compile(value)
|
||||
end
|
||||
|
||||
def display_value(value)
|
||||
if value.kind_of?(Regexp)
|
||||
return value.source
|
||||
elsif value.kind_of?(String)
|
||||
return display_value(normalize(value))
|
||||
end
|
||||
|
||||
return super
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,34 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
module Msf
|
||||
|
||||
###
|
||||
#
|
||||
# Mult-byte character string option.
|
||||
#
|
||||
###
|
||||
class OptString < OptBase
|
||||
def type
|
||||
return 'string'
|
||||
end
|
||||
|
||||
def normalize(value)
|
||||
if (value =~ /^file:(.*)/)
|
||||
path = $1
|
||||
begin
|
||||
value = File.read(path)
|
||||
rescue ::Errno::ENOENT, ::Errno::EISDIR
|
||||
value = nil
|
||||
end
|
||||
end
|
||||
value
|
||||
end
|
||||
|
||||
def valid?(value=self.value)
|
||||
value = normalize(value)
|
||||
return false if empty_required_value?(value)
|
||||
return super
|
||||
end
|
||||
end
|
||||
|
||||
end
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue