Skip to content

Commit cb2bef8

Browse files
committed
Land rapid7#4504, @disenchant's get/getg improvement
2 parents 2ba0f82 + 243c856 commit cb2bef8

File tree

8 files changed

+180
-0
lines changed

8 files changed

+180
-0
lines changed

features/commands/help.feature

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ Feature: Help command
1919
connect Communicate with a host
2020
edit Edit the current module with $VISUAL or $EDITOR
2121
exit Exit the console
22+
get Gets the value of a variable
23+
getg Gets the value of a global variable
2224
go_pro Launch Metasploit web GUI
2325
grep Grep the output of another command
2426
help Help menu

lib/msf/core/rpc/v10/rpc_core.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ def rpc_stop
1515
self.service.stop
1616
end
1717

18+
def rpc_getg(var)
19+
val = framework.datastore[var]
20+
{ var.to_s => val.to_s }
21+
end
22+
1823
def rpc_setg(var, val)
1924
framework.datastore[var] = val
2025
{ "result" => "success" }

lib/msf/ui/console/command_dispatcher/core.rb

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ def commands
115115
"color" => "Toggle color",
116116
"exit" => "Exit the console",
117117
"edit" => "Edit the current module with $VISUAL or $EDITOR",
118+
"get" => "Gets the value of a variable",
119+
"getg" => "Gets the value of a global variable",
118120
"go_pro" => "Launch Metasploit web GUI",
119121
"grep" => "Grep the output of another command",
120122
"help" => "Help menu",
@@ -2298,6 +2300,81 @@ def cmd_unload_tabs(str, words)
22982300
return tabs
22992301
end
23002302

2303+
def cmd_get_help
2304+
print_line "Usage: get var1 [var2 ...]"
2305+
print_line
2306+
print_line "The get command is used to get the value of one or more variables."
2307+
print_line
2308+
end
2309+
2310+
#
2311+
# Gets a value if it's been set.
2312+
#
2313+
def cmd_get(*args)
2314+
2315+
# Figure out if these are global variables
2316+
global = false
2317+
2318+
if (args[0] == '-g')
2319+
args.shift
2320+
global = true
2321+
end
2322+
2323+
# No arguments? No cookie.
2324+
if args.empty?
2325+
global ? cmd_getg_help : cmd_get_help
2326+
return false
2327+
end
2328+
2329+
# Determine which data store we're operating on
2330+
if (active_module && !global)
2331+
datastore = active_module.datastore
2332+
else
2333+
datastore = framework.datastore
2334+
end
2335+
2336+
args.each { |var| print_line("#{var} => #{datastore[var]}") }
2337+
end
2338+
2339+
#
2340+
# Tab completion for the get command
2341+
#
2342+
# @param str [String] the string currently being typed before tab was hit
2343+
# @param words [Array<String>] the previously completed words on the command line. words is always
2344+
# at least 1 when tab completion has reached this stage since the command itself has been completed
2345+
2346+
def cmd_get_tabs(str, words)
2347+
datastore = active_module ? active_module.datastore : self.framework.datastore
2348+
datastore.keys
2349+
end
2350+
2351+
def cmd_getg_help
2352+
print_line "Usage: getg var1 [var2 ...]"
2353+
print_line
2354+
print_line "Exactly like get -g, get global variables"
2355+
print_line
2356+
end
2357+
2358+
#
2359+
# Gets variables in the global data store.
2360+
#
2361+
def cmd_getg(*args)
2362+
args.unshift('-g')
2363+
2364+
cmd_get(*args)
2365+
end
2366+
2367+
#
2368+
# Tab completion for the getg command
2369+
#
2370+
# @param str [String] the string currently being typed before tab was hit
2371+
# @param words [Array<String>] the previously completed words on the command line. words is always
2372+
# at least 1 when tab completion has reached this stage since the command itself has been completed
2373+
2374+
def cmd_getg_tabs(str, words)
2375+
self.framework.datastore.keys
2376+
end
2377+
23012378
def cmd_unset_help
23022379
print_line "Usage: unset [-g] var1 var2 var3 ..."
23032380
print_line
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# -*- coding:binary -*-
2+
require 'spec_helper'
3+
4+
require 'msf/core/rpc/v10/rpc_base'
5+
require 'msf/core/rpc/v10/rpc_core'
6+
require 'msf/core/rpc/v10/service'
7+
8+
describe Msf::RPC::RPC_Core do
9+
include_context 'Msf::Simple::Framework'
10+
11+
let(:service) do
12+
Msf::RPC::Service.new(framework)
13+
end
14+
15+
let(:core) do
16+
Msf::RPC::RPC_Core.new(service)
17+
end
18+
19+
describe '#rpc_getg' do
20+
it 'should show an empty value if the variable is unset' do
21+
expect(core.rpc_getg('FOO')).to eq({'FOO' => ''})
22+
end
23+
it 'should show the correct value if the variable is set' do
24+
core.rpc_setg('FOO', 'BAR')
25+
expect(core.rpc_getg('FOO')).to eq({'FOO' => 'BAR'})
26+
end
27+
end
28+
end

