Don't raise in the middle

MSP-11343

This means we don't bomb out with an unhandled exception, instead
continuing attempting logins against the host even though it will never
succeed. Next up: verify state before running scan!()
This commit is contained in:
James Lee 2014-09-10 19:47:24 -05:00
parent 5477d5452e
commit 84e4db9035
2 changed files with 42 additions and 71 deletions

View File

@ -5,10 +5,6 @@ module Metasploit
module Framework
module LoginScanner
# I don't want to raise RuntimeError to be able to abort login
class GlassfishError < StandardError
end
# The Glassfish HTTP LoginScanner class provides methods to do login routines
# for Glassfish 2, 3 and 4.
class Glassfish < HTTP
@ -24,7 +20,6 @@ module Metasploit
# @return [String] Cookie session
attr_accessor :jsession
# Sends a HTTP request with Rex
#
# @param (see Rex::Proto::Http::Resquest#request_raw)
@ -126,9 +121,9 @@ module Metasploit
return {:status => Metasploit::Model::Login::Status::SUCCESSFUL, :proof => res.body}
end
elsif res && is_secure_admin_disabled?(res)
return {:status => Metasploit::Model::Login::Status::SUCCESSFUL, :proof => res.body}
return {:status => Metasploit::Model::Login::Status::DENIED_ACCESS, :proof => res.body}
elsif res && res.code == 400
raise GlassfishError, "400: Bad HTTP request from try_login"
return {:status => Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, :proof => res.body}
end
{:status => Metasploit::Model::Login::Status::INCORRECT, :proof => res.body}
@ -146,12 +141,10 @@ module Metasploit
case self.version
when /^[29]\.x$/
status = try_glassfish_2(credential)
result_opts.merge!(status: status[:status], proof:status[:proof])
result_opts.merge!(status)
when /^[34]\./
status = try_glassfish_3(credential)
result_opts.merge!(status: status[:status], proof:status[:proof])
else
raise GlassfishError, "Glassfish version '#{self.version}' not supported"
result_opts.merge!(status)
end
rescue ::EOFError, Rex::ConnectionError, ::Timeout::Error
result_opts.merge!(status: Metasploit::Model::Login::Status::UNABLE_TO_CONNECT)
@ -160,6 +153,29 @@ module Metasploit
Result.new(result_opts)
end
#
# Extract the target's glassfish version from the HTTP Server header
# (ex: Sun Java System Application Server 9.x)
#
# @param banner [String] `Server` header from a Glassfish service response
# @return [String] version string, e.g. '2.x'
# @return [nil] If the banner did not match any of the expected values
def extract_version(banner)
# Set version. Some GlassFish servers return banner "GlassFish v3".
if banner =~ /(GlassFish Server|Open Source Edition)[[:blank:]]*(\d\.\d)/
@version = $2
elsif banner =~ /GlassFish v(\d)/
@version = $1
elsif banner =~ /Sun GlassFish Enterprise Server v2/
@version = '2.x'
elsif banner =~ /Sun Java System Application Server 9/
@version = '9.x'
end
return @version
end
end
end
end

View File

