Lucene search
K

Contao CMS 3.2.4 Code Execution Vulnerability

🗓️ 05 Feb 2014 00:00:00Reported by Pedro RibeiroType 
zdt
 zdt
🔗 0day.today👁 76 Views

Contao CMS 3.2.4 Code Execution Vulnerability, PHP object injection through unserialize(

Related
Code
ReporterTitlePublishedViews
Family
CVE
CVE-2014-1860
8 Jan 202015:37
cve
Cvelist
CVE-2014-1860
8 Jan 202015:37
cvelist
EUVD
EUVD-2014-1923
7 Oct 202500:30
euvd
NVD
CVE-2014-1860
8 Jan 202016:15
nvd
Prion
Design/Logic Flaw
8 Jan 202016:15
prion
RedhatCVE
CVE-2014-1860
22 May 202505:41
redhatcve
Hi,

I have discovered a vulnerability that might lead to code execution in
Contao CMS <= 3.2.4
Contao CMS <= 3.2.4 does not properly validate user input in several
locations which is then passed directly into PHP's unserialize.

This has been fixed in Contao 3.2.5 as per commit:
https://github.com/contao/core/commit/8c9cb044bdc887a8202bb65a64545c025664f957
and
https://github.com/contao/core/commit/1717336598fdcf1ed3f4ad488e140147cb31516d

Announcements can be found at

https://contao.org/en/news/contao-3_2_5.html

https://contao.org/en/news/contao-2_11_14.html

Thanks to the Contao developers for being so responsive.
The full report can be found at my repo in
https://github.com/pedrib/PoC/blob/master/contao-3.2.4.txt

Regards,

Pedro Ribeiro
Agile Information Security


------
Proof of concept:

> Vulnerabilities in Contao 3.2.4
> Discovered by Pedro Ribeiro ([email protected]) of Agile Information Security

====================================================================
Vulnerability: PHP object injection leading to all kinds of badness
File(line): contao-core-3.2.4/system/modules/core/drivers/DC_Table.php(149)
File(line): contao-core-3.2.4/system/modules/core/drivers/DC_Folder.php(124)
File(line): contao-core-3.2.4/system/modules/core/widgets/KeyValueWizard.php(73)
File(line): Potentially many others that call deserialize with user input
Code snippet:

contao-core-3.2.4/system/modules/core/drivers/DC_Table.php(149):
if (\Input::post('FORM_SUBMIT') == 'tl_select')
{
$ids = deserialize(\Input::post('IDS'));

if (!is_array($ids) || empty($ids))
{
$this->reload();
}

$session = $this->Session->getData();
$session['CURRENT']['IDS'] = deserialize(\Input::post('IDS'));


contao-core-3.2.4/system/modules/core/drivers/DC_Folder.php(124):
if (\Input::post('FORM_SUBMIT') == 'tl_select')
{
$ids = deserialize(\Input::post('IDS'));


contao-core-3.2.4/system/modules/core/widgets/KeyValueWizard.php(73)
public function validate()
{
$mandatory = $this->mandatory;
$options = deserialize($this->getPost($this->strName));


deserialize from functions.php (starting at line 280):
/**
 * Return an unserialized array or the argument
 * @param mixed
 * @param boolean
 * @return mixed
 */
function deserialize($varValue, $blnForceArray=false)
{
if (is_array($varValue))
{
return $varValue;
}

if (!is_string($varValue))
{
return $blnForceArray ? (($varValue === null) ? array() : array($varValue)) : $varValue;
}
elseif (trim($varValue) == '')
{
return $blnForceArray ? array() : '';
}

$varUnserialized = @unserialize($varValue);

if (is_array($varUnserialized))
{
$varValue = $varUnserialized;
}
elseif ($blnForceArray)
{
$varValue = array($varValue);
}

return $varValue;
}


The Input class does good validation on POST and GET variables for XSS, but in this case it provides no protection because the malicious data is a well formed PHP object.

post from Input class:
public static function post($strKey, $blnDecodeEntities=false)
{
$strCacheKey = $blnDecodeEntities ? 'postDecoded' : 'postEncoded';

if (!isset(static::$arrCache[$strCacheKey][$strKey]))
{
$varValue = static::findPost($strKey);

if ($varValue === null)
{
return $varValue;
}

$varValue = static::stripSlashes($varValue);
$varValue = static::decodeEntities($varValue);
$varValue = static::xssClean($varValue, true);
$varValue = static::stripTags($varValue);

if (!$blnDecodeEntities)
{
$varValue = static::encodeSpecialChars($varValue);
}

static::$arrCache[$strCacheKey][$strKey] = $varValue;
}

return static::$arrCache[$strCacheKey][$strKey];
}


getPost from Widget class (starting at line 722):
/**
 * Find and return a $_POST variable
 *
 * @param string $strKey The variable name
 *
 * @return mixed The variable value
 */
protected function getPost($strKey)
{
$strMethod = $this->allowHtml ? 'postHtml' : 'post';

if ($this->preserveTags)
{
$strMethod = 'postRaw';
}

// Support arrays (thanks to Andreas Schempp)
$arrParts = explode('[', str_replace(']', '', $strKey));

if (!empty($arrParts))
{
$varValue = \Input::$strMethod(array_shift($arrParts), $this->decodeEntities);

foreach($arrParts as $part)
{
if (!is_array($varValue))
{
break;
}

$varValue = $varValue[$part];
}

return $varValue;
}

return \Input::$strMethod($strKey, $this->decodeEntities);
}


There are a few magic methods that seem exploitable.
For example on contao-core-3.2.4/system/modules/core/classes/FrontendUser.php, it might be possible to overwrite the admin session with another session by manipulating the intId parameter (which is the userID):
public function __destruct()
{
$session = $this->Session->getData();

if (!isset($_GET['pdf']) && !isset($_GET['file']) && !isset($_GET['id']) && $session['referer']['current'] != \Environment::get('requestUri'))
{
$session['referer']['last'] = $session['referer']['current'];
$session['referer']['current'] = substr(\Environment::get('requestUri'), strlen(TL_PATH) + 1);
}

$this->Session->setData($session);

if ($this->intId)
{
$this->Database->prepare("UPDATE " . $this->strTable . " SET session=? WHERE id=?")
->execute(serialize($session), $this->intId);
}
}


Overwriting configuration files in contao-core-3.2.4/system/modules/core/library/Contao/Config.php

/**
* Automatically save the local configuration
*/
public function __destruct()
{
if ($this->blnIsModified)
{
$this->save();
}
}


public function save()
{
if ($this->strTop == '')
{
$this->strTop = '<?php';
}

$strFile = trim($this->strTop) . "\n\n";
$strFile .= "### INSTALL SCRIPT START ###\n";

foreach ($this->arrData as $k=>$v)
{
$strFile .= "$k = $v\n";
}

$strFile .= "### INSTALL SCRIPT STOP ###\n";
$this->strBottom = trim($this->strBottom);

if ($this->strBottom != '')
{
$strFile .= "\n" . $this->strBottom . "\n";
}

$strTemp = md5(uniqid(mt_rand(), true));

// Write to a temp file first
$objFile = fopen(TL_ROOT . '/system/tmp/' . $strTemp, 'wb');
fputs($objFile, $strFile);
fclose($objFile);

// Make sure the file has been written (see #4483)
if (!filesize(TL_ROOT . '/system/tmp/' . $strTemp))
{
\System::log('The local configuration file could not be written. Have your reached your quota limit?', __METHOD__, TL_ERROR);
return;
}

// Then move the file to its final destination
$this->Files->rename('system/tmp/' . $strTemp, 'system/config/localconfig.php');


Arbitrary file deletion in contao-core-3.2.4/system/modules/core/library/Contao/ZipWriter.php:
public function __destruct()
{
if (is_resource($this->resFile))
{
@fclose($this->resFile);
}

if (file_exists($this->strTemp))
{
@unlink($this->strTemp);
}


Again arbitrary file deletion in contao-core-3.2.4/system/modules/core/vendor/swiftmailer/classes/Swift/ByteStream/TemporaryFileByteStream.php:
    public function __destruct()
    {
        if (file_exists($this->getPath())) {
            @unlink($this->getPath());
        }
    }


Comment:
User input is passed directly into unserialize(), possibly leading to code execution.

References:
https://www.owasp.org/index.php/PHP_Object_Injection
http://www.alertlogic.com/writing-exploits-for-exotic-bug-classes/
http://www.suspekt.org/downloads/POC2009-ShockingNewsInPHPExploitation.pdf
http://vagosec.org/2013/12/wordpress-rce-exploit/

#  0day.today [2018-02-06]  #

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation