diff --git a/lib/msf/core/exploit/http/client.rb b/lib/msf/core/exploit/http/client.rb index 5b57e2e408..5d6636e155 100644 --- a/lib/msf/core/exploit/http/client.rb +++ b/lib/msf/core/exploit/http/client.rb @@ -1,4 +1,5 @@ # -*- coding: binary -*- + require 'uri' require 'digest' require 'rex/proto/ntlm/crypt' @@ -370,24 +371,47 @@ module Exploit::Remote::HttpClient return res unless res && res.redirect? && redirect_depth > 0 redirect_depth -= 1 - location = res.redirection - return res if location.nil? - - opts['redirect_uri'] = location - opts['uri'] = location.path - opts['rhost'] = location.host - opts['vhost'] = location.host - opts['rport'] = location.port - - if location.scheme == 'https' - opts['ssl'] = true - else - opts['ssl'] = false - end + return res if res.redirection.nil? + reconfig_redirect_opts!(res, opts) send_request_cgi!(opts, actual_timeout, redirect_depth) end + + # Modifies the HTTP request options for a redirection. + # + # @param res [Rex::Proto::HTTP::Response] HTTP Response. + # @param opts [Hash] The HTTP request options to modify. + # @return [void] + def reconfig_redirect_opts!(res, opts) + location = res.redirection + + if location.relative? + parent_path = File.dirname(opts['uri'].to_s) + parent_path = '/' if parent_path == '.' + new_redirect_uri = normalize_uri(parent_path, location.path.gsub(/^\./, '')) + opts['redirect_uri'] = new_redirect_uri + opts['uri'] = new_redirect_uri + opts['rhost'] = datastore['RHOST'] + opts['vhost'] = opts['vhost'] || opts['rhost'] || self.vhost() + opts['rport'] = datastore['RPORT'] + + opts['ssl'] = ssl + else + opts['redirect_uri'] = location + opts['uri'] = location.path + opts['rhost'] = location.host + opts['vhost'] = location.host + opts['rport'] = location.port + + if location.scheme == 'https' + opts['ssl'] = true + else + opts['ssl'] = false + end + end + end + # # Combine the user/pass into an auth string for the HTTP Client # diff --git a/spec/lib/msf/core/exploit/http/client_spec.rb b/spec/lib/msf/core/exploit/http/client_spec.rb index dc7705294d..27756e1841 100644 --- a/spec/lib/msf/core/exploit/http/client_spec.rb +++ b/spec/lib/msf/core/exploit/http/client_spec.rb @@ -12,6 +12,38 @@ RSpec.describe Msf::Exploit::Remote::HttpClient do mod end + describe '#reconfig_redirect_opts!' do + context 'when URI is http://127.0.0.1/test/redirect.php' do + it 'should return /test/redirect.php as the URI path' do + res = Rex::Proto::Http::Response.new + allow(res).to receive(:headers).and_return({'Location'=>'http://127.0.0.1/test/redirect.php'}) + opts = {} + subject.reconfig_redirect_opts!(res, opts) + expect(opts['uri']).to eq('/test/redirect.php') + end + end + + context 'when URI is /test/redirect.php' do + it 'should return /test/redirect.php' do + res = Rex::Proto::Http::Response.new + allow(res).to receive(:headers).and_return({'Location'=>'/test/redirect.php'}) + opts = {} + subject.reconfig_redirect_opts!(res, opts) + expect(opts['uri']).to eq('/test/redirect.php') + end + end + + context 'when URI is ./redirect.php' do + it 'should return /redirect.php' do + res = Rex::Proto::Http::Response.new + allow(res).to receive(:headers).and_return({'Location'=>'./redirect.php'}) + opts = {} + subject.reconfig_redirect_opts!(res, opts) + expect(opts['uri']).to eq('/redirect.php') + end + end + end + describe '#vhost' do let(:rhost) do