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.rb
bug/bundler_fix
OJ 2015-05-05 17:18:01 +10:00
commit 62fa14326d
7 changed files with 149 additions and 43 deletions

View File

@ -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.

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -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:

View File

@ -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={})

View File

@ -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?))