When we think about application security, we often focus on traditional attack vectors: buffer overflows, SQL injection, and other well-documented vulnerabilities. But using legitimate functionality for post exploitation activity is right up a red team's alley (and is a decent bypass technique). Swapping out native Node.js modules in Electron applications is what we’re talking about here.
Recent work from Atredis Partners shows succinctly that Node.js can be weaponized as a post-exploitation loader for your arbitrary code. This isn't exploiting a bug—it's leveraging intended functionality in ways that are difficult to prevent.
After we read their article, our intern, Claude, wrote two tools - one to find Electron applications that aren’t hardened against this, and one to simply compile Node.js addons.
.node
filesCompiled Node.js files (.node
files) are compiled binary files that allow Node.js applications to interface with native code written in languages like C, C++, or Objective-C as native addon modules.
Unlike JavaScript files which are mostly readable, assuming they’re not obfuscated and minified, .node
files are compiled binaries that can contain machine code and run with the same privileges as the Node.js process that loads them, without the constraints of the JavaScript sandbox. These extensions can directly call system APIs and perform operations that pure JavaScript code cannot, like making system calls.
These addons can use Objective-C++ to leverage native macOS APIs directly from Node.js. This allows arbitrary code execution outside the normal sandboxing that would constrain a typical Electron application.
When an Electron application uses a module that contains a compiled .node
file, it automatically loads and executes the binary code within it. Many Electron apps use the ASAR (Atom Shell Archive) file format to package the application's source code. ASAR integrity checking is a security feature that checks the file integrity and prevents tampering with files within the ASAR archive. It is disabled by default.
When ASAR integrity is enabled, your Electron app will verify the header hash of the ASAR archive on runtime. If no hash is present or if there is a mismatch in the hashes, the app will forcefully terminate.
This prevents files from being modified within the ASAR archive. Note that it appears the integrity check is a string that you can regenerate after modifying files, then find and replace in the executable file as well. See more here.
But many applications run from outside the verified archive, under app.asar.unpacked
since the compiled .node
files (the native modules) cannot be executed directly from within an ASAR archive.
And so even with the proper security features enabled, a local attacker can modify or replace .node
files within the unpacked directory - not so different than DLL hijacking on Windows.
Is simple:
.node
native modules in the application bundle, replace legitimate modules with malicious ones, restart the applicationIf you’re following along on macOS, and using the CLI to mv
or cp
files, the Transparency, Consent, and Control (TCC) framework provides some protection by requiring explicit user permission for file system access.
By default CLI apps won’t be able to modify application paths unless they’ve been granted Full Disk Access. You’ll receive an Operation not permitted
error.
However, this protection isn’t always perfect in real word use cases since many users grant Terminal Full Disk Access (for legitimate purposes). And there are occasional methods to bypass TCC restrictions, especially for outdated versions of macOS.
What can we do to fix this? Not much. Enterprises should continue to use EDR tools to identify malicious behavioral activity, unusual process creation, and network activity from Electron apps. If osquery is in use, you may be able to monitor for file integrity within the application directories, but the false positive rate is bound to be high. Everyone else should keep things updated, be diligent, and use a firewall app like LuLu for increased monitoring.