what you don't know can hurt you
Home Files News &[SERVICES_TAB]About Contact Add New

Contao CMS 3.2.4 Code Execution

Contao CMS 3.2.4 Code Execution
Posted Feb 4, 2014
Authored by Pedro Ribeiro

Contao CMS versions 3.2.4 and below suffer from a code execution vulnerability.

tags | advisory, code execution
advisories | CVE-2014-1860
SHA-256 | 3325f9526c412938ec9ebe20c8778c890efd75ee7fc5b9592bb65c2db48c7fbc

Contao CMS 3.2.4 Code Execution

Change Mirror Download
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 (pedrib@gmail.com) 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/


Login or Register to add favorites

File Archive:

April 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Apr 1st
    10 Files
  • 2
    Apr 2nd
    26 Files
  • 3
    Apr 3rd
    40 Files
  • 4
    Apr 4th
    6 Files
  • 5
    Apr 5th
    26 Files
  • 6
    Apr 6th
    0 Files
  • 7
    Apr 7th
    0 Files
  • 8
    Apr 8th
    22 Files
  • 9
    Apr 9th
    14 Files
  • 10
    Apr 10th
    10 Files
  • 11
    Apr 11th
    13 Files
  • 12
    Apr 12th
    14 Files
  • 13
    Apr 13th
    0 Files
  • 14
    Apr 14th
    0 Files
  • 15
    Apr 15th
    30 Files
  • 16
    Apr 16th
    10 Files
  • 17
    Apr 17th
    22 Files
  • 18
    Apr 18th
    45 Files
  • 19
    Apr 19th
    8 Files
  • 20
    Apr 20th
    0 Files
  • 21
    Apr 21st
    0 Files
  • 22
    Apr 22nd
    11 Files
  • 23
    Apr 23rd
    68 Files
  • 24
    Apr 24th
    0 Files
  • 25
    Apr 25th
    0 Files
  • 26
    Apr 26th
    0 Files
  • 27
    Apr 27th
    0 Files
  • 28
    Apr 28th
    0 Files
  • 29
    Apr 29th
    0 Files
  • 30
    Apr 30th
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2022 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close