The Wiert Corner – irregular stream of stuff

Jeroen W. Pluimers on .NET, C#, Delphi, databases, and personal interests

  • My badges

  • Twitter Updates

  • My Flickr Stream

  • Pages

  • All categories

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 1,860 other subscribers

evilsocket/jscythe: Abuse the node.js inspector mechanism in order to force any node.js/electron/v8 based process to execute arbitrary javascript code.

Posted by jpluimers on 2025/02/13

This is based on SIGUSR1, so means you need to run as the same user on the same local system, but it can be used for interesting techniques like extending node.js/electron based applications beyond what they were designed for.

[Wayback/Archive] evilsocket/jscythe: Abuse the node.js inspector mechanism in order to force any node.js/electron/v8 based process to execute arbitrary javascript code.

The behaviour has been documented and was known for a long time: [Wayback/Archive] sigusr1 node.js – Twitter Search.

It got my attention because of [Wayback/Archive] Simone Margaritelli on Twitter: “You can force any v8/Electron process to execute arbitrary js code (child_process, http, etc) by forcefully enabling and abusing the builtin debug mechanism … here’s VS Code executing Calc, but I suspect any Electron app is susceptible 🔥 it works with SIP enabled on macOS”

The combination of “SIP enabled on macOS” and “🔥” put a lot of people on the wrong foot as it kind of implicated it was a serious security vulnerability imposing a threat model.

Later they clarified: [Wayback/Archive] Simone Margaritelli on Twitter: “@addisoncrump_vr what’s the threat model for process injection? i was trying to work around SIP on macOS”.

On SIGUSR1

SIGUSR1 is one of the two user Signals that are used for Inter-Process Communication specifically for this purpose:

The SIGUSR1 and SIGUSR2 signals are sent to a process to indicate user-defined conditions.

It is, like other signals, supported by [Wayback/Archive] Process: signal-events | Node.js v18.8.0 Documentation, specifically:

'SIGUSR1' is reserved by Node.js to start the [Wayback/Archive] debugger. It’s possible to install a listener but doing so might interfere with the debugger.

When SIGUSR1 is received by a Node.js process, Node.js will start the debugger.

The signal used to trigger the creation of a diagnostic report. Defaults to 'SIGUSR2'.

Not just node.js does support SIGUSR1, Electron based applications do too as at the core they are node.js based..

Thread and responses

More messages in this [Wayback/Archive] Thread by @evilsocket on Thread Reader App including [Wayback/Archive] Simone Margaritelli on Twitter: “Source code -> github.com/evilsocket/jscythe.

Others chimed in with links too, for instance:

The result

I split this apart as there was no alt-text to the picture so I used Google Lens to OCR it which takes a bit more space to include above.

[Wayback/Archive] Simone Margaritelli on Twitter: “FINALLY!!!! Node.js universal API hooking on macOS with SIP enabled using jscythe injection 🥳 it’s interesting that by using the global Runtime object and targeting the extensionHost proces, this affects every extension running in VSCode … that’s all I wanted to achieve”

Image

var HOOKED_FUNCTIONS = HOOKED_FUNCTIONS || {};
var FUNCTION_LOGS = FUNCTION_LOGS || [];

function hook(mod, mod_name, fn_name, fn) {
  var fn_full_name = mod_name + '.' + fn_name;
  if(!(fn_full_name in HOOKED_FUNCTIONS) ){
    mod[fn_name] = function(args) {
      var ret = fn(args);
      FUNCTION_LOGS.push({
        timestamp: Math.floor(Date.now() / 1000),
        module: mod_name,
        func: fn_name,
        args: args,
        ret: ret,
      });
      return ret;
    };
    HOOKED_FUNCTIONS [fn_full_name] = true;
  }
}

var mod_name = 'fs';

for( var attr_name in require(mod_name) ) { 
  var maybe_fn = require(mod_name)[attr_name]; 
  if(typeof maybe_fn == 'function') {
    hook(require(mod_name), mod_name, attr_name, maybe_fn); 
  }
}

JSON.stringify(HOOKED_FUNCTIONS)

--jeroen

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.