-
-
[翻译] 渗透测试Node.js应用
-
发表于: 2017-3-22 11:04 5614
-
在本文中我们将介绍,在渗透中遇到Node.js应用如何处理,以及常见的一些Node.js的漏洞。
Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。Node.js
使用了一个事件驱动、非阻塞式 I/O
的模型,使其对于数据敏感的应用程序来说既轻量又高效。它是单线类型的服务,这也意味着,任何善意的或恶意的DOS将直接导致服务挂死,所有接入的客户端离线,所以做好采用负载均衡的多实例方式。本文中,我们将介绍一些Node.js方面的漏洞,以及介绍在实际中如何利用。
与针对其他WEB应用的信息采集阶段一样,我们要留意比如特殊的cookies name[“connect.sid”],server以及X-powered-By等头信息。如下图所示,X-powered-By 显示该应用是基于Express框架的。之后,我们可以深挖更多关于此框架的漏洞信息。
现在我们知道了一个简单的判断Node.js应用的方法。我们继续关注一下其漏洞,常见漏洞类型如下:
Node.js的代码注入同样围绕著名的函数”eval”。所以,一定不要在你的代码中使用eval函数,同样也意味着不要直接将用户输入的数据直接插入到任何系统函数中,比如setTimeOut,setInterval等。
在我们的demo代码中,我们使用eval函数转换输入的参数类型,本例中是整型,之后将其相加,返回和。我们可以使用函数parseInt
实现相同的功能。
正如看到的,我们可以直接执行我们的payload,强制应用退出。
如下代码可以实现一个反向Shell
当review一段Node.js代码时,一定要留意模块child_process的函数,因为这个模块包含了创建一个新进程来执行系统命令的功能。如下,我们一段demo来执行Ping命令。但是没有验证穿入得参数ip,从而导致命令执行。
可以添加命令:ipconfig /all
正则表达式的DOS攻击主要围绕着术语叫做:Catastrophic Backtracking的方式来进行,暗含着正则引擎如何解析用户特定匹配模式语句。看如下的例子:
此处我们要查找以x开始,y结束的字符串,此刻有一个问题,如果用户输入的字符串并没有以y结尾,而是一直重复多个x呢?每一个x将导致重复backtrack,最终将会陷入无限的backtrack循环,直到确定结尾是否有y。如下我们可以看到正确的使用:
此处只提供了特定数量的x。日下图所示,执行时间增加了近1秒钟。Node.js是单线程程序,假设大量用户在同一时刻使用了同样的服务呢?
Node.js有一个奇怪的特性,允许一个参数有多个值。假设有一个参数叫做email,我们给这个参数传递了多个值,最终email参数将包含这两个值,两个值之间用逗号隔开。
该特性可用来进行参数解析漏洞的利用。
现在大部分应用程序都采用MVC架构。我们首先了解这个MVC是什么。MVC将应用程序分成三个逻辑组件:Model,View,Controller。其有效地帮助开发人员和软件架构师将业务逻辑从代码层面分离出来。
所有的URL被称为路由,保存在路由文件中。有一个“路由器”来协调当用户点击了链接http://www.example.com/abc时,应该触发那个控制器。
而在可信和不可信路由之间就容易产生这样一个问题,从名字我们就可以猜到,可信的路由就是某用户登陆以后有权限访问的页面URL。
为了演示这个功能, 我们构建了一个Node.js的测试平台Nodegoat。它是一个有多个用户的退休金管理平台。但是只有一个管理员可以查看其他用户的退休金。
如下所示,退休金路由(URL)并没有检查访问用户是否是管理员,因此任意的用户都能查看他人的退休金
。
如下所示,我们以普通用户身份登录,没有显示退休金的功能:
我们以管理员登录,该功能出现了:
为了验证上述漏洞,我们切换到普通用户,强制浏览器访问退休金页面,我们成功的查看到了页面的内容:
修复未保护的路由(URL)
我们增加一个isAdmin的中间件来确保只有管理员可以访问该页面:
之后,我们又一次尝试访问退休金页面,则被跳转到重新登陆页面:
当一个变量定义在全局作用域的范围内时,该应用上的所有的代码都可以访问和修改该变量值,这就容易产生一个confusion,不同的函数任意时刻访问这个变量可能会有相同的、不同的、甚至被覆盖的值。这个行为被称作Global
Namespace
Pollution(全局命名空间污染)。从安全的角度来看,这种行为可能会被利用,取决于存储在全局作用域的值是什么类型的变量或函数。
如下所示,我们定义了一个变量叫做global,我们只是简单的将其加一,然后打印:
问题就是,无论什么时候用户访问,该值都会加一,然后显示给用户。这中行为有一个风险,如果session token被存储在全局名字空间中,且和这样有相似的行为,则attacker可以轻易的猜测到下一个要分配给用户的session cookie。
XSS通常是由于在缺乏合适的有效的验证,不可信的用户输入被包含在了应用服务的响应当中。就Node.js而言,内置的模块没有对抗XSS攻击。这样会导致新手程序员会犯一些低级错误,而给attacker留下了一些可趁之机。
如下所示,我们直接显示了用户的输入,没有丝毫验证:
进一步利用:
在Node.js中为了对抗XSS攻击,显然我们需要实现上下文相关的过滤,我们可以使用一个包叫做html-entities,可以使用命令npm install html-entities安装。添加后的现象,可见payload并没有执行。
不安全的组件的问题影响所有你使用的第三方库。从一个安全角度来看,在使用这些库时,非常有必要review下它们的代码。查看它们官网的漏洞公告,来确保你使用的是最新和最稳定的版本。更进一步也可以使用特定的工具来自动检查这个风险,本节之后将提到。
我们使用nodegota来举例说明,它用到的一个包marked曾有一个版本有XSS漏洞。如下所示,当插入如下payload时,它一个link被嵌入JavaScript脚本。
我们可以使用现成的工具snyk和npm-check来自动验证不安全和过时的组件。可以使用如下命令来安装这些工具:
我们在测试程序nodegota上执行这些工具,看看效果。如下,npm-check的检查给一些不宜使用的包打flag,告诉我们这些包该升级了。
对于使用synk,你需要配置你的账户,配置好之后,切换到nodegoat的主目录,执行命令snyk test
。
如下所示:它发现了有漏洞的包,同时标记出来:
对于一个大型的应用来说实现代码review是一个极其费力的活,需要遍历成百上千行的代码。一般建议使用半自动化的方式来实现代码review。比如手工检查业务逻辑,同时自动完成重复性的那些工作,比如查找漏洞函数,包,模块的名字和配置等。确保所有的函数都进行了,用户输入的处理,文件的操作,数据库的查询,硬编码的信息,不安全的SSL/TLS版本,不安全的加密,全局变量等等。进一步,我们使用上述提到的工具snyk和node-check来检查过时和有漏洞的包。
从这个系列提到的漏洞中,我们可以得出,大部分的漏洞都是源于不安全的用户输入。因此,要经常进行过滤和验证用户的输入,确保使用了合适的中间件来避免不可信的流程。这篇文章没有提到Ajin Abraham开发的神奇的工具NodeJsScan。该工具是一款静态代码分析工具。它使用了大量的正则表达式规则来扫描可能的漏洞代码和不安全的配置,同时允许用户扩展自己的功能。可以从这下载NodeJsScan。
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课