Fix #6806 and #6820 - Fix send_request_cgi! redirection

This patch fixes two problems:

1. 6820 - If the HTTP server returns a relative path
   (example: /test), there is no host to extract, therefore the HOST
   header in the HTTP request ends up being empty. When the web
   server sees this, it might return an HTTP 400 Bad Request, and
   the redirection fails.

2. 6806 - If the HTTP server returns a relative path that begins
   with a dot, send_request_cgi! will literally send that in the
   GET request. Since that isn't a valid GET request path format,
   the redirection fails.

Fix #6806
Fix #6820
bug/bundler_fix
wchen-r7 2016-04-25 14:30:46 -05:00
parent f28d280199
commit 47d52a250e
2 changed files with 70 additions and 14 deletions

View File

@ -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
#

View File

@ -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