Module: Msf::Module::ModuleInfo

Included in:
Msf::Module
Defined in:
lib/msf/core/module/module_info.rb

Constant Summary collapse

UpdateableOptions =

The list of options that don’t support merging in an information hash.

['Name', 'Description', 'Alias', 'PayloadCompat', 'Stance'].freeze
ReferencesWithOptionalThirdElement =

Reference types that can have 2 or 3 elements (e.g., GHSA with optional repo)

['GHSA'].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#module_infoObject (protected)



60
61
62
# File 'lib/msf/core/module/module_info.rb', line 60

def module_info
  @module_info
end

Instance Method Details

#aliasObject

Returns the module’s alias, if it has one. Otherwise, the module’s name is returned.



20
21
22
# File 'lib/msf/core/module/module_info.rb', line 20

def alias
  module_info['Alias']
end

#descriptionObject

Return the module’s description.



27
28
29
# File 'lib/msf/core/module/module_info.rb', line 27

def description
  module_info['Description']
end

#disclosure_dateObject

Returns the disclosure date, if known.



34
35
36
# File 'lib/msf/core/module/module_info.rb', line 34

def disclosure_date
  date_str = Date.parse(module_info['DisclosureDate'].to_s) rescue nil
end

#info_fixupsObject (protected)

Register options with a specific owning class.



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/msf/core/module/module_info.rb', line 69

def info_fixups
  # Each reference should be an array consisting of two or three elements
  refs = module_info['References']
  return unless refs&.any?

  refs.reject! do |ref|
    next true unless ref.respond_to?('[]') && !ref.empty?

    # Some reference types can have 2 or 3 elements (e.g., GHSA with optional repo)
    # Other references should have 2 elements
    ref_type = ref[0]
    can_have_third_element = ReferencesWithOptionalThirdElement.include?(ref_type)
    valid_length = can_have_third_element ? (ref.length == 2 || ref.length == 3) : (ref.length == 2)

    !valid_length
  end
end

#merge_check_key(info, name, val) ⇒ Object (protected)

Checks and merges the supplied key/value pair in the supplied hash.



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/msf/core/module/module_info.rb', line 90

def merge_check_key(info, name, val)
  merge_method = "merge_info_#{name.downcase}"
  return __send__(merge_method, info, val) if respond_to?(merge_method, true)

  return info[name] = val unless info[name]

  # Handle hash merging recursively
  if info[name].is_a?(Hash)
    raise TypeError, 'can only merge a hash into a hash' unless val.is_a?(Hash)
    val.each_pair { |val_key, val_val| merge_check_key(info[name], val_key, val_val) }
    return
  end

  # Convert to array if needed
  info[name] = Array(info[name]) unless info[name].is_a?(Array)

  # Merge values, avoiding duplicates
  values_to_add = val.is_a?(Array) ? val : [val]
  values_to_add.each { |v| info[name] << v unless info[name].include?(v) }
end

#merge_info(info, opts) ⇒ Object (protected)

Merges options in the info hash in a sane fashion, as some options require special attention.



115
116
117
118
119
120
121
# File 'lib/msf/core/module/module_info.rb', line 115

def merge_info(info, opts)
  opts.each_pair { |name, val|
    merge_check_key(info, name, val)
  }

  info
end

#merge_info_advanced_options(info, val) ⇒ Object (protected)

Merges advanced options.



126
127
128
# File 'lib/msf/core/module/module_info.rb', line 126

def merge_info_advanced_options(info, val)
  merge_info_options(info, val, true, false)
end

#merge_info_alias(info, val) ⇒ Object (protected)

Merge aliases with an underscore delimiter.



133
134
135
# File 'lib/msf/core/module/module_info.rb', line 133

def merge_info_alias(info, val)
  merge_info_string(info, 'Alias', val, '_')
end

#merge_info_description(info, val) ⇒ Object (protected)

Merges the module description.



140
141
142
143
144
145
146
147
148
149
150
# File 'lib/msf/core/module/module_info.rb', line 140

def merge_info_description(info, val)
  key = 'Description'
  unless info[key]
    info[key] = val
    return
  end

  current_value = Msf::Serializer::ReadableText.word_wrap_description(info[key])
  new_value = Msf::Serializer::ReadableText.word_wrap_description(val)
  info[key] = current_value.end_with?('.') ? "#{current_value}\n#{val}" : "#{current_value}.\n\n#{new_value}"
end

#merge_info_evasion_options(info, val) ⇒ Object (protected)

Merges advanced options.



155
156
157
# File 'lib/msf/core/module/module_info.rb', line 155

def merge_info_evasion_options(info, val)
  merge_info_options(info, val, false, true)
end

#merge_info_name(info, val) ⇒ Object (protected)

Merges the module name.



162
163
164
# File 'lib/msf/core/module/module_info.rb', line 162

def merge_info_name(info, val)
  merge_info_string(info, 'Name', val, ', ', true)
end

#merge_info_options(info, val, advanced = false, evasion = false) ⇒ Object (protected)

Merges options.



169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/msf/core/module/module_info.rb', line 169

def merge_info_options(info, val, advanced = false, evasion = false)

  key_name = ((advanced) ? 'Advanced' : (evasion) ? 'Evasion' : '') + 'Options'

  new_cont = Msf::OptionContainer.new
  new_cont.add_options(val, advanced, evasion)
  cur_cont = Msf::OptionContainer.new
  cur_cont.add_options(info[key_name] || [], advanced, evasion)

  new_cont.each_option { |name, option|
    next if (cur_cont.get(name))

    info[key_name]  = [] if (!info[key_name])
    info[key_name] << option
  }
end

#merge_info_string(info, key, val, delim = ', ', inverse = false) ⇒ Object (protected)

Merges a given key in the info hash with a delimiter.



189
190
191
192
193
194
195
196
197
198
199
# File 'lib/msf/core/module/module_info.rb', line 189

def merge_info_string(info, key, val, delim = ', ', inverse = false)
  if (info[key])
    if (inverse == true)
      info[key] = info[key] + delim + val
    else
      info[key] = val + delim + info[key]
    end
  else
    info[key] = val
  end
end

#merge_info_version(info, val) ⇒ Object (protected)

Merge the module version.



204
205
206
# File 'lib/msf/core/module/module_info.rb', line 204

def merge_info_version(info, val)
  merge_info_string(info, 'Version', val)
end

#nameObject

Return the module’s name from the module information hash.



41
42
43
# File 'lib/msf/core/module/module_info.rb', line 41

def name
  module_info['Name']
end

#notesObject

Return the module’s notes (including AKA and NOCVE descriptors).



49
50
51
# File 'lib/msf/core/module/module_info.rb', line 49

def notes
  module_info['Notes']
end

#update_info(info, opts) ⇒ Object (protected)

Updates information in the supplied info hash and merges other information. This method is used to override things like Name, Version, and Description without losing the ability to merge architectures, platforms, and options.



214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
# File 'lib/msf/core/module/module_info.rb', line 214

def update_info(info, opts)
  opts.each_pair do |name, val|
    # If the supplied option name is one of the ones that we should
    # override by default
    if UpdateableOptions.include?(name)
      # Only if the entry is currently nil do we use our value
      if info[name].nil?
        info[name] = val
      end
      # Otherwise, perform the merge operation like normal
    else
      merge_check_key(info, name, val)
    end
  end

  info
end