作者:[niubl@TSRC](https://security.tencent.com/index.php/blog/msg/121?from=timeline&isappinstalled=0 "niubl@TSRC")
#### 1. 漏洞简介
2017年9月28日,公司扫描器发现某业务存在一例任意文件读取漏洞,团队跟进分析后发现这是Node.js和Express共同导致的一个通用漏洞。在我们准备告知官方时,发现Node.js官网于9月29号给出了漏洞公告,对应的CVE编号为CVE-2017-14849。
###### 1.1 关于Node.js
Node.js是一个Javascript运行环境(runtime),发布于2009年5月,由Ryan Dahl开发,实质是对Chrome V8引擎进行了封装。Node.js对一些特殊用例进行优化,提供替代的API,使得V8在非浏览器环境下运行得更好。
###### 1.2 关于Express
Express 是一个简洁而灵活的 node.js Web应用框架, 提供一系列强大特性帮助你创建各种Web应用。Express 不对 node.js 已有的特性进行二次抽象,我们只是在它之上扩展了Web应用所需的功能。丰富的HTTP工具以及来自Connect框架的中间件随取随用,创建强健、友好的API变得快速又简单。
###### 1.3 漏洞影响
Node.js 8.5.0 + Express 3.19.0-3.21.2
Node.js 8.5.0 + Express 4.11.0-4.15.5
#### 2. 漏洞演示
1. 安装Node.js 8.5.0
2. 下载并解压express-4.15.5.zip
3. expresss-4.15.5目录下执行npm install
4. expresss-4.15.5/examples/static-files目录里执行nodejs index.js
5. 使用POC测试(web监听了5678端口,默认3000)如下图
![](https://images.seebug.org/content/images/2017/11/39134d0a-2d62-4479-abd5-8ee044f1e928.png-w331s)
#### 3. 漏洞分析
Express依赖Send组件,Send组件0.11.0-0.15.6版本pipe()函数中,如图:
![](https://images.seebug.org/content/images/2017/11/75afe6b8-1f68-4d1c-b138-9b8bec538205.png-w331s)
Send模块通过`normalize('.' + sep + path)`标准化路径path后,并没有赋值给path,而是仅仅判断了下是否存在目录跳转字符。如果我们能绕过目录跳转字符的判断,就能把目录跳转字符带入545行的`join(root, path)`函数中,跳转到我们想要跳转到的目录中,这是Send模块的一个bug,目前已经修复。
再来看Node.js,Node.js 8.5.0对path.js文件中的`normalizeStringPosix`函数进行了修改,使其能够对路径做到如下的标准化:
```
assert.strictEqual(path.posix.normalize('bar/foo../..'), 'bar');
```
新的修改带来了问题,通过单步调试我们发现,可以通过`foo../../`和目录跳转字符一起注入到路径中,`foo../../`可以把变量`isAboveRoot`设置为`false`(代码161行),并且在代码135行把自己删掉;变量`isAboveRoot`为`false`的情况下,可以在`foo../../`两边设置同样数量的跳转字符,让他们同样在代码135行把自己删除,这样就可以构造出一个带有跳转字符,但是通过`normalizeStringPosix`函数标准化后又会全部自动移除的payload,这个payload配合上面提到的Send模块bug就能够成功的返回一个我们想要的物理路径,最后在Send模块中读取并返回文件。`normalizeStringPosix`函数如下图:
![](https://images.seebug.org/content/images/2017/11/6f883df5-1a57-44c3-b078-662bde331d43.png-w331s)
![](https://images.seebug.org/content/images/2017/11/a6e7a61c-da87-4880-8d16-3bdfd426e8bb.png-w331s)
暂无评论