295 lines
6.3 KiB
Ruby
295 lines
6.3 KiB
Ruby
require 'msf/core'
|
|
require 'msf/base'
|
|
require 'msf/ui'
|
|
require 'msf/ui/console/framework_event_manager'
|
|
require 'msf/ui/console/command_dispatcher'
|
|
require 'msf/ui/console/table'
|
|
require 'find'
|
|
|
|
module Msf
|
|
module Ui
|
|
module Console
|
|
|
|
|
|
###
|
|
#
|
|
# This class implements a user interface driver on a console interface.
|
|
#
|
|
###
|
|
class Driver < Msf::Ui::Driver
|
|
|
|
ConfigCore = "framework/core"
|
|
ConfigGroup = "framework/ui/console"
|
|
|
|
#
|
|
# The console driver processes various framework notified events.
|
|
#
|
|
include FrameworkEventManager
|
|
|
|
#
|
|
# The console driver is a command shell.
|
|
#
|
|
include Rex::Ui::Text::DispatcherShell
|
|
|
|
#
|
|
# Initializes a console driver instance with the supplied prompt string and
|
|
# prompt character.
|
|
#
|
|
def initialize(prompt = "%umsf", prompt_char = ">%c")
|
|
# Call the parent
|
|
super
|
|
|
|
# Temporarily disable output
|
|
self.disable_output = true
|
|
|
|
# Load pre-configuration
|
|
load_preconfig
|
|
|
|
# Initialize attributes
|
|
self.framework = Msf::Simple::Framework.create
|
|
|
|
# Add the core command dispatcher as the root of the dispatcher
|
|
# stack
|
|
enstack_dispatcher(CommandDispatcher::Core)
|
|
|
|
# Register event handlers
|
|
register_event_handlers
|
|
|
|
# Load console-specific configuration
|
|
load_config
|
|
|
|
# Re-enable output
|
|
self.disable_output = false
|
|
|
|
# Process things before we actually display the prompt and get rocking
|
|
on_startup
|
|
|
|
# Process the resource script
|
|
process_rc_file
|
|
|
|
# Initialize the tab completion array
|
|
self.tab_words = []
|
|
end
|
|
|
|
#
|
|
# Loads configuration that needs to be analyzed before the framework
|
|
# instance is created.
|
|
#
|
|
def load_preconfig
|
|
begin
|
|
conf = Msf::Config.load
|
|
rescue
|
|
wlog("Failed to load configuration: #{$!}")
|
|
return
|
|
end
|
|
|
|
if (conf.group?(ConfigCore))
|
|
conf[ConfigCore].each_pair { |k, v|
|
|
on_variable_set(true, k, v)
|
|
}
|
|
end
|
|
end
|
|
|
|
#
|
|
# Loads configuration for the console.
|
|
#
|
|
def load_config
|
|
begin
|
|
conf = Msf::Config.load
|
|
rescue
|
|
wlog("Failed to load configuration: #{$!}")
|
|
return
|
|
end
|
|
|
|
# If we have configuration, process it
|
|
if (conf.group?(ConfigGroup))
|
|
conf[ConfigGroup].each_pair { |k, v|
|
|
case k.downcase
|
|
when "activemodule"
|
|
run_single("use #{v}")
|
|
end
|
|
}
|
|
end
|
|
end
|
|
|
|
#
|
|
# Saves configuration for the console.
|
|
#
|
|
def save_config
|
|
# Build out the console config group
|
|
group = {}
|
|
|
|
if (active_module)
|
|
group['ActiveModule'] = active_module.fullname
|
|
end
|
|
|
|
# Save it
|
|
begin
|
|
Msf::Config.save(
|
|
ConfigGroup => group)
|
|
rescue
|
|
log_error("Failed to save console config: #{$!}")
|
|
end
|
|
end
|
|
|
|
#
|
|
# TODO:
|
|
#
|
|
# Processes the resource script file for the console.
|
|
#
|
|
def process_rc_file
|
|
end
|
|
|
|
#
|
|
# Called before things actually get rolling such that banners can be
|
|
# displayed, scripts can be processed, and other fun can be had.
|
|
#
|
|
def on_startup
|
|
# Build the banner message
|
|
run_single("banner")
|
|
end
|
|
|
|
#
|
|
# Called when a variable is set to a specific value. This allows the
|
|
# console to do extra processing, such as enabling logging or doing
|
|
# some other kind of task. If this routine returns false it will indicate
|
|
# that the variable is not being set to a valid value.
|
|
#
|
|
def on_variable_set(glob, var, val)
|
|
case var.downcase
|
|
when "payload"
|
|
if (framework.modules.valid?(val) == false)
|
|
return false
|
|
end
|
|
when "sessionlogging"
|
|
handle_session_logging(val) if (glob)
|
|
when "consolelogging"
|
|
handle_console_logging(val) if (glob)
|
|
when "evasion"
|
|
handle_evasion(val) if (glob)
|
|
when "loglevel"
|
|
handle_loglevel(val) if (glob)
|
|
end
|
|
end
|
|
|
|
#
|
|
# Called when a variable is unset. If this routine returns false it is an
|
|
# indication that the variable should not be allowed to be unset.
|
|
#
|
|
def on_variable_unset(glob, var)
|
|
case var.downcase
|
|
when "sessionlogging"
|
|
handle_session_logging('0') if (glob)
|
|
when "consolelogging"
|
|
handle_console_logging('0') if (glob)
|
|
when "evasion"
|
|
handle_evasion(EVASION_NORMAL) if (glob)
|
|
when "loglevel"
|
|
handle_loglevel(nil) if (glob)
|
|
end
|
|
end
|
|
|
|
#
|
|
# The framework instance associated with this driver.
|
|
#
|
|
attr_reader :framework
|
|
#
|
|
# The active module associated with the driver.
|
|
#
|
|
attr_accessor :active_module
|
|
|
|
protected
|
|
|
|
attr_writer :framework # :nodoc:
|
|
attr_accessor :tab_words # :nodoc:
|
|
|
|
##
|
|
#
|
|
# Handlers for various global configuration values
|
|
#
|
|
##
|
|
|
|
#
|
|
# SessionLogging.
|
|
#
|
|
def handle_session_logging(val)
|
|
if (val =~ /^(yes|y|true|t|1)/i)
|
|
Msf::Logging.enable_session_logging(true)
|
|
print_line("Session logging will be enabled for future sessions.")
|
|
else
|
|
Msf::Logging.enable_session_logging(false)
|
|
print_line("Session logging will be disabled for future sessions.")
|
|
end
|
|
end
|
|
|
|
#
|
|
# ConsoleLogging.
|
|
#
|
|
def handle_console_logging(val)
|
|
if (val =~ /^(yes|y|true|t|1)/i)
|
|
Msf::Logging.enable_log_source('console')
|
|
print_line("Console logging is now enabled.")
|
|
|
|
set_log_source('console')
|
|
|
|
rlog("\n[*] Console logging started: #{Time.now}\n\n", 'console')
|
|
else
|
|
rlog("\n[*] Console logging stopped: #{Time.now}\n\n", 'console')
|
|
|
|
unset_log_source
|
|
|
|
Msf::Logging.disable_log_source('console')
|
|
print_line("Console logging is now disabled.")
|
|
end
|
|
end
|
|
|
|
#
|
|
# Evasion. Sets the global evasion level based on the supplied argument.
|
|
#
|
|
def handle_evasion(val)
|
|
if (val =~ /^(normal|low|high)$/i)
|
|
Rex::Evasion.set_level(val.downcase)
|
|
else
|
|
false
|
|
end
|
|
end
|
|
|
|
#
|
|
# This method handles adjusting the global log level threshold.
|
|
#
|
|
def handle_loglevel(val)
|
|
set_log_level(Rex::LogSource, val)
|
|
set_log_level(Msf::LogSource, val)
|
|
end
|
|
|
|
#
|
|
# This method accepts the entire line of text from the Readline
|
|
# routine, stores all completed words, and passes the partial
|
|
# word to the real tab completion function. This works around
|
|
# a design problem in the Readline module and depends on the
|
|
# Readline.basic_word_break_characters variable being set to \x00
|
|
#
|
|
def tab_complete(str)
|
|
# Check trailing whitespace so we can tell 'x' from 'x '
|
|
str_match = str.match(/\s+$/)
|
|
str_trail = (str_match.nil?) ? '' : str_match[0]
|
|
|
|
# Split the line up by whitespace into words
|
|
str_words = str.split(/[\s\t\n]+/)
|
|
|
|
# Append an empty word if we had trailing whitespace
|
|
str_words << '' if str_trail.length > 0
|
|
|
|
# Place the word list into an instance variable
|
|
self.tab_words = str_words
|
|
|
|
# Pop the last word and pass it to the parent
|
|
super(self.tab_words.pop)
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
end
|
|
end
|