Tonight while chatting via IRC with Egyp7 he mentioned that Meterpreter should have capability of using Resource files for cleanup in post exploitation and for automating tasks by users without the knowledge in Ruby and the Framework to write a Meterpreter Script or Post Module. He opened and ticket and assigned me the task. Here are the results
I first opened the file lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb this file has all the command for the Meterpreter console so the first this was defining the Resource command:
def commands
c = {"?" => "Help menu","background" => "Backgrounds the current session","close" => "Closes a channel","channel" => "Displays information about active channels","exit" => "Terminate the meterpreter session","help" => "Help menu","interact" => "Interacts with a channel","irb" => "Drop into irb scripting mode","migrate" => "Migrate the server to another process","use" => "Load a one or more meterpreter extensions","quit" => "Terminate the meterpreter session","resource" => "Run the commands stored in a file","read" => "Reads data from a channel","run" => "Executes a meterpreter script or Post module","bgrun" => "Executes a meterpreter script as a background thread","bgkill" => "Kills a background meterpreter script","bglist" => "Lists running background scripts","write" => "Writes data to a channel",}
Once this was done I added 2 methods, the first one for tab completion of the command:
1: def cmd_resource_tabs(str, words)
2: return [] if words.length > 13:4: tab_complete_filenames(str, words)5: end
6:
Then the method that defined the command it self:
1: def cmd_resource(*args)
2: if args.empty?
3: print(
4: "Usage: resource path1 path2" +
5: "Run the commands stored in the supplied files.\n")
6: return false7: end
8: args.each do |glob|9: files = ::Dir.glob(::File.expand_path(glob))10: if files.empty?
11: print_error("No such file #{glob}")
12: next
13: end
14: files.each do |filename|
15: print_status("Reading #{filename}")
16: if (not ::File.readable?(filename))17: print_error("Could not read file #{filename}")
18: next
19: else
20: ::File.open(filename, "r").each_line do |line|21: next if line.strip.length < 122: next if line[0,1] == "#"23: begin
24: print_status("Running #{line}")
25: client.console.run_single(line)26: rescue ::Exception => e27: print_error("Error Running Command #{line}: #{e.class} #{e}")
28: end
29:30: end
31: end
32: end
33: end
34: end
35:
One of the first things I did was from lines 1 to 7 is check if an argument is given if not display a help message and return false. Next thing I do from lines 8 to 13 is check that each argument is actually a file. You can give it several files to process. Then from lines 14 to the end of the method you will see I check if the file is readable, open it and use the client.console.run_single() to run each command as if they where typed in the console. You will notice that on lines 21 and 22 I check for empty lines and commented lines, this will allow you to comment your resource files.
To use the command simply use the command resource and the file containing the commands here you can see an example run:
meterpreter > resource /tmp/cmd.rc[*] Reading /tmp/cmd.rc[*] Running sysinfoSystem Language : en_USOS : Windows 7 (Build 7600).Computer : INFIDEL01Architecture : x64 (Current Process is WOW64)Meterpreter : x86/win32[*] Running getuidServer username: Infidel01\Carlos
The contents of the file is as follows:
loki:trunk cperez$ cat /tmp/cmd.rcsysinfogetuid