require 'rex/post/meterpreter' require 'rex/parser/arguments' module Rex module Post module Meterpreter module Ui ### # # Core meterpreter client commands that provide only the required set of # commands for having a functional meterpreter client<->server instance. # ### class Console::CommandDispatcher::Core include Console::CommandDispatcher # # Initializes an instance of the core command set using the supplied shell # for interactivity. # def initialize(shell) super self.extensions = [] self.bgjobs = [] self.bgjob_id = 0 @msf_loaded = nil end def msf_loaded? return @msf_loaded unless @msf_loaded.nil? # if we get here we must not have initialized yet if client.framework # We have a framework instance so the msf libraries should be # available. Load up the ones we're going to use require 'msf/base/serializer/readable_text' end @msf_loaded = !!(client.framework) @msf_loaded end @@use_opts = Rex::Parser::Arguments.new( "-l" => [ false, "List all available extensions" ], "-h" => [ false, "Help menu." ]) # # List of supported commands. # 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", "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", } if (msf_loaded?) c["info"] = "Displays information about a Post module" end c end # # Core baby. # def name "Core" end def cmd_background client.interacting = false end # # Displays information about active channels # @@channel_opts = Rex::Parser::Arguments.new( "-l" => [ false, "List active channels." ], "-h" => [ false, "Help menu." ]) # # Performs operations on the supplied channel. # def cmd_channel(*args) if (args.length == 0) args.unshift("-h") end mode = nil # Parse options @@channel_opts.parse(args) { |opt, idx, val| case opt when "-h" print( "Usage: channel [options]\n\n" + "Displays information about active channels.\n" + @@channel_opts.usage) return true when "-l" mode = 'list' end } # No mode, no service. if (mode == nil) return true elsif (mode == 'list') tbl = Rex::Ui::Text::Table.new( 'Indent' => 4, 'Columns' => [ 'Id', 'Class', 'Type' ]) items = 0 client.channels.each_pair { |cid, channel| tbl << [ cid, channel.class.cls, channel.type ] items += 1 } if (items == 0) print_line("No active channels.") else print("\n" + tbl.to_s + "\n") end end end # # Closes a supplied channel. # def cmd_close(*args) if (args.length == 0) print_line( "Usage: close channel_id\n\n" + "Closes the supplied channel.") return true end cid = args[0].to_i channel = client.find_channel(cid) if (!channel) print_error("Invalid channel identifier specified.") return true else channel._close # Issue #410 print_status("Closed channel #{cid}.") end end # # Terminates the meterpreter session. # def cmd_exit(*args) shell.stop end alias cmd_quit cmd_exit # # Interacts with a channel. # def cmd_interact(*args) if (args.length == 0) print_line( "Usage: interact channel_id\n\n" + "Interacts with the supplied channel.") return true end cid = args[0].to_i channel = client.find_channel(cid) if (channel) print_line("Interacting with channel #{cid}...\n") shell.interact_with_channel(channel) else print_error("Invalid channel identifier specified.") end end # # Runs the IRB scripting shell # def cmd_irb(*args) print_status("Starting IRB shell") print_status("The 'client' variable holds the meterpreter client\n") Rex::Ui::Text::IrbShell.new(binding).run end # # Migrates the server to the supplied process identifier. # def cmd_migrate(*args) if (args.length == 0) print_line( "Usage: migrate pid\n\n" + "Migrates the server instance to another process.\n" + "Note: Any open channels or other dynamic state will be lost.") return true end pid = args[0].to_i if(pid == 0) print_error("A process ID must be specified, not a process name") return end print_status("Migrating to #{pid}...") # Do this thang. client.core.migrate(pid) print_status("Migration completed successfully.") end # # Loads one or more meterpreter extensions. # def cmd_use(*args) if (args.length == 0) args.unshift("-h") end modules = nil @@use_opts.parse(args) { |opt, idx, val| case opt when "-l" exts = [] path = ::File.join(Msf::Config.install_root, 'data', 'meterpreter') ::Dir.entries(path).each { |f| if (::File.file?(::File.join(path, f)) && f =~ /ext_server_(.*)\.#{client.binary_suffix}/ ) exts.push($1) end } print(exts.sort.join("\n") + "\n") return true when "-h" print( "Usage: use ext1 ext2 ext3 ...\n\n" + "Loads a meterpreter extension module or modules.\n" + @@use_opts.usage) return true end } # Load each of the modules args.each { |m| md = m.downcase if (extensions.include?(md)) print_error("The '#{md}' extension has already been loaded.") next end print("Loading extension #{md}...") begin # Use the remote side, then load the client-side if (client.core.use(md) == true) add_extension_client(md) end rescue print_line log_error("Failed to load extension: #{$!}") next end print_line("success.") } return true end def cmd_use_tabs(str, words) tabs = [] path = ::File.join(Msf::Config.install_root, 'data', 'meterpreter') ::Dir.entries(path).each { |f| if (::File.file?(::File.join(path, f)) && f =~ /ext_server_(.*)\.#{client.binary_suffix}/ ) if (not extensions.include?($1)) tabs.push($1) end end } return tabs end # # Reads data from a channel. # def cmd_read(*args) if (args.length == 0) print_line( "Usage: read channel_id [length]\n\n" + "Reads data from the supplied channel.") return true end cid = args[0].to_i length = (args.length >= 2) ? args[1].to_i : 16384 channel = client.find_channel(cid) if (!channel) print_error("Channel #{cid} is not valid.") return true end data = channel.read(length) if (data and data.length) print("Read #{data.length} bytes from #{cid}:\n\n#{data}\n") else print_error("No data was returned.") end return true end def cmd_run_help print_line "Usage: run