spec/lib/msf/ui/command_dispatcher/core_spec.rb renamed to spec/lib/msf/ui/console/command_dispatcher/core_spec.rb

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,4 +95,72 @@ def cell(table, row, column)
9595
end
9696
end
9797
end
98+
99+
it { is_expected.to respond_to :cmd_get }
100+
it { is_expected.to respond_to :cmd_getg }
101+
102+
def set_and_test_variable(name, framework_value, module_value, framework_re, module_re)
103+
# set the current module
104+
allow(core).to receive(:active_module).and_return(mod)
105+
# always assume set variables validate (largely irrelevant because ours are random)
106+
allow(driver).to receive(:on_variable_set).and_return(true)
107+
# the specified global value
108+
core.cmd_setg(name, framework_value) if framework_value
109+
# set the specified local value
110+
core.cmd_set(name, module_value) if module_value
111+
112+
# test the global value if specified
113+
if framework_re
114+
@output = []
115+
core.cmd_getg(name)
116+
@output.join.should =~ framework_re
117+
end
118+
119+
# test the local value if specified
120+
if module_re
121+
@output = []
122+
core.cmd_get(name)
123+
@output.join.should =~ module_re
124+
end
125+
end
126+
127+
describe "#cmd_get and #cmd_getg" do
128+
describe "without arguments" do
129+
it "should show the correct help message" do
130+
core.cmd_get
131+
@output.join.should =~ /Usage: get /
132+
@output = []
133+
core.cmd_getg
134+
@output.join.should =~ /Usage: getg /
135+
end
136+
end
137+
138+
describe "with arguments" do
139+
let(:name) { ::Rex::Text.rand_text_alpha(10).upcase }
140+
141+
context "with an active module" do
142+
let(:mod) do
143+
mod = ::Msf::Module.new
144+
mod.send(:initialize, {})
145+
mod
146+
end
147+
148+
it "should show no value if not set in the framework or module" do
149+
set_and_test_variable(name, nil, nil, /^#{name} => $/, /^#{name} => $/)
150+
end
151+
152+
it "should show the correct value when only the module has this variable" do
153+
set_and_test_variable(name, nil, 'MODULE', /^#{name} => $/, /^#{name} => MODULE$/)
154+
end
155+
156+
it "should show the correct value when only the framework has this variable" do
157+
set_and_test_variable(name, 'FRAMEWORK', nil, /^#{name} => FRAMEWORK$/, /^#{name} => $/)
158+
end
159+
160+
it "should show the correct value when both the module and the framework have this variable" do
161+
set_and_test_variable(name, 'FRAMEWORK', 'MODULE', /^#{name} => FRAMEWORK$/, /^#{name} => MODULE$/)
162+
end
163+
end
164+
end
165+
end
98166
end

0 commit comments

Comments
 (0)