微擎cms整理


又是一次失败的rce审计

最新痴迷与找cms的反序列化漏洞,相对于框架而且,cms的难度大了许多,重要的是就算有反序列化的触发点,也不一定有反序列化的利用链

而且,在框架二次开发的cms中,利用链随随便便用,但是在单一cms,就需要特定的条件

微擎cms中site的entry的访问机制

听说之前存在未授权的,现在不得行了

model的获取是根据数据库ims_modules的那么参数获取的

这个时候如果存在direct变量就可以绕过登录检查

1
2
3
4
5
6
7
8
9
10
11
12
if (!$entry['direct']) {
checklogin();
$referer = (url_params(referer()));
if (empty($_W['isajax']) && empty($_W['ispost']) && empty($_GPC['version_id']) && intval($referer['version_id']) > 0 &&
('wxapp' == $referer['c'] ||
'site' == $referer['c'] && in_array($referer['a'], array('entry', 'nav')) ||
'home' == $referer['c'] && 'welcome' == $referer['a'] ||
'module' == $referer['c'] && in_array($referer['a'], array('manage-account', 'permission')))) {
itoast('', $_W['siteurl'] . '&version_id=' . $referer['version_id']);
}
...
}

但是这个是访问addons下的模块并创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
if (!defined('IN_MOBILE') || !class_exists($classname)) {
$classname = "{$name}ModuleSite";
if (!class_exists($classname)) {
$file = IA_ROOT . "/addons/{$name}/site.php";
if (!is_file($file)) {
$file = IA_ROOT . "/framework/builtin/{$name}/site.php";
}
if (!is_file($file)) {
trigger_error('ModuleSite Definition File Not Found ' . $file, E_USER_WARNING);

return null;
}
require $file;
}
}

没有的话就放弃吧,我本来是以为可以未首权访问当前site模块下的任意方法,其实不是

微擎cms的加载机制

load方法

  • load()->model() //加载模块
  • load()->func() //加载方法
  • load()->class() //加载类
  • load()->library() //加载类库
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
// load方法
function load() {
static $loader;
if (empty($loader)) {
$loader = new Loader();
}

return $loader;
}
...
...
// 类库加载机制
private $libraryMap = array(
'agent' => 'agent/agent.class',
'captcha' => 'captcha/captcha.class',
'pdo' => 'pdo/PDO.class',
'qrcode' => 'qrcode/phpqrcode',
'ftp' => 'ftp/ftp',
'pinyin' => 'pinyin/pinyin',
'pkcs7' => 'pkcs7/pkcs7Encoder',
'json' => 'json/JSON',
'phpmailer' => 'phpmailer/PHPMailerAutoload',
'oss' => 'alioss/autoload',
'qiniu' => 'qiniu/autoload',
'cosv5' => 'cosv5/index',
'sentry' => 'sentry/Raven/Autoloader',
);

之前的研究中,确定guzzlehttp第三方类库是存在完整的反序列化利用链的

在微擎cms中cosv5引用了此类库

要想利用反序列化利用链,需要查找,在什么地方调用了此类库

在系统定义的file_remote_upload方法中调用了此类库

1605768390506

在调用file_remote_upload的方法中有一处调用了file_delete方法

1605768490625

简单跟了下file_delete方法,以及其调用的过滤方法,对phar没什么影响就是不能使用../跳转目录了

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
function file_delete($file) {
global $_W;
if (empty($file)) {
return false;
}
$file = safe_gpc_path($file);
$file_extension = pathinfo($file, PATHINFO_EXTENSION);
if (in_array($file_extension, array('php', 'html', 'js', 'css', 'ttf', 'otf', 'eot', 'svg', 'woff'))) {
return false;
}

$uni_remote_setting = uni_setting_load('remote');
if (empty($uni_remote_setting['remote']) && empty($_W['setting']['remote']['type'])) {
if (file_exists(ATTACHMENT_ROOT . '/' . $file) && file_is_uni_attach(ATTACHMENT_ROOT . '/' . $file)) {
file_change_uni_attchsize(ATTACHMENT_ROOT . '/' . $file, false);
}
}
if (file_exists($file)) {
@unlink($file);
}
if (file_exists(ATTACHMENT_ROOT . '/' . $file)) {
@unlink(ATTACHMENT_ROOT . '/' . $file);
}

return true;
}

然后悲催的事情发生了,$file[‘path’]不可控,其他调用的地方均不可控,遂放弃

被阉割的ssrf

file控制器中的fetch操作

1605782426282

进入了ihttp_get方法

1605782715297

复现,访问一个存在的端口

1605782891567

不存在的端口会出错

1605782923555

历史漏洞

  • 任意文件删除

  • 1.8后台上传

  • 后台备份

文章地址:https://pan.baidu.com/s/1FQ_QnQ019yPAyjbt_Pqgbw

提取码:qius

经过测试,新版本中sql执行的功能已被删除

1605784490689

不存在run操作了,只是前端页面没有删而已,而且还不能访问

微擎中的$_GPC接收参数,对参数进行了转义实体编码等等

底层在对处理update、delete、save等方法时,又做了预处理,然后id类的参数全被加上了单引号,变成了字符型,所以常规从前端传入的,哪怕没有intval过滤,也是不存在注入

寻找注入的方式

  • 直接拼接的
  • 参数经过多重编码处理且可控

在editor下面有个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
28
29
30
31
32
33
34
35
36
37
if ($do == 'uc') {
if (!empty($_GPC['wapeditor'])) {
...
$data = array(
...
);
...

$nav = json_decode(ihtml_entity_decode($_GPC['wapeditor']['nav']), true);
$ids = array(0);
if (!empty($nav)) {
foreach ($nav as $row) {
$data = array(
'uniacid' => $_W['uniacid'],
'name' => $row['name'],
'position' => 2,
'url' => $row['url'],
'icon' => '',
'css' => iserializer($row['css']),
'status' => $row['status'],
'displayorder' => 0,
);
if (!empty($row['id'])) {
print_r($row);
table('site_nav')
->where(array(
'id' => $row['id'],
'uniacid' => $_W['uniacid']
))
->fill($data)
->save();
} else {
$data['status'] = 1;
table('site_nav')->fill($data)->save();
$row['id'] = pdo_insertid();
}
die('aaaaa');

可以发现,已经绕过了$_GPC的过滤,进入底层的处理函数

1607055645088