@ -51,52 +51,11 @@ class Metasploit3 < Msf::Auxiliary
# the LoginScanner class so the authentication can proceed properly
#
def jsession
@jsession || ''
end
def set_jsession(res)
if res && res.get_cookies =~ /JSESSIONID=(\w*);/i
@scanner.jsession = $1
end
end
# Overrides the ssl method from HttpClient
def ssl
@scanner.ssl || datastore['SSL']
end
#
# Return GlassFish's edition (Open Source or Commercial) and version (2.x, 3.0, 3.1, 9.x, 4.0) and
# banner (ex: Sun Java System Application Server 9.x)
#
def get_version(res)
# Extract banner from response
banner = res.headers['Server'] || ''
# Default value for edition and glassfish version
edition = 'Commercial'
version = 'Unknown'
# Set edition (Open Source or Commercial)
p = /(Open Source|Sun GlassFish Enterprise Server|Sun Java System Application Server)/
edition = 'Open Source' if banner =~ p
# Set version. Some GlassFish servers return banner "GlassFish v3".
if banner =~ /(GlassFish Server|Open Source Edition)[[:blank:]]*(\d\.\d)/
version = $2
elsif banner =~ /GlassFish v(\d)/ && version.nil?
version = $1
elsif banner =~ /Sun GlassFish Enterprise Server v2/ && version == 'Unknown'
version = '2.x'
elsif banner =~ /Sun Java System Application Server 9/ && version == 'Unknown'
version = '9.x'
end
return edition, version, banner
end
#
# For a while, older versions of Glassfish didn't need to set a password for admin,
# but looks like no longer the case anymore, which means this method is getting useless
@ -107,14 +66,12 @@ class Metasploit3 < Msf::Auxiliary
if version =~ /^[29]\.x$/
res = send_request_cgi({'uri'=>'/applications/upload.jsf'})
set_jsession(res)
p = /<title>Deploy Enterprise Applications\/Modules/
if (res && res.code.to_i == 200 && res.body.match(p) != nil)
success = true
end
elsif version =~ /^3\./
res = send_request_cgi({'uri'=>'/common/applications/uploadFrame.jsf'})
set_jsession(res)
p = /<title>Deploy Applications or Modules/
if (res && res.code.to_i == 200 && res.body.match(p) != nil)
success = true
@ -185,6 +142,10 @@ class Metasploit3 < Msf::Auxiliary
print_brute :level => :good, :ip => ip, :msg => "Success: '#{result.credential}'"
do_report(ip, rport, result)
:next_user
when Metasploit::Model::Login::Status::DENIED_ACCESS
print_brute :level => :status, :ip => ip, :msg => "Correct credentials, but unable to login: '#{result.credential}'"
do_report(ip, rport, result)
:next_user
when Metasploit::Model::Login::Status::UNABLE_TO_CONNECT
print_brute :level => :verror, :ip => ip, :msg => "Could not connect"
invalidate_login(
@ -220,21 +181,20 @@ class Metasploit3 < Msf::Auxiliary
tried = false
begin
print_status("Sending a request to /common/index.jsf...")
print_brute :level=>:status, :ip=>rhost, :msg=>"Sending a request to /common/index.jsf..."
res = send_request_cgi({'uri'=>'/common/index.jsf'})
set_jsession(res)
# Abort if res returns nil due to an exception (broken pipe or timeout)
if res.nil?
print_error('Unable to get a response from the server.')
print_brute :level=>:error, :ip=>rhost, :msg=>'Unable to get a response from the server.'
return
end
# Automatic HTTP to HTTPS transition (when needed)
if @scanner.ssl == false && res && res.headers['Location'] =~ /^https:\/\//
print_status("Glassfish is asking us to use HTTPS")
print_status("SSL option automatically set to: true")
print_status("SSL version option automatically set to: #{datastore['SSLVersion']}")
print_brute :level=>:status, :ip=>rhost, :msg=>"Glassfish is asking us to use HTTPS"
print_brute :level=>:status, :ip=>rhost, :msg=>"SSL option automatically set to: true"
print_brute :level=>:status, :ip=>rhost, :msg=>"SSL version option automatically set to: #{datastore['SSLVersion']}"
@scanner.ssl = true
@scanner.ssl_version = datastore['SSLVersion']
# Set the SSL options, and let the exception handler to resend the HTTP request
@ -255,7 +215,6 @@ class Metasploit3 < Msf::Auxiliary
# A normal client starts with /login.jsf, so we start with /login.jsf
if res && res.code.to_i == 302
res = send_request_cgi({'uri' => '/login.jsf'})
set_jsession(res)
end
res
@ -268,21 +227,17 @@ class Metasploit3 < Msf::Auxiliary
def run_host(ip)
init_loginscanner(ip)
res = init_bruteforce
edition, version, banner = get_version(res)
@scanner.version = version
return if res.nil?
@scanner.extract_version(res.headers['Server'])
print_status('Checking if Glassfish requires a password...')
if version =~ /^[239]\.x$/ && is_password_required?(version)
print_brute :level=>:status, :ip=>rhost, :msg=>('Checking if Glassfish requires a password...')
if @scanner.version =~ /^[239]\.x$/ && is_password_required?(@scanner.version)
print_brute :level => :good, :ip => ip, :msg => "Note: This Glassfish does not require a password"
else
print_status("Glassfish is protected with a password")
print_brute :level=>:status, :ip=>rhost, :msg=>("Glassfish is protected with a password")
end
begin
bruteforce(ip) unless version.blank?
rescue ::Metasploit::Framework::LoginScanner::GlassfishError => e
print_error(e.message)
end
bruteforce(ip) unless @scanner.version.blank?
end
end