Aggirare il livello zero

Jan 05 2023
Dall'inizio di L2BEAT, ci siamo impegnati molto per analizzare e comprendere i rischi associati ai protocolli L2. Facciamo del nostro meglio per essere un cane da guardia imparziale e indipendente, agendo nel migliore interesse degli utenti e dell'ecosistema.

Dall'inizio di L2BEAT, ci siamo impegnati molto per analizzare e comprendere i rischi associati ai protocolli L2. Facciamo del nostro meglio per essere un cane da guardia imparziale e indipendente, agendo nel migliore interesse degli utenti e dell'ecosistema. Non lasciamo che le nostre preferenze personali per il progetto o il team coinvolto si intromettano. Ecco perché è comune che dobbiamo attivare gli allarmi rossi o segnalare le nostre preoccupazioni in vari protocolli, anche se apprezziamo il tempo e il lavoro dedicato dai team specifici ai loro progetti. Avere discussioni relative alla sicurezza in anticipo consente all'intero ecosistema di prepararsi meglio a potenziali rischi e reagire prima a qualsiasi comportamento sospetto.

Oggi vorremmo aprire un dibattito sui modelli di sicurezza condivisa delle applicazioni cross-chain. Attualmente esistono due approcci: sicurezza condivisa e sicurezza per applicazione. Il primo, sicurezza condivisa, viene utilizzato, ad esempio, da tutti i rollup. La seconda, la sicurezza per applicazione, viene utilizzata dai progetti “omnichain”. Il primo esempio di tale progetto è LayerZero.

Sicurezza condivisa e sicurezza isolata

Per sicurezza condivisa intendiamo che specifici token o app in esecuzione su una determinata infrastruttura non scelgono liberamente il proprio modello di sicurezza. Invece, devono obbedire a qualsiasi requisito di sicurezza imposto dall'infrastruttura. Ad esempio, i rollup ottimistici di solito impongono una finestra di finalità di 7 giorni: le app in esecuzione su tali rollup non possono semplicemente ignorare o abbreviare questo periodo. Può sembrare un ostacolo, ma è un ostacolo messo in atto per un motivo. Consente di fornire agli utenti una garanzia di sicurezza che possono aspettarsi di essere trattenuta da qualsiasi app stiano utilizzando su quel rollup, indipendentemente dalla politica di sicurezza interna delle app. L'app potrebbe solo rafforzare la politica dei rollup, non indebolirla.

Per sicurezza isolata intendiamo che ogni app è responsabile della definizione della propria sicurezza, non essendo in alcun modo limitata dall'infrastruttura. All'inizio può sembrare una buona idea. Dopotutto, gli sviluppatori dell'app sanno meglio di quali misure di sicurezza potrebbe aver bisogno l'app. Allo stesso tempo, però, trasferisce all'utente finale la responsabilità di valutare i rischi associati ai criteri di sicurezza di ogni app. Inoltre, se gli sviluppatori dell'app sono liberi di scegliere la propria politica dell'app, possono anche scegliere di cambiarla ogni volta che lo desiderano. Quindi non è sufficiente valutare i rischi una volta per ogni app, dovrebbero essere valutati ogni volta che la politica delle app cambia.

Il problema

Riteniamo che il modello di sicurezza isolato in cui ogni app può definire liberamente la propria politica di sicurezza ponga seri problemi di sicurezza. Innanzitutto, aumenta i rischi per gli utenti finali, in quanto devono convalidare separatamente i rischi inclini a ogni app che intendono utilizzare.

Aumenta anche il rischio per le app che utilizzano tale modello. La sicurezza isolata aggiunge ulteriore rischio per quanto riguarda la modifica della politica di sicurezza: se l'attaccante riesce a modificare il modello di sicurezza per l'applicazione, potrebbe anche semplicemente disabilitarlo, fornendo la possibilità di drenare i fondi o utilizzarlo in modo improprio in qualsiasi altro modo. Non esiste alcun livello di sicurezza aggiuntivo sopra l'applicazione che protegga da un uso improprio.

Inoltre, con le policy di sicurezza in grado di cambiare istantaneamente in qualsiasi momento diventa praticamente impossibile monitorare quotidianamente le app e informare gli utenti sui rischi.

