Skip to content

Commit

Permalink
Only fire off on_session_open event after we know the session is fu…
Browse files Browse the repository at this point in the history
…lly initialised
  • Loading branch information
dwelch-r7 committed Mar 9, 2021
1 parent 17ef194 commit 38688e1
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 64 deletions.
121 changes: 58 additions & 63 deletions lib/msf/base/sessions/meterpreter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -122,87 +122,82 @@ def shell_init
def bootstrap(datastore = {}, handler = nil)
session = self

init_session = Proc.new do
# Configure unicode encoding before loading stdapi
session.encode_unicode = datastore['EnableUnicodeEncoding']
# Configure unicode encoding before loading stdapi
session.encode_unicode = datastore['EnableUnicodeEncoding']

session.init_ui(self.user_input, self.user_output)
session.init_ui(self.user_input, self.user_output)

verification_timeout = datastore['AutoVerifySessionTimeout']&.to_i || session.comm_timeout
begin
session.tlv_enc_key = session.core.negotiate_tlv_encryption(timeout: verification_timeout)
rescue Rex::TimeoutError
end

if session.tlv_enc_key.nil?
# Fail-closed if TLV encryption can't be negotiated (close the session as invalid)
dlog("Session #{session.sid} failed to negotiate TLV encryption")
print_error("Meterpreter session #{session.sid} is not valid and will be closed")
# Terminate the session without cleanup if it did not validate
session.skip_cleanup = true
session.kill
return nil
end
verification_timeout = datastore['AutoVerifySessionTimeout']&.to_i || session.comm_timeout
begin
session.tlv_enc_key = session.core.negotiate_tlv_encryption(timeout: verification_timeout)
rescue Rex::TimeoutError
end

# always make sure that the new session has a new guid if it's not already known
guid = session.session_guid
if guid == "\x00" * 16
guid = [SecureRandom.uuid.gsub(/-/, '')].pack('H*')
session.core.set_session_guid(guid)
session.session_guid = guid
# TODO: New stageless session, do some account in the DB so we can track it later.
else
# TODO: This session was either staged or previously known, and so we should do some accounting here!
end
if session.tlv_enc_key.nil?
# Fail-closed if TLV encryption can't be negotiated (close the session as invalid)
dlog("Session #{session.sid} failed to negotiate TLV encryption")
print_error("Meterpreter session #{session.sid} is not valid and will be closed")
# Terminate the session without cleanup if it did not validate
session.skip_cleanup = true
session.kill
return nil
end

session.commands.concat(session.core.get_loaded_extension_commands('core'))
# always make sure that the new session has a new guid if it's not already known
guid = session.session_guid
if guid == "\x00" * 16
guid = [SecureRandom.uuid.gsub(/-/, '')].pack('H*')
session.core.set_session_guid(guid)
session.session_guid = guid
# TODO: New stageless session, do some account in the DB so we can track it later.
else
# TODO: This session was either staged or previously known, and so we should do some accounting here!
end

# Unhook the process prior to loading stdapi to reduce logging/inspection by any AV/PSP
if datastore['AutoUnhookProcess'] == true
console.run_single('load unhook')
console.run_single('unhook_pe')
end
session.commands.concat(session.core.get_loaded_extension_commands('core'))

unless datastore['AutoLoadStdapi'] == false
# Unhook the process prior to loading stdapi to reduce logging/inspection by any AV/PSP
if datastore['AutoUnhookProcess'] == true
console.run_single('load unhook')
console.run_single('unhook_pe')
end

session.load_stdapi
unless datastore['AutoLoadStdapi'] == false

unless datastore['AutoSystemInfo'] == false
session.load_session_info
end
session.load_stdapi

# only load priv on native windows
# TODO: abstract this too, to remove windows stuff
if session.platform == 'windows' && [ARCH_X86, ARCH_X64].include?(session.arch)
session.load_priv rescue nil
end
unless datastore['AutoSystemInfo'] == false
session.load_session_info
end

# TODO: abstract this a little, perhaps a "post load" function that removes
# platform-specific stuff?
if session.platform == 'android'
session.load_android
# only load priv on native windows
# TODO: abstract this too, to remove windows stuff
if session.platform == 'windows' && [ARCH_X86, ARCH_X64].include?(session.arch)
session.load_priv rescue nil
end
end

['InitialAutoRunScript', 'AutoRunScript'].each do |key|
unless datastore[key].nil? || 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)
end
end
# TODO: abstract this a little, perhaps a "post load" function that removes
# platform-specific stuff?
if session.platform == 'android'
session.load_android
end

# Process the auto-run scripts for this session
if self.respond_to?(:process_autoruns)
self.process_autoruns(datastore)
['InitialAutoRunScript', 'AutoRunScript'].each do |key|
unless datastore[key].nil? || 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)
end
end

# Tell the handler that we have a session
handler.on_session(self) if handler
# Process the auto-run scripts for this session
if self.respond_to?(:process_autoruns)
self.process_autoruns(datastore)
end

# Defer the session initialization to the Session Manager scheduler
framework.sessions.schedule init_session
# Tell the handler that we have a session
handler.on_session(self) if handler
end

##
Expand Down
15 changes: 14 additions & 1 deletion lib/msf/core/handler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,11 @@ def create_session(conn, opts={})
# If the session is valid, register it with the framework and
# notify any waiters we may have.
if (s)
register_session(s)
# Defer the session registration to the Session Manager scheduler
registration = Proc.new do
register_session(s)
end
framework.sessions.schedule registration
end

return s
Expand All @@ -274,6 +278,15 @@ def register_session(session)
on_session(session)
end

# Notify the framework that we have a new session opening up...
# Don't let errant event handlers kill our session
begin
framework.events.on_session_open(session)
rescue ::Exception => e
wlog("Exception in on_session_open event handler: #{e.class}: #{e}")
wlog("Call Stack\n#{e.backtrace.join("\n")}")
end

# If there is an exploit associated with this payload, then let's notify
# anyone who is interested that this exploit succeeded
if assoc_exploit
Expand Down

0 comments on commit 38688e1

Please sign in to comment.