Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/plugins/alias.rb
Views: 11705
require 'rex/text/table'12module Msf3class Plugin::Alias < Msf::Plugin4class AliasCommandDispatcher5include Msf::Ui::Console::CommandDispatcher67attr_reader :aliases89def initialize(driver)10super(driver)11@aliases = {}12end1314def name15'Alias'16end1718@@alias_opts = Rex::Parser::Arguments.new(19'-h' => [ false, 'Help banner.' ],20'-c' => [ true, 'Clear an alias (* to clear all).'],21'-f' => [ true, 'Force an alias assignment.' ]22)23#24# Returns the hash of commands supported by this dispatcher.25#26# driver.dispatcher_stack[3].commands27def commands28{29'alias' => 'create or view an alias.'30# "alias_clear" => "clear an alias (or all aliases).",31# "alias_force" => "Force an alias (such as to override)"32}.merge(aliases) # make aliased commands available as commands of their own33end3435#36# the main alias command handler37#38# usage: alias [options] [name [value]]39def cmd_alias(*args)40# we parse args manually instead of using @@alias.opts.parse to handle special cases41case args.length42when 0 # print the list of current aliases43if @aliases.empty?44return print_status('No aliases currently defined')45else46tbl = Rex::Text::Table.new(47'Header' => 'Current Aliases',48'Prefix' => "\n",49'Postfix' => "\n",50'Columns' => [ '', 'Alias Name', 'Alias Value' ]51)52# add 'alias' in front of each row so that the output can be copy pasted into an rc file if desired53@aliases.each_pair do |key, val|54tbl << ['alias', key, val]55end56return print(tbl.to_s)57end58when 1 # display the alias if one matches this name (or help)59return cmd_alias_help if (args[0] == '-h') || (args[0] == '--help')6061if @aliases.keys.include?(args[0])62print_status("\'#{args[0]}\' is aliased to \'#{@aliases[args[0]]}\'")63else64print_status("\'#{args[0]}\' is not currently aliased")65end66else # let's see if we can assign or clear the alias67force = false68clear = false69# if using -f or -c, they must be the first arg, because -f/-c may also show up in the alias70# value so we can't do something like if args.include("-f") or delete_if etc71# we should never have to force and clear simultaneously.72if args[0] == '-f'73force = true74args.shift75elsif args[0] == '-c'76clear = true77args.shift78end79name = args.shift80# alias name can NEVER be certain reserved words like 'alias', add any other reserved words here81# We prevent the user from naming the alias "alias" cuz they could end up unable to clear the aliases,82# for example you 'alias -f set unset and then 'alias -f alias sessions', now you're screwed. The byproduct83# of this is that it prevents you from aliasing 'alias' to 'alias -f' etc, but that's acceptable84reserved_words = [/^alias$/i]85reserved_words.each do |regex|86if name =~ regex87print_error "You cannot use #{name} as the name for an alias, sorry"88return false89end90end9192if clear93# clear all aliases if "*"94if name == '*'95@aliases.each_key do |a|96deregister_alias(a)97end98print_status 'Cleared all aliases'99elsif @aliases.keys.include?(name) # clear the named alias if it exists100deregister_alias(name)101print_status "Cleared alias #{name}"102else103print_error("#{name} is not a currently active alias")104end105return106end107# smash everything that's left together108value = args.join(' ')109value.strip!110# value can NEVER be certain bad words like 'rm -rf /', add any other reserved words here111# this is basic idiot protection, not meant to be impervious to subversive intentions112reserved_words = [%r{^rm +(-rf|-r +-f|-f +-r) +/.*$}]113reserved_words.each do |regex|114if value =~ regex115print_error "You cannot use #{value} as the value for an alias, sorry"116return false117end118end119120is_valid_alias = valid_alias?(name, value)121# print_good "Alias validity = #{is_valid_alias}"122is_sys_cmd = Rex::FileUtils.find_full_path(name)123is_already_alias = @aliases.keys.include?(name)124if is_valid_alias && !is_sys_cmd && !is_already_alias125register_alias(name, value)126elsif force127if !is_valid_alias128print_status 'The alias failed validation, but force is set so we allow this. This is often the case'129print_status "when for instance 'exploit' is being overridden but msfconsole is not currently in the"130print_status 'exploit context (an exploit is not loaded), or you are overriding a system command'131end132register_alias(name, value)133else134print_error("#{name} already exists as a system command, use -f to force override") if is_sys_cmd135print_error("#{name} is already an alias, use -f to force override") if is_already_alias136if !is_valid_alias && !force137print_error("'#{name}' is not a permitted name or '#{value}' is not valid/permitted")138print_error("It's possible the responding dispatcher isn't loaded yet, try changing to the proper context or using -f to force")139end140end141end142end143144def cmd_alias_help145print_line 'Usage: alias [options] [name [value]]'146print_line147print(@@alias_opts.usage)148end149150#151# Tab completion for the alias command152#153def cmd_alias_tabs(_str, words)154if words.length <= 1155# puts "1 word or less"156return @@alias_opts.option_keys + tab_complete_aliases_and_commands157else158# puts "more than 1 word"159return tab_complete_aliases_and_commands160end161end162163private164165#166# do everything needed to add an alias of +name+ having the value +value+167#168def register_alias(name, value)169# TODO: begin rescue?170# TODO: security concerns since we are using eval171172# define some class instance methods173class_eval do174# define a class instance method that will respond for the alias175define_method "cmd_#{name}" do |*args|176# just replace the alias w/the alias' value and run that177driver.run_single("#{value} #{args.join(' ')}")178end179# define a class instance method that will tab complete the aliased command180# we just proxy to the top-level tab complete function and let them handle it181define_method "cmd_#{name}_tabs" do |str, words|182# we need to repair the tab complete string/words and pass back183# replace alias name with the root alias value184value_words = value.split(/[\s\t\n]+/) # in case value is e.g. 'sessions -l'185# valwords is now [sessions,-l]186words[0] = value_words[0]187# words[0] is now 'sessions' (was 'sue')188value_words.shift # valwords is now ['-l']189# insert any remaining parts of value and rebuild the line190line = words.join(' ') + ' ' + value_words.join(' ') + ' ' + str191192[driver.tab_complete(line.strip), :override_completions]193end194# add a cmd_#{name}_help method195define_method "cmd_#{name}_help" do |*_args|196driver.run_single("help #{value}")197end198end199# add the alias to the list200@aliases[name] = value201end202203#204# do everything required to remove an alias of name +name+205#206def deregister_alias(name)207class_eval do208# remove the class methods we created when the alias was registered209remove_method("cmd_#{name}")210remove_method("cmd_#{name}_tabs")211remove_method("cmd_#{name}_help")212end213# remove the alias from the list of active aliases214@aliases.delete(name)215end216217#218# Validate a proposed alias with the +name+ and having the value +value+219#220def valid_alias?(name, value)221# print_good "Assessing validay for #{name} and #{value}"222# we validate two things, the name and the value223224### name225# we don't check if this alias name exists or if it's a console command already etc as -f can override226# that so those need to be checked externally, we pretty much just check to see if the name is sane227name.strip!228bad_words = [/\*/] # add any additional "bad word" regexes here229bad_words.each do |regex|230# don't mess around, just return false in this case, prevents wasted processing231return false if name =~ regex232end233234### value235# value is considered valid if it's a ref to a valid console cmd, a system executable, or an existing236# alias AND isn't a "bad word"237# Here we check for "bad words" to avoid for the value...value would have to NOT match these regexes238# this is just basic idiot protection239value.strip!240bad_words = [/^msfconsole$/]241bad_words.each do |regex|242# don't mess around, just return false if we match243return false if value =~ regex244end245246# we're only gonna validate the first part of the cmd, e.g. just ls from "ls -lh"247value = value.split(' ').first248return true if @aliases.keys.include?(value)249250[value, value + '.exe'].each do |cmd|251return true if Rex::FileUtils.find_full_path(cmd)252end253254# gather all the current commands the driver's dispatcher's have & check 'em255driver.dispatcher_stack.each do |dispatcher|256next unless dispatcher.respond_to?(:commands)257next if dispatcher.commands.nil?258next if dispatcher.commands.empty?259260if dispatcher.respond_to?("cmd_#{value.split(' ').first}")261# print_status "Dispatcher (#{dispatcher.name}) responds to cmd_#{value.split(" ").first}"262return true263end264end265266false267end268269#270# Provide tab completion list for aliases and commands271#272def tab_complete_aliases_and_commands273items = []274# gather all the current commands the driver's dispatcher's have275driver.dispatcher_stack.each do |dispatcher|276next unless dispatcher.respond_to?(:commands)277next if (dispatcher.commands.nil? || dispatcher.commands.empty?)278279items.concat(dispatcher.commands.keys)280end281# add all the current aliases to the list282items.concat(@aliases.keys)283return items284end285286end287288#289# The constructor is called when an instance of the plugin is created. The290# framework instance that the plugin is being associated with is passed in291# the framework parameter. Plugins should call the parent constructor when292# inheriting from Msf::Plugin to ensure that the framework attribute on293# their instance gets set.294#295def initialize(framework, opts)296super297298## Register the commands above299add_console_dispatcher(AliasCommandDispatcher)300end301302#303# The cleanup routine for plugins gives them a chance to undo any actions304# they may have done to the framework. For instance, if a console305# dispatcher was added, then it should be removed in the cleanup routine.306#307def cleanup308# If we had previously registered a console dispatcher with the console,309# deregister it now.310remove_console_dispatcher('Alias')311312# we don't need to remove class methods we added because they were added to313# AliasCommandDispatcher class314end315316#317# This method returns a short, friendly name for the plugin.318#319def name320'alias'321end322323#324# This method returns a brief description of the plugin. It should be no325# more than 60 characters, but there are no hard limits.326#327def desc328'Adds the ability to alias console commands'329end330331end332end333334335