class Rex::Post::Meterpreter::Ui::Console::CommandDispatcher::Core
Core
meterpreter client commands that provide only the required set of commands for having a functional meterpreter client<->server instance.
Constants
- CommDispatcher
Public Class Methods
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 1403 def self.add_client_extension_search_path(path) @@client_extension_search_paths << path unless @@client_extension_search_paths.include?(path) end
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 1406 def self.client_extension_search_paths @@client_extension_search_paths end
Initializes an instance of the core command set using the supplied shell for interactivity.
Rex::Post::Meterpreter::Ui::Console::CommandDispatcher::new
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 24 def initialize(shell) super self.extensions = [] self.bgjobs = [] self.bgjob_id = 0 # keep a lookup table to refer to transports by index @transport_map = {} end
Public Instance Methods
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 120 def cmd_background print_status "Backgrounding session #{client.name}..." client.interacting = false end
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 113 def cmd_background_help print_line "Usage: background" print_line print_line "Stop interacting with this session and return to the parent prompt" print_line end
Kill a background job
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 1195 def cmd_bgkill(*args) if args.length == 0 print_line("Usage: bgkill [id]") return end args.each do |jid| jid = jid.to_i if self.bgjobs[jid] print_status("Killing background job #{jid}...") self.bgjobs[jid].kill self.bgjobs[jid] = nil else print_error("Job #{jid} was not running") end end end
List background jobs
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 1216 def cmd_bglist(*args) self.bgjobs.each_index do |jid| if self.bgjobs[jid] print_status("Job #{jid}: #{self.bgjobs[jid][:args].inspect}") end end end
Executes a script in the context of the meterpreter session in the background
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 1156 def cmd_bgrun(*args) if args.length == 0 print_line( "Usage: bgrun <script> [arguments]\n\n" + "Executes a ruby script in the context of the meterpreter session.") return true end jid = self.bgjob_id self.bgjob_id += 1 # Get the script name self.bgjobs[jid] = Rex::ThreadFactory.spawn("MeterpreterBGRun(#{args[0]})-#{jid}", false, jid, args) do |myjid,xargs| ::Thread.current[:args] = xargs.dup begin # the rest of the arguments get passed in through the binding client.execute_script(args.shift, args) rescue ::Exception print_error("Error in script: #{$!.class} #{$!}") elog("Error in script: #{$!.class} #{$!}") dlog("Callstack: #{$@.join("\n")}") end self.bgjobs[myjid] = nil print_status("Background script with Job ID #{myjid} has completed (#{::Thread.current[:args].inspect})") end print_status("Executed Meterpreter with Job ID #{jid}") end
Map this to the normal run command tab completion
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 1188 def cmd_bgrun_tabs(*args) cmd_run_tabs(*args) end
Performs operations on the supplied channel.
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 147 def cmd_channel(*args) if args.empty? or args.include?("-h") or args.include?("--help") cmd_channel_help return end mode = nil chan = nil # Parse options @@channel_opts.parse(args) { |opt, idx, val| case opt when "-l" mode = :list when "-c", "-k" mode = :close chan = val when "-i" mode = :interact chan = val when "-r" mode = :read chan = val when "-w" mode = :write chan = val end if @@channel_opts.arg_required?(opt) unless chan print_error("Channel ID required") return end end } case mode when :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 when :close cmd_close(chan) when :interact cmd_interact(chan) when :read cmd_read(chan) when :write cmd_write(chan) else # No mode, no service. return true end end
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 137 def cmd_channel_help print_line "Usage: channel [options]" print_line print_line "Displays information about active channels." print_line @@channel_opts.usage end
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 218 def cmd_channel_tabs(str, words) case words.length when 1 @@channel_opts.fmt.keys when 2 case words[1] when "-k", "-c", "-i", "-r", "-w" tab_complete_channels else [] end else [] end end
Closes a supplied channel.
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 244 def cmd_close(*args) if (args.length == 0) cmd_close_help 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
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 234 def cmd_close_help print_line "Usage: close <channel_id>" print_line print_line "Closes the supplied channel." print_line end
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 263 def cmd_close_tabs(str, words) return [] if words.length > 1 return tab_complete_channels end
Disconnects the session
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 295 def cmd_detach(*args) client.shutdown_passive_dispatcher shell.stop end
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 281 def cmd_detach_help print_line "Detach from the victim. Only possible for non-stream sessions (http/https)" print_line print_line "The victim will continue to attempt to call back to the handler until it" print_line "successfully connects (which may happen immediately if you have a handler" print_line "running in the background), or reaches its expiration." print_line print_line "This session may #{client.passive_service ? "" : "NOT"} be detached." print_line end
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 1396 def cmd_disable_unicode_encoding client.encode_unicode = false print_status("Unicode encoding is disabled") end
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 1391 def cmd_enable_unicode_encoding client.encode_unicode = true print_status("Unicode encoding is enabled") end
Terminates the meterpreter session.
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 272 def cmd_exit(*args) print_status("Shutting down Meterpreter...") client.core.shutdown rescue nil client.shutdown_passive_dispatcher shell.stop end
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 410 def cmd_get_timeouts(*args) # Calling set without passing values is the same as # getting all the current timeouts timeouts = client.core.set_transport_timeouts print_timeouts(timeouts) end
Show info for a given Post
module.
See also cmd_info
in lib/msf/ui/console/command_dispatcher/core.rb
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 1236 def cmd_info(*args) return unless msf_loaded? if args.length != 1 or args.include?("-h") cmd_info_help return end module_name = args.shift mod = client.framework.modules.create(module_name); if mod.nil? print_error 'Invalid module: ' << module_name end if (mod) print_line(::Msf::Serializer::ReadableText.dump_module(mod)) mod_opt = ::Msf::Serializer::ReadableText.dump_options(mod, ' ') print_line("\nModule options (#{mod.fullname}):\n\n#{mod_opt}") if (mod_opt and mod_opt.length > 0) end end
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 1224 def cmd_info_help print_line 'Usage: info <module>' print_line print_line 'Prints information about a post-exploitation module' print_line end
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 1258 def cmd_info_tabs(*args) return unless msf_loaded? tab_complete_postmods end
Interacts with a channel.
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 310 def cmd_interact(*args) if (args.length == 0) cmd_info_help 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
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 300 def cmd_interact_help print_line "Usage: interact <channel_id>" print_line print_line "Interacts with the supplied channel." print_line end
Runs the IRB scripting shell
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 340 def cmd_irb(*args) expressions = [] # Parse the command options @@irb_opts.parse(args) do |opt, idx, val| case opt when '-e' expressions << val when '-h' return cmd_irb_help end end session = client framework = client.framework if expressions.empty? print_status("Starting IRB shell") print_status("The 'client' variable holds the meterpreter client\n") Rex::Ui::Text::IrbShell.new(binding).run else expressions.each { |expression| eval(expression, binding) } end end
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 330 def cmd_irb_help print_line "Usage: irb" print_line print_line "Execute commands in a Ruby environment" print @@irb_opts.usage end
Loads one or more meterpreter extensions.
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 960 def cmd_load(*args) if (args.length == 0) args.unshift("-h") end @@load_opts.parse(args) { |opt, idx, val| case opt when "-l" exts = SortedSet.new msf_path = MetasploitPayloads.msf_meterpreter_dir gem_path = MetasploitPayloads.local_meterpreter_dir [msf_path, gem_path].each do |path| ::Dir.entries(path).each { |f| if (::File.file?(::File.join(path, f)) && f =~ /ext_server_(.*)\.#{client.binary_suffix}/ ) exts.add($1) end } end print(exts.to_a.join("\n") + "\n") return true when "-h" cmd_load_help 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
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 950 def cmd_load_help print_line("Usage: load ext1 ext2 ext3 ...") print_line print_line "Loads a meterpreter extension module or modules." print_line @@load_opts.usage end
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 1015 def cmd_load_tabs(str, words) tabs = SortedSet.new msf_path = MetasploitPayloads.msf_meterpreter_dir gem_path = MetasploitPayloads.local_meterpreter_dir [msf_path, gem_path].each do |path| ::Dir.entries(path).each { |f| if (::File.file?(::File.join(path, f)) && f =~ /ext_server_(.*)\.#{client.binary_suffix}/ ) if (not extensions.include?($1)) tabs.add($1) end end } end return tabs.to_a end
Get the machine ID of the target
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 435 def cmd_machine_id(*args) client.machine_id = client.core.machine_id unless client.machine_id print_good("Machine ID: #{client.machine_id}") end
Migrates the server to the supplied process identifier.
@param args [Array<String>] Commandline arguments, -h or a pid. On linux
platforms a path for the unix domain socket used for IPC.
@return [void]
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 843 def cmd_migrate(*args) if args.length == 0 || args.any? { |arg| %w(-h --pid --name).include? arg } cmd_migrate_help return true end pid = nil writable_dir = nil opts = { timeout: nil } @@migrate_opts.parse(args) do |opt, idx, val| case opt when '-t' opts[:timeout] = val.to_i when '-p' writable_dir = val when '-P' unless val =~ /^\d+$/ print_error("Not a PID: #{val}") return end pid = val.to_i when '-N' if val.to_s.empty? print_error("No process name provided") return end # this will migrate to the first process with a matching name unless (process = client.sys.process.processes.find { |p| p['name'] == val }) print_error("Could not find process name #{val}") return end pid = process['pid'] end end unless pid unless (pid = args.first) print_error('A process ID or name argument must be provided') return end unless pid =~ /^\d+$/ print_error("Not a PID: #{pid}") return end pid = pid.to_i end begin server = client.sys.process.open rescue TimeoutError => e elog(e.to_s) rescue RequestError => e elog(e.to_s) end service = client.pfservice # If we have any open port forwards, we need to close them down # otherwise we'll end up with local listeners which aren't connected # to valid channels in the migrated meterpreter instance. existing_relays = [] if service service.each_tcp_relay do |lhost, lport, rhost, rport, opts| next unless opts['MeterpreterRelay'] if existing_relays.empty? print_status('Removing existing TCP relays...') end if (service.stop_tcp_relay(lport, lhost)) print_status("Successfully stopped TCP relay on #{lhost || '0.0.0.0'}:#{lport}") existing_relays << { :lport => lport, :opts => opts } else print_error("Failed to stop TCP relay on #{lhost || '0.0.0.0'}:#{lport}") next end end unless existing_relays.empty? print_status("#{existing_relays.length} TCP relay(s) removed.") end end server ? print_status("Migrating from #{server.pid} to #{pid}...") : print_status("Migrating to #{pid}") # Do this thang. client.core.migrate(pid, writable_dir, opts) print_status('Migration completed successfully.') # Update session info (we may have a new username) client.update_session_info unless existing_relays.empty? print_status('Recreating TCP relay(s)...') existing_relays.each do |r| client.pfservice.start_tcp_relay(r[:lport], r[:opts]) print_status("Local TCP relay recreated: #{r[:opts]['LocalHost'] || '0.0.0.0'}:#{r[:lport]} <-> #{r[:opts]['PeerHost']}:#{r[:opts]['PeerPort']}") end end end
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 825 def cmd_migrate_help if client.platform =~ /linux/ print_line('Usage: migrate <<pid> | -P <pid> | -N <name>> [-p writable_path] [-t timeout]') else print_line('Usage: migrate <<pid> | -P <pid> | -N <name>> [-t timeout]') end print_line print_line('Migrates the server instance to another process.') print_line('NOTE: Any open channels or other dynamic state will be lost.') print_line end
Reads data from a channel.
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 1048 def cmd_read(*args) if (args.length == 0) cmd_read_help 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
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 1038 def cmd_read_help print_line "Usage: read <channel_id> [length]" print_line print_line "Reads data from the supplied channel." print_line end
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 1353 def cmd_resource(*args) if args.empty? return false end args.each do |glob| files = ::Dir.glob(::File.expand_path(glob)) if files.empty? print_error("No such file #{glob}") next end files.each do |filename| print_status("Reading #{filename}") if (not ::File.readable?(filename)) print_error("Could not read file #{filename}") next else ::File.open(filename, "r").each_line do |line| next if line.strip.length < 1 next if line[0,1] == "#" begin print_status("Running #{line}") client.console.run_single(line) rescue ::Exception => e print_error("Error Running Command #{line}: #{e.class} #{e}") end end end end end end
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 1346 def cmd_resource_help print_line "Usage: resource <path1> [path2 ...]" print_line print_line "Run the commands stored in the supplied files." print_line end
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 1385 def cmd_resource_tabs(str, words) return [] if words.length > 1 tab_complete_filenames(str, words) end
Executes a script in the context of the meterpreter session.
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 1088 def cmd_run(*args) if args.length == 0 cmd_run_help return true end # Get the script name begin script_name = args.shift # First try it as a Post module if we have access to the Metasploit # Framework instance. If we don't, or if no such module exists, # fall back to using the scripting interface. if (msf_loaded? and mod = client.framework.modules.create(script_name)) original_mod = mod reloaded_mod = client.framework.modules.reload_module(original_mod) unless reloaded_mod error = client.framework.modules.module_load_error_by_path[original_mod.file_path] print_error("Failed to reload module: #{error}") return end opts = (args + [ "SESSION=#{client.sid}" ]).join(',') reloaded_mod.run_simple( #'RunAsJob' => true, 'LocalInput' => shell.input, 'LocalOutput' => shell.output, 'OptionStr' => opts ) else # the rest of the arguments get passed in through the binding client.execute_script(script_name, args) end rescue print_error("Error in script: #{$!.class} #{$!}") elog("Error in script: #{$!.class} #{$!}") dlog("Callstack: #{$@.join("\n")}") end end
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 1076 def cmd_run_help print_line "Usage: run <script> [arguments]" print_line print_line "Executes a ruby script or Metasploit Post module in the context of the" print_line "meterpreter session. Post modules can take arguments in var=val format." print_line "Example: run post/foo/bar BAZ=abcd" print_line end
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 1129 def cmd_run_tabs(str, words) tabs = [] if(not words[1] or not words[1].match(/^\//)) begin if (msf_loaded?) tabs += tab_complete_postmods end [ ::Msf::Sessions::Meterpreter.script_base, ::Msf::Sessions::Meterpreter.user_script_base ].each do |dir| next if not ::File.exist? dir tabs += ::Dir.new(dir).find_all { |e| path = dir + ::File::SEPARATOR + e ::File.file?(path) and ::File.readable?(path) } end rescue Exception end end return tabs.map { |e| e.sub(/\.rb$/, '') } end
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 381 def cmd_set_timeouts(*args) if ( args.length == 0 or args.include?("-h") ) cmd_set_timeouts_help return end opts = {} @@set_timeouts_opts.parse(args) do |opt, idx, val| case opt when '-c' opts[:comm_timeout] = val.to_i if val when '-x' opts[:session_exp] = val.to_i if val when '-t' opts[:retry_total] = val.to_i if val when '-w' opts[:retry_wait] = val.to_i if val end end if opts.keys.length == 0 print_error("No options set") else timeouts = client.core.set_transport_timeouts(opts) print_timeouts(timeouts) end end
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 373 def cmd_set_timeouts_help print_line('Usage: set_timeouts [options]') print_line print_line('Set the current timeout options.') print_line('Any or all of these can be set at once.') print_line(@@set_timeouts_opts.usage) end
Handle the sleep command.
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 545 def cmd_sleep(*args) if args.length == 0 cmd_sleep_help return end seconds = args.shift.to_i if seconds <= 0 cmd_sleep_help return end print_status("Telling the target instance to sleep for #{seconds} seconds ...") if client.core.transport_sleep(seconds) print_good("Target instance has gone to sleep, terminating current session.") client.shutdown_passive_dispatcher shell.stop else print_error("Target instance failed to go to sleep.") end end
Display help for the sleep.
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 532 def cmd_sleep_help print_line('Usage: sleep <time>') print_line print_line(' time: Number of seconds to wait (positive integer)') print_line print_line(' This command tells Meterpreter to go to sleep for the specified') print_line(' number of seconds. Sleeping will result in the transport being') print_line(' shut down and restarted after the designated timeout.') end
Handle the SSL verification querying and setting function.
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 471 def cmd_ssl_verify(*args) if ( args.length == 0 or args.include?("-h") ) cmd_ssl_verify_help return end query = false enable = false disable = false settings = 0 @@ssl_verify_opts.parse(args) do |opt, idx, val| case opt when '-q' query = true settings += 1 when '-e' enable = true settings += 1 when '-d' disable = true settings += 1 end end # Make sure only one action has been chosen if settings != 1 cmd_ssl_verify_help return end if query hash = client.core.get_ssl_hash_verify if hash print_good("SSL verification is enabled. SHA1 Hash: #{hash.unpack("H*")[0]}") else print_good("SSL verification is disabled.") end elsif enable hash = client.core.enable_ssl_hash_verify if hash print_good("SSL verification has been enabled. SHA1 Hash: #{hash.unpack("H*")[0]}") else print_error("Failed to enable SSL verification") end else if client.core.disable_ssl_hash_verify print_good('SSL verification has been disabled') else print_error("Failed to disable SSL verification") end end end
Help for ssl verification
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 460 def cmd_ssl_verify_help print_line('Usage: ssl_verify [options]') print_line print_line('Change and query the current setting for SSL verification') print_line('Only one of the following options can be used at a time') print_line(@@ssl_verify_opts.usage) end
Manage transports
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 616 def cmd_transport(*args) if ( args.length == 0 or args.include?("-h") ) cmd_transport_help return end command = args.shift unless ['list', 'add', 'change', 'prev', 'next', 'remove'].include?(command) cmd_transport_help return end opts = { :uuid => client.payload_uuid, :transport => nil, :lhost => nil, :lport => nil, :uri => nil, :ua => nil, :proxy_host => nil, :proxy_port => nil, :proxy_type => nil, :proxy_user => nil, :proxy_pass => nil, :comm_timeout => nil, :session_exp => nil, :retry_total => nil, :retry_wait => nil, :cert => nil, :verbose => false } valid = true transport_index = 0 @@transport_opts.parse(args) do |opt, idx, val| case opt when '-c' opts[:cert] = val when '-u' opts[:uri] = val when '-i' transport_index = val.to_i when '-ph' opts[:proxy_host] = val when '-pp' opts[:proxy_port] = val.to_i when '-pt' opts[:proxy_type] = val when '-pu' opts[:proxy_user] = val when '-ps' opts[:proxy_pass] = val when '-ua' opts[:ua] = val when '-to' opts[:comm_timeout] = val.to_i if val when '-ex' opts[:session_exp] = val.to_i if val when '-rt' opts[:retry_total] = val.to_i if val when '-rw' opts[:retry_wait] = val.to_i if val when '-p' opts[:lport] = val.to_i if val when '-l' opts[:lhost] = val when '-v' opts[:verbose] = true when '-t' unless client.core.valid_transport?(val) cmd_transport_help return end opts[:transport] = val else valid = false end end unless valid cmd_transport_help return end update_transport_map case command when 'list' result = client.core.transport_list current_transport_url = result[:transports].first[:url] sorted_by_url = result[:transports].sort_by { |k| k[:url] } # this will output the session timeout first print_timeouts(result) columns =[ 'ID', 'Curr', 'URL', 'Comms T/O', 'Retry Total', 'Retry Wait' ] if opts[:verbose] columns << 'User Agent' columns << 'Proxy Host' columns << 'Proxy User' columns << 'Proxy Pass' columns << 'Cert Hash' end # next draw up a table of transport entries tbl = Rex::Ui::Text::Table.new( 'SortIndex' => 0, # sort by ID 'Indent' => 4, 'Columns' => columns) sorted_by_url.each_with_index do |t, i| entry = [ i+1, (current_transport_url == t[:url]) ? '*' : '', t[:url], t[:comm_timeout], t[:retry_total], t[:retry_wait] ] if opts[:verbose] entry << t[:ua] entry << t[:proxy_host] entry << t[:proxy_user] entry << t[:proxy_pass] entry << (t[:cert_hash] || '').unpack("H*")[0] end tbl << entry end print("\n" + tbl.to_s + "\n") when 'next' print_status("Changing to next transport ...") if client.core.transport_next print_good("Successfully changed to the next transport, killing current session.") client.shutdown_passive_dispatcher shell.stop else print_error("Failed to change transport, please check the parameters") end when 'prev' print_status("Changing to previous transport ...") if client.core.transport_prev print_good("Successfully changed to the previous transport, killing current session.") client.shutdown_passive_dispatcher shell.stop else print_error("Failed to change transport, please check the parameters") end when 'change' print_status("Changing to new transport ...") if client.core.transport_change(opts) print_good("Successfully added #{opts[:transport]} transport, killing current session.") client.shutdown_passive_dispatcher shell.stop else print_error("Failed to change transport, please check the parameters") end when 'add' print_status("Adding new transport ...") if client.core.transport_add(opts) print_good("Successfully added #{opts[:transport]} transport.") else print_error("Failed to add transport, please check the parameters") end when 'remove' if opts[:transport] && !opts[:transport].end_with?('_tcp') && opts[:uri].nil? print_error("HTTP/S transport specified without session URI") return end if !transport_index.zero? && @transport_map.has_key?(transport_index) # validate the URL url_to_delete = @transport_map[transport_index][:url] begin uri = URI.parse(url_to_delete) opts[:transport] = "reverse_#{uri.scheme}" opts[:lhost] = uri.host opts[:lport] = uri.port opts[:uri] = uri.path[1..-2] if uri.scheme.include?("http") rescue URI::InvalidURIError print_error("Failed to parse URL: #{url_to_delete}") return end end print_status("Removing transport ...") if client.core.transport_remove(opts) print_good("Successfully removed #{opts[:transport]} transport.") else print_error("Failed to remove transport, please check the parameters") end end end
Display help for transport management.
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 594 def cmd_transport_help print_line('Usage: transport <list|change|add|next|prev|remove> [options]') print_line print_line(' list: list the currently active transports.') print_line(' add: add a new transport to the transport list.') print_line(' change: same as add, but changes directly to the added entry.') print_line(' next: jump to the next transport in the list (no options).') print_line(' prev: jump to the previous transport in the list (no options).') print_line(' remove: remove an existing, non-active transport.') print_line(@@transport_opts.usage) end
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 1031 def cmd_use(*args) #print_error("Warning: The 'use' command is deprecated in favor of 'load'") cmd_load(*args) end
Get the machine ID of the target
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 443 def cmd_uuid(*args) client.payload_uuid = client.core.uuid unless client.payload_uuid print_good("UUID: #{client.payload_uuid}") end
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 1277 def cmd_write(*args) if (args.length == 0 or args.include?("-h")) cmd_write_help return end src_file = nil cid = nil @@write_opts.parse(args) { |opt, idx, val| case opt when "-f" src_file = val else cid = val.to_i end } # Find the channel associated with this cid, assuming the cid is valid. if ((!cid) or (!(channel = client.find_channel(cid)))) print_error("Invalid channel identifier specified.") return true end # If they supplied a source file, read in its contents and write it to # the channel if (src_file) begin data = '' ::File.open(src_file, 'rb') { |f| data = f.read(f.stat.size) } rescue Errno::ENOENT print_error("Invalid source file specified: #{src_file}") return true end if (data and data.length > 0) channel.write(data) print_status("Wrote #{data.length} bytes to channel #{cid}.") else print_error("No data to send from file #{src_file}") return true end # Otherwise, read from the input descriptor until we're good to go. else print("Enter data followed by a '.' on an empty line:\n\n") data = '' # Keep truckin' while (s = shell.input.gets) break if (s =~ /^\.\r?\n?$/) data += s end if (!data or data.length == 0) print_error("No data to send.") else channel.write(data) print_status("Wrote #{data.length} bytes to channel #{cid}.") end end return true end
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 1270 def cmd_write_help print_line "Usage: write [options] channel_id" print_line print_line "Writes data to the supplied channel." print_line @@write_opts.usage end
List of supported commands.
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 46 def commands c = { "?" => "Help menu", "background" => "Backgrounds the current session", "close" => "Closes a channel", "channel" => "Displays information or control active channels", "exit" => "Terminate the meterpreter session", "help" => "Help menu", "irb" => "Drop into irb scripting mode", "use" => "Deprecated alias for 'load'", "load" => "Load one or more meterpreter extensions", "machine_id" => "Get the MSF ID of the machine attached to the session", "quit" => "Terminate the meterpreter session", "resource" => "Run the commands stored in a file", "uuid" => "Get the UUID for the current 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", "get_timeouts" => "Get the current session timeout values", "set_timeouts" => "Set the current session timeout values", "bglist" => "Lists running background scripts", "write" => "Writes data to a channel", "enable_unicode_encoding" => "Enables encoding of unicode strings", "disable_unicode_encoding" => "Disables encoding of unicode strings" } if client.passive_service c["detach"] = "Detach the meterpreter session (for http/https)" end # Currently we have some windows-specific core commands` if client.platform =~ /win/ # only support the SSL switching for HTTPS if client.passive_service && client.sock.type? == 'tcp-ssl' c["ssl_verify"] = "Modify the SSL certificate verification setting" end end if client.platform =~ /win/ || client.platform =~ /linux/ # Migration only supported on windows and linux c["migrate"] = "Migrate the server to another process" end if client.platform =~ /win/ || client.platform =~ /linux/ || client.platform =~ /python/ || client.platform =~ /java/ # Yet to implement transport hopping for other meterpreters. c["transport"] = "Change the current transport mechanism" # sleep functionality relies on the transport features, so only # wire that in with the transport stuff. c["sleep"] = "Force Meterpreter to go quiet, then re-establish session." end if (msf_loaded?) c["info"] = "Displays information about a Post module" end c end
Core
baby.
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 109 def name "Core" end
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 417 def print_timeouts(timeouts) if timeouts[:session_exp] print_line("Session Expiry : @ #{(Time.now + timeouts[:session_exp]).strftime('%Y-%m-%d %H:%M:%S')}") end if timeouts[:comm_timeout] print_line("Comm Timeout : #{timeouts[:comm_timeout]} seconds") end if timeouts[:retry_total] print_line("Retry Total Time: #{timeouts[:retry_total]} seconds") end if timeouts[:retry_wait] print_line("Retry Wait Time : #{timeouts[:retry_wait]} seconds") end end
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 606 def update_transport_map result = client.core.transport_list @transport_map.clear sorted_by_url = result[:transports].sort_by { |k| k[:url] } sorted_by_url.each_with_index { |t, i| @transport_map[i+1] = t } end
Protected Instance Methods
Loads the client extension specified in mod
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 1420 def add_extension_client(mod) loaded = false klass = nil self.class.client_extension_search_paths.each do |path| path = ::File.join(path, "#{mod}.rb") klass = CommDispatcher.check_hash(path) if (klass == nil) old = CommDispatcher.constants next unless ::File.exist? path if (require(path)) new = CommDispatcher.constants diff = new - old next if (diff.empty?) klass = CommDispatcher.const_get(diff[0]) CommDispatcher.set_hash(path, klass) loaded = true break else print_error("Failed to load client script file: #{path}") return false end else # the klass is already loaded, from a previous invocation loaded = true break end end unless loaded print_error("Failed to load client portion of #{mod}.") return false end # Enstack the dispatcher self.shell.enstack_dispatcher(klass) # Insert the module into the list of extensions self.extensions << mod end
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 1477 def tab_complete_channels client.channels.keys.map { |k| k.to_s } end
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb, line 1463 def tab_complete_postmods tabs = client.framework.modules.post.map { |name,klass| mod = client.framework.modules.post.create(name) if mod and mod.session_compatible?(client) mod.fullname.dup else nil end } # nils confuse readline tabs.compact end