Merge branch 'upstream/master' into multi-transport-support
Merged with HD's stuff as he fixed up a few things that I had done too. Conflicts: lib/msf/base/sessions/meterpreter_options.rb lib/rex/post/meterpreter/client_core.rb lib/rex/post/meterpreter/packet_dispatcher.rbbug/bundler_fix
commit
62fa14326d
|
@ -527,6 +527,8 @@ class ReadableText
|
|||
indent = opts[:indent] || DefaultIndent
|
||||
col = opts[:col] || DefaultColumnWrap
|
||||
|
||||
return dump_sessions_verbose(framework, opts) if verbose
|
||||
|
||||
columns =
|
||||
[
|
||||
'Id',
|
||||
|
@ -535,9 +537,6 @@ class ReadableText
|
|||
'Connection'
|
||||
]
|
||||
|
||||
columns << 'Via' if verbose
|
||||
columns << 'PayloadId' if verbose
|
||||
|
||||
tbl = Rex::Ui::Text::Table.new(
|
||||
'Indent' => indent,
|
||||
'Header' => "Active sessions",
|
||||
|
@ -554,12 +553,7 @@ class ReadableText
|
|||
|
||||
row = [ session.sid.to_s, session.type.to_s, sinfo, session.tunnel_to_s + " (#{session.session_host})" ]
|
||||
if session.respond_to? :platform
|
||||
row[1] += " " + session.platform
|
||||
end
|
||||
|
||||
if verbose
|
||||
row << session.via_exploit.to_s
|
||||
row << session.payload_uuid.to_s
|
||||
row[1] << (" " + session.platform)
|
||||
end
|
||||
|
||||
tbl << row
|
||||
|
@ -568,6 +562,59 @@ class ReadableText
|
|||
return framework.sessions.length > 0 ? tbl.to_s : "#{tbl.header_to_s}No active sessions.\n"
|
||||
end
|
||||
|
||||
# Dumps the list of active sessions in verbose mode
|
||||
#
|
||||
# @param framework [Msf::Framework] the framework to dump.
|
||||
# @param opts [Hash] the options to dump with.
|
||||
# @option opts :session_ids [Array] the list of sessions to dump (no
|
||||
# effect).
|
||||
# @return [String] the formatted list of sessions.
|
||||
def self.dump_sessions_verbose(framework, opts={})
|
||||
ids = (opts[:session_ids] || framework.sessions.keys).sort
|
||||
|
||||
out = "Active sessions\n" +
|
||||
"===============\n\n"
|
||||
|
||||
if framework.sessions.length == 0
|
||||
out << "No active sessions.\n"
|
||||
return out
|
||||
end
|
||||
|
||||
framework.sessions.each_sorted do |k|
|
||||
session = framework.sessions[k]
|
||||
|
||||
sess_info = session.info.to_s
|
||||
sess_id = session.sid.to_s
|
||||
sess_tunnel = session.tunnel_to_s + " (#{session.session_host})"
|
||||
sess_via = session.via_exploit.to_s
|
||||
sess_type = session.type.to_s
|
||||
sess_uuid = session.payload_uuid.to_s
|
||||
sess_checkin = "<none>"
|
||||
sess_machine_id = session.machine_id.to_s
|
||||
|
||||
if session.respond_to? :platform
|
||||
sess_type << (" " + session.platform)
|
||||
end
|
||||
|
||||
if session.respond_to?(:last_checkin) && session.last_checkin
|
||||
sess_checkin = "#{(Time.now.to_i - session.last_checkin.to_i)}s ago @ #{session.last_checkin.to_s}"
|
||||
end
|
||||
|
||||
out << " Session ID: #{sess_id}\n"
|
||||
out << " Type: #{sess_type}\n"
|
||||
out << " Info: #{sess_info}\n"
|
||||
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 << "\n"
|
||||
end
|
||||
|
||||
out << "\n"
|
||||
return out
|
||||
end
|
||||
|
||||
# Dumps the list of running jobs.
|
||||
#
|
||||
# @param framework [Msf::Framework] the framework.
|
||||
|
|
|
@ -255,9 +255,10 @@ class Meterpreter < Rex::Post::Meterpreter::Client
|
|||
def kill
|
||||
begin
|
||||
cleanup_meterpreter
|
||||
self.sock.close
|
||||
self.sock.close if self.sock
|
||||
rescue ::Exception
|
||||
end
|
||||
# deregister will actually trigger another cleanup
|
||||
framework.sessions.deregister(self)
|
||||
end
|
||||
|
||||
|
@ -298,6 +299,24 @@ class Meterpreter < Rex::Post::Meterpreter::Client
|
|||
console.disable_output = original
|
||||
end
|
||||
|
||||
#
|
||||
# Validate session information by checking for a machine_id response
|
||||
#
|
||||
def is_valid_session?(timeout=10)
|
||||
return true if self.machine_id
|
||||
|
||||
begin
|
||||
self.machine_id = self.core.machine_id(timeout)
|
||||
return true
|
||||
rescue ::Rex::Post::Meterpreter::RequestError
|
||||
# This meterpreter doesn't support core_machine_id
|
||||
return true
|
||||
rescue ::Exception => e
|
||||
dlog("Session #{self.sid} did not respond to validation request #{e.class}: #{e}")
|
||||
end
|
||||
false
|
||||
end
|
||||
|
||||
#
|
||||
# Populate the session information.
|
||||
#
|
||||
|
@ -452,6 +471,7 @@ class Meterpreter < Rex::Post::Meterpreter::Client
|
|||
attr_accessor :binary_suffix
|
||||
attr_accessor :console # :nodoc:
|
||||
attr_accessor :skip_ssl
|
||||
attr_accessor :skip_cleanup
|
||||
attr_accessor :target_id
|
||||
|
||||
protected
|
||||
|
|
|
@ -12,6 +12,7 @@ module MeterpreterOptions
|
|||
register_advanced_options(
|
||||
[
|
||||
OptBool.new('AutoLoadStdapi', [true, "Automatically load the Stdapi extension", true]),
|
||||
OptBool.new('AutoVerifySession', [true, "Automatically verify and drop invalid sessions", true]),
|
||||
OptString.new('InitialAutoRunScript', [false, "An initial script to run on session creation (before AutoRunScript)", '']),
|
||||
OptString.new('AutoRunScript', [false, "A script to run automatically on session creation.", '']),
|
||||
OptBool.new('AutoSystemInfo', [true, "Automatically capture system information on initialization.", true]),
|
||||
|
@ -39,31 +40,49 @@ module MeterpreterOptions
|
|||
|
||||
session.init_ui(self.user_input, self.user_output)
|
||||
|
||||
if (datastore['AutoLoadStdapi'] == true)
|
||||
valid = true
|
||||
|
||||
session.load_stdapi
|
||||
|
||||
if datastore['AutoSystemInfo']
|
||||
session.load_session_info
|
||||
end
|
||||
|
||||
if session.platform =~ /win32|win64/i
|
||||
session.load_priv rescue nil
|
||||
if datastore['AutoVerifySession'] == true
|
||||
if not session.is_valid_session?
|
||||
print_error("Meterpreter session #{session.sid} is not valid and will be closed")
|
||||
valid = false
|
||||
end
|
||||
end
|
||||
|
||||
if session.platform =~ /android/i
|
||||
if datastore['AutoLoadAndroid']
|
||||
session.load_android
|
||||
if valid
|
||||
|
||||
if datastore['AutoLoadStdapi'] == true
|
||||
|
||||
session.load_stdapi
|
||||
|
||||
if datastore['AutoSystemInfo']
|
||||
session.load_session_info
|
||||
end
|
||||
|
||||
if session.platform =~ /win32|win64/i
|
||||
session.load_priv rescue nil
|
||||
end
|
||||
end
|
||||
|
||||
if session.platform =~ /android/i
|
||||
if datastore['AutoLoadAndroid']
|
||||
session.load_android
|
||||
end
|
||||
end
|
||||
|
||||
[ 'InitialAutoRunScript', 'AutoRunScript' ].each do |key|
|
||||
if (datastore[key].empty? == false)
|
||||
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)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
[ 'InitialAutoRunScript', 'AutoRunScript' ].each do |key|
|
||||
if (datastore[key].empty? == false)
|
||||
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)
|
||||
end
|
||||
# Terminate the session without cleanup if it did not validate
|
||||
if not valid
|
||||
session.skip_cleanup = true
|
||||
session.kill
|
||||
end
|
||||
|
||||
}
|
||||
|
|
|
@ -377,10 +377,6 @@ module Session
|
|||
#
|
||||
attr_accessor :info
|
||||
#
|
||||
# The identifier for the machine of the current session
|
||||
#
|
||||
attr_accessor :machine_id
|
||||
#
|
||||
# The unique identifier of this session
|
||||
#
|
||||
attr_accessor :uuid
|
||||
|
@ -393,6 +389,10 @@ module Session
|
|||
#
|
||||
attr_accessor :payload_uuid
|
||||
#
|
||||
# The unique machine identifier for the host that created this session
|
||||
#
|
||||
attr_accessor :machine_id
|
||||
#
|
||||
# The actual exploit module instance that created this session
|
||||
#
|
||||
attr_accessor :exploit
|
||||
|
|
|
@ -85,11 +85,18 @@ class Client
|
|||
# Cleans up the meterpreter instance, terminating the dispatcher thread.
|
||||
#
|
||||
def cleanup_meterpreter
|
||||
ext.aliases.each_value do | extension |
|
||||
extension.cleanup if extension.respond_to?( 'cleanup' )
|
||||
if not self.skip_cleanup
|
||||
ext.aliases.each_value do | extension |
|
||||
extension.cleanup if extension.respond_to?( 'cleanup' )
|
||||
end
|
||||
end
|
||||
|
||||
dispatcher_thread.kill if dispatcher_thread
|
||||
core.shutdown rescue nil
|
||||
|
||||
if not self.skip_cleanup
|
||||
core.shutdown rescue nil
|
||||
end
|
||||
|
||||
shutdown_passive_dispatcher
|
||||
end
|
||||
|
||||
|
@ -474,6 +481,10 @@ class Client
|
|||
# A list of the commands
|
||||
#
|
||||
attr_reader :commands
|
||||
#
|
||||
# The timestamp of the last received response
|
||||
#
|
||||
attr_accessor :last_checkin
|
||||
|
||||
protected
|
||||
attr_accessor :parser, :ext_aliases # :nodoc:
|
||||
|
|
|
@ -306,14 +306,16 @@ class ClientCore < Extension
|
|||
return Msf::Payload::UUID.new({:raw => id})
|
||||
end
|
||||
|
||||
def machine_id
|
||||
def machine_id(timeout=nil)
|
||||
request = Packet.create_request('core_machine_id')
|
||||
|
||||
response = client.send_request(request)
|
||||
args = [ request ]
|
||||
args << timeout if timeout
|
||||
|
||||
id = response.get_tlv_value(TLV_TYPE_MACHINE_ID)
|
||||
# TODO: Determine if we're going to MD5/SHA1 this
|
||||
return Rex::Text.md5(id)
|
||||
response = client.send_request(*args)
|
||||
|
||||
mid = response.get_tlv_value(TLV_TYPE_MACHINE_ID)
|
||||
return Rex::Text.md5(mid)
|
||||
end
|
||||
|
||||
def transport_add(opts={})
|
||||
|
|
|
@ -79,9 +79,11 @@ module PacketDispatcher
|
|||
|
||||
def shutdown_passive_dispatcher
|
||||
return if not self.passive_service
|
||||
resource = self.conn_id
|
||||
resource += "/" unless resource.end_with?("/")
|
||||
self.passive_service.remove_resource(resource)
|
||||
|
||||
# Ensure that there is only one leading and trailing slash on the URI
|
||||
resource_uri = "/" + self.conn_id.to_s.gsub(/(^\/|\/$)/, '') + "/"
|
||||
|
||||
self.passive_service.remove_resource(resource_uri)
|
||||
|
||||
# If there are no more resources registered on the service, stop it entirely
|
||||
if self.passive_service.resources.empty?
|
||||
|
@ -104,6 +106,8 @@ module PacketDispatcher
|
|||
resp['Content-Type'] = 'application/octet-stream'
|
||||
resp['Connection'] = 'close'
|
||||
|
||||
self.last_checkin = Time.now
|
||||
|
||||
# If the first 4 bytes are "RECV", return the oldest packet from the outbound queue
|
||||
if req.body[0,4] == "RECV"
|
||||
rpkt = send_queue.shift
|
||||
|
@ -496,6 +500,9 @@ module PacketDispatcher
|
|||
client = self
|
||||
end
|
||||
|
||||
# Update our last reply time
|
||||
client.last_checkin = Time.now
|
||||
|
||||
# If the packet is a response, try to notify any potential
|
||||
# waiters
|
||||
if ((resp = packet.response?))
|
||||
|
|
Loading…
Reference in New Issue