NodeJS - __proto__ & prototype Pollution
Last updated
Last updated
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)
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.
Un oggetto vuoto è simile a un dizionario vuoto, rappresentato come {}
.
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.
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.
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.
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:
L'accesso al prototipo Object è possibile tramite:
Aggiungendo proprietà al prototipo Object, ogni oggetto JavaScript erediterà queste nuove proprietà:
Per uno scenario in cui l'uso di __proto__
è limitato, modificare il prototipo di una funzione è un'alternativa:
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 l'Object.prototype
:
Inquinare il prototipo di un costruttore per una struttura comunemente usata:
Dopo queste operazioni, ogni oggetto JavaScript può eseguire i metodi goodbye
e greet
.
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:
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).
Quando si genera un elemento HTML tramite JS, è possibile sovrascrivere l'attributo innerHTML
per farlo scrivere codice HTML arbitrario. Idea ed esempio da questo writeup.
Una contaminazione del prototipo si verifica a causa di un difetto nell'applicazione che consente di sovrascrivere le proprietà su Object.prototype
. Questo 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:
Se l'attributo admin
è indefinito è possibile abusare di un PP e impostarlo su True con qualcosa come:
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.
Altri payload:
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:
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 amministratore se proprietà come isAdmin
vengono controllate senza una corretta verifica di esistenza.
Per ulteriori dettagli, controlla questo articolo
Lodash ha incontrato vulnerabilità simili di inquinamento del prototipo (CVE-2018–3721, CVE-2019–10744). Questi problemi sono stati risolti nella versione 4.17.11.
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 nell'inquinamento del prototipo lato server.
NodeJS utilizza ampiamente gli Abstract Syntax Trees (AST) in JavaScript per funzionalità come motori di template e TypeScript. Questa sezione esplora le vulnerabilità relative all'inquinamento del prototipo nei motori di template, specificamente Handlebars e Pug.
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
su undefined
dopo aver aggiunto la sorgente.
Processo di sfruttamento
Lo sfruttamento sfrutta l'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 a Program
, 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:
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: Problema su GitHub.
Riferimento Esterno: Problema relativo alla contaminazione del prototipo nella libreria 'flat'
Esempio di exploit di contaminazione del prototipo in Python:
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:
Per ridurre il rischio di inquinamento del prototipo, possono essere impiegate le strategie elencate di seguito:
Immutabilità degli Oggetti: Object.prototype
può essere reso immutabile applicando Object.freeze
.
Validazione degli Input: Gli input JSON devono essere rigorosamente validati rispetto allo schema dell'applicazione.
Funzioni di Fusione Sicure: L'uso non sicuro di funzioni di fusione ricorsive dovrebbe essere evitato.
Oggetti Senza Prototipo: Gli oggetti senza proprietà di prototipo possono essere creati utilizzando Object.create(null)
.
Uso di Map: Invece di Object
, si dovrebbe usare Map
per 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.
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)