Skip to content

Commit 4f9c8d0

Browse files
committed
Add support for moving transports and uuid fetching
The 'next' and 'prev' commands were added so that the session can jump transports without having to add new ones at the same time. There's also a command which gives the UUID now so that this can be reused across sessions.
1 parent f711e5d commit 4f9c8d0

File tree

6 files changed

+172
-93
lines changed

6 files changed

+172
-93
lines changed

lib/msf/base/sessions/meterpreter.rb

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -307,8 +307,12 @@ def load_session_info()
307307
begin
308308
::Timeout.timeout(60) do
309309
# Gather username/system information
310-
username = self.sys.config.getuid
311-
sysinfo = self.sys.config.sysinfo
310+
username = self.sys.config.getuid
311+
sysinfo = self.sys.config.sysinfo
312+
313+
# TODO: use one of these to determine of the end shell is dead?
314+
self.payload_uuid = self.core.uuid
315+
self.machinie_id = self.core.machine_id
312316

313317
safe_info = "#{username} @ #{sysinfo['Computer']}"
314318
safe_info.force_encoding("ASCII-8BIT") if safe_info.respond_to?(:force_encoding)

lib/msf/base/sessions/meterpreter_options.rb

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -47,18 +47,6 @@ def on_session(session)
4747
session.load_session_info
4848
end
4949

50-
=begin
51-
admin = false
52-
begin
53-
::Timeout.timeout(30) do
54-
if session.railgun and session.railgun.shell32.IsUserAnAdmin()["return"] == true
55-
admin = true
56-
session.info += " (ADMIN)"
57-
end
58-
end
59-
rescue ::Exception
60-
end
61-
=end
6250
if session.platform =~ /win32|win64/i
6351
session.load_priv rescue nil
6452
end

lib/msf/core/session.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,10 @@ def alive?
377377
#
378378
attr_accessor :info
379379
#
380+
# The identifier for the machine of the current session
381+
#
382+
attr_accessor :machine_id
383+
#
380384
# The unique identifier of this session
381385
#
382386
attr_accessor :uuid

lib/rex/post/meterpreter/client_core.rb

Lines changed: 101 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,16 @@ def use(mod, opts = { })
273273
return true
274274
end
275275

276+
def uuid
277+
request = Packet.create_request('core_uuid')
278+
279+
response = client.send_request(request)
280+
281+
id = response.get_tlv_value(TLV_TYPE_UUID)
282+
283+
return id
284+
end
285+
276286
def machine_id
277287
request = Packet.create_request('core_machine_id')
278288

@@ -283,83 +293,34 @@ def machine_id
283293
return Rex::Text.md5(id)
284294
end
285295

286-
def transport_change(opts={})
287-
288-
unless valid_transport?(opts[:transport]) && opts[:lport]
289-
return false
290-
end
291-
292-
if opts[:transport].starts_with?('reverse')
293-
return false unless opts[:lhost]
294-
else
295-
# Bind shouldn't have lhost set
296-
opts[:lhost] = nil
297-
end
298-
299-
transport = VALID_TRANSPORTS[opts[:transport]]
300-
301-
request = Packet.create_request('core_transport_change')
302-
303-
scheme = opts[:transport].split('_')[1]
304-
url = "#{scheme}://#{opts[:lhost]}:#{opts[:lport]}"
305-
306-
if opts[:comm_timeout]
307-
request.add_tlv(TLV_TYPE_TRANS_COMM_TIMEOUT, opts[:comm_timeout])
308-
end
296+
def transport_add(opts={})
297+
request = transport_prepare_request('core_transport_add', opts)
309298

310-
if opts[:session_exp]
311-
request.add_tlv(TLV_TYPE_TRANS_SESSION_EXP, opts[:session_exp])
312-
end
313-
314-
if opts[:retry_total]
315-
request.add_tlv(TLV_TYPE_TRANS_RETRY_TOTAL, opts[:retry_total])
316-
end
317-
318-
if opts[:retry_wait]
319-
request.add_tlv(TLV_TYPE_TRANS_RETRY_WAIT, opts[:retry_wait])
320-
end
299+
return false unless request
321300

322-
# do more magic work for http(s) payloads
323-
unless opts[:transport].ends_with?('tcp')
324-
sum = uri_checksum_lookup(:connect)
325-
uuid = client.payload_uuid
326-
unless uuid
327-
arch, plat = client.platform.split('/')
328-
uuid = Msf::Payload::UUID.new({
329-
arch: arch,
330-
platform: plat.starts_with?('win') ? 'windows' : plat
331-
})
332-
end
333-
url << generate_uri_uuid(sum, uuid) + '/'
301+
client.send_request(request)
334302

335-
# TODO: randomise if not specified?
336-
opts[:ua] ||= 'Mozilla/4.0 (compatible; MSIE 6.1; Windows NT)'
337-
request.add_tlv(TLV_TYPE_TRANS_UA, opts[:ua])
303+
return true
304+
end
338305

339-
if transport == METERPRETER_TRANSPORT_HTTPS && opts[:cert]
340-
hash = Rex::Parser::X509Certificate.get_cert_file_hash(opts[:cert])
341-
request.add_tlv(TLV_TYPE_TRANS_CERT_HASH, hash)
342-
end
306+
def transport_change(opts={})
307+
request = transport_prepare_request('core_transport_change', opts)
343308

344-
if opts[:proxy_host] && opts[:proxy_port]
345-
prefix = 'http://'
346-
prefix = 'socks=' if opts[:proxy_type] == 'socks'
347-
proxy = "#{prefix}#{opts[:proxy_host]}:#{opts[:proxy_port]}"
348-
request.add_tlv(TLV_TYPE_TRANS_PROXY_INFO, proxy)
309+
return false unless request
349310

350-
if opts[:proxy_user]
351-
request.add_tlv(TLV_TYPE_TRANS_PROXY_USER, opts[:proxy_user])
352-
end
353-
if opts[:proxy_pass]
354-
request.add_tlv(TLV_TYPE_TRANS_PROXY_PASS, opts[:proxy_pass])
355-
end
356-
end
311+
client.send_request(request)
357312

358-
end
313+
return true
314+
end
359315

360-
request.add_tlv(TLV_TYPE_TRANS_TYPE, transport)
361-
request.add_tlv(TLV_TYPE_TRANS_URL, url)
316+
def transport_next
317+
request = Packet.create_request('core_transport_next')
318+
client.send_request(request)
319+
return true
320+
end
362321

322+
def transport_prev
323+
request = Packet.create_request('core_transport_prev')
363324
client.send_request(request)
364325
return true
365326
end
@@ -602,6 +563,78 @@ def valid_transport?(transport)
602563

603564
private
604565

566+
def transport_prepare_request(method, opts={})
567+
unless valid_transport?(opts[:transport]) && opts[:lport]
568+
return nil
569+
end
570+
571+
if opts[:transport].starts_with?('reverse')
572+
return false unless opts[:lhost]
573+
else
574+
# Bind shouldn't have lhost set
575+
opts[:lhost] = nil
576+
end
577+
578+
transport = VALID_TRANSPORTS[opts[:transport]]
579+
580+
request = Packet.create_request(method)
581+
582+
scheme = opts[:transport].split('_')[1]
583+
url = "#{scheme}://#{opts[:lhost]}:#{opts[:lport]}"
584+
585+
if opts[:comm_timeout]
586+
request.add_tlv(TLV_TYPE_TRANS_COMM_TIMEOUT, opts[:comm_timeout])
587+
end
588+
589+
if opts[:session_exp]
590+
request.add_tlv(TLV_TYPE_TRANS_SESSION_EXP, opts[:session_exp])
591+
end
592+
593+
if opts[:retry_total]
594+
request.add_tlv(TLV_TYPE_TRANS_RETRY_TOTAL, opts[:retry_total])
595+
end
596+
597+
if opts[:retry_wait]
598+
request.add_tlv(TLV_TYPE_TRANS_RETRY_WAIT, opts[:retry_wait])
599+
end
600+
601+
# do more magic work for http(s) payloads
602+
unless opts[:transport].ends_with?('tcp')
603+
sum = uri_checksum_lookup(:connect)
604+
url << generate_uri_uuid(sum, uuid) + '/'
605+
606+
# TODO: randomise if not specified?
607+
opts[:ua] ||= 'Mozilla/4.0 (compatible; MSIE 6.1; Windows NT)'
608+
request.add_tlv(TLV_TYPE_TRANS_UA, opts[:ua])
609+
610+
if transport == METERPRETER_TRANSPORT_HTTPS && opts[:cert]
611+
hash = Rex::Parser::X509Certificate.get_cert_file_hash(opts[:cert])
612+
request.add_tlv(TLV_TYPE_TRANS_CERT_HASH, hash)
613+
end
614+
615+
if opts[:proxy_host] && opts[:proxy_port]
616+
prefix = 'http://'
617+
prefix = 'socks=' if opts[:proxy_type] == 'socks'
618+
proxy = "#{prefix}#{opts[:proxy_host]}:#{opts[:proxy_port]}"
619+
request.add_tlv(TLV_TYPE_TRANS_PROXY_INFO, proxy)
620+
621+
if opts[:proxy_user]
622+
request.add_tlv(TLV_TYPE_TRANS_PROXY_USER, opts[:proxy_user])
623+
end
624+
if opts[:proxy_pass]
625+
request.add_tlv(TLV_TYPE_TRANS_PROXY_PASS, opts[:proxy_pass])
626+
end
627+
end
628+
629+
end
630+
631+
request.add_tlv(TLV_TYPE_TRANS_TYPE, transport)
632+
request.add_tlv(TLV_TYPE_TRANS_URL, url)
633+
634+
return request
635+
end
636+
637+
605638
def generate_payload_stub(process)
606639
case client.platform
607640
when /win/i

lib/rex/post/meterpreter/packet.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ module Meterpreter
101101
TLV_TYPE_TRANS_RETRY_WAIT = TLV_META_TYPE_UINT | 440
102102

103103
TLV_TYPE_MACHINE_ID = TLV_META_TYPE_STRING | 460
104+
TLV_TYPE_UUID = TLV_META_TYPE_STRING | 461
104105

105106
TLV_TYPE_CIPHER_NAME = TLV_META_TYPE_STRING | 500
106107
TLV_TYPE_CIPHER_PARAMETERS = TLV_META_TYPE_GROUP | 501
@@ -205,6 +206,7 @@ def inspect
205206
when TLV_TYPE_TRANS_RETRY_TOTAL; "TRANS-RETRY-TOTAL"
206207
when TLV_TYPE_TRANS_RETRY_WAIT; "TRANS-RETRY-WAIT"
207208
when TLV_TYPE_MACHINE_ID; "MACHINE-ID"
209+
when TLV_TYPE_UUID; "UUID"
208210

209211
#when Extensions::Stdapi::TLV_TYPE_NETWORK_INTERFACE; 'network-interface'
210212
#when Extensions::Stdapi::TLV_TYPE_IP; 'ip-address'

lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb

Lines changed: 59 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ def commands
5050
"use" => "Deprecated alias for 'load'",
5151
"load" => "Load one or more meterpreter extensions",
5252
"machine_id" => "Get the MSF ID of the machine attached to the session",
53+
"uuid" => "Get the UUID for the current session",
5354
"quit" => "Terminate the meterpreter session",
5455
"resource" => "Run the commands stored in a file",
5556
"read" => "Reads data from a channel",
@@ -392,7 +393,16 @@ def print_timeouts(timeouts)
392393
# Get the machine ID of the target
393394
#
394395
def cmd_machine_id(*args)
395-
print_good("Machine ID: #{client.core.machine_id}")
396+
client.machine_id = client.core.machine_id unless client.machine_id
397+
print_good("Machine ID: #{client.machine_id}")
398+
end
399+
400+
#
401+
# Get the machine ID of the target
402+
#
403+
def cmd_uuid(*args)
404+
client.payload_uuid = client.core.uuid unless client.payload_uuid
405+
print_good("UUID: #{client.payload_uuid}")
396406
end
397407

398408
#
@@ -497,24 +507,33 @@ def cmd_ssl_verify(*args)
497507
'-h' => [ false, 'Help menu' ])
498508

499509
#
500-
# Display help for transport switching
510+
# Display help for transport management.
501511
#
502512
def cmd_transport_help
503-
print_line('Usage: transport [options]')
513+
print_line('Usage: transport <change|add|next|prev> [options]')
504514
print_line
505-
print_line('Change the current Meterpreter transport mechanism')
515+
print_line(' add: add a new transport to the transport list.')
516+
print_line(' change: same as add, but changes directly to the added entry.')
517+
print_line(' next: jump to the next transport in the list (no options).')
518+
print_line(' prev: jump to the previous transport in the list (no options).')
506519
print_line(@@transport_opts.usage)
507520
end
508521

509522
#
510-
# Change the current transport setings.
523+
# Manage transports
511524
#
512525
def cmd_transport(*args)
513526
if ( args.length == 0 or args.include?("-h") )
514527
cmd_transport_help
515528
return
516529
end
517530

531+
command = args.shift
532+
unless ['add', 'change', 'prev', 'next'].include?(command)
533+
cmd_transport_help
534+
return
535+
end
536+
518537
opts = {
519538
:transport => nil,
520539
:lhost => nil,
@@ -569,12 +588,41 @@ def cmd_transport(*args)
569588
end
570589
end
571590

572-
print_status("Swapping transport ...")
573-
if client.core.transport_change(opts)
574-
client.shutdown_passive_dispatcher
575-
shell.stop
576-
else
577-
print_error("Failed to switch transport, please check the parameters")
591+
case command
592+
when 'next'
593+
print_status("Changing to next transport ...")
594+
if client.core.transport_next
595+
print_good("Successfully changed to the next transport, killing current session.")
596+
client.shutdown_passive_dispatcher
597+
shell.stop
598+
else
599+
print_error("Failed to change transport, please check the parameters")
600+
end
601+
when 'prev'
602+
print_status("Changing to previous transport ...")
603+
if client.core.transport_prev
604+
print_good("Successfully changed to the previous transport, killing current session.")
605+
client.shutdown_passive_dispatcher
606+
shell.stop
607+
else
608+
print_error("Failed to change transport, please check the parameters")
609+
end
610+
when 'change'
611+
print_status("Changing to new transport ...")
612+
if client.core.transport_change(opts)
613+
print_good("Successfully added #{opts[:transport]} transport, killing current session.")
614+
client.shutdown_passive_dispatcher
615+
shell.stop
616+
else
617+
print_error("Failed to change transport, please check the parameters")
618+
end
619+
when 'add'
620+
print_status("Adding new transport ...")
621+
if client.core.transport_add(opts)
622+
print_good("Successfully added #{opts[:transport]} transport.")
623+
else
624+
print_error("Failed to add transport, please check the parameters")
625+
end
578626
end
579627
end
580628

0 commit comments

Comments
 (0)