Lo troviamo simile all'aggiornabilità dei contratti intelligenti. Lo mettiamo già in guardia su L2BEAT . Informiamo gli utenti sui rollup e sui bridge che dispongono di meccanismi di aggiornabilità nei loro contratti intelligenti, nonché sull'esatto meccanismo che regola l'aggiornabilità in ogni caso. Questo è già piuttosto complesso e con un modello di sicurezza isolato, questo si moltiplica per ogni app, rendendo quasi impossibile tracciare in modo efficace.

Ecco perché consideriamo un modello di sicurezza isolato come un rischio per la sicurezza in sé e postuliamo di trattare ogni app che utilizza tale modello come rischiosa per impostazione predefinita fino a prova contraria.

Il programma

Abbiamo deciso di testare le nostre ipotesi nel mondo reale, sulla rete principale. Il framework LayerZero è stato scelto per l'esperimento perché è una delle soluzioni più popolari che utilizza la sicurezza isolata al suo interno. Abbiamo implementato un token omnichain sicuro e successivamente è stata aggiornata la configurazione di sicurezza che ha consentito il ritiro di token dannosi. Il codice del token si basa sugli esempi forniti da LayerZero ed è molto simile o identico a molti altri token e app omnichain distribuiti in produzione.

Ma prima di approfondire i dettagli, diamo una breve occhiata a come si presenta il modello di sicurezza LayerZero.

Come afferma chiaramente il white paper di LayerZero, la sua "comunicazione inter-chain senza fiducia" si basa su due attori indipendenti (l'oracolo e il relayer) che agiscono insieme per garantire la sicurezza del protocollo.

Come afferma LayerZero sul suo sito Web, il suo concetto principale è che si tratta di un "endpoint on-chain configurabile dall'applicazione utente che esegue un ULN (UltraLightNode)". I componenti on-chain di LayerZero si affidano a due parti esterne off-chain per inoltrare i messaggi tra le catene: Oracle e Relayer.

Ogni volta che un messaggio M viene inviato dalla catena A alla catena B, si verificano le seguenti due azioni:

  • in primo luogo, l'Oracolo attende fino a quando la transazione che invia il messaggio M sulla catena A viene finalizzata e quindi scrive sulla catena B l'impegno per il pacchetto di messaggi, ad esempio l'hash dell'intestazione del blocco (il formato esatto può variare tra diverse catene/oracoli) alla catena A contenente quel messaggio M
  • quindi il Relayer invia alla catena B una "prova" (ad esempio una Merkle Proof) che l'intestazione memorizzata contiene il messaggio M

LayerZero afferma che "il design di LayerZero elimina la possibilità di collusione". Ma in realtà, questa affermazione non è vera (cosa che dimostriamo nell'esperimento presentato di seguito), poiché ogni applicazione utente può definire il proprio Relayer e Oracle. LayerZero non garantisce in base alla progettazione che tali componenti siano indipendenti e che non possano colludere. Spetta all'applicazione utente fornire tali garanzie. E se l'applicazione sceglie di violarli, non c'è nulla nella meccanica di LayerZero che possa impedirgli di farlo.

Inoltre, per impostazione predefinita, tutte le applicazioni utente sono in grado di modificare Relayer e Oracle in qualsiasi momento, ridefinendo completamente i presupposti di sicurezza. Quindi non è sufficiente controllare una volta la sicurezza dell'app data, poiché potrebbe essere cambiata in qualsiasi momento dopo il controllo, come mostreremo nel nostro esperimento.

L'esperimento

Nel nostro esperimento, abbiamo deciso di creare un semplice token omnichain, CarpetMoon, funzionante sia su Ethereum che su Optimism, utilizzando ZeroLayer per comunicare tra le due catene.

Il nostro token utilizza inizialmente il modello di sicurezza predefinito fornito da LayerZero, quindi sembra quasi uguale alla maggior parte (se non a tutte) delle applicazioni LayerZero attualmente distribuite. Pertanto, è generalmente sicuro come qualsiasi altro token che utilizza LayerZero.

Innanzitutto, distribuiamo i nostri contratti token sia su Ethereum che su Optimism:
https://ethtx.info/mainnet/0xf4d1cdabb6927c363bb30e7e65febad8b9c0f6f76f1984cd74c7f364e3ab7ca9/
https://optimistic.etherscan.io/tx/0xf41389d71fa3942de5225efb067072728c6c6de56c241574187781db7c73d221

E impostiamo il routing in modo che LayerZero sappia quale contratto corrisponde a quale su entrambe le catene:
https://ethtx.info/mainnet/0x19d78abb03179969d6404a7bd503148b4ac14d711f503752495339c96a7776e9/
https://optimistic.etherscan.io/tx/0x037b1bad33faa5607bb5835460a1d5caaf3a147dc3a09762ac7703befcdb3c3c

Quindi il token è impostato, sembra esattamente come tutti gli altri token omnichain che utilizzano LayerZero, con configurazione predefinita, niente di sospetto.

Forniamo al nostro utente di prova, chiamiamola Alice, i token di prova, quindi Alice ha 1B di token CarpetMoon su Ethereum:
https://ethtx.info/mainnet/0x7e2faa8426dacae92830efbf356ca2da760833eca28e652ff9261fc03042b313/

Ora Alice collega quei token all'ottimismo usando LayerZero.

Blocchiamo i token in un escrow su Ethereum:
https://ethtx.info/mainnet/0xe4dc3757b86bfda8e7baddc088fb1a599e083ed77034c29e5dd8bd11f1e17771/

Il messaggio con la transazione viene consegnato a Optimism tramite LayerZero:
https://layerzeroscan.com/101/address/0xc6005ccc1de4b300d538903b74848bff881d5dc5/message/111/address/0x201fe0d843b546f2e24d4c8444318d1c71b7d10d/nonce/1

E i token con bridge vengono coniati su Optimism, Alice ora ha token MoonCarpet da 1 miliardo su Optimism:
https://optimistic.etherscan.io/tx/0x5388ced88cf562acafff82d6798f791b0b38b90ee106df9bf91c0d86306ec302

Ok, quindi tutto ha funzionato come previsto, Alice ha collegato i suoi token e ha visto che ci sono 1 miliardo di token MoonCarpet nell'escrow su Ethereum e 1 miliardo di token MoonCarpet sul suo account su Optimism. Ma per assicurarsi che tutto funzioni correttamente, trasferisce nuovamente metà dei token (500 milioni di MoonCarpet) su Ethereum.

Quindi iniziamo con la transazione che brucia 500 milioni di token su Optimism:
https://optimistic.etherscan.io/tx/0x118a57106488ad0bae1f3b920b1fd98b187752ad966f3a901fc53cff47f2097f

Le informazioni su quella transazione vengono trasmesse a Ethereum:
https://layerzeroscan.com/111/address/0x201fe0d843b546f2e24d4c8444318d1c71b7d10d/message/101/address/0xc6005ccc1de4b300d538903b74848bff881d5dc5/nonce/1

E, come previsto, 500 milioni di token MoonCarpet vengono restituiti all'indirizzo di Alice dall'impegno:
https://etherscan.io/tx/0x27702e07a65a9c6a7d1917222799ddb13bb3d05159d33bbeff2ca1ed414f6a18

Fino ad ora, tutto funziona bene, esattamente come ipotizzato. Alice ha verificato di poter trasferire token da Ethereum a Optimism e viceversa, non ha motivo di aver paura dei suoi token MoonCarpet.

Ma supponiamo che qualcosa vada storto, ad esempio il team dietro il nostro token viene compromesso e il malintenzionato Bob ottiene l'accesso alla configurazione di LayerZero per la nostra app.

Con tale accesso, Bob può modificare Oracle e Relayer da quelli predefiniti a quelli sotto il suo controllo.

Tieni presente che questo è un meccanismo fornito a ogni app che utilizza LayerZero, radicato nell'architettura di LayerZero, non è un tipo di backdoor ma piuttosto un meccanismo standard.

Quindi Bob cambia l'Oracolo in un EOA sotto il suo controllo:
https://ethtx.info/mainnet/0x4dc84726da6ca7d750eef3d33710b5f63bf73cbe03746f88dd8375c3f4672f2f/

E fa lo stesso con il Relayer:
https://ethtx.info/mainnet/0xc1d7ba5032af2817e95ee943018393622bf54eb87e6ff414136f5f7c48c6d19a/

E ora succedono cose strane. Con Oracle e Relayer ora sotto il pieno controllo di Bob, è in grado di rubare i token di Alice. Anche se non viene eseguita alcuna azione sull'ottimismo (i token MoonCarpet sono ancora nel portafoglio di Alice lì) Bob è in grado di convincere lo smart contract MoonCarpet su Ethereum (utilizzando i meccanismi LayerZero) che ha bruciato i token su un'altra catena ed è in grado di ritirare i token MoonCarpet su Ethereum.

Per prima cosa, aggiorna il blockhash su Ethereum usando Oracle canaglia:
https://ethtx.info/0xde2edee2cc7f070120e96c9df90d86696970befcfc221e18c6ac4168bb5b1d92/

E ora può ritirare i gettoni rimanenti dall'impegno:
https://ethtx.info/0xda695f374b375d5372efeca37aae4c5a17f114d5a76db1e86edebb0924bcdcc7/

Il risultato

Alice non saprà nemmeno perché e quando è successo qualcosa di sbagliato. All'improvviso i suoi token MoonCarpet su Optimism non sono più supportati da token su Ethereum.

Gli smart contract non sono aggiornabili e funzionano come previsto. L'unica attività sospetta è il cambio di Oracle e Relayer, ma questo è un normale meccanismo integrato in LayerZero, quindi Alice non può nemmeno sapere se questo cambiamento è stato intenzionale o meno. E anche se Alice venisse a conoscenza di quel cambiamento, sarebbe già troppo tardi: l'aggressore è in grado di prosciugare i fondi prima ancora che lei possa reagire.

E anche LayerZero non poteva essere d'aiuto qui: erano tutte esecuzioni valide dei loro meccanismi, che non possono più controllare. Teoricamente, l'applicazione stessa può bloccarsi dal modificare Oracle e Relayer, ma per quanto ne sappiamo nessuna delle applicazioni già distribuite lo ha fatto.

Abbiamo fatto questo esperimento per verificare se qualcuno se ne accorge, ma come ci aspettavamo, nessuno l'ha fatto. È praticamente impossibile monitorare efficacemente tutte le applicazioni create con LayerZero per verificare se la loro politica di sicurezza non è cambiata e avvisare gli utenti se ciò accade.

Anche se si riuscisse a capire che Oracle e Relayer sono cambiati in un modo che pone rischi per la sicurezza, quando succede è già troppo tardi. Poiché il nuovo Oracle e Relayer possono ora scegliere liberamente di censurare o semplicemente disabilitare la comunicazione tra le catene, gli utenti di solito non possono fare nulla al riguardo. Ciò è chiaramente dimostrato nel nostro esperimento, poiché anche se Alice nota il cambiamento nella configurazione dell'applicazione, non può fare molto con i suoi token con bridge: il nuovo Oracle e Relayer non ascoltano più sulla catena originale, quindi non inoltrano il messaggi a Ethereum.

Conclusioni e CTA

Come abbiamo potuto vedere sopra, anche se il nostro token è stato creato utilizzando LayerZero e ha utilizzato i suoi meccanismi come previsto, siamo stati in grado di rubare fondi dall'impegno dei token. Ovviamente è stata colpa dell'applicazione (token CarpetMoon nel nostro caso) e non di LayerZero stesso, ma ciò dimostra che LayerZero da solo non fornisce alcuna garanzia di sicurezza .

Quando LayerZero descrive il loro modello di sicurezza relativo a Oracle e Relayer, presumono che i proprietari delle app (o qualcuno in possesso delle loro chiavi private) non faranno nulla di irrazionale. Ma tale ipotesi non è corretta in un ambiente contraddittorio. Inoltre, richiede agli utenti di fidarsi dei proprietari dell'applicazione come terza parte fidata.

In pratica, di conseguenza, non è possibile fare alcuna ipotesi sulla sicurezza delle applicazioni create utilizzando LayerZero: ogni app dovrebbe essere considerata rischiosa fino a prova contraria.

In realtà, l'intera storia è iniziata per noi con un PR con il quale abbiamo pianificato di includere tutti i token omnichain sul sito L2BEAT: abbiamo avuto difficoltà a capire come valutare i loro rischi. Durante l'analisi dei vettori di rischio ci è venuta l'idea per il nostro esperimento.

Per L2BEAT le conseguenze sono che dobbiamo inserire avvisi in cima a ogni app creata utilizzando LayerZero, avvertendo sui possibili rischi per la sicurezza. Ma vorremmo aprire una discussione più ampia sui modelli di sicurezza, poiché riteniamo che la sicurezza isolata sia un anti-modello che dovrebbe essere evitato, specialmente nel nostro spazio.

Siamo fiduciosi che man mano che i modelli di sicurezza isolati come in LayerZero diventeranno sempre più popolari, ci saranno sempre più progetti che ne abusano, causando molti danni e aumentando l'incertezza sull'intero settore.