diff --git a/lib/msf/base/serializer/readable_text.rb b/lib/msf/base/serializer/readable_text.rb index 4a89ca1c2b..f007fe6d04 100644 --- a/lib/msf/base/serializer/readable_text.rb +++ b/lib/msf/base/serializer/readable_text.rb @@ -618,7 +618,6 @@ class ReadableText sess_luri = session.exploit_datastore['LURI'] || "" sess_checkin = "" - sess_machine_id = session.machine_id.to_s sess_registration = "No" if session.respond_to? :platform @@ -642,15 +641,12 @@ class ReadableText out << " Tunnel: #{sess_tunnel}\n" out << " Via: #{sess_via}\n" out << " UUID: #{sess_uuid}\n" - out << " MachineID: #{sess_machine_id}\n" out << " CheckIn: #{sess_checkin}\n" out << " Registered: #{sess_registration}\n" - if !sess_luri.empty? + unless sess_luri.empty? out << " LURI: #{sess_luri}\n" end - - out << "\n" end diff --git a/lib/msf/base/sessions/meterpreter_options.rb b/lib/msf/base/sessions/meterpreter_options.rb index a9dcf83be4..00058b4c7e 100644 --- a/lib/msf/base/sessions/meterpreter_options.rb +++ b/lib/msf/base/sessions/meterpreter_options.rb @@ -51,6 +51,17 @@ module MeterpreterOptions end if valid + # always make sure that the new session has a new guid if it's not already known + guid = session.core.get_session_guid + if guid == '00000000-0000-0000-0000-000000000000' + guid = SecureRandom.uuid + session.core.set_session_guid(guid) + session.guid = guid + # TODO: New statgeless session, do some account in the DB so we can track it later. + else + session.guid = guid + # TODO: This session was either staged or previously known, and so we shold do some accounting here! + end if datastore['AutoLoadStdapi'] @@ -71,7 +82,7 @@ module MeterpreterOptions end [ 'InitialAutoRunScript', 'AutoRunScript' ].each do |key| - if !datastore[key].empty? + unless datastore[key].empty? args = Shellwords.shellwords( datastore[key] ) print_status("Session ID #{session.sid} (#{session.tunnel_to_s}) processing #{key} '#{datastore[key]}'") session.execute_script(args.shift, *args) diff --git a/lib/msf/core/payload/android.rb b/lib/msf/core/payload/android.rb index 9b17e68aa2..3c564843f2 100644 --- a/lib/msf/core/payload/android.rb +++ b/lib/msf/core/payload/android.rb @@ -51,7 +51,8 @@ module Msf::Payload::Android arch: opts[:uuid].arch, expiration: ds['SessionExpirationTimeout'].to_i, uuid: opts[:uuid], - transports: opts[:transport_config] || [transport_config(opts)] + transports: opts[:transport_config] || [transport_config(opts)], + stageless: opts[:stageless] == true } config = Rex::Payloads::Meterpreter::Config.new(config_opts).to_b diff --git a/lib/msf/core/payload/java/meterpreter_loader.rb b/lib/msf/core/payload/java/meterpreter_loader.rb index c11114c14e..8c590465a8 100644 --- a/lib/msf/core/payload/java/meterpreter_loader.rb +++ b/lib/msf/core/payload/java/meterpreter_loader.rb @@ -69,7 +69,8 @@ module Payload::Java::MeterpreterLoader arch: opts[:uuid].arch, expiration: ds['SessionExpirationTimeout'].to_i, uuid: opts[:uuid], - transports: opts[:transport_config] || [transport_config(opts)] + transports: opts[:transport_config] || [transport_config(opts)], + stageless: opts[:stageless] == true } # create the configuration instance based off the parameters diff --git a/lib/msf/core/payload/python/meterpreter_loader.rb b/lib/msf/core/payload/python/meterpreter_loader.rb index 0d5199d3aa..dfd27e3fbd 100644 --- a/lib/msf/core/payload/python/meterpreter_loader.rb +++ b/lib/msf/core/payload/python/meterpreter_loader.rb @@ -74,6 +74,13 @@ module Payload::Python::MeterpreterLoader uuid = Rex::Text.to_hex(uuid.to_raw, prefix = '') met.sub!("PAYLOAD_UUID = \'\'", "PAYLOAD_UUID = \'#{uuid}\'") + if opts[:stageless] == true + session_guid = "00" * 16 + else + session_guid = SecureRandom.uuid.gsub(/-/, '') + end + met.sub!("SESSION_GUID = \'\'", "SESSION_GUID = \'#{session_guid}\'.decode(\'hex\')") + http_user_agent = opts[:http_user_agent] || ds['MeterpreterUserAgent'] http_proxy_host = opts[:http_proxy_host] || ds['PayloadProxyHost'] || ds['PROXYHOST'] http_proxy_port = opts[:http_proxy_port] || ds['PayloadProxyPort'] || ds['PROXYPORT'] diff --git a/lib/msf/core/payload/windows/meterpreter_loader.rb b/lib/msf/core/payload/windows/meterpreter_loader.rb index 7190d4f8b9..922aa9951d 100644 --- a/lib/msf/core/payload/windows/meterpreter_loader.rb +++ b/lib/msf/core/payload/windows/meterpreter_loader.rb @@ -82,7 +82,8 @@ module Payload::Windows::MeterpreterLoader expiration: ds['SessionExpirationTimeout'].to_i, uuid: opts[:uuid], transports: opts[:transport_config] || [transport_config(opts)], - extensions: [] + extensions: [], + stageless: opts[:stageless] == true } # create the configuration instance based off the parameters diff --git a/lib/msf/core/payload/windows/x64/meterpreter_loader.rb b/lib/msf/core/payload/windows/x64/meterpreter_loader.rb index cd5ba7c708..ce70242b53 100644 --- a/lib/msf/core/payload/windows/x64/meterpreter_loader.rb +++ b/lib/msf/core/payload/windows/x64/meterpreter_loader.rb @@ -84,7 +84,8 @@ module Payload::Windows::MeterpreterLoader_x64 expiration: ds['SessionExpirationTimeout'].to_i, uuid: opts[:uuid], transports: opts[:transport_config] || [transport_config(opts)], - extensions: [] + extensions: [], + stageless: opts[:stageless] == true } # create the configuration instance based off the parameters diff --git a/lib/msf/core/session.rb b/lib/msf/core/session.rb index f781f2864b..8ab8003ad4 100644 --- a/lib/msf/core/session.rb +++ b/lib/msf/core/session.rb @@ -385,6 +385,10 @@ module Session # attr_accessor :machine_id # + # The guid that identifies an active Meterpreter session + # + attr_accessor :guid + # # The actual exploit module instance that created this session # attr_accessor :exploit diff --git a/lib/rex/payloads/meterpreter/config.rb b/lib/rex/payloads/meterpreter/config.rb index dac1c744ff..838d7f4814 100644 --- a/lib/rex/payloads/meterpreter/config.rb +++ b/lib/rex/payloads/meterpreter/config.rb @@ -3,6 +3,7 @@ require 'msf/core/payload/uuid' require 'msf/core/payload/windows' require 'msf/core/reflective_dll_loader' require 'rex/socket/x509_certificate' +require 'securerandom' class Rex::Payloads::Meterpreter::Config @@ -50,14 +51,23 @@ private uuid = opts[:uuid].to_raw exit_func = Msf::Payload::Windows.exit_types[opts[:exitfunk]] + # if no session guid is given then we'll just pass the blank + # guid through. this is important for stageless payloads + if opts[:stageless] == true + session_guid = "\x00" * 16 + else + session_guid = [SecureRandom.uuid.gsub(/-/, '')].pack('H*') + end + session_data = [ 0, # comms socket, patched in by the stager exit_func, # exit function identifer opts[:expiration], # Session expiry - uuid # the UUID + uuid, # the UUID + session_guid # the Session GUID ] - session_data.pack('VVVA*') + session_data.pack('VVVA*A*') end def transport_block(opts) diff --git a/lib/rex/post/meterpreter/client_core.rb b/lib/rex/post/meterpreter/client_core.rb index 2f7c231e60..a09b6ced5f 100644 --- a/lib/rex/post/meterpreter/client_core.rb +++ b/lib/rex/post/meterpreter/client_core.rb @@ -125,6 +125,9 @@ class ClientCore < Extension result end + # + # Set associated transport timeouts for the currently active transport. + # def set_transport_timeouts(opts={}) request = Packet.create_request('core_transport_set_timeouts') @@ -298,6 +301,9 @@ class ClientCore < Extension return true end + # + # Set the UUID on the target session. + # def set_uuid(uuid) request = Packet.create_request('core_set_uuid') request.add_tlv(TLV_TYPE_UUID, uuid.to_raw) @@ -307,10 +313,42 @@ class ClientCore < Extension true end + # + # Set the session GUID on the target session. + # + def set_session_guid(guid) + request = Packet.create_request('core_set_session_guid') + request.add_tlv(TLV_TYPE_SESSION_GUID, [guid.gsub(/-/, '')].pack('H*')) + + client.send_request(request) + + true + end + + # + # Get the session GUID from the target session. + # + def get_session_guid(timeout=nil) + request = Packet.create_request('core_get_session_guid') + + args = [request] + args << timeout if timeout + + response = client.send_request(*args) + + bytes = response.get_tlv_value(TLV_TYPE_SESSION_GUID) + + parts = bytes.unpack('H*')[0] + [parts[0, 8], parts[8, 4], parts[12, 4], parts[16, 4], parts[20, 12]].join('-') + end + + # + # Get the machine ID from the target session. + # def machine_id(timeout=nil) request = Packet.create_request('core_machine_id') - args = [ request ] + args = [request] args << timeout if timeout response = client.send_request(*args) @@ -325,6 +363,9 @@ class ClientCore < Extension Rex::Text.md5(mid.to_s.downcase.strip) end + # + # Get the current native arch from the target session. + # def native_arch(timeout=nil) # Not all meterpreter implementations support this request = Packet.create_request('core_native_arch') @@ -337,6 +378,9 @@ class ClientCore < Extension response.get_tlv_value(TLV_TYPE_STRING) end + # + # Remove a transport from the session based on the provided options. + # def transport_remove(opts={}) request = transport_prepare_request('core_transport_remove', opts) @@ -347,6 +391,9 @@ class ClientCore < Extension return true end + # + # Add a transport to the session based on the provided options. + # def transport_add(opts={}) request = transport_prepare_request('core_transport_add', opts) @@ -357,6 +404,9 @@ class ClientCore < Extension return true end + # + # Change the currently active transport on the session. + # def transport_change(opts={}) request = transport_prepare_request('core_transport_change', opts) @@ -367,6 +417,9 @@ class ClientCore < Extension return true end + # + # Sleep the current session for the given number of seconds. + # def transport_sleep(seconds) return false if seconds == 0 @@ -379,12 +432,18 @@ class ClientCore < Extension return true end + # + # Change the active transport to the next one in the transport list. + # def transport_next request = Packet.create_request('core_transport_next') client.send_request(request) return true end + # + # Change the active transport to the previous one in the transport list. + # def transport_prev request = Packet.create_request('core_transport_prev') client.send_request(request) @@ -623,10 +682,17 @@ class ClientCore < Extension private + # + # Get a reference to the currently active transport. + # def get_current_transport transport_list[:transports][0] end + # + # Generate a migrate stub that is specific to the current transport type and the + # target process. + # def generate_migrate_stub(target_process) stub = nil @@ -663,6 +729,10 @@ private stub end + # + # Helper function to prepare a transport request that will be sent to the + # attached session. + # def transport_prepare_request(method, opts={}) unless valid_transport?(opts[:transport]) && opts[:lport] return nil @@ -751,6 +821,9 @@ private end + # + # Create a full migration payload specific to the target process. + # def generate_migrate_payload(target_process) case client.platform when 'windows' @@ -764,6 +837,9 @@ private blob end + # + # Create a full Windows-specific migration payload specific to the target process. + # def generate_migrate_windows_payload(target_process) c = Class.new( ::Msf::Payload ) c.include( ::Msf::Payload::Stager ) @@ -783,16 +859,25 @@ private migrate_stager.stage_meterpreter end + # + # Create a full Linux-specific migration payload specific to the target process. + # def generate_migrate_linux_payload MetasploitPayloads.read('meterpreter', 'msflinker_linux_x86.bin') end + # + # Determine the elf entry poitn for the given payload. + # def elf_ep(payload) elf = Rex::ElfParsey::Elf.new( Rex::ImageSource::Memory.new( payload ) ) ep = elf.elf_header.e_entry return ep end + # + # Get the tmp folder for the session. + # def tmp_folder tmp = client.sys.config.getenv('TMPDIR') diff --git a/lib/rex/post/meterpreter/packet.rb b/lib/rex/post/meterpreter/packet.rb index 1e70ea0f13..2ab6420493 100644 --- a/lib/rex/post/meterpreter/packet.rb +++ b/lib/rex/post/meterpreter/packet.rb @@ -105,6 +105,7 @@ TLV_TYPE_TRANS_GROUP = TLV_META_TYPE_GROUP | 441 TLV_TYPE_MACHINE_ID = TLV_META_TYPE_STRING | 460 TLV_TYPE_UUID = TLV_META_TYPE_RAW | 461 +TLV_TYPE_SESSION_GUID = TLV_META_TYPE_RAW | 462 TLV_TYPE_CIPHER_NAME = TLV_META_TYPE_STRING | 500 TLV_TYPE_CIPHER_PARAMETERS = TLV_META_TYPE_GROUP | 501 @@ -215,6 +216,7 @@ class Tlv when TLV_TYPE_TRANS_RETRY_WAIT; "TRANS-RETRY-WAIT" when TLV_TYPE_MACHINE_ID; "MACHINE-ID" when TLV_TYPE_UUID; "UUID" + when TLV_TYPE_SESSION_GUID; "SESSION-GUID" #when Extensions::Stdapi::TLV_TYPE_NETWORK_INTERFACE; 'network-interface' #when Extensions::Stdapi::TLV_TYPE_IP; 'ip-address' diff --git a/lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb b/lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb index e5e4bd6925..49815f90d3 100644 --- a/lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb +++ b/lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb @@ -34,59 +34,60 @@ class Console::CommandDispatcher::Core end @@irb_opts = Rex::Parser::Arguments.new( - "-h" => [ false, "Help banner." ], - "-e" => [ true, "Expression to evaluate." ]) + '-h' => [false, 'Help banner.'], + '-e' => [true, 'Expression to evaluate.']) @@load_opts = Rex::Parser::Arguments.new( - "-l" => [ false, "List all available extensions" ], - "-h" => [ false, "Help menu." ]) + '-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 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", - "sessions" => "Quickly switch to another session", - "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" + '?' => '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', + 'guid' => 'Get the session GUID', + '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', + 'sessions' => 'Quickly switch to another session', + '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)" + c['detach'] = 'Detach the meterpreter session (for http/https)' end # Currently we have some windows-specific core commands` if client.platform == 'windows' # 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" + c['ssl_verify'] = 'Modify the SSL certificate verification setting' end end if client.platform == 'windows' || client.platform == 'linux' # Migration only supported on windows and linux - c["migrate"] = "Migrate the server to another process" + c['migrate'] = 'Migrate the server to another process' end # TODO: This code currently checks both platform and architecture for the python @@ -97,15 +98,15 @@ class Console::CommandDispatcher::Core client.platform == 'python' || client.platform == 'java' || client.arch == ARCH_PYTHON || client.platform == 'android' # Yet to implement transport hopping for other meterpreters. - c["transport"] = "Change the current transport mechanism" + 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." + c['sleep'] = 'Force Meterpreter to go quiet, then re-establish session.' end if msf_loaded? - c["info"] = "Displays information about a Post module" + c['info'] = 'Displays information about a Post module' end c @@ -115,7 +116,7 @@ class Console::CommandDispatcher::Core # Core baby. # def name - "Core" + 'Core' end def cmd_sessions_help @@ -141,14 +142,14 @@ class Console::CommandDispatcher::Core end def cmd_background_help - print_line "Usage: background" + print_line('Usage: background') print_line - print_line "Stop interacting with this session and return to the parent prompt" + print_line('Stop interacting with this session and return to the parent prompt') print_line end def cmd_background - print_status "Backgrounding session #{client.name}..." + print_status("Backgrounding session #{client.name}...") client.interacting = false end @@ -156,26 +157,26 @@ class Console::CommandDispatcher::Core # Displays information about active channels # @@channel_opts = Rex::Parser::Arguments.new( - "-c" => [ true, "Close the given channel." ], - "-k" => [ true, "Close the given channel." ], - "-i" => [ true, "Interact with the given channel." ], - "-l" => [ false, "List active channels." ], - "-r" => [ true, "Read from the given channel." ], - "-w" => [ true, "Write to the given channel." ], - "-h" => [ false, "Help menu." ]) + '-c' => [ true, 'Close the given channel.' ], + '-k' => [ true, 'Close the given channel.' ], + '-i' => [ true, 'Interact with the given channel.' ], + '-l' => [ false, 'List active channels.' ], + '-r' => [ true, 'Read from the given channel.' ], + '-w' => [ true, 'Write to the given channel.' ], + '-h' => [ false, 'Help menu.' ]) def cmd_channel_help - print_line "Usage: channel [options]" + print_line('Usage: channel [options]') print_line - print_line "Displays information about active channels." - print_line @@channel_opts.usage + print_line('Displays information about active channels.') + print_line(@@channel_opts.usage) end # # Performs operations on the supplied channel. # def cmd_channel(*args) - if args.empty? or args.include?("-h") or args.include?("--help") + if args.empty? || args.include?('-h') cmd_channel_help return end @@ -186,24 +187,25 @@ class Console::CommandDispatcher::Core # Parse options @@channel_opts.parse(args) { |opt, idx, val| case opt - when "-l" + when '-l' mode = :list - when "-c", "-k" + when '-c', '-k' mode = :close chan = val - when "-i" + when '-i' mode = :interact chan = val - when "-r" + when '-r' mode = :read chan = val - when "-w" + when '-w' mode = :write chan = val end + if @@channel_opts.arg_required?(opt) unless chan - print_error("Channel ID required") + print_error('Channel ID required') return end end @@ -213,12 +215,7 @@ class Console::CommandDispatcher::Core when :list tbl = Rex::Text::Table.new( 'Indent' => 4, - 'Columns' => - [ - 'Id', - 'Class', - 'Type' - ]) + 'Columns' => ['Id', 'Class', 'Type']) items = 0 client.channels.each_pair { |cid, channel| @@ -227,7 +224,7 @@ class Console::CommandDispatcher::Core } if (items == 0) - print_line("No active channels.") + print_line('No active channels.') else print("\n" + tbl.to_s + "\n") end @@ -251,7 +248,7 @@ class Console::CommandDispatcher::Core @@channel_opts.fmt.keys when 2 case words[1] - when "-k", "-c", "-i", "-r", "-w" + when '-k', '-c', '-i', '-r', '-w' tab_complete_channels else [] @@ -262,9 +259,9 @@ class Console::CommandDispatcher::Core end def cmd_close_help - print_line "Usage: close " + print_line('Usage: close ') print_line - print_line "Closes the supplied channel." + print_line('Closes the supplied channel.') print_line end @@ -272,22 +269,22 @@ class Console::CommandDispatcher::Core # Closes a supplied channel. # def cmd_close(*args) - if (args.length == 0) + if args.length == 0 cmd_close_help return true end - cid = args[0].to_i + cid = args[0].to_i channel = client.find_channel(cid) - if (!channel) - print_error("Invalid channel identifier specified.") + unless channel + print_error('Invalid channel identifier specified.') return true - else - channel._close # Issue #410 - - print_status("Closed channel #{cid}.") end + + channel._close # Issue #410 + + print_status("Closed channel #{cid}.") end def cmd_close_tabs(str, words) @@ -300,7 +297,7 @@ class Console::CommandDispatcher::Core # Terminates the meterpreter session. # def cmd_exit(*args) - print_status("Shutting down Meterpreter...") + print_status('Shutting down Meterpreter...') client.core.shutdown rescue nil client.shutdown_passive_dispatcher shell.stop @@ -309,13 +306,13 @@ class Console::CommandDispatcher::Core alias cmd_quit cmd_exit def cmd_detach_help - print_line "Detach from the victim. Only possible for non-stream sessions (http/https)" + 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('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("This session may #{client.passive_service ? "" : "NOT"} be detached.") print_line end @@ -328,9 +325,9 @@ class Console::CommandDispatcher::Core end def cmd_interact_help - print_line "Usage: interact " + print_line('Usage: interact ') print_line - print_line "Interacts with the supplied channel." + print_line('Interacts with the supplied channel.') print_line end @@ -338,29 +335,29 @@ class Console::CommandDispatcher::Core # Interacts with a channel. # def cmd_interact(*args) - if (args.length == 0) + if args.length == 0 cmd_info_help return true end - cid = args[0].to_i + cid = args[0].to_i channel = client.find_channel(cid) - if (channel) + if channel print_line("Interacting with channel #{cid}...\n") shell.interact_with_channel(channel) else - print_error("Invalid channel identifier specified.") + print_error('Invalid channel identifier specified.') end end alias cmd_interact_tabs cmd_close_tabs def cmd_irb_help - print_line "Usage: irb" + print_line('Usage: irb') print_line - print_line "Execute commands in a Ruby environment" + print_line('Execute commands in a Ruby environment') print @@irb_opts.usage end @@ -384,8 +381,9 @@ class Console::CommandDispatcher::Core framework = client.framework if expressions.empty? - print_status("Starting IRB shell") - print_status("The 'client' variable holds the meterpreter client\n") + print_status('Starting IRB shell') + print_status('The "client" variable holds the meterpreter client') + print_line Rex::Ui::Text::IrbShell.new(binding).run else @@ -394,11 +392,11 @@ class Console::CommandDispatcher::Core end @@set_timeouts_opts = Rex::Parser::Arguments.new( - '-c' => [ true, 'Comms timeout (seconds)' ], - '-x' => [ true, 'Expiration timout (seconds)' ], - '-t' => [ true, 'Retry total time (seconds)' ], - '-w' => [ true, 'Retry wait time (seconds)' ], - '-h' => [ false, 'Help menu' ]) + '-c' => [true, 'Comms timeout (seconds)'], + '-x' => [true, 'Expiration timout (seconds)'], + '-t' => [true, 'Retry total time (seconds)'], + '-w' => [true, 'Retry wait time (seconds)'], + '-h' => [false, 'Help menu']) def cmd_set_timeouts_help print_line('Usage: set_timeouts [options]') @@ -409,7 +407,7 @@ class Console::CommandDispatcher::Core end def cmd_set_timeouts(*args) - if ( args.length == 0 or args.include?("-h") ) + if args.length == 0 || args.include?('-h') cmd_set_timeouts_help return end @@ -430,7 +428,7 @@ class Console::CommandDispatcher::Core end if opts.keys.length == 0 - print_error("No options set") + print_error('No options set') else timeouts = client.core.set_transport_timeouts(opts) print_timeouts(timeouts) @@ -467,6 +465,14 @@ class Console::CommandDispatcher::Core print_good("Machine ID: #{client.machine_id}") end + # + # Get the session GUID + # + def cmd_guid(*args) + client.guid = client.core.get_session_guid unless client.guid + print_good("Session GUID: #{client.guid}") + end + # # Get the machine ID of the target (should always be up to date locally) # @@ -534,7 +540,7 @@ class Console::CommandDispatcher::Core if hash print_good("SSL verification is enabled. SHA1 Hash: #{hash.unpack("H*")[0]}") else - print_good("SSL verification is disabled.") + print_good('SSL verification is disabled.') end elsif enable @@ -542,14 +548,14 @@ class Console::CommandDispatcher::Core if hash print_good("SSL verification has been enabled. SHA1 Hash: #{hash.unpack("H*")[0]}") else - print_error("Failed to enable SSL verification") + 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") + print_error('Failed to disable SSL verification') end end @@ -598,25 +604,25 @@ class Console::CommandDispatcher::Core # Arguments for transport switching # @@transport_opts = Rex::Parser::Arguments.new( - '-t' => [ true, "Transport type: #{Rex::Post::Meterpreter::ClientCore::VALID_TRANSPORTS.keys.join(', ')}" ], - '-l' => [ true, 'LHOST parameter (for reverse transports)' ], - '-p' => [ true, 'LPORT parameter' ], - '-i' => [ true, 'Specify transport by index (currently supported: remove)' ], - '-u' => [ true, 'Custom URI for HTTP/S transports (used when removing transports)' ], - '-lu' => [ true, 'Local URI for HTTP/S transports (used when adding/changing transports with a custom LURI)' ], - '-ua' => [ true, 'User agent for HTTP/S transports (optional)' ], - '-ph' => [ true, 'Proxy host for HTTP/S transports (optional)' ], - '-pp' => [ true, 'Proxy port for HTTP/S transports (optional)' ], - '-pu' => [ true, 'Proxy username for HTTP/S transports (optional)' ], - '-ps' => [ true, 'Proxy password for HTTP/S transports (optional)' ], - '-pt' => [ true, 'Proxy type for HTTP/S transports (optional: http, socks; default: http)' ], - '-c' => [ true, 'SSL certificate path for https transport verification (optional)' ], - '-to' => [ true, 'Comms timeout (seconds) (default: same as current session)' ], - '-ex' => [ true, 'Expiration timout (seconds) (default: same as current session)' ], - '-rt' => [ true, 'Retry total time (seconds) (default: same as current session)' ], - '-rw' => [ true, 'Retry wait time (seconds) (default: same as current session)' ], - '-v' => [ false, 'Show the verbose format of the transport list' ], - '-h' => [ false, 'Help menu' ]) + '-t' => [true, "Transport type: #{Rex::Post::Meterpreter::ClientCore::VALID_TRANSPORTS.keys.join(', ')}"], + '-l' => [true, 'LHOST parameter (for reverse transports)'], + '-p' => [true, 'LPORT parameter'], + '-i' => [true, 'Specify transport by index (currently supported: remove)'], + '-u' => [true, 'Custom URI for HTTP/S transports (used when removing transports)'], + '-lu' => [true, 'Local URI for HTTP/S transports (used when adding/changing transports with a custom LURI)'], + '-ua' => [true, 'User agent for HTTP/S transports (optional)'], + '-ph' => [true, 'Proxy host for HTTP/S transports (optional)'], + '-pp' => [true, 'Proxy port for HTTP/S transports (optional)'], + '-pu' => [true, 'Proxy username for HTTP/S transports (optional)'], + '-ps' => [true, 'Proxy password for HTTP/S transports (optional)'], + '-pt' => [true, 'Proxy type for HTTP/S transports (optional: http, socks; default: http)'], + '-c' => [true, 'SSL certificate path for https transport verification (optional)'], + '-to' => [true, 'Comms timeout (seconds) (default: same as current session)'], + '-ex' => [true, 'Expiration timout (seconds) (default: same as current session)'], + '-rt' => [true, 'Retry total time (seconds) (default: same as current session)'], + '-rw' => [true, 'Retry wait time (seconds) (default: same as current session)'], + '-v' => [false, 'Show the verbose format of the transport list'], + '-h' => [false, 'Help menu']) # # Display help for transport management. @@ -656,23 +662,23 @@ class Console::CommandDispatcher::Core 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 + :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 @@ -742,14 +748,7 @@ class Console::CommandDispatcher::Core # this will output the session timeout first print_timeouts(result) - columns =[ - 'ID', - 'Curr', - 'URL', - 'Comms T/O', - 'Retry Total', - 'Retry Wait' - ] + columns = ['ID', 'Curr', 'URL', 'Comms T/O', 'Retry Total', 'Retry Wait'] if opts[:verbose] columns << 'User Agent' @@ -766,8 +765,8 @@ class Console::CommandDispatcher::Core '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] ] + 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] @@ -782,42 +781,42 @@ class Console::CommandDispatcher::Core print("\n" + tbl.to_s + "\n") when 'next' - print_status("Changing to next transport ...") + print_status('Changing to next transport ...') if client.core.transport_next - print_good("Successfully changed to the next transport, killing current session.") + 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") + print_error('Failed to change transport, please check the parameters') end when 'prev' - print_status("Changing to previous transport ...") + print_status('Changing to previous transport ...') if client.core.transport_prev - print_good("Successfully changed to the previous transport, killing current session.") + 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") + print_error('Failed to change transport, please check the parameters') end when 'change' - print_status("Changing to new transport ...") + 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") + print_error('Failed to change transport, please check the parameters') end when 'add' - print_status("Adding new transport ...") + 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") + 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") + print_error('HTTP/S transport specified without session URI') return end @@ -829,7 +828,7 @@ class Console::CommandDispatcher::Core opts[:transport] = "reverse_#{uri.scheme}" opts[:lhost] = uri.host opts[:lport] = uri.port - opts[:uri] = uri.path[1..-2] if uri.scheme.include?("http") + opts[:uri] = uri.path[1..-2] if uri.scheme.include?('http') rescue URI::InvalidURIError print_error("Failed to parse URL: #{url_to_delete}") @@ -837,11 +836,11 @@ class Console::CommandDispatcher::Core end end - print_status("Removing transport ...") + 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") + print_error('Failed to remove transport, please check the parameters') end end end @@ -849,8 +848,8 @@ class Console::CommandDispatcher::Core @@migrate_opts = Rex::Parser::Arguments.new( '-P' => [true, 'PID to migrate to.'], '-N' => [true, 'Process name to migrate to.'], - '-p' => [true, 'Writable path - Linux only (eg. /tmp).'], - '-t' => [true, 'The number of seconds to wait for migration to finish (default: 60).'], + '-p' => [true, 'Writable path - Linux only (eg. /tmp).'], + '-t' => [true, 'The number of seconds to wait for migration to finish (default: 60).'], '-h' => [false, 'Help menu.'] ) @@ -898,7 +897,7 @@ class Console::CommandDispatcher::Core pid = val.to_i when '-N' if val.to_s.empty? - print_error("No process name provided") + print_error('No process name provided') return end # this will migrate to the first process with a matching name @@ -980,23 +979,23 @@ class Console::CommandDispatcher::Core end def cmd_load_help - print_line("Usage: load ext1 ext2 ext3 ...") + print_line('Usage: load ext1 ext2 ext3 ...') print_line - print_line "Loads a meterpreter extension module or modules." - print_line @@load_opts.usage + print_line('Loads a meterpreter extension module or modules.') + print_line(@@load_opts.usage) end # # Loads one or more meterpreter extensions. # def cmd_load(*args) - if (args.length == 0) - args.unshift("-h") + if args.length == 0 + args.unshift('-h') end @@load_opts.parse(args) { |opt, idx, val| case opt - when "-l" + when '-l' exts = SortedSet.new msf_path = MetasploitPayloads.msf_meterpreter_dir gem_path = MetasploitPayloads.local_meterpreter_dir @@ -1010,7 +1009,7 @@ class Console::CommandDispatcher::Core print(exts.to_a.join("\n") + "\n") return true - when "-h" + when '-h' cmd_load_help return true end @@ -1038,7 +1037,7 @@ class Console::CommandDispatcher::Core next end - print_line("success.") + print_line('Success.') } return true @@ -1068,9 +1067,9 @@ class Console::CommandDispatcher::Core alias cmd_use_tabs cmd_load_tabs def cmd_read_help - print_line "Usage: read [length]" + print_line('Usage: read [length]') print_line - print_line "Reads data from the supplied channel." + print_line('Reads data from the supplied channel.') print_line end @@ -1078,7 +1077,7 @@ class Console::CommandDispatcher::Core # Reads data from a channel. # def cmd_read(*args) - if (args.length == 0) + if args.length == 0 cmd_read_help return true end @@ -1087,17 +1086,17 @@ class Console::CommandDispatcher::Core length = (args.length >= 2) ? args[1].to_i : 16384 channel = client.find_channel(cid) - if (!channel) + unless channel print_error("Channel #{cid} is not valid.") return true end data = channel.read(length) - if (data and data.length) + if data && data.length print("Read #{data.length} bytes from #{cid}:\n\n#{data}\n") else - print_error("No data was returned.") + print_error('No data was returned.') end return true @@ -1106,11 +1105,11 @@ class Console::CommandDispatcher::Core alias cmd_read_tabs cmd_close_tabs def cmd_run_help - print_line "Usage: run