diff --git a/features/commands/help.feature b/features/commands/help.feature index a5395f347a..43af1fb62e 100644 --- a/features/commands/help.feature +++ b/features/commands/help.feature @@ -19,6 +19,8 @@ Feature: Help command connect Communicate with a host edit Edit the current module with $VISUAL or $EDITOR exit Exit the console + get Gets the value of a variable + getg Gets the value of a global variable go_pro Launch Metasploit web GUI grep Grep the output of another command help Help menu diff --git a/lib/msf/core/rpc/v10/rpc_core.rb b/lib/msf/core/rpc/v10/rpc_core.rb index f484deec8d..ebe975d291 100644 --- a/lib/msf/core/rpc/v10/rpc_core.rb +++ b/lib/msf/core/rpc/v10/rpc_core.rb @@ -15,6 +15,11 @@ class RPC_Core < RPC_Base self.service.stop end + def rpc_getg(var) + val = framework.datastore[var] + { var.to_s => val.to_s } + end + def rpc_setg(var, val) framework.datastore[var] = val { "result" => "success" } diff --git a/lib/msf/ui/console/command_dispatcher/core.rb b/lib/msf/ui/console/command_dispatcher/core.rb index fe7ff3488c..bf2814cd2c 100644 --- a/lib/msf/ui/console/command_dispatcher/core.rb +++ b/lib/msf/ui/console/command_dispatcher/core.rb @@ -115,6 +115,8 @@ class Core "color" => "Toggle color", "exit" => "Exit the console", "edit" => "Edit the current module with $VISUAL or $EDITOR", + "get" => "Gets the value of a variable", + "getg" => "Gets the value of a global variable", "go_pro" => "Launch Metasploit web GUI", "grep" => "Grep the output of another command", "help" => "Help menu", @@ -2298,6 +2300,81 @@ class Core return tabs end + def cmd_get_help + print_line "Usage: get var1 [var2 ...]" + print_line + print_line "The get command is used to get the value of one or more variables." + print_line + end + + # + # Gets a value if it's been set. + # + def cmd_get(*args) + + # Figure out if these are global variables + global = false + + if (args[0] == '-g') + args.shift + global = true + end + + # No arguments? No cookie. + if args.empty? + global ? cmd_getg_help : cmd_get_help + return false + end + + # Determine which data store we're operating on + if (active_module && !global) + datastore = active_module.datastore + else + datastore = framework.datastore + end + + args.each { |var| print_line("#{var} => #{datastore[var]}") } + end + + # + # Tab completion for the get command + # + # @param str [String] the string currently being typed before tab was hit + # @param words [Array] the previously completed words on the command line. words is always + # at least 1 when tab completion has reached this stage since the command itself has been completed + + def cmd_get_tabs(str, words) + datastore = active_module ? active_module.datastore : self.framework.datastore + datastore.keys + end + + def cmd_getg_help + print_line "Usage: getg var1 [var2 ...]" + print_line + print_line "Exactly like get -g, get global variables" + print_line + end + + # + # Gets variables in the global data store. + # + def cmd_getg(*args) + args.unshift('-g') + + cmd_get(*args) + end + + # + # Tab completion for the getg command + # + # @param str [String] the string currently being typed before tab was hit + # @param words [Array] the previously completed words on the command line. words is always + # at least 1 when tab completion has reached this stage since the command itself has been completed + + def cmd_getg_tabs(str, words) + self.framework.datastore.keys + end + def cmd_unset_help print_line "Usage: unset [-g] var1 var2 var3 ..." print_line diff --git a/spec/lib/msf/core/rpc/v10/rpc_core_spec.rb b/spec/lib/msf/core/rpc/v10/rpc_core_spec.rb new file mode 100644 index 0000000000..06cdd96025 --- /dev/null +++ b/spec/lib/msf/core/rpc/v10/rpc_core_spec.rb @@ -0,0 +1,28 @@ +# -*- coding:binary -*- +require 'spec_helper' + +require 'msf/core/rpc/v10/rpc_base' +require 'msf/core/rpc/v10/rpc_core' +require 'msf/core/rpc/v10/service' + +describe Msf::RPC::RPC_Core do + include_context 'Msf::Simple::Framework' + + let(:service) do + Msf::RPC::Service.new(framework) + end + + let(:core) do + Msf::RPC::RPC_Core.new(service) + end + + describe '#rpc_getg' do + it 'should show an empty value if the variable is unset' do + expect(core.rpc_getg('FOO')).to eq({'FOO' => ''}) + end + it 'should show the correct value if the variable is set' do + core.rpc_setg('FOO', 'BAR') + expect(core.rpc_getg('FOO')).to eq({'FOO' => 'BAR'}) + end + end +end diff --git a/spec/lib/msf/ui/command_dispatcher/auxiliary_spec.rb b/spec/lib/msf/ui/console/command_dispatcher/auxiliary_spec.rb similarity index 100% rename from spec/lib/msf/ui/command_dispatcher/auxiliary_spec.rb rename to spec/lib/msf/ui/console/command_dispatcher/auxiliary_spec.rb diff --git a/spec/lib/msf/ui/command_dispatcher/core_spec.rb b/spec/lib/msf/ui/console/command_dispatcher/core_spec.rb similarity index 51% rename from spec/lib/msf/ui/command_dispatcher/core_spec.rb rename to spec/lib/msf/ui/console/command_dispatcher/core_spec.rb index f83188c8cf..234ae76c3a 100644 --- a/spec/lib/msf/ui/command_dispatcher/core_spec.rb +++ b/spec/lib/msf/ui/console/command_dispatcher/core_spec.rb @@ -95,4 +95,72 @@ describe Msf::Ui::Console::CommandDispatcher::Core do end end end + + it { is_expected.to respond_to :cmd_get } + it { is_expected.to respond_to :cmd_getg } + + def set_and_test_variable(name, framework_value, module_value, framework_re, module_re) + # set the current module + allow(core).to receive(:active_module).and_return(mod) + # always assume set variables validate (largely irrelevant because ours are random) + allow(driver).to receive(:on_variable_set).and_return(true) + # the specified global value + core.cmd_setg(name, framework_value) if framework_value + # set the specified local value + core.cmd_set(name, module_value) if module_value + + # test the global value if specified + if framework_re + @output = [] + core.cmd_getg(name) + @output.join.should =~ framework_re + end + + # test the local value if specified + if module_re + @output = [] + core.cmd_get(name) + @output.join.should =~ module_re + end + end + + describe "#cmd_get and #cmd_getg" do + describe "without arguments" do + it "should show the correct help message" do + core.cmd_get + @output.join.should =~ /Usage: get / + @output = [] + core.cmd_getg + @output.join.should =~ /Usage: getg / + end + end + + describe "with arguments" do + let(:name) { ::Rex::Text.rand_text_alpha(10).upcase } + + context "with an active module" do + let(:mod) do + mod = ::Msf::Module.new + mod.send(:initialize, {}) + mod + end + + it "should show no value if not set in the framework or module" do + set_and_test_variable(name, nil, nil, /^#{name} => $/, /^#{name} => $/) + end + + it "should show the correct value when only the module has this variable" do + set_and_test_variable(name, nil, 'MODULE', /^#{name} => $/, /^#{name} => MODULE$/) + end + + it "should show the correct value when only the framework has this variable" do + set_and_test_variable(name, 'FRAMEWORK', nil, /^#{name} => FRAMEWORK$/, /^#{name} => $/) + end + + it "should show the correct value when both the module and the framework have this variable" do + set_and_test_variable(name, 'FRAMEWORK', 'MODULE', /^#{name} => FRAMEWORK$/, /^#{name} => MODULE$/) + end + end + end + end end diff --git a/spec/lib/msf/ui/command_dispatcher/db_spec.rb b/spec/lib/msf/ui/console/command_dispatcher/db_spec.rb similarity index 100% rename from spec/lib/msf/ui/command_dispatcher/db_spec.rb rename to spec/lib/msf/ui/console/command_dispatcher/db_spec.rb diff --git a/spec/lib/msf/ui/command_dispatcher/exploit_spec.rb b/spec/lib/msf/ui/console/command_dispatcher/exploit_spec.rb similarity index 100% rename from spec/lib/msf/ui/command_dispatcher/exploit_spec.rb rename to spec/lib/msf/ui/console/command_dispatcher/exploit_spec.rb