外刊君还在考虑在公司内做一些 Node.js 的尝试,正要撸起袖子写几行代码,就被这个漏洞给吓尿了, 。妈啊,这种惊天大漏洞,外刊君今年试点 Node.js 的 kpi 是不是完不成了?
读了读上面这三篇文章,文中都提到了一个 node-serialize 的 Node.js 库。这个库提供的 API unserialize 函数提供了注入的可能:
- var serialize = require('node-serialize');
- var payload = '{"rce":"_$$ND_FUNC$$_function(){require(\'child_process\').exec(\'ls /\',function(error, stdout, stderr) { console.log(stdout)});}()"}';
- serialize.unserialize(payload);
unserialize 内部有这么一段代码(简单起见,我稍微加工了一下):
- if (obj[key].indexOf('_$$ND_FUNC$$_') === 0) {
- obj[key] = eval('(' + obj[key].substring('_$$ND_FUNC$$_'.length) + ')');
- }
我们简化一下,
- eval('(function(){require(\'child_process\').exec(\'ls /\',function(error, stdout, stderr) { console.log(stdout)});}()"})')
简化一下例子,如果用户输入 {"rce":"_$$ND_FUNC$$_process.exit()"},就能把服务器给停掉。
- eval('(process.exit())')
看看国家安全漏洞共享平台是怎么说的:
根据漏洞研究者测试结果,由于涉及 IIFE 函数表达式,漏洞影响到 Node.js 现有的所有版本。根据 CNVD 秘书处的普查结果,目前互联网上直接标定使用 node.js 运行环境的服务器约有 6.8 万余台,其中排名前五名的国家和地区是美国(占比 58.9%)、中国(23.2%)、英国(4.1%)、荷兰(3.6%)、德国(3.0%)。由于一个应用广泛的名为 Express 的 web 应用开发框架是基于 node.js 运行环境的,根据 CNVD 秘书处初步普查结果,受该漏洞影响的网站服务器有可能超过 70 万台,后续 CNVD 将进一步进行漏洞实际威胁影响的精确评估,做好境内用户的应急响应工作。
本段的说法有几点有待商磋。
由于涉及 IIFE 函数表达式,漏洞影响到 Node.js 现有的所有版本:这个漏洞处在 eval 函数而不是 IIFE;本文的开头已经给出了对应 CVE(通用漏洞列表)的链接 :
Apache Struts 2.3.20.x before 2.3.20.3, 2.3.24.x before 2.3.24.3, and 2.3.28.x before 2.3.28.1, when Dynamic Method Invocation is enabled, allow remote attackers to execute arbitrary code via vectors related to an ! (exclamation mark) operator to the REST Plugin.
例子是 Apache Struts 的,攻击者可以远程通过动态调用来实现攻击。这与 eval 的问题是异曲同工的。
由于一个应用广泛的名为 Express 的 WEB 应用开发框架是基于 node.js 运行环境的,根据 CNVD 秘书处初步普查结果,受该漏洞影响的网站服务器有可能超过 70 万台:node-serialize 包的有问题,就推导出 Node.js 有问题,然后再说使用 Express 的这 70 万台服务器有问题,这似乎没有道理。
狭隘地说,这个漏洞只是类库 node-serialize 在使用 eval 这种 JavaScript 社区不推荐使用的函数造成的。这不是 Node.js 的漏洞,因为问题并不是出现在 Node.js 的源码中。
影响有多大呢?外刊君去看了这个项目在 github 上的 star 是 20,在 上可以看到有几个类库依赖它,但这些依赖它的类库每个月下载量甚至是个位数。因此影响超过 70 万台的说法完全是无中生有嘛。
往广里说,这其实是 JavaScript 自身的问题。JavaScript 提供了 eval 函数,对一段字符串形式的 JavaScript 代码进行求值。但是:
Don't use eval needlessly!
eval() is a dangerous function, which executes the code it's passed with the privileges of the caller. If you run eval() with a string that could be affected by a malicious party, you may end up running malicious code on the user's machine with the permissions of your webpage / extension. More importantly, third party code can see the scope in which eval() was invoked, which can lead to possible attacks in ways to which the similar Function is not susceptible.——
其实在 JavaScript 中已经非常不倡导使用 eval 很久了。
针对 node-serialize,这个漏洞无法从源码上修复。这个库的目标是:
Serialize a object including it's function into a JSON
将一个对象序列化成 JSON 字符串,包括这个对象上的函数。也就是在反序列化时,必须将字符串函数通过 eval 或者 new Function() 转成函数。实现这个库的目标,必须使用这种不安全的方式,因此无论 node-serialize 怎么处理对传入的字符串进行检查,都会留下不安全的隐患。
因此,库的作者给出了两条建议:
在外刊君看来,唯一修复或者避免这个漏洞的方法,就是不再使用 node-serialize 这个库,不再使用 eval 之类可以给注入者带来无限可能的 JavaScript 糟粕,尤其是在后端代码中。
eval 不能用,eval 不能用,eval 不能用,重要的事情说三遍。当然,new Function 也不能用,这是一个无限的坑。可以使用比如 ESLint 这样的工具来进行检查。
来源: http://www.tuicool.com/articles/uQ7F3aV