MetInfo(米拓企业建站系统)是一款中文的开源企业网站管理系统,它能够帮助企业用户快速搭建、管理网站。

利用条件

  • MetInfo 6.x (6.0.0-6.1.3)

环境搭建

漏洞分析

XSS漏洞(CVE-2018-20486)

漏洞位于 admin/login/login_check.php 第12行,将 url_array 数组的一部分赋值给 turefileturefile 经过 authcode 加密插入数据库。

common.inc.php 第10行中,url_array 是本地文件的绝对路径分割而成的数组。

commin.inc.php 第77-82行,这是对传入的cookie、post和get方法的参数进行变量注册的循环,并且是在$url_array赋值之后,存在变量覆盖漏洞。

如果我们构造url_array[]的内容以get的方法上传至服务器会有什么效果呢?

/admin/login/login_check.php?url_array[]=inject here&url_array[]=a

可见,url_array的内容已经被修改成功。而turefile同样被修改,最终被存储在数据库,存在存储型xss漏洞。xss激活点位于 /app/system/safe/admin/index.class.php 的doindex方法中,此方法对应着后台的【安全-安全与效率】操作。

/app/system/safe/admin/index.clss.php 的行首调用了sys_class方法加载系统类文件,这里加载了/app/system/include/class/admin.class.php。

进到 admin.class.php ,发现admin类又继承了common类。

因此继承类的关系:index <- admin <- common,common中load_config_global()接口加载全站配置数据。将数据库所有的信息加载在 $_M 变量。

112行中 _M['config']['met_adminfile'] 解密,此时返回/app/system/safe/admin/index.class.php,解密后的XSS payload进入$localurl_admin

index.class.php中包含了模板/app/system/safe/admin/templates/index.php

跟进到index.php,未过滤直接输出了$localurl_admin,最终导致了XSS。

测试POC:/admin/login/login_check.php?url_array[]=<script>alert(1)</script>&url_array[]=a

进入后台,点击【效率与安全】直接触发。

任意文件写入漏洞(CVE-2018-13024)

漏洞发生在/admin/column/save.php的 column_copyconfig 函数。跟进 Copyindx()

1
2
3
4
5
6
7
8
function Copyindx($newindx,$type){
if(!file_exists($newindx)){
$oldcont ="<?php\n# MetInfo Enterprise Content Management System \n# Copyright (C) MetInfo Co.,Ltd (http://www.metinfo.cn). All rights reserved. \n\$filpy = basename(dirname(__FILE__));\n\$fmodule=$type;\nrequire_once '../include/module.php'; \nrequire_once \$module; \n# This program is an open source system, commercial use, please consciously to purchase commercial license.\n# Copyright (C) MetInfo Co., Ltd. (http://www.metinfo.cn). All rights reserved.\n?>";
$fp = fopen($newindx,w);
fputs($fp, $oldcont);
fclose($fp);
}
}

可以看到这里将 $type 变量直接写入了文件中,而 $type 变量一直可以追溯到column_copyconfig的$module变量而metinfo一个经典的伪全局变量覆盖,在/admin/include/common.inc.php中。

1
2
3
4
5
6
foreach(array('_COOKIE', '_POST', '_GET') as $_request) {
foreach($$_request as $_key => $_value) {
$_key{0} != '_' && $$_key = daddslashes($_value,0,0,1);
$_M['form'][$_key]=daddslashes($_value,0,0,1);
}
}

这样我们可以通过传入get参数,覆盖$module变量,导致任意文件写入。

中间人攻击(CVE-2018-9934)

如果我们知道了某个注册用户的邮箱,那么我们就能够通过头注入的方式重置任意用户的密码。所以这个漏洞的攻击前提是在于用户必须要绑定邮箱,且我们知道这个用户的邮箱。

正常的找回密码发送的请求如下:

通过这个图片可以看出来,由于我们是在本地搭建的,所有请求头是localhost。所以我们收到的重置密码的链接如下:

其中这个重置密码连接的Host头就是来自于我们上面找回密码发送请求时的Host头。如果我们修改找回密码时的请求头为我们的恶意Host,那么重置密码的链接也将发生改变。
所以如果一个攻击这修改了请求头为自己的DNS服务器,并且知道某位用户的邮箱,就可以发送一份伪造的重置密码的邮件到用户的邮箱。当用户点击之后,攻击者就可以收到这个请求包括其中的Token,攻击者将其替换为真实的请求头,那么就可以修改掉用户的密码了。

操作步骤如下:

1、修改重置密码请求的Host头

2、用户收到的重置密码邮箱如下:

3、用户点击重置密码的连接

4、攻击者通过自己的DNS服务器收到如下的信息。

5、攻击者将其替换为真实的请求头,让访问这个连接就可以修改用户的密码了。

漏洞原因:
造成这个漏洞的原因是在于,在进行邮件请求地址拼接的时候,使用是通过$_M取的host都信息,而$_M是通过$_SERVER[‘HTTP_HOST’]直接获取的HOST头信息,没有进行任何的校验,所以导致攻击者能够能够修改Host头信息,从而进行重置密码的链接的修改。