2018-07-03 10:10:53 -05:00
|
|
|
# -*- coding: binary -*-
|
|
|
|
|
# CLI for interaction with modules outside of msfconsole
|
|
|
|
|
|
|
|
|
|
require 'optparse'
|
|
|
|
|
|
|
|
|
|
module Msf::Modules::External::CLI
|
|
|
|
|
def self.parse_options(mod)
|
|
|
|
|
action = 'run'
|
|
|
|
|
actions = ['run'] + mod.meta['capabilities']
|
|
|
|
|
args = mod.meta['options'].reduce({}) do |defaults, (n, opt)|
|
|
|
|
|
if opt['default'].nil?
|
|
|
|
|
if opt['required']
|
|
|
|
|
defaults
|
|
|
|
|
else
|
|
|
|
|
defaults[n] = nil
|
|
|
|
|
defaults
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
defaults[n] = opt['default']
|
|
|
|
|
defaults
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
op = OptionParser.new do |opts|
|
|
|
|
|
if $0 != mod.path
|
|
|
|
|
opts.banner = "Usage: #{$0} #{mod.path} [OPTIONS] [ACTION]"
|
|
|
|
|
end
|
|
|
|
|
opts.separator ""
|
|
|
|
|
|
|
|
|
|
opts.separator mod.meta['description']
|
|
|
|
|
opts.separator ""
|
|
|
|
|
|
|
|
|
|
opts.separator "Postitional arguments:"
|
|
|
|
|
opts.separator " ACTION: The action to take (#{actions.inspect})"
|
|
|
|
|
opts.separator ""
|
|
|
|
|
|
|
|
|
|
opts.separator "Required arguments:"
|
|
|
|
|
make_options opts, args, mod.meta['options'].select {|n, o| o['required'] && o['default'].nil?}
|
|
|
|
|
opts.separator ""
|
|
|
|
|
|
|
|
|
|
opts.separator "Optional arguments:"
|
|
|
|
|
make_options opts, args, mod.meta['options'].select {|n, o| !o['required'] || !o['default'].nil?}
|
|
|
|
|
|
|
|
|
|
opts.on '-h', '--help', 'Prints this help' do
|
|
|
|
|
$stderr.puts opts
|
|
|
|
|
exit
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
begin
|
|
|
|
|
extra = op.permute *ARGV
|
|
|
|
|
# If no extra args are given we use the default action
|
|
|
|
|
if extra.length == 1
|
|
|
|
|
action = extra.shift
|
|
|
|
|
elsif extra.length > 1
|
|
|
|
|
action = extra.shift
|
|
|
|
|
$stderr.puts "WARNING: unrecognized arguments #{extra.inspect}"
|
|
|
|
|
end
|
|
|
|
|
rescue OptionParser::InvalidArgument => e
|
|
|
|
|
$stderr.puts e.message
|
|
|
|
|
abort
|
|
|
|
|
rescue OptionParser::MissingArgument => e
|
|
|
|
|
$stderr.puts e.message
|
|
|
|
|
abort
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
required = mod.meta['options'].select {|_, o| o['required']}.map {|n, _| n}.sort
|
|
|
|
|
|
|
|
|
|
# Were we run with any non-module options if we need them?
|
|
|
|
|
if args.empty? && !required.empty?
|
|
|
|
|
$stderr.puts op
|
|
|
|
|
exit
|
|
|
|
|
# Did someone forget to add some options we need?
|
|
|
|
|
elsif (args.keys & required).sort != required
|
|
|
|
|
missing = required - (args.keys & required)
|
|
|
|
|
abort "Missing required option(s): #{missing.map {|o| '--' + o}.join ', '}"
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
unless action == 'run' || mod.meta['capabilities'].include?(action)
|
|
|
|
|
$stderr.puts "Invalid ACTION choice #{action.inspect} (choose from #{actions.inspect})"
|
|
|
|
|
abort
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
action =
|
|
|
|
|
case action
|
|
|
|
|
when 'run'; :run
|
|
|
|
|
when 'soft_check'; :soft_check
|
|
|
|
|
when 'hard_check'; :hard_check
|
|
|
|
|
end
|
|
|
|
|
[args, action]
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def self.choose_type(t)
|
|
|
|
|
if t == 'int' or t == 'port'
|
|
|
|
|
Integer
|
|
|
|
|
elsif t == 'float'
|
|
|
|
|
Float
|
|
|
|
|
elsif t.match /range$/
|
|
|
|
|
Array
|
|
|
|
|
else # XXX TODO add validation for addresses and other MSF option types
|
|
|
|
|
String
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def self.make_options(parser, out, args)
|
|
|
|
|
args.each do |n, opt|
|
2018-09-17 09:54:07 -04:00
|
|
|
name = n.tr('_', '-')
|
2018-07-03 10:10:53 -05:00
|
|
|
desc = if opt['default']
|
|
|
|
|
"#{opt['description']}, (default: #{opt['default']})"
|
|
|
|
|
else
|
|
|
|
|
opt['description']
|
|
|
|
|
end
|
|
|
|
|
parser.on "--#{name} #{n.upcase}", choose_type(opt['type']), desc do |arg|
|
|
|
|
|
out[n] = arg
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|