199 lines
6.9 KiB
Ruby
199 lines
6.9 KiB
Ruby
# -*- coding: binary -*-
|
|
|
|
class Msf::Modules::External::Shim
|
|
def self.generate(module_path, framework)
|
|
mod = Msf::Modules::External.new(module_path, framework: framework)
|
|
# first check if meta exists and raise an issue if not, #14281
|
|
# raise instead of returning nil to avoid confusion
|
|
unless mod.meta
|
|
raise LoadError, " Try running file manually to check for errors or dependency issues."
|
|
end
|
|
case mod.meta['type']
|
|
when 'remote_exploit'
|
|
remote_exploit(mod)
|
|
when 'remote_exploit_cmd_stager'
|
|
remote_exploit_cmd_stager(mod)
|
|
when 'capture_server'
|
|
capture_server(mod)
|
|
when 'dos'
|
|
dos(mod)
|
|
when 'single_scanner'
|
|
single_scanner(mod)
|
|
when 'single_host_login_scanner'
|
|
single_host_login_scanner(mod)
|
|
when 'multi_scanner'
|
|
multi_scanner(mod)
|
|
when 'evasion'
|
|
evasion(mod)
|
|
else
|
|
nil
|
|
end
|
|
end
|
|
|
|
def self.render_template(name, meta = {})
|
|
template = File.join(File.dirname(__FILE__), 'templates', name)
|
|
ERB.new(File.read(template)).result(binding)
|
|
end
|
|
|
|
def self.common_metadata(meta = {}, default_options: {})
|
|
# Combine any template defaults with the defaults specified within the external module's metadata
|
|
default_options = default_options.merge(meta[:default_options])
|
|
render_template('common_metadata.erb', meta.merge(default_options: default_options))
|
|
end
|
|
|
|
def self.common_check(meta = {})
|
|
render_template('common_check.erb', meta)
|
|
end
|
|
|
|
def self.mod_meta_common(mod, meta = {}, ignore_options: [])
|
|
meta[:path] = mod.path.dump
|
|
meta[:name] = mod.meta['name'].dump
|
|
meta[:description] = mod.meta['description'].dump
|
|
meta[:authors] = mod.meta['authors'].map(&:dump).join(",\n ")
|
|
meta[:license] = mod.meta['license'].nil? ? 'MSF_LICENSE' : mod.meta['license']
|
|
meta[:options] = mod_meta_common_options(mod, ignore_options: ignore_options)
|
|
meta[:advanced_options] = mod_meta_common_options(mod, ignore_options: ignore_options, advanced: true)
|
|
meta[:capabilities] = mod.meta['capabilities']
|
|
meta[:notes] = transform_notes(mod.meta['notes'])
|
|
|
|
# Additionally check the 'describe_payload_options' key for backwards compatibility
|
|
meta[:default_options] = (mod.meta['default_options'] || mod.meta['describe_payload_options'] || {})
|
|
|
|
meta
|
|
end
|
|
|
|
def self.mod_meta_common_options(mod, ignore_options: [], advanced: false)
|
|
# Set modules without options to have an empty map
|
|
if mod.meta['options'].nil?
|
|
mod.meta['options'] = {}
|
|
end
|
|
|
|
options = mod.meta['options'].map do |n, o|
|
|
next if ignore_options.include? n
|
|
next unless o.fetch('advanced', false) == advanced
|
|
|
|
if o['values']
|
|
"Opt#{o['type'].camelize}.new(#{n.dump},
|
|
[#{o['required']}, #{o['description'].dump}, #{o['default'].inspect}, #{o['values'].inspect}])"
|
|
else
|
|
"Opt#{o['type'].camelize}.new(#{n.dump},
|
|
[#{o['required']}, #{o['description'].dump}, #{o['default'].inspect}])"
|
|
end
|
|
end
|
|
options.compact!
|
|
options.join(",\n ")
|
|
end
|
|
|
|
def self.mod_meta_exploit(mod, meta = {})
|
|
meta[:rank] = mod.meta['rank'].nil? ? 'NormalRanking' : "#{mod.meta['rank'].capitalize}Ranking"
|
|
meta[:date] = mod.meta['date'].dump
|
|
meta[:wfsdelay] = mod.meta['wfsdelay'] || 5
|
|
meta[:privileged] = mod.meta['privileged'].inspect
|
|
meta[:platform] = mod.meta['targets'].map do |t|
|
|
t['platform'].dump
|
|
end.uniq.join(",\n ")
|
|
meta[:arch] = mod.meta['targets'].map do |t|
|
|
t['arch'].dump
|
|
end.uniq.join(",\n ")
|
|
meta[:references] = mod.meta['references'].map do |r|
|
|
"[#{r['type'].upcase.dump}, #{r['ref'].dump}]"
|
|
end.join(",\n ")
|
|
meta[:targets] = mod.meta['targets'].map do |t|
|
|
"[#{t['platform'].dump} + ' ' + #{t['arch'].dump}, {'Arch' => ARCH_#{t['arch'].upcase}, 'Platform' => #{t['platform'].dump} }]"
|
|
end.join(",\n ")
|
|
meta
|
|
end
|
|
|
|
def self.remote_exploit(mod)
|
|
meta = mod_meta_common(mod)
|
|
meta = mod_meta_exploit(mod, meta)
|
|
render_template('remote_exploit.erb', meta)
|
|
end
|
|
|
|
def self.remote_exploit_cmd_stager(mod)
|
|
meta = mod_meta_common(mod, ignore_options: ['command'])
|
|
meta = mod_meta_exploit(mod, meta)
|
|
meta[:command_stager_flavor] = mod.meta['payload']['command_stager_flavor'].dump
|
|
render_template('remote_exploit_cmd_stager.erb', meta)
|
|
end
|
|
|
|
def self.capture_server(mod)
|
|
meta = mod_meta_common(mod)
|
|
render_template('capture_server.erb', meta)
|
|
end
|
|
|
|
def self.single_scanner(mod)
|
|
meta = mod_meta_common(mod, ignore_options: ['rhost'])
|
|
meta[:date] = mod.meta['date'].dump
|
|
meta[:references] = mod.meta['references'].map do |r|
|
|
"[#{r['type'].upcase.dump}, #{r['ref'].dump}]"
|
|
end.join(",\n ")
|
|
render_template('single_scanner.erb', meta)
|
|
end
|
|
|
|
def self.single_host_login_scanner(mod)
|
|
meta = mod_meta_common(mod, ignore_options: ['rhost'])
|
|
meta[:date] = mod.meta['date'].dump
|
|
meta[:references] = mod.meta['references'].map do |r|
|
|
"[#{r['type'].upcase.dump}, #{r['ref'].dump}]"
|
|
end.join(",\n ")
|
|
|
|
render_template('single_host_login_scanner.erb', meta)
|
|
end
|
|
|
|
def self.multi_scanner(mod)
|
|
meta = mod_meta_common(mod)
|
|
meta[:date] = mod.meta['date'].dump
|
|
meta[:references] = mod.meta['references'].map do |r|
|
|
"[#{r['type'].upcase.dump}, #{r['ref'].dump}]"
|
|
end.join(",\n ")
|
|
|
|
render_template('multi_scanner.erb', meta)
|
|
end
|
|
|
|
def self.dos(mod)
|
|
meta = mod_meta_common(mod)
|
|
meta[:date] = mod.meta['date'].dump
|
|
meta[:references] = mod.meta['references'].map do |r|
|
|
"[#{r['type'].upcase.dump}, #{r['ref'].dump}]"
|
|
end.join(",\n ")
|
|
|
|
render_template('dos.erb', meta)
|
|
end
|
|
|
|
def self.evasion(mod)
|
|
meta = mod_meta_common(mod, ignore_options: ['payload_raw', 'payload_encoded', 'target'])
|
|
meta[:platform] = mod.meta['targets'].map do |t|
|
|
t['platform'].dump
|
|
end.uniq.join(",\n ")
|
|
meta[:arch] = mod.meta['targets'].map do |t|
|
|
t['arch'].dump
|
|
end.uniq.join(",\n ")
|
|
meta[:references] = mod.meta['references'].map do |r|
|
|
"[#{r['type'].upcase.dump}, #{r['ref'].dump}]"
|
|
end.join(",\n ")
|
|
meta[:targets] = mod.meta['targets'].map do |t|
|
|
if t['name']
|
|
"[#{t['name'].dump}, {'Arch' => ARCH_#{t['arch'].upcase}, 'Platform' => #{t['platform'].dump} }]"
|
|
else
|
|
"[#{t['platform'].dump} + ' ' + #{t['arch'].dump}, {'Arch' => ARCH_#{t['arch'].upcase}, 'Platform' => #{t['platform'].dump} }]"
|
|
end
|
|
end.join(",\n ")
|
|
render_template('evasion.erb', meta)
|
|
end
|
|
|
|
#
|
|
# In case certain notes are not properly capitalized in the external module definition,
|
|
# ensure that they are properly capitalized before rendering.
|
|
#
|
|
def self.transform_notes(notes)
|
|
return {} unless notes
|
|
|
|
notes.reduce({}) do |acc, (key, val)|
|
|
acc[key.upcase] = val
|
|
acc
|
|
end
|
|
end
|
|
|
|
end
|