Land #5004, Http Login Refactor
Land Wei's PR to refactor the http login scanner moving the send request code into it's own methodbug/bundler_fix
commit
6546d30505
|
@ -187,13 +187,66 @@ module Metasploit
|
|||
error_message
|
||||
end
|
||||
|
||||
# Sends a HTTP request with Rex
|
||||
#
|
||||
# @param [Hash] Native support includes the following (also see Rex::Proto::Http::Request#request_cgi)
|
||||
# @option opts[String] 'host' The remote host
|
||||
# @option opts[Fixnum] 'port' The remote port
|
||||
# @option opts[Boolean] 'ssl' The SSL setting, TrueClass or FalseClass
|
||||
# @option opts[String] 'proxies' The proxies setting
|
||||
# @option opts[Credential] 'credential' A credential object
|
||||
# @option opts['Hash'] 'context' A context
|
||||
# @raise [Rex::ConnectionError] One of these errors has occured: EOFError, Errno::ETIMEDOUT, Rex::ConnectionError, ::Timeout::Error
|
||||
# @return [Rex::Proto::Http::Response] The HTTP response
|
||||
# @return [NilClass] An error has occured while reading the response (see #Rex::Proto::Http::Client#read_response)
|
||||
def send_request(opts)
|
||||
rhost = opts['host'] || host
|
||||
rport = opts['rport'] || port
|
||||
cli_ssl = opts['ssl'] || ssl
|
||||
cli_ssl_version = opts['ssl_version'] || ssl_version
|
||||
cli_proxies = opts['proxies'] || proxies
|
||||
username = opts['credential'] ? opts['credential'].public : ''
|
||||
password = opts['credential'] ? opts['credential'].private : ''
|
||||
realm = opts['credential'] ? opts['credential'].realm : nil
|
||||
context = opts['context'] || { 'Msf' => framework, 'MsfExploit' => framework_module}
|
||||
|
||||
res = nil
|
||||
cli = Rex::Proto::Http::Client.new(
|
||||
rhost,
|
||||
rport,
|
||||
context,
|
||||
cli_ssl,
|
||||
cli_ssl_version,
|
||||
cli_proxies,
|
||||
username,
|
||||
password
|
||||
)
|
||||
configure_http_client(cli)
|
||||
|
||||
if realm
|
||||
cli.set_config('domain' => credential.realm)
|
||||
end
|
||||
|
||||
begin
|
||||
cli.connect
|
||||
req = cli.request_cgi(opts)
|
||||
res = cli.send_recv(req)
|
||||
rescue ::EOFError, Errno::ETIMEDOUT, Rex::ConnectionError, ::Timeout::Error => e
|
||||
raise Rex::ConnectionError, e.message
|
||||
ensure
|
||||
cli.close
|
||||
end
|
||||
|
||||
res
|
||||
end
|
||||
|
||||
|
||||
# Attempt a single login with a single credential against the target.
|
||||
#
|
||||
# @param credential [Credential] The credential object to attempt to
|
||||
# login with.
|
||||
# @return [Result] A Result object indicating success or failure
|
||||
def attempt_login(credential)
|
||||
|
||||
result_opts = {
|
||||
credential: credential,
|
||||
status: Metasploit::Model::Login::Status::INCORRECT,
|
||||
|
@ -209,32 +262,13 @@ module Metasploit
|
|||
result_opts[:service_name] = 'http'
|
||||
end
|
||||
|
||||
http_client = Rex::Proto::Http::Client.new(
|
||||
host, port, {'Msf' => framework, 'MsfExploit' => framework_module}, ssl, ssl_version,
|
||||
proxies, credential.public, credential.private
|
||||
)
|
||||
|
||||
configure_http_client(http_client)
|
||||
|
||||
if credential.realm
|
||||
http_client.set_config('domain' => credential.realm)
|
||||
end
|
||||
|
||||
begin
|
||||
http_client.connect
|
||||
request = http_client.request_cgi(
|
||||
'uri' => uri,
|
||||
'method' => method
|
||||
)
|
||||
|
||||
response = http_client.send_recv(request)
|
||||
response = send_request('credential'=>credential, 'uri'=>uri, 'method'=>method)
|
||||
if response && response.code == 200
|
||||
result_opts.merge!(status: Metasploit::Model::Login::Status::SUCCESSFUL, proof: response.headers)
|
||||
end
|
||||
rescue ::EOFError, Errno::ETIMEDOUT, Rex::ConnectionError, ::Timeout::Error => e
|
||||
rescue Rex::ConnectionError => e
|
||||
result_opts.merge!(status: Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: e)
|
||||
ensure
|
||||
http_client.close
|
||||
end
|
||||
|
||||
Result.new(result_opts)
|
||||
|
|
|
@ -27,41 +27,6 @@ module Metasploit
|
|||
end
|
||||
|
||||
|
||||
# Sends a HTTP request with Rex
|
||||
#
|
||||
# @param (see Rex::Proto::Http::Request#request_raw)
|
||||
# @raise [Rex::ConnectionError] Something has gone wrong while sending the HTTP request
|
||||
# @return [Rex::Proto::Http::Response] The HTTP response
|
||||
def send_request(opts)
|
||||
res = nil
|
||||
cli = Rex::Proto::Http::Client.new(host, port,
|
||||
{
|
||||
'Msf' => framework,
|
||||
'MsfExploit' => framework_module
|
||||
},
|
||||
ssl,
|
||||
ssl_version,
|
||||
proxies
|
||||
)
|
||||
configure_http_client(cli)
|
||||
begin
|
||||
cli.connect
|
||||
req = cli.request_cgi(opts)
|
||||
res = cli.send_recv(req)
|
||||
rescue ::Errno::EPIPE, ::Timeout::Error => e
|
||||
# We are trying to mimic the same type of exception rescuing in
|
||||
# Msf::Exploit::Remote::HttpClient. But instead of returning nil, we'll consistently
|
||||
# raise Rex::ConnectionError so the #attempt_login can return the error message back
|
||||
# to the login module.
|
||||
raise Rex::ConnectionError, e.message
|
||||
ensure
|
||||
cli.close
|
||||
end
|
||||
|
||||
res
|
||||
end
|
||||
|
||||
|
||||
# Returns the latest sid from Symantec Web Gateway.
|
||||
#
|
||||
# @returns [String] The PHP Session ID for Symantec Web Gateway login
|
||||
|
|
|
@ -8,4 +8,26 @@ describe Metasploit::Framework::LoginScanner::HTTP do
|
|||
it_behaves_like 'Metasploit::Framework::LoginScanner::RexSocket'
|
||||
it_behaves_like 'Metasploit::Framework::LoginScanner::HTTP'
|
||||
|
||||
subject do
|
||||
described_class.new
|
||||
end
|
||||
|
||||
let(:response) { Rex::Proto::Http::Response.new(200, 'OK') }
|
||||
|
||||
before(:each) do
|
||||
allow_any_instance_of(Rex::Proto::Http::Client).to receive(:request_cgi).with(any_args)
|
||||
allow_any_instance_of(Rex::Proto::Http::Client).to receive(:send_recv).with(any_args).and_return(response)
|
||||
allow_any_instance_of(Rex::Proto::Http::Client).to receive(:set_config).with(any_args)
|
||||
allow_any_instance_of(Rex::Proto::Http::Client).to receive(:close)
|
||||
allow_any_instance_of(Rex::Proto::Http::Client).to receive(:connect)
|
||||
end
|
||||
|
||||
describe '#send_request' do
|
||||
context 'when a valid request is sent' do
|
||||
it 'returns a response object' do
|
||||
expect(subject.send_request({'uri'=>'/'})).to be_kind_of(Rex::Proto::Http::Response)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -72,14 +72,6 @@ describe Metasploit::Framework::LoginScanner::SymantecWebGateway do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#send_request' do
|
||||
context 'when a valid request is sent' do
|
||||
it 'returns a response object' do
|
||||
expect(subject.send_request({'uri'=>'/'})).to be_kind_of(Rex::Proto::Http::Response)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#get_last_sid' do
|
||||
let(:response) do
|
||||
res = Rex::Proto::Http::Response.new(200, 'OK')
|
||||
|
|
Loading…
Reference in New Issue