Skip to content

Commit faeffc3

Browse files
author
Brent Cook
committed
Land rapid7#8973, remove obsolete code from Meterpreter client core
2 parents d967ce4 + d8ee415 commit faeffc3

File tree

3 files changed

+90
-128
lines changed

3 files changed

+90
-128
lines changed

lib/msf/base/sessions/meterpreter_options.rb

Lines changed: 67 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,74 @@
33
require 'shellwords'
44

55
module Msf
6-
module Sessions
7-
module MeterpreterOptions
6+
module Sessions
7+
#
8+
# Defines common options across all Meterpreter implementations
9+
#
10+
module MeterpreterOptions
811

9-
def initialize(info = {})
10-
super(info)
12+
TIMEOUT_SESSION = 24 * 3600 * 7 # 1 week
13+
TIMEOUT_COMMS = 300 # 5 minutes
14+
TIMEOUT_RETRY_TOTAL = 60 * 60 # 1 hour
15+
TIMEOUT_RETRY_WAIT = 10 # 10 seconds
1116

12-
register_advanced_options(
13-
[
14-
OptBool.new('AutoLoadStdapi', [true, "Automatically load the Stdapi extension", true]),
15-
OptBool.new('AutoVerifySession', [true, "Automatically verify and drop invalid sessions", true]),
16-
OptInt.new('AutoVerifySessionTimeout', [false, "Timeout period to wait for session validation to occur, in seconds", 30]),
17-
OptString.new('InitialAutoRunScript', [false, "An initial script to run on session creation (before AutoRunScript)", '']),
18-
OptString.new('AutoRunScript', [false, "A script to run automatically on session creation.", '']),
19-
OptBool.new('AutoSystemInfo', [true, "Automatically capture system information on initialization.", true]),
20-
OptBool.new('EnableUnicodeEncoding', [true, "Automatically encode UTF-8 strings as hexadecimal", Rex::Compat.is_windows]),
21-
OptPath.new('HandlerSSLCert', [false, "Path to a SSL certificate in unified PEM format, ignored for HTTP transports"]),
22-
OptInt.new('SessionRetryTotal', [false, "Number of seconds try reconnecting for on network failure", Rex::Post::Meterpreter::ClientCore::TIMEOUT_RETRY_TOTAL]),
23-
OptInt.new('SessionRetryWait', [false, "Number of seconds to wait between reconnect attempts", Rex::Post::Meterpreter::ClientCore::TIMEOUT_RETRY_WAIT]),
24-
OptInt.new('SessionExpirationTimeout', [ false, 'The number of seconds before this session should be forcibly shut down', Rex::Post::Meterpreter::ClientCore::TIMEOUT_SESSION]),
25-
OptInt.new('SessionCommunicationTimeout', [ false, 'The number of seconds of no activity before this session should be killed', Rex::Post::Meterpreter::ClientCore::TIMEOUT_COMMS])
26-
], self.class)
27-
end
17+
def initialize(info = {})
18+
super(info)
2819

20+
register_advanced_options(
21+
[
22+
OptBool.new(
23+
'AutoLoadStdapi',
24+
[true, "Automatically load the Stdapi extension", true]
25+
),
26+
OptBool.new(
27+
'AutoVerifySession',
28+
[true, "Automatically verify and drop invalid sessions", true]
29+
),
30+
OptInt.new(
31+
'AutoVerifySessionTimeout',
32+
[false, "Timeout period to wait for session validation to occur, in seconds", 30]
33+
),
34+
OptString.new(
35+
'InitialAutoRunScript',
36+
[false, "An initial script to run on session creation (before AutoRunScript)", '']
37+
),
38+
OptString.new(
39+
'AutoRunScript',
40+
[false, "A script to run automatically on session creation.", '']
41+
),
42+
OptBool.new(
43+
'AutoSystemInfo',
44+
[true, "Automatically capture system information on initialization.", true]
45+
),
46+
OptBool.new(
47+
'EnableUnicodeEncoding',
48+
[true, "Automatically encode UTF-8 strings as hexadecimal", Rex::Compat.is_windows]
49+
),
50+
OptPath.new(
51+
'HandlerSSLCert',
52+
[false, "Path to a SSL certificate in unified PEM format, ignored for HTTP transports"]
53+
),
54+
OptInt.new(
55+
'SessionRetryTotal',
56+
[false, "Number of seconds try reconnecting for on network failure", TIMEOUT_RETRY_TOTAL]
57+
),
58+
OptInt.new(
59+
'SessionRetryWait',
60+
[false, "Number of seconds to wait between reconnect attempts", TIMEOUT_RETRY_WAIT]
61+
),
62+
OptInt.new(
63+
'SessionExpirationTimeout',
64+
[ false, 'The number of seconds before this session should be forcibly shut down', TIMEOUT_SESSION]
65+
),
66+
OptInt.new(
67+
'SessionCommunicationTimeout',
68+
[ false, 'The number of seconds of no activity before this session should be killed', TIMEOUT_COMMS]
69+
)
70+
],
71+
self.class
72+
)
73+
end
74+
end
75+
end
2976
end
30-
end
31-
end
32-

lib/rex/post/meterpreter/client_core.rb

Lines changed: 21 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -34,24 +34,12 @@ module Meterpreter
3434
###
3535
class ClientCore < Extension
3636

37-
UNIX_PATH_MAX = 108
38-
DEFAULT_SOCK_PATH = "/tmp/meterpreter.sock"
39-
40-
METERPRETER_TRANSPORT_SSL = 0
41-
METERPRETER_TRANSPORT_HTTP = 1
42-
METERPRETER_TRANSPORT_HTTPS = 2
43-
44-
TIMEOUT_SESSION = 24*3600*7 # 1 week
45-
TIMEOUT_COMMS = 300 # 5 minutes
46-
TIMEOUT_RETRY_TOTAL = 60*60 # 1 hour
47-
TIMEOUT_RETRY_WAIT = 10 # 10 seconds
48-
49-
VALID_TRANSPORTS = {
50-
'reverse_tcp' => METERPRETER_TRANSPORT_SSL,
51-
'reverse_http' => METERPRETER_TRANSPORT_HTTP,
52-
'reverse_https' => METERPRETER_TRANSPORT_HTTPS,
53-
'bind_tcp' => METERPRETER_TRANSPORT_SSL
54-
}
37+
VALID_TRANSPORTS = [
38+
'reverse_tcp',
39+
'reverse_http',
40+
'reverse_https',
41+
'bind_tcp'
42+
]
5543

5644
include Rex::Payloads::Meterpreter::UriChecksum
5745

@@ -577,46 +565,12 @@ def migrate(target_pid, writable_dir = nil, opts = {})
577565
raise RuntimeError, 'Cannot migrate into current process', caller
578566
end
579567

580-
if client.platform == 'linux'
581-
if writable_dir.to_s.strip.empty?
582-
writable_dir = tmp_folder
583-
end
584-
585-
stat_dir = client.fs.filestat.new(writable_dir)
586-
587-
unless stat_dir.directory?
588-
raise RuntimeError, "Directory #{writable_dir} not found", caller
589-
end
590-
# Rex::Post::FileStat#writable? isn't available
591-
end
592-
593568
migrate_stub = generate_migrate_stub(target_process)
594569
migrate_payload = generate_migrate_payload(target_process)
595570

596571
# Build the migration request
597572
request = Packet.create_request('core_migrate')
598573

599-
if client.platform == 'linux'
600-
socket_path = File.join(writable_dir, Rex::Text.rand_text_alpha_lower(5 + rand(5)))
601-
602-
if socket_path.length > UNIX_PATH_MAX - 1
603-
raise RuntimeError, 'The writable dir is too long', caller
604-
end
605-
606-
pos = migrate_payload.index(DEFAULT_SOCK_PATH)
607-
608-
if pos.nil?
609-
raise RuntimeError, 'The meterpreter binary is wrong', caller
610-
end
611-
612-
migrate_payload[pos, socket_path.length + 1] = socket_path + "\x00"
613-
614-
ep = elf_ep(migrate_payload)
615-
request.add_tlv(TLV_TYPE_MIGRATE_BASE_ADDR, 0x20040000)
616-
request.add_tlv(TLV_TYPE_MIGRATE_ENTRY_POINT, ep)
617-
request.add_tlv(TLV_TYPE_MIGRATE_SOCKET_PATH, socket_path, false, client.capabilities[:zlib])
618-
end
619-
620574
request.add_tlv(TLV_TYPE_MIGRATE_PID, target_pid)
621575
request.add_tlv(TLV_TYPE_MIGRATE_PAYLOAD_LEN, migrate_payload.length)
622576
request.add_tlv(TLV_TYPE_MIGRATE_PAYLOAD, migrate_payload, false, client.capabilities[:zlib])
@@ -722,11 +676,8 @@ def shutdown
722676
# Indicates if the given transport is a valid transport option.
723677
#
724678
def valid_transport?(transport)
725-
if transport
726-
VALID_TRANSPORTS.has_key?(transport.downcase)
727-
else
728-
false
729-
end
679+
return false if transport.nil?
680+
VALID_TRANSPORTS.include?(transport.downcase)
730681
end
731682

732683
#
@@ -830,11 +781,11 @@ def transport_prepare_request(method, opts={})
830781
opts[:lhost] = nil
831782
end
832783

833-
transport = VALID_TRANSPORTS[opts[:transport]]
784+
transport = opts[:transport].downcase
834785

835786
request = Packet.create_request(method)
836787

837-
scheme = opts[:transport].split('_')[1]
788+
scheme = transport.split('_')[1]
838789
url = "#{scheme}://#{opts[:lhost]}:#{opts[:lport]}"
839790

840791
if opts[:luri] && opts[:luri].length > 0
@@ -864,7 +815,7 @@ def transport_prepare_request(method, opts={})
864815
end
865816

866817
# do more magic work for http(s) payloads
867-
unless opts[:transport].ends_with?('tcp')
818+
unless transport.ends_with?('tcp')
868819
if opts[:uri]
869820
url << '/' unless opts[:uri].start_with?('/')
870821
url << opts[:uri]
@@ -878,7 +829,7 @@ def transport_prepare_request(method, opts={})
878829
opts[:ua] ||= 'Mozilla/4.0 (compatible; MSIE 6.1; Windows NT)'
879830
request.add_tlv(TLV_TYPE_TRANS_UA, opts[:ua])
880831

881-
if transport == METERPRETER_TRANSPORT_HTTPS && opts[:cert]
832+
if transport == 'reverse_https' && opts[:cert]
882833
hash = Rex::Socket::X509Certificate.get_cert_file_hash(opts[:cert])
883834
request.add_tlv(TLV_TYPE_TRANS_CERT_HASH, hash)
884835
end
@@ -902,24 +853,7 @@ def transport_prepare_request(method, opts={})
902853
request.add_tlv(TLV_TYPE_TRANS_TYPE, transport)
903854
request.add_tlv(TLV_TYPE_TRANS_URL, url)
904855

905-
return request
906-
end
907-
908-
909-
#
910-
# Create a full migration payload specific to the target process.
911-
#
912-
def generate_migrate_payload(target_process)
913-
case client.platform
914-
when 'windows'
915-
blob = generate_migrate_windows_payload(target_process)
916-
when 'linux'
917-
blob = generate_migrate_linux_payload
918-
else
919-
raise RuntimeError, "Unsupported platform '#{client.platform}'"
920-
end
921-
922-
blob
856+
request
923857
end
924858

925859
#
@@ -945,34 +879,18 @@ def generate_migrate_windows_payload(target_process)
945879
end
946880

947881
#
948-
# Create a full Linux-specific migration payload specific to the target process.
949-
#
950-
def generate_migrate_linux_payload
951-
MetasploitPayloads.read('meterpreter', 'msflinker_linux_x86.bin')
952-
end
953-
954-
#
955-
# Determine the elf entry poitn for the given payload.
956-
#
957-
def elf_ep(payload)
958-
elf = Rex::ElfParsey::Elf.new( Rex::ImageSource::Memory.new( payload ) )
959-
ep = elf.elf_header.e_entry
960-
return ep
961-
end
962-
963-
#
964-
# Get the tmp folder for the session.
882+
# Create a full migration payload specific to the target process.
965883
#
966-
def tmp_folder
967-
tmp = client.sys.config.getenv('TMPDIR')
968-
969-
if tmp.to_s.strip.empty?
970-
tmp = '/tmp'
884+
def generate_migrate_payload(target_process)
885+
case client.platform
886+
when 'windows'
887+
blob = generate_migrate_windows_payload(target_process)
888+
else
889+
raise RuntimeError, "Unsupported platform '#{client.platform}'"
971890
end
972891

973-
tmp
892+
blob
974893
end
975-
976894
end
977895

978896
end; end; end

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ def cmd_pivot_help
142142
print_line(@@pivot_opts.usage)
143143
print_line
144144
print_line('Supported pivot types:')
145-
print_line(' - pipe (using named pipes over SMB)')
145+
print_line(' - pipe (using named pipes over SMB)')
146146
print_line('Supported arhiectures:')
147147
@@pivot_supported_archs.each do |a|
148148
print_line(' - ' + a)
@@ -757,7 +757,7 @@ def cmd_sleep(*args)
757757
# Arguments for transport switching
758758
#
759759
@@transport_opts = Rex::Parser::Arguments.new(
760-
'-t' => [true, "Transport type: #{Rex::Post::Meterpreter::ClientCore::VALID_TRANSPORTS.keys.join(', ')}"],
760+
'-t' => [true, "Transport type: #{Rex::Post::Meterpreter::ClientCore::VALID_TRANSPORTS.join(', ')}"],
761761
'-l' => [true, 'LHOST parameter (for reverse transports)'],
762762
'-p' => [true, 'LPORT parameter'],
763763
'-i' => [true, 'Specify transport by index (currently supported: remove)'],

0 commit comments

Comments
 (0)