Skip to content

Commit 65412cd

Browse files
committed
Land rapid7#9201, enhanced tab completion
2 parents 244acc4 + bc691cb commit 65412cd

File tree

5 files changed

+99
-12
lines changed

5 files changed

+99
-12
lines changed

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

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2198,16 +2198,7 @@ def option_values_dispatch(o, str, words)
21982198
if rh and not rh.empty?
21992199
res << Rex::Socket.source_address(rh)
22002200
else
2201-
res << Rex::Socket.source_address
2202-
# getifaddrs was introduced in 2.1.2
2203-
if Socket.respond_to?(:getifaddrs)
2204-
ifaddrs = Socket.getifaddrs.find_all do |ifaddr|
2205-
((ifaddr.flags & Socket::IFF_LOOPBACK) == 0) &&
2206-
ifaddr.addr &&
2207-
ifaddr.addr.ip?
2208-
end
2209-
res += ifaddrs.map { |ifaddr| ifaddr.addr.ip_address }
2210-
end
2201+
res += tab_complete_source_address
22112202
end
22122203
else
22132204
end

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,21 @@ def cmd_exploit(*args)
164164
end
165165
end
166166

167+
def cmd_exploit_tabs(str, words)
168+
fmt = {
169+
'-e' => [ framework.encoders.map { |refname, mod| refname } ],
170+
'-f' => [ nil ],
171+
'-h' => [ nil ],
172+
'-j' => [ nil ],
173+
'-n' => [ framework.nops.map { |refname, mod| refname } ],
174+
'-o' => [ true ],
175+
'-p' => [ framework.payloads.map { |refname, mod| refname } ],
176+
'-t' => [ true ],
177+
'-z' => [ nil ]
178+
}
179+
tab_complete_generic(fmt, str, words)
180+
end
181+
167182
alias cmd_run cmd_exploit
168183

169184
def cmd_exploit_help

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,19 @@ def cmd_handler(*args)
341341

342342
print_status "Payload handler running as background job #{job_id}."
343343
end
344+
345+
def cmd_handler_tabs(str, words)
346+
fmt = {
347+
'-h' => [ nil ],
348+
'-x' => [ nil ],
349+
'-p' => [ framework.payloads.map { |refname, mod| refname } ],
350+
'-P' => [ true ],
351+
'-H' => [ :address ],
352+
'-e' => [ framework.encoders.map { |refname, mod| refname } ],
353+
'-n' => [ true ]
354+
}
355+
tab_complete_generic(fmt, str, words)
356+
end
344357
end
345358
end
346359
end

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

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class Payload
1313
include Msf::Ui::Console::ModuleCommandDispatcher
1414

1515
# Load supported formats
16-
supported_formats = \
16+
@@supported_formats = \
1717
Msf::Simple::Buffer.transform_formats + \
1818
Msf::Util::EXE.to_executable_fmt_formats
1919

@@ -25,7 +25,7 @@ class Payload
2525
"-o" => [ true, "A comma separated list of options in VAR=VAL format." ],
2626
"-s" => [ true, "NOP sled length." ],
2727
"-f" => [ true, "The output file name (otherwise stdout)" ],
28-
"-t" => [ true, "The output format: #{supported_formats.join(',')}" ],
28+
"-t" => [ true, "The output format: #{@@supported_formats.join(',')}" ],
2929
"-p" => [ true, "The Platform for output." ],
3030
"-k" => [ false, "Keep the template executable functional" ],
3131
"-x" => [ true, "The executable template to use" ],
@@ -151,6 +151,24 @@ def cmd_generate(*args)
151151
end
152152
true
153153
end
154+
155+
def cmd_generate_tabs(str, words)
156+
fmt = {
157+
'-b' => [ true ],
158+
'-E' => [ nil ],
159+
'-e' => [ framework.encoders.map { |refname, mod| refname } ],
160+
'-h' => [ nil ],
161+
'-o' => [ true ],
162+
'-s' => [ true ],
163+
'-f' => [ :file ],
164+
'-t' => [ @@supported_formats ],
165+
'-p' => [ true ],
166+
'-k' => [ nil ],
167+
'-x' => [ :file ],
168+
'-i' => [ true ]
169+
}
170+
tab_complete_generic(fmt, str, words)
171+
end
154172
end
155173
end
156174
end

lib/rex/ui/text/dispatcher_shell.rb

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,56 @@ def tab_complete_filenames(str, words)
249249
matches
250250
end
251251

252+
#
253+
# Provide a generic tab completion function based on the specification
254+
# pass as fmt. The fmt argument in a hash where values are an array
255+
# defining how the command should be completed. The first element of the
256+
# array can be one of:
257+
# nil - This argument is a flag and takes no option.
258+
# true - This argument takes an option with no suggestions.
259+
# :address - This option is a source address.
260+
# :bool - This option is a boolean.
261+
# :file - This option is a file path.
262+
# Array - This option is an array of possible values.
263+
#
264+
def tab_complete_generic(fmt, str, words)
265+
last_word = words[-1]
266+
fmt = fmt.select { |key, value| last_word == key || !words.include?(key) }
267+
268+
val = fmt[last_word]
269+
return fmt.keys if !val # the last word does not look like a fmtspec
270+
arg = val[0]
271+
return fmt.keys if !arg # the last word is a fmtspec that takes no argument
272+
273+
tabs = []
274+
if arg.to_s.to_sym == :address
275+
tabs = tab_complete_source_address
276+
elsif arg.to_s.to_sym == :bool
277+
tabs = ['true', 'false']
278+
elsif arg.to_s.to_sym == :file
279+
tabs = tab_complete_filenames(str, words)
280+
elsif arg.kind_of?(Array)
281+
tabs = arg.map {|a| a.to_s}
282+
end
283+
tabs
284+
end
285+
286+
#
287+
# Return a list of possible source addresses for tab completion.
288+
#
289+
def tab_complete_source_address
290+
addresses = [Rex::Socket.source_address]
291+
# getifaddrs was introduced in 2.1.2
292+
if Socket.respond_to?(:getifaddrs)
293+
ifaddrs = Socket.getifaddrs.find_all do |ifaddr|
294+
((ifaddr.flags & Socket::IFF_LOOPBACK) == 0) &&
295+
ifaddr.addr &&
296+
ifaddr.addr.ip?
297+
end
298+
addresses += ifaddrs.map { |ifaddr| ifaddr.addr.ip_address }
299+
end
300+
addresses
301+
end
252302
end
253303

254304
#

0 commit comments

Comments
 (0)