Loki: Node.js Command & Control for Script-Jacking Vulnerable Electron Applications
Loki is a stage-1 command and control (C2) framework written in Node.js, built to script-jack vulnerable Electron apps MITRE ATT&CK T1218.015. Developed for red team operations, Loki enables evasion of security software and bypasses application controls by exploiting trusted, signed Electron apps.
Script-jacking hijacks the execution flow of an Electron app by modifying JavaScript files loaded in at runtime with arbitrary Node.js code. This technique can be leveraged to:
- Backdoor Electron app
- Hollow Electron app
- Chain execution to another process
While several tools already address leveraging script-jacking to chain execution to another process, Loki is the first to enable backdooring and hollowing of signed Electron apps without invalidating their code signing signature.
Features & Details
- Azure Storage Blob C2 channel
- SAS Token to protect C2 storage account
- AES encrypted C2 messages
- Proxy-aware agent
- Uses Chromium renderer child processes for agent, shellcode execution, and assembly fork-n-run style execution — inherits proxy-aware capabilities of Chromium.
- Teamserver-less
- Unlike traditional C2’s where agents send messages to a Teamserver, there is no Teamserver
- The GUI client & agents both checkin to the same data-store
- Hidden exection — runs in the background
Backdooring Electron Apps and Keeping the real Application Working as Normal
The most straightforward way to use Loki is to replace the files in {ELECTRONAPP}/resources/app/
with the Loki files. This hollows out the app, meaning the app won’t function normally — Loki replaced its functionality.
If you really want to keep the Electron application running and have it also deploy Loki in the background all hope is not lost! John Hammond and I figured out a way to keep the real Electron application running. We’ve added the file you will need to /loki/backdoor/init.js
in this repo.
It is currently setup to work for Cursor, discovered to be vulnerable by John Hammond.
For doing this you will need to:
- Download the Cursor app
- Paste all Loki files except
package.json
tocursor/resources/app/
- Don’t replace the real
package.json
- Don’t replace the real
- Copy
/loki/backdoor/init.js
tocursor/resources/app/
- Modify contents of
cursor/resources/app/package.json
to:- set
"main":"init.js",
- delete
"type":"module",
- delete
"private":true,
- set
- With these changes
Cursor.exe
will load ininit.js
on click / execution init.js
reads inpackage.json
init.js
changes"main":"init.js",
->"main":"main.js",
main.js
is Loki
init.js
spawns and disowns a newCursor.exe
which points to Loki- Loki is spawned in the background
init.js
reads inpackage.json
againinit.js
changes"main":"main.js",
->"main":"./out/main.js",
./out/main.js"
is the real Cursor application
init.js
spawns and disowns a newCursor.exe
which points to the real Cursor- Real Cursor app is spawned, visible and operates as normal
- When Cursor is exited by the user:
init.js
catches the exitinit.js
reads inpackage.json
for a third timeinit.js
changes"main":"./out/main.js",
->"main":"init.js",
This way the app is persistently backdoored and operates as normal. If the cursor app is exited loki will continue to run in the background.