Skip to content

Commit 3a5af39

Browse files
committed
Split all the option classes into their own files
1 parent aa4489d commit 3a5af39

23 files changed

+841
-765
lines changed

lib/msf/core/module.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
module Msf
55

6+
autoload :OptionContainer, 'msf/core/option_container'
7+
68
###
79
#
810
# The module base class is responsible for providing the common interface

lib/msf/core/opt.rb

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# -*- coding: binary -*-
2+
3+
module Msf
4+
5+
###
6+
#
7+
# The core supported option types are:
8+
#
9+
# OptString - Multi-byte character string
10+
# OptRaw - Multi-byte raw string
11+
# OptBool - Boolean true or false indication
12+
# OptPort - TCP/UDP service port
13+
# OptAddress - IP address or hostname
14+
# OptPath - Path name on disk or an Object ID
15+
# OptInt - An integer value
16+
# OptEnum - Select from a set of valid values
17+
# OptAddressRange - A subnet or range of addresses
18+
# OptSession - A session identifier
19+
# OptRegexp - Valid Ruby regular expression
20+
#
21+
###
22+
23+
#
24+
# Builtin framework options with shortcut methods
25+
#
26+
module Opt
27+
28+
@@builtin_opts =
29+
{
30+
'RHOST' => [ Msf::OptAddress, 'nil', true, '"The target address"' ],
31+
'RPORT' => [ Msf::OptPort, 'nil', true, '"The target port"' ],
32+
'LHOST' => [ Msf::OptAddress, 'nil', true, '"The listen address"' ],
33+
'LPORT' => [ Msf::OptPort, 'nil', true, '"The listen port"' ],
34+
'CPORT' => [ Msf::OptPort, 'nil', false, '"The local client port"' ],
35+
'CHOST' => [ Msf::OptAddress, 'nil', false, '"The local client address"' ],
36+
'Proxies' => [ Msf::OptString, 'nil', 'false', '"A proxy chain of format type:host:port[,type:host:port][...]"']
37+
}
38+
39+
#
40+
# Build the builtin_xyz methods on the fly using the type information for each
41+
# of the builtin framework options, such as RHOST.
42+
#
43+
class <<self
44+
@@builtin_opts.each_pair { |opt, info|
45+
eval(
46+
"
47+
def builtin_#{opt.downcase}(default = #{info[1]}, required = #{info[2]}, desc = #{info[3]})
48+
#{info[0]}.new('#{opt}', [ required, desc, default ])
49+
end
50+
51+
alias #{opt} builtin_#{opt.downcase}
52+
")
53+
}
54+
end
55+
56+
#
57+
# Define the constant versions of the options which are merely redirections to
58+
# the class methods.
59+
#
60+
@@builtin_opts.each_pair { |opt, info|
61+
eval("#{opt} = Msf::Opt::builtin_#{opt.downcase}")
62+
}
63+
64+
end
65+
66+
end

lib/msf/core/opt_address.rb

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# -*- coding: binary -*-
2+
3+
module Msf
4+
5+
###
6+
#
7+
# Network address option.
8+
#
9+
###
10+
class OptAddress < OptBase
11+
def type
12+
return 'address'
13+
end
14+
15+
def valid?(value)
16+
return false if empty_required_value?(value)
17+
return false unless value.kind_of?(String) or value.kind_of?(NilClass)
18+
19+
if (value != nil and value.empty? == false)
20+
begin
21+
getaddr_result = ::Rex::Socket.getaddress(value, true)
22+
# Covers a wierdcase where an incomplete ipv4 address will have it's
23+
# missing octets filled in with 0's. (e.g 192.168 become 192.0.0.168)
24+
# which does not feel like a legit behaviour
25+
if value =~ /^\d{1,3}(\.\d{1,3}){1,3}$/
26+
return false unless value =~ Rex::Socket::MATCH_IPV4
27+
end
28+
rescue
29+
return false
30+
end
31+
end
32+
33+
return super
34+
end
35+
end
36+
37+
end

lib/msf/core/opt_address_range.rb

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# -*- coding: binary -*-
2+
3+
module Msf
4+
5+
###
6+
#
7+
# Network address range option.
8+
#
9+
###
10+
class OptAddressRange < OptBase
11+
def type
12+
return 'addressrange'
13+
end
14+
15+
def normalize(value)
16+
return nil unless value.kind_of?(String)
17+
if (value =~ /^file:(.*)/)
18+
path = $1
19+
return false if not File.exists?(path) or File.directory?(path)
20+
return File.readlines(path).map{ |s| s.strip}.join(" ")
21+
elsif (value =~ /^rand:(.*)/)
22+
count = $1.to_i
23+
return false if count < 1
24+
ret = ''
25+
count.times {
26+
ret << " " if not ret.empty?
27+
ret << [ rand(0x100000000) ].pack("N").unpack("C*").map{|x| x.to_s }.join(".")
28+
}
29+
return ret
30+
end
31+
return value
32+
end
33+
34+
def valid?(value)
35+
return false if empty_required_value?(value)
36+
return false unless value.kind_of?(String) or value.kind_of?(NilClass)
37+
38+
if (value != nil and value.empty? == false)
39+
normalized = normalize(value)
40+
return false if normalized.nil?
41+
walker = Rex::Socket::RangeWalker.new(normalized)
42+
if (not walker or not walker.valid?)
43+
return false
44+
end
45+
end
46+
47+
return super
48+
end
49+
end
50+
51+
end

lib/msf/core/opt_base.rb

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
# -*- coding: binary -*-
2+
require 'resolv'
3+
require 'msf/core'
4+
require 'rex/socket'
5+
6+
module Msf
7+
8+
autoload :Opt, 'msf/core/opt'
9+
10+
autoload :OptAddress, 'msf/core/opt_address'
11+
autoload :OptAddressRange, 'msf/core/opt_address_range'
12+
autoload :OptBool, 'msf/core/opt_bool'
13+
autoload :OptEnum, 'msf/core/opt_enum'
14+
autoload :OptInt, 'msf/core/opt_int'
15+
autoload :OptPath, 'msf/core/opt_path'
16+
autoload :OptPort, 'msf/core/opt_port'
17+
autoload :OptRaw, 'msf/core/opt_raw'
18+
autoload :OptRegexp, 'msf/core/opt_regexp'
19+
autoload :OptString, 'msf/core/opt_string'
20+
21+
###
22+
#
23+
# The base class for all options.
24+
#
25+
###
26+
class OptBase
27+
28+
#
29+
# Initializes a named option with the supplied attribute array.
30+
# The array is composed of three values.
31+
#
32+
# attrs[0] = required (boolean type)
33+
# attrs[1] = description (string)
34+
# attrs[2] = default value
35+
# attrs[3] = possible enum values
36+
# attrs[4] = Regex to validate the option
37+
#
38+
def initialize(in_name, attrs = [])
39+
self.name = in_name
40+
self.advanced = false
41+
self.evasion = false
42+
self.required = attrs[0] || false
43+
self.desc = attrs[1]
44+
self.default = attrs[2]
45+
self.enums = [ *(attrs[3]) ].map { |x| x.to_s }
46+
regex_temp = attrs[4] || nil
47+
if regex_temp
48+
# convert to string
49+
regex_temp = regex_temp.to_s if regex_temp.is_a? Regexp
50+
# remove start and end character, they will be added later
51+
regex_temp = regex_temp.sub(/^\^/, '').sub(/\$$/, '')
52+
# Add start and end marker to match the whole regex
53+
regex_temp = "^#{regex_temp}$"
54+
begin
55+
Regexp.compile(regex_temp)
56+
self.regex = regex_temp
57+
rescue RegexpError, TypeError => e
58+
raise("Invalid Regex #{regex_temp}: #{e}")
59+
end
60+
end
61+
end
62+
63+
#
64+
# Returns true if this is a required option.
65+
#
66+
def required?
67+
return required
68+
end
69+
70+
#
71+
# Returns true if this is an advanced option.
72+
#
73+
def advanced?
74+
return advanced
75+
end
76+
77+
#
78+
# Returns true if this is an evasion option.
79+
#
80+
def evasion?
81+
return evasion
82+
end
83+
84+
#
85+
# Returns true if the supplied type is equivalent to this option's type.
86+
#
87+
def type?(in_type)
88+
return (type == in_type)
89+
end
90+
91+
#
92+
# If it's required and the value is nil or empty, then it's not valid.
93+
#
94+
def valid?(value)
95+
if required?
96+
# required variable not set
97+
return false if (value == nil or value.to_s.empty?)
98+
end
99+
if regex
100+
if value.match(regex)
101+
return true
102+
else
103+
return false
104+
end
105+
end
106+
return true
107+
end
108+
109+
#
110+
# Returns true if the value supplied is nil and it's required to be
111+
# a valid value
112+
#
113+
def empty_required_value?(value)
114+
return (required? and value.nil?)
115+
end
116+
117+
#
118+
# Normalizes the supplied value to conform with the type that the option is
119+
# conveying.
120+
#
121+
def normalize(value)
122+
value
123+
end
124+
125+
#
126+
# Returns a string representing a user-friendly display of the chosen value
127+
#
128+
def display_value(value)
129+
value.to_s
130+
end
131+
132+
#
133+
# The name of the option.
134+
#
135+
attr_reader :name
136+
#
137+
# Whether or not the option is required.
138+
#
139+
attr_reader :required
140+
#
141+
# The description of the option.
142+
#
143+
attr_reader :desc
144+
#
145+
# The default value of the option.
146+
#
147+
attr_reader :default
148+
#
149+
# Storing the name of the option.
150+
#
151+
attr_writer :name
152+
#
153+
# Whether or not this is an advanced option.
154+
#
155+
attr_accessor :advanced
156+
#
157+
# Whether or not this is an evasion option.
158+
#
159+
attr_accessor :evasion
160+
#
161+
# The module or entity that owns this option.
162+
#
163+
attr_accessor :owner
164+
#
165+
# The list of potential valid values
166+
#
167+
attr_accessor :enums
168+
#
169+
# A optional regex to validate the option value
170+
#
171+
attr_accessor :regex
172+
173+
protected
174+
175+
attr_writer :required, :desc, :default # :nodoc:
176+
end
177+
178+
end
179+

lib/msf/core/opt_bool.rb

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# -*- coding: binary -*-
2+
3+
module Msf
4+
5+
###
6+
#
7+
# Boolean option.
8+
#
9+
###
10+
class OptBool < OptBase
11+
12+
TrueRegex = /^(y|yes|t|1|true)$/i
13+
14+
def type
15+
return 'bool'
16+
end
17+
18+
def valid?(value)
19+
return false if empty_required_value?(value)
20+
21+
if ((value != nil and
22+
(value.to_s.empty? == false) and
23+
(value.to_s.match(/^(y|yes|n|no|t|f|0|1|true|false)$/i) == nil)))
24+
return false
25+
end
26+
27+
true
28+
end
29+
30+
def normalize(value)
31+
if(value.nil? or value.to_s.match(TrueRegex).nil?)
32+
false
33+
else
34+
true
35+
end
36+
end
37+
38+
def is_true?(value)
39+
return normalize(value)
40+
end
41+
42+
def is_false?(value)
43+
return !is_true?(value)
44+
end
45+
46+
end
47+
48+
end

0 commit comments

Comments
 (0)