Split all the option classes into their own files

bug/bundler_fix
James Lee 2014-11-03 16:20:21 -06:00
parent aa4489dd21
commit 3a5af3939d
No known key found for this signature in database
GPG Key ID: 2D6094C7CEA0A321
23 changed files with 870 additions and 794 deletions

View File

@ -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

66
lib/msf/core/opt.rb Normal file
View File

@ -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

View File

@ -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

View File

@ -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

179
lib/msf/core/opt_base.rb Normal file
View File

@ -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

48
lib/msf/core/opt_bool.rb Normal file
View File

@ -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

48
lib/msf/core/opt_enum.rb Normal file
View File

@ -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

35
lib/msf/core/opt_int.rb Normal file
View File

@ -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

44
lib/msf/core/opt_path.rb Normal file
View File

@ -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

31
lib/msf/core/opt_port.rb Normal file
View File

@ -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

34
lib/msf/core/opt_raw.rb Normal file
View File

@ -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

View File

@ -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

View File

@ -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