Skip to content

Commit 940573a

Browse files
committed
Support ruby directives in Meterpreter rc scripts
1 parent e70ca74 commit 940573a

File tree

3 files changed

+122
-30
lines changed

3 files changed

+122
-30
lines changed

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ def cmd_resource(*args)
5959
elsif
6060
# let's check to see if it's in the scripts/resource dir (like when tab completed)
6161
[
62-
::Msf::Config.script_directory + ::File::SEPARATOR + "resource",
63-
::Msf::Config.user_script_directory + ::File::SEPARATOR + "resource"
62+
::Msf::Config.script_directory + ::File::SEPARATOR + 'resource',
63+
::Msf::Config.user_script_directory + ::File::SEPARATOR + 'resource'
6464
].each do |dir|
6565
res_path = dir + ::File::SEPARATOR + res
6666
if ::File.exist?(res_path)
@@ -97,7 +97,7 @@ def cmd_resource_tabs(str, words)
9797
[
9898
::Msf::Config.script_directory + File::SEPARATOR + "resource",
9999
::Msf::Config.user_script_directory + File::SEPARATOR + "resource",
100-
"."
100+
'.'
101101
].each do |dir|
102102
next if not ::File.exist? dir
103103
tabs += ::Dir.new(dir).find_all { |e|

lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb

Lines changed: 51 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1530,49 +1530,73 @@ def cmd_write(*args)
15301530
end
15311531

15321532
def cmd_resource_help
1533-
print_line('Usage: resource <path1> [path2 ...]')
1533+
print_line "Usage: resource path1 [path2 ...]"
15341534
print_line
1535-
print_line('Run the commands stored in the supplied files.')
1535+
print_line "Run the commands stored in the supplied files (- for stdin)."
1536+
print_line "Resource files may also contain ERB or Ruby code between <ruby></ruby> tags."
15361537
print_line
15371538
end
15381539

15391540
def cmd_resource(*args)
15401541
if args.empty?
1542+
cmd_resource_help
15411543
return false
15421544
end
15431545

1544-
args.each do |glob|
1545-
files = ::Dir.glob(::File.expand_path(glob))
1546-
if files.empty?
1547-
print_error("No such file #{glob}")
1548-
next
1549-
end
1550-
files.each do |filename|
1551-
print_status("Reading #{filename}")
1552-
if (not ::File.readable?(filename))
1553-
print_error("Could not read file #{filename}")
1554-
next
1555-
else
1556-
::File.open(filename, 'r').each_line do |line|
1557-
next if line.strip.length < 1
1558-
next if line[0,1] == '#'
1559-
begin
1560-
print_status("Running #{line}")
1561-
client.console.run_single(line)
1562-
rescue ::Exception => e
1563-
print_error("Error Running Command #{line}: #{e.class} #{e}")
1564-
end
1565-
1546+
args.each do |res|
1547+
good_res = nil
1548+
if res == '-'
1549+
good_res = res
1550+
elsif ::File.exist?(res)
1551+
good_res = res
1552+
elsif
1553+
# let's check to see if it's in the scripts/resource dir (like when tab completed)
1554+
[
1555+
::Msf::Config.script_directory + ::File::SEPARATOR + 'resource' + ::File::SEPARATOR + 'meterpreter',
1556+
::Msf::Config.user_script_directory + ::File::SEPARATOR + 'resource' + ::File::SEPARATOR + 'meterpreter'
1557+
].each do |dir|
1558+
res_path = dir + ::File::SEPARATOR + res
1559+
if ::File.exist?(res_path)
1560+
good_res = res_path
1561+
break
15661562
end
15671563
end
15681564
end
1565+
if good_res
1566+
client.console.load_resource(good_res)
1567+
else
1568+
print_error("#{res} is not a valid resource file")
1569+
next
1570+
end
15691571
end
15701572
end
15711573

15721574
def cmd_resource_tabs(str, words)
1573-
return [] if words.length > 1
1574-
1575-
tab_complete_filenames(str, words)
1575+
tabs = []
1576+
#return tabs if words.length > 1
1577+
if ( str and str =~ /^#{Regexp.escape(::File::SEPARATOR)}/ )
1578+
# then you are probably specifying a full path so let's just use normal file completion
1579+
return tab_complete_filenames(str,words)
1580+
elsif (not words[1] or not words[1].match(/^\//))
1581+
# then let's start tab completion in the scripts/resource directories
1582+
begin
1583+
[
1584+
::Msf::Config.script_directory + ::File::SEPARATOR + 'resource' + ::File::SEPARATOR + 'meterpreter',
1585+
::Msf::Config.user_script_directory + ::File::SEPARATOR + 'resource' + ::File::SEPARATOR + 'meterpreter',
1586+
'.'
1587+
].each do |dir|
1588+
next if not ::File.exist? dir
1589+
tabs += ::Dir.new(dir).find_all { |e|
1590+
path = dir + ::File::SEPARATOR + e
1591+
::File.file?(path) and ::File.readable?(path)
1592+
}
1593+
end
1594+
rescue Exception
1595+
end
1596+
else
1597+
tabs += tab_complete_filenames(str,words)
1598+
end
1599+
return tabs
15761600
end
15771601

15781602
def cmd_enable_unicode_encoding

lib/rex/ui/text/dispatcher_shell.rb

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
require 'rex/ui'
33
require 'pp'
44
require 'rex/text/table'
5+
require 'erb'
56

67
module Rex
78
module Ui
@@ -368,6 +369,73 @@ def tab_complete_helper(dispatcher, str, words)
368369
return items
369370
end
370371

372+
# Processes a resource script file for the console.
373+
#
374+
# @param path [String] Path to a resource file to run
375+
# @return [void]
376+
def load_resource(path)
377+
if path == '-'
378+
resource_file = $stdin.read
379+
path = 'stdin'
380+
elsif ::File.exist?(path)
381+
resource_file = ::File.read(path)
382+
else
383+
print_error("Cannot find resource script: #{path}")
384+
return
385+
end
386+
387+
# Process ERB directives first
388+
print_status "Processing #{path} for ERB directives."
389+
erb = ERB.new(resource_file)
390+
processed_resource = erb.result(binding)
391+
392+
lines = processed_resource.each_line.to_a
393+
bindings = {}
394+
while lines.length > 0
395+
396+
line = lines.shift
397+
break if not line
398+
line.strip!
399+
next if line.length == 0
400+
next if line =~ /^#/
401+
402+
# Pretty soon, this is going to need an XML parser :)
403+
# TODO: case matters for the tag and for binding names
404+
if line =~ /<ruby/
405+
if line =~ /\s+binding=(?:'(\w+)'|"(\w+)")(>|\s+)/
406+
bin = ($~[1] || $~[2])
407+
bindings[bin] = binding unless bindings.has_key? bin
408+
bin = bindings[bin]
409+
else
410+
bin = binding
411+
end
412+
buff = ''
413+
while lines.length > 0
414+
line = lines.shift
415+
break if not line
416+
break if line =~ /<\/ruby>/
417+
buff << line
418+
end
419+
if ! buff.empty?
420+
session = client
421+
framework = client.framework
422+
423+
print_status("resource (#{path})> Ruby Code (#{buff.length} bytes)")
424+
begin
425+
eval(buff, bin)
426+
rescue ::Interrupt
427+
raise $!
428+
rescue ::Exception => e
429+
print_error("resource (#{path})> Ruby Error: #{e.class} #{e} #{e.backtrace}")
430+
end
431+
end
432+
else
433+
print_line("resource (#{path})> #{line}")
434+
run_single(line)
435+
end
436+
end
437+
end
438+
371439
#
372440
# Run a single command line.
373441
#

0 commit comments

Comments
 (0)