Skip to content

Commit 37b9cd0

Browse files
committed
Add support for the session GUID in the UI
The Session GUID will identify active sessions, and is the beginning of work that will allow for tracking of sessions that have come back alive after failing or switching transports.
1 parent 8c35e54 commit 37b9cd0

28 files changed

+389
-240
lines changed

lib/msf/base/serializer/readable_text.rb

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -618,7 +618,6 @@ def self.dump_sessions_verbose(framework, opts={})
618618
sess_luri = session.exploit_datastore['LURI'] || ""
619619

620620
sess_checkin = "<none>"
621-
sess_machine_id = session.machine_id.to_s
622621
sess_registration = "No"
623622

624623
if session.respond_to? :platform
@@ -642,15 +641,12 @@ def self.dump_sessions_verbose(framework, opts={})
642641
out << " Tunnel: #{sess_tunnel}\n"
643642
out << " Via: #{sess_via}\n"
644643
out << " UUID: #{sess_uuid}\n"
645-
out << " MachineID: #{sess_machine_id}\n"
646644
out << " CheckIn: #{sess_checkin}\n"
647645
out << " Registered: #{sess_registration}\n"
648-
if !sess_luri.empty?
646+
unless sess_luri.empty?
649647
out << " LURI: #{sess_luri}\n"
650648
end
651649

652-
653-
654650
out << "\n"
655651
end
656652

lib/msf/base/sessions/meterpreter_options.rb

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,17 @@ def on_session(session)
5151
end
5252

5353
if valid
54+
# always make sure that the new session has a new guid if it's not already known
55+
guid = session.core.get_session_guid
56+
if guid == '00000000-0000-0000-0000-000000000000'
57+
guid = SecureRandom.uuid
58+
session.core.set_session_guid(guid)
59+
session.guid = guid
60+
# TODO: New statgeless session, do some account in the DB so we can track it later.
61+
else
62+
session.guid = guid
63+
# TODO: This session was either staged or previously known, and so we shold do some accounting here!
64+
end
5465

5566
if datastore['AutoLoadStdapi']
5667

@@ -71,7 +82,7 @@ def on_session(session)
7182
end
7283

7384
[ 'InitialAutoRunScript', 'AutoRunScript' ].each do |key|
74-
if !datastore[key].empty?
85+
unless datastore[key].empty?
7586
args = Shellwords.shellwords( datastore[key] )
7687
print_status("Session ID #{session.sid} (#{session.tunnel_to_s}) processing #{key} '#{datastore[key]}'")
7788
session.execute_script(args.shift, *args)

lib/msf/core/payload/android.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ def generate_config(opts={})
5151
arch: opts[:uuid].arch,
5252
expiration: ds['SessionExpirationTimeout'].to_i,
5353
uuid: opts[:uuid],
54-
transports: opts[:transport_config] || [transport_config(opts)]
54+
transports: opts[:transport_config] || [transport_config(opts)],
55+
stageless: opts[:stageless] == true
5556
}
5657

5758
config = Rex::Payloads::Meterpreter::Config.new(config_opts).to_b

lib/msf/core/payload/java/meterpreter_loader.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ def generate_config(opts={})
6969
arch: opts[:uuid].arch,
7070
expiration: ds['SessionExpirationTimeout'].to_i,
7171
uuid: opts[:uuid],
72-
transports: opts[:transport_config] || [transport_config(opts)]
72+
transports: opts[:transport_config] || [transport_config(opts)],
73+
stageless: opts[:stageless] == true
7374
}
7475

7576
# create the configuration instance based off the parameters

lib/msf/core/payload/python/meterpreter_loader.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,13 @@ def stage_meterpreter(opts={})
7474
uuid = Rex::Text.to_hex(uuid.to_raw, prefix = '')
7575
met.sub!("PAYLOAD_UUID = \'\'", "PAYLOAD_UUID = \'#{uuid}\'")
7676

77+
if opts[:stageless] == true
78+
session_guid = "00" * 16
79+
else
80+
session_guid = SecureRandom.uuid.gsub(/-/, '')
81+
end
82+
met.sub!("SESSION_GUID = \'\'", "SESSION_GUID = \'#{session_guid}\'.decode(\'hex\')")
83+
7784
http_user_agent = opts[:http_user_agent] || ds['MeterpreterUserAgent']
7885
http_proxy_host = opts[:http_proxy_host] || ds['PayloadProxyHost'] || ds['PROXYHOST']
7986
http_proxy_port = opts[:http_proxy_port] || ds['PayloadProxyPort'] || ds['PROXYPORT']

lib/msf/core/payload/windows/meterpreter_loader.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ def generate_config(opts={})
8282
expiration: ds['SessionExpirationTimeout'].to_i,
8383
uuid: opts[:uuid],
8484
transports: opts[:transport_config] || [transport_config(opts)],
85-
extensions: []
85+
extensions: [],
86+
stageless: opts[:stageless] == true
8687
}
8788

8889
# create the configuration instance based off the parameters

lib/msf/core/payload/windows/x64/meterpreter_loader.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@ def generate_config(opts={})
8484
expiration: ds['SessionExpirationTimeout'].to_i,
8585
uuid: opts[:uuid],
8686
transports: opts[:transport_config] || [transport_config(opts)],
87-
extensions: []
87+
extensions: [],
88+
stageless: opts[:stageless] == true
8889
}
8990

9091
# create the configuration instance based off the parameters

lib/msf/core/session.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,10 @@ def session_type
385385
#
386386
attr_accessor :machine_id
387387
#
388+
# The guid that identifies an active Meterpreter session
389+
#
390+
attr_accessor :guid
391+
#
388392
# The actual exploit module instance that created this session
389393
#
390394
attr_accessor :exploit

lib/rex/payloads/meterpreter/config.rb

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
require 'msf/core/payload/windows'
44
require 'msf/core/reflective_dll_loader'
55
require 'rex/socket/x509_certificate'
6+
require 'securerandom'
67

78
class Rex::Payloads::Meterpreter::Config
89

@@ -50,14 +51,23 @@ def session_block(opts)
5051
uuid = opts[:uuid].to_raw
5152
exit_func = Msf::Payload::Windows.exit_types[opts[:exitfunk]]
5253

54+
# if no session guid is given then we'll just pass the blank
55+
# guid through. this is important for stageless payloads
56+
if opts[:stageless] == true
57+
session_guid = "\x00" * 16
58+
else
59+
session_guid = [SecureRandom.uuid.gsub(/-/, '')].pack('H*')
60+
end
61+
5362
session_data = [
5463
0, # comms socket, patched in by the stager
5564
exit_func, # exit function identifer
5665
opts[:expiration], # Session expiry
57-
uuid # the UUID
66+
uuid, # the UUID
67+
session_guid # the Session GUID
5868
]
5969

60-
session_data.pack('VVVA*')
70+
session_data.pack('VVVA*A*')
6171
end
6272

6373
def transport_block(opts)

lib/rex/post/meterpreter/client_core.rb

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,9 @@ def transport_list
125125
result
126126
end
127127

128+
#
129+
# Set associated transport timeouts for the currently active transport.
130+
#
128131
def set_transport_timeouts(opts={})
129132
request = Packet.create_request('core_transport_set_timeouts')
130133

@@ -298,6 +301,9 @@ def use(mod, opts = { })
298301
return true
299302
end
300303

304+
#
305+
# Set the UUID on the target session.
306+
#
301307
def set_uuid(uuid)
302308
request = Packet.create_request('core_set_uuid')
303309
request.add_tlv(TLV_TYPE_UUID, uuid.to_raw)
@@ -307,10 +313,42 @@ def set_uuid(uuid)
307313
true
308314
end
309315

316+
#
317+
# Set the session GUID on the target session.
318+
#
319+
def set_session_guid(guid)
320+
request = Packet.create_request('core_set_session_guid')
321+
request.add_tlv(TLV_TYPE_SESSION_GUID, [guid.gsub(/-/, '')].pack('H*'))
322+
323+
client.send_request(request)
324+
325+
true
326+
end
327+
328+
#
329+
# Get the session GUID from the target session.
330+
#
331+
def get_session_guid(timeout=nil)
332+
request = Packet.create_request('core_get_session_guid')
333+
334+
args = [request]
335+
args << timeout if timeout
336+
337+
response = client.send_request(*args)
338+
339+
bytes = response.get_tlv_value(TLV_TYPE_SESSION_GUID)
340+
341+
parts = bytes.unpack('H*')[0]
342+
[parts[0, 8], parts[8, 4], parts[12, 4], parts[16, 4], parts[20, 12]].join('-')
343+
end
344+
345+
#
346+
# Get the machine ID from the target session.
347+
#
310348
def machine_id(timeout=nil)
311349
request = Packet.create_request('core_machine_id')
312350

313-
args = [ request ]
351+
args = [request]
314352
args << timeout if timeout
315353

316354
response = client.send_request(*args)
@@ -325,6 +363,9 @@ def machine_id(timeout=nil)
325363
Rex::Text.md5(mid.to_s.downcase.strip)
326364
end
327365

366+
#
367+
# Get the current native arch from the target session.
368+
#
328369
def native_arch(timeout=nil)
329370
# Not all meterpreter implementations support this
330371
request = Packet.create_request('core_native_arch')
@@ -337,6 +378,9 @@ def native_arch(timeout=nil)
337378
response.get_tlv_value(TLV_TYPE_STRING)
338379
end
339380

381+
#
382+
# Remove a transport from the session based on the provided options.
383+
#
340384
def transport_remove(opts={})
341385
request = transport_prepare_request('core_transport_remove', opts)
342386

@@ -347,6 +391,9 @@ def transport_remove(opts={})
347391
return true
348392
end
349393

394+
#
395+
# Add a transport to the session based on the provided options.
396+
#
350397
def transport_add(opts={})
351398
request = transport_prepare_request('core_transport_add', opts)
352399

@@ -357,6 +404,9 @@ def transport_add(opts={})
357404
return true
358405
end
359406

407+
#
408+
# Change the currently active transport on the session.
409+
#
360410
def transport_change(opts={})
361411
request = transport_prepare_request('core_transport_change', opts)
362412

@@ -367,6 +417,9 @@ def transport_change(opts={})
367417
return true
368418
end
369419

420+
#
421+
# Sleep the current session for the given number of seconds.
422+
#
370423
def transport_sleep(seconds)
371424
return false if seconds == 0
372425

@@ -379,12 +432,18 @@ def transport_sleep(seconds)
379432
return true
380433
end
381434

435+
#
436+
# Change the active transport to the next one in the transport list.
437+
#
382438
def transport_next
383439
request = Packet.create_request('core_transport_next')
384440
client.send_request(request)
385441
return true
386442
end
387443

444+
#
445+
# Change the active transport to the previous one in the transport list.
446+
#
388447
def transport_prev
389448
request = Packet.create_request('core_transport_prev')
390449
client.send_request(request)
@@ -623,10 +682,17 @@ def valid_transport?(transport)
623682

624683
private
625684

685+
#
686+
# Get a reference to the currently active transport.
687+
#
626688
def get_current_transport
627689
transport_list[:transports][0]
628690
end
629691

692+
#
693+
# Generate a migrate stub that is specific to the current transport type and the
694+
# target process.
695+
#
630696
def generate_migrate_stub(target_process)
631697
stub = nil
632698

@@ -663,6 +729,10 @@ def generate_migrate_stub(target_process)
663729
stub
664730
end
665731

732+
#
733+
# Helper function to prepare a transport request that will be sent to the
734+
# attached session.
735+
#
666736
def transport_prepare_request(method, opts={})
667737
unless valid_transport?(opts[:transport]) && opts[:lport]
668738
return nil
@@ -751,6 +821,9 @@ def transport_prepare_request(method, opts={})
751821
end
752822

753823

824+
#
825+
# Create a full migration payload specific to the target process.
826+
#
754827
def generate_migrate_payload(target_process)
755828
case client.platform
756829
when 'windows'
@@ -764,6 +837,9 @@ def generate_migrate_payload(target_process)
764837
blob
765838
end
766839

840+
#
841+
# Create a full Windows-specific migration payload specific to the target process.
842+
#
767843
def generate_migrate_windows_payload(target_process)
768844
c = Class.new( ::Msf::Payload )
769845
c.include( ::Msf::Payload::Stager )
@@ -783,16 +859,25 @@ def generate_migrate_windows_payload(target_process)
783859
migrate_stager.stage_meterpreter
784860
end
785861

862+
#
863+
# Create a full Linux-specific migration payload specific to the target process.
864+
#
786865
def generate_migrate_linux_payload
787866
MetasploitPayloads.read('meterpreter', 'msflinker_linux_x86.bin')
788867
end
789868

869+
#
870+
# Determine the elf entry poitn for the given payload.
871+
#
790872
def elf_ep(payload)
791873
elf = Rex::ElfParsey::Elf.new( Rex::ImageSource::Memory.new( payload ) )
792874
ep = elf.elf_header.e_entry
793875
return ep
794876
end
795877

878+
#
879+
# Get the tmp folder for the session.
880+
#
796881
def tmp_folder
797882
tmp = client.sys.config.getenv('TMPDIR')
798883

0 commit comments

Comments
 (0)