Skip to content

Commit 3080feb

Browse files
author
HD Moore
committed
Track the machine_id and drop non-responsive sessions automatically
1 parent d00f6a8 commit 3080feb

File tree

5 files changed

+61
-34
lines changed

5 files changed

+61
-34
lines changed

lib/msf/base/serializer/readable_text.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -597,7 +597,7 @@ def self.dump_sessions_verbose(framework, opts={})
597597
end
598598

599599
if session.respond_to?(:last_checkin) && session.last_checkin
600-
sess_checkin = "#{(Time.now.to_i - session.last_checkin.to_i)}s Ago @ #{session.last_checkin.to_s}"
600+
sess_checkin = "#{(Time.now.to_i - session.last_checkin.to_i)}s ago @ #{session.last_checkin.to_s}"
601601
end
602602

603603
out << " Session ID: #{sess_id}\n"

lib/msf/base/sessions/meterpreter.rb

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,24 @@ def load_priv()
298298
console.disable_output = original
299299
end
300300

301+
#
302+
# Validate session information by checking for a machine_id response
303+
#
304+
def is_valid_session?(timeout=10)
305+
return true if self.machine_id
306+
307+
begin
308+
self.machine_id = self.core.machine_id(timeout)
309+
return true
310+
rescue ::Rex::Post::Meterpreter::RequestError
311+
# This meterpreter doesn't support core_machine_id
312+
return true
313+
rescue ::Exception => e
314+
dlog("Session #{self.sid} did not respond to validation request #{e.class}: #{e}")
315+
end
316+
false
317+
end
318+
301319
#
302320
# Populate the session information.
303321
#

lib/msf/base/sessions/meterpreter_options.rb

Lines changed: 31 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ def initialize(info = {})
1212
register_advanced_options(
1313
[
1414
OptBool.new('AutoLoadStdapi', [true, "Automatically load the Stdapi extension", true]),
15+
OptBool.new('AutoVerifySession', [true, "Automatically verify and drop invalid sessions", true]),
1516
OptString.new('InitialAutoRunScript', [false, "An initial script to run on session creation (before AutoRunScript)", '']),
1617
OptString.new('AutoRunScript', [false, "A script to run automatically on session creation.", '']),
1718
OptBool.new('AutoSystemInfo', [true, "Automatically capture system information on initialization.", true]),
@@ -35,45 +36,47 @@ def on_session(session)
3536

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

38-
if (datastore['AutoLoadStdapi'] == true)
39+
valid = true
3940

40-
session.load_stdapi
41-
42-
if datastore['AutoSystemInfo']
43-
session.load_session_info
41+
if datastore['AutoVerifySession'] == true
42+
if not session.is_valid_session?
43+
print_error("Meterpreter session #{session.sid} is not valid and will be closed")
44+
valid = false
4445
end
46+
end
47+
48+
if valid
49+
50+
if datastore['AutoLoadStdapi'] == true
4551

46-
=begin
47-
admin = false
48-
begin
49-
::Timeout.timeout(30) do
50-
if session.railgun and session.railgun.shell32.IsUserAnAdmin()["return"] == true
51-
admin = true
52-
session.info += " (ADMIN)"
53-
end
52+
session.load_stdapi
53+
54+
if datastore['AutoSystemInfo']
55+
session.load_session_info
56+
end
57+
58+
if session.platform =~ /win32|win64/i
59+
session.load_priv rescue nil
5460
end
55-
rescue ::Exception
56-
end
57-
=end
58-
if session.platform =~ /win32|win64/i
59-
session.load_priv rescue nil
6061
end
61-
end
6262

63-
if session.platform =~ /android/i
64-
if datastore['AutoLoadAndroid']
65-
session.load_android
63+
if session.platform =~ /android/i
64+
if datastore['AutoLoadAndroid']
65+
session.load_android
66+
end
6667
end
67-
end
6868

69-
[ 'InitialAutoRunScript', 'AutoRunScript' ].each do |key|
70-
if (datastore[key].empty? == false)
71-
args = Shellwords.shellwords( datastore[key] )
72-
print_status("Session ID #{session.sid} (#{session.tunnel_to_s}) processing #{key} '#{datastore[key]}'")
73-
session.execute_script(args.shift, *args)
69+
[ 'InitialAutoRunScript', 'AutoRunScript' ].each do |key|
70+
if (datastore[key].empty? == false)
71+
args = Shellwords.shellwords( datastore[key] )
72+
print_status("Session ID #{session.sid} (#{session.tunnel_to_s}) processing #{key} '#{datastore[key]}'")
73+
session.execute_script(args.shift, *args)
74+
end
7475
end
7576
end
7677

78+
session.kill if not valid
79+
7780
}
7881

7982
end

lib/msf/core/session.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,10 @@ def alive?
389389
#
390390
attr_accessor :payload_uuid
391391
#
392+
# The unique machine identifier for the host that created this session
393+
#
394+
attr_accessor :machine_id
395+
#
392396
# The actual exploit module instance that created this session
393397
#
394398
attr_accessor :exploit

lib/rex/post/meterpreter/client_core.rb

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -245,14 +245,16 @@ def use(mod, opts = { })
245245
return true
246246
end
247247

248-
def machine_id
248+
def machine_id(timeout=nil)
249249
request = Packet.create_request('core_machine_id')
250250

251-
response = client.send_request(request)
251+
args = [ request ]
252+
args << timeout if timeout
253+
254+
response = client.send_request(*args)
252255

253-
id = response.get_tlv_value(TLV_TYPE_MACHINE_ID)
254-
# TODO: Determine if we're going to MD5/SHA1 this
255-
return Rex::Text.md5(id)
256+
mid = response.get_tlv_value(TLV_TYPE_MACHINE_ID)
257+
return Rex::Text.md5(mid)
256258
end
257259

258260
def transport_change(opts={})

0 commit comments

Comments
 (0)