L'attacco flash loan del 13 marzo contro Euler Finance ha causato perdite per oltre 195 milioni di $. Ha causato un contagio che si è diffuso attraverso molteplici protocolli di finanza decentralizzata (DeFi) e almeno 11 protocolli diversi da Euler hanno subito perdite a causa dell'attacco.
Nei successivi 23 giorni, con grande sollievo di molti utenti Euler, l'aggressore restituì tutti i fondi sfruttati.
Ma mentre la comunità delle criptovalute può festeggiare la restituzione dei fondi, resta da chiedersi se attacchi simili possano causare perdite ingenti in futuro.
Potrebbe essere utile analizzare come è avvenuto l'attacco e capire se sviluppatori e utenti possono fare qualcosa per prevenire questo tipo di attacchi in futuro.
Fortunatamente, i documenti per gli sviluppatori di Euler spiegano chiaramente come funziona il protocollo e la blockchain stessa ha conservato una registrazione completa dell’attacco.
Come funziona Euler Finance
Secondo i documenti ufficiali del protocollo, Euler è una piattaforma di prestito simile a Compound o Aave. Gli utenti possono depositare criptovalute e consentire al protocollo di prestarle ad altri, oppure possono usare un deposito come garanzia per prendere in prestito criptovalute.
Il valore della garanzia di un utente deve sempre essere superiore a quanto prende in prestito. Supponiamo che la garanzia di un utente scenda al di sotto di un rapporto specifico tra valore della garanzia e valore del debito. In tal caso, la piattaforma consentirà loro di essere "liquidati", il che significa che la loro garanzia verrà venduta per ripagare i loro debiti. L'importo esatto della garanzia di cui un utente ha bisogno dipende dall'asset depositato rispetto all'asset preso in prestito.
Gli eToken sono asset, mentre i dToken sono debiti
Ogni volta che gli utenti depositano su Euler, ricevono eToken che rappresentano le monete depositate. Ad esempio, se un utente deposita 1.000 USD Coin (USDC), riceverà la stessa quantità di eUSDC in cambio.
Poiché il loro valore aumenta rispetto alle monete sottostanti man mano che il deposito matura interessi, gli eToken non hanno una corrispondenza 1:1 con l'asset sottostante in termini di valore.
Euler consente inoltre agli utenti di ottenere una leva finanziaria coniando eToken. Ma se lo fanno, il protocollo invierà loro token di debito (dToken) per bilanciare gli asset creati.
Ad esempio, i documenti affermano che se un utente deposita 1.000 USDC, può coniare 5.000 eUSDC. Tuttavia, se lo fa, il protocollo gli invierà anche 5.000 di un token di debito chiamato "dUSDC".
La funzione di trasferimento per un dToken è scritta in modo diverso rispetto a un token ERC-20 standard. Se possiedi un token di debito, non puoi trasferirlo a un'altra persona, ma chiunque può prendere un dToken da te se lo desidera.
Secondo la documentazione di Euler, un utente può coniare solo tanti eToken quanti ne avrebbe potuti coniare depositando e prendendo in prestito più e più volte, come afferma: "La funzione Mint imita cosa accadrebbe se un utente depositasse 1.000 USDC, quindi prendesse in prestito 900 USDC, quindi ridepositasse quei 900 USDC, per prendere in prestito altri 810 USDC e così via".
Gli utenti vengono liquidati se i punteggi di salute scendono a 1 o meno
Secondo un post del blog di Euler, ogni utente ha un "punteggio di salute" basato sul valore degli eToken detenuti nei propri wallet rispetto al valore dei dToken detenuti. Un utente deve avere un valore in dollari maggiore di eToken rispetto ai dToken, ma quanto in più dipende dalle monete specifiche che sta prendendo in prestito o depositando. In ogni caso, un utente con abbastanza eToken avrà un punteggio di salute maggiore di 1.
Se l'utente scende appena sotto il numero richiesto di eToken, avrà un punteggio di salute di esattamente 1. Ciò lo sottoporrà a una "liquidazione soft". I bot liquidatori possono chiamare una funzione per trasferire alcuni degli eToken e dToken dell'utente a se stessi finché il punteggio di salute del mutuatario non torna a 1,25. Poiché un utente che è appena al di sotto dei requisiti di garanzia avrà comunque più garanzia che debito, il liquidatore dovrebbe trarre profitto da questa transazione.
Se il punteggio di salute di un utente scende sotto 1, viene concesso uno sconto crescente al liquidatore in base a quanto è basso il punteggio di salute. Più è basso il punteggio di salute, maggiore è lo sconto al liquidatore. Questo ha lo scopo di garantire che qualcuno liquiderà sempre un account prima che accumuli troppi crediti inesigibili.
Il post di Euler sostiene che altri protocolli offrono uno “sconto fisso” per la liquidazione e spiega perché ritiene che gli sconti variabili siano superiori.
Come è avvenuto l'attacco di Eulero
I dati della blockchain rivelano che l'attaccante ha condotto una serie di attacchi che hanno prosciugato vari token dal protocollo. Il primo attacco ha prosciugato circa 8,9 milioni di dollari di Dai (DAI) dal pool di deposito Dai. È stato poi ripetuto più e più volte per altri pool di deposito fino a quando l'importo totale non è stato prosciugato.
L'attaccante ha utilizzato tre diversi indirizzi Ethereum per eseguire l'attacco. Il primo era uno smart contract, che Etherscan ha etichettato come "Euler Exploit Contract 1", utilizzato per prendere in prestito da Aave. Il secondo indirizzo è stato utilizzato per depositare e prendere in prestito da Euler, e il terzo è stato utilizzato per eseguire una liquidazione.
Per evitare di dover ripetutamente specificare gli indirizzi che Etherscan non ha etichettato, il secondo account verrà denominato "Mutuatario" e il terzo account "Liquidatore", come mostrato di seguito:
Indirizzi Ethereum utilizzati dall'hacker. Fonte: Etherscan
Il primo attacco consisteva in 20 transazioni nello stesso blocco.
Innanzitutto, Euler Exploit Contract 1 ha preso in prestito 30 milioni di DAI da Aave in un prestito flash. Ha poi inviato questo prestito al conto del mutuatario.
Dopo aver ricevuto i 30 milioni di DAI, il mutuatario ne ha depositati 20 milioni a Euler. Euler ha quindi risposto coniando circa 19,6 milioni di eDAI e inviandoli al mutuatario.
Queste monete eDAI erano una ricevuta per il deposito, quindi non è stata coniata una quantità corrispondente di dDai nel processo. E poiché ogni eDAI può essere riscattato per poco più di un DAI, il mutuatario ha ricevuto solo 19,6 milioni invece dei 20 milioni completi.
Dopo aver eseguito questo deposito iniziale, il mutuatario ha coniato circa 195,7 milioni di eDAI. In risposta, Euler ha coniato 200 milioni di dDAI e li ha inviati al mutuatario.
A questo punto, il mutuatario era vicino al limite di conio dell'eDAI, poiché aveva preso in prestito circa 10 volte la quantità di DAI che aveva depositato. Quindi il suo passo successivo era quello di saldare alcuni dei debiti. Depositarono gli altri 10 milioni di DAI che avevano trattenuto, rimborsando di fatto 10 milioni di $ del prestito. In risposta, Euler prese 10 milioni di dDAI dal portafoglio del mutuatario e li bruciò, riducendo il debito del mutuatario di 10 milioni di $.
L'attaccante era quindi libero di coniare altri eDAI. Il mutuatario ha coniato altri 195,7 milioni di eDAI, portando il totale degli eDAI coniati a circa 391,4 milioni. I 19,6 milioni di eDAI nelle ricevute di deposito hanno portato il totale degli eDAI del mutuatario a circa 411 milioni.
In risposta, Euler coniò altri 200 milioni di dDai e li inviò al mutuatario, portando il debito totale del mutuatario a 400 milioni di dollari.
Una volta che il mutuatario ha massimizzato la sua capacità di conio di eDAI, ha inviato 100 milioni di eDai all'indirizzo nullo, distruggendolo di fatto.
Ciò ha portato il loro punteggio di salute ben al di sotto di 1, poiché ora avevano 400 milioni di dollari di debiti contro circa 320 milioni di dollari di attività.
È qui che entra in gioco il conto liquidatore. Chiamato funzione di liquidazione, inserendo l'indirizzo del mutuatario come conto da liquidare.
Evento di liquidazione emesso durante l'attacco di Euler. Fonte: dati della blockchain di Ethereum
In risposta, Euler ha avviato il processo di liquidazione. Per prima cosa ha preso circa 254 milioni di dDAI dal mutuatario e li ha distrutti, poi ha coniato 254 milioni di nuovi dDai e li ha trasferiti al liquidatore. Questi due passaggi hanno trasferito 254 milioni di dollari di debito dal mutuatario al liquidatore.
Successivamente, Euler ha coniato altri 5,08 milioni di dDAI e li ha inviati al liquidatore. Ciò ha portato il debito del liquidatore a 260 milioni di $. Infine, Euler ha trasferito circa 310,9 milioni di eDAI dal mutuatario al liquidatore, completando il processo di liquidazione.
Alla fine, il mutuatario si è ritrovato senza eDAI, senza DAI e con 146 milioni di dDAI. Ciò significava che il conto non aveva asset e 146 milioni di dollari di debiti.
D'altro canto, il liquidatore aveva circa 310,9 milioni di eDAI e solo 260 milioni di dDAI.
Una volta completata la liquidazione, il liquidatore ha riscattato 38 milioni di eDAI (38,9 milioni di $), ricevendo in cambio 38,9 milioni di DAI. Hanno quindi restituito 30 milioni di DAI più interessi a Euler Exploiter Contract 1, che il contratto ha utilizzato per rimborsare il prestito da Aave.
Alla fine, il liquidatore si è ritrovato con circa 8,9 milioni di dollari di profitti che erano stati sfruttati da altri utenti del protocollo.
Questo attacco è stato ripetuto per molti altri token, tra cui Wrapped Bitcoin (WBTC), Staked Ether (stETH) e USDC, per un totale di 197 milioni di dollari in criptovalute sfruttate.
Perdite dall'attacco di Eulero. Fonte: Blocksec Cosa è andato storto nell'attacco di Eulero
Le aziende di sicurezza blockchain Omniscia e SlowMist hanno analizzato l'attacco per cercare di determinare cosa avrebbe potuto prevenirlo.
Secondo un rapporto del 13 marzo di Omniscia, il problema principale di Euler era la sua funzione "donateToReserves". Questa funzione consentiva all'attaccante di donare il proprio eDAI alle riserve di Euler, rimuovendo asset dal proprio portafoglio senza rimuovere una quantità corrispondente di debito. Omnisica afferma che questa funzione non era nella versione originale di Euler, ma è stata introdotta in Euler Improvement Proposal 14 (eIP-14).
Il codice per eIP-14 rivela che è stata creata una funzione chiamata donateToReserves, che consente all'utente di trasferire token dal proprio saldo a una variabile di protocollo chiamata "assetStorage.reserveBalance". Ogni volta che questa funzione viene chiamata, il contratto emette un evento "RequestDonate" che fornisce informazioni sulla transazione.
I dati della blockchain mostrano che questo evento RequestDonate è stato emesso per un valore di 100 milioni di token. Questa è la quantità esatta che Etherscan mostra essere stata bruciata, spingendo l'account verso l'insolvenza.
L'evento RequestDonate di Euler viene emesso durante l'attacco. Fonte: dati della blockchain di Ethereum
Nella loro analisi del 15 marzo, SlowMist concorda con Omniscia sull'importanza della funzione donateToReserve, affermando:
"La mancata verifica se l'utente si trovasse in uno stato di liquidazione dopo aver donato fondi all'indirizzo di riserva ha comportato l'attivazione diretta del meccanismo di liquidazione soft."
L'attaccante avrebbe potuto anche essere in grado di eseguire l'attacco anche se la funzione di donazione non fosse esistita. Il codice del contratto Euler "EToken.sol" su GitHub contiene una funzione di "trasferimento" ERC-20 standard. Ciò sembra implicare che l'attaccante avrebbe potuto trasferire i propri eToken a un altro utente casuale o all'indirizzo nullo invece di donare, spingendosi comunque verso l'insolvenza.
Funzione di trasferimento del contratto Euler eToken. Fonte: GitHub
Tuttavia, l'aggressore ha scelto di donare i fondi anziché trasferirli, il che suggerisce che il trasferimento non avrebbe funzionato.
Cointelegraph ha contattato Omniscia, SlowMist e il team di Euler per avere chiarimenti sul fatto che la funzione donateToReserves fosse essenziale per l'attacco. Tuttavia, non ha ricevuto risposta al momento della pubblicazione.
Le due aziende hanno concordato che un'altra vulnerabilità importante in Euler erano gli sconti elevati offerti ai liquidatori. Secondo SlowMist, quando un protocollo di prestito ha un "meccanismo di liquidazione che aggiorna dinamicamente gli sconti", "crea opportunità di arbitraggio redditizie per gli aggressori per sottrarre una grande quantità di garanzie senza la necessità di garanzie o rimborso del debito". Omniscia ha fatto osservazioni simili, affermando:
"Quando il trasgressore si autoliquida, viene applicato uno sconto percentuale [...] garantendo che rimarrà 'a galla' e contrarrà solo il debito che corrisponde alla garanzia che acquisirà".
Come prevenire un futuro attacco di Eulero
Nella sua analisi, SlowMist ha consigliato agli sviluppatori come prevenire un altro attacco in stile Euler in futuro. Ha sostenuto che i protocolli di prestito non dovrebbero consentire agli utenti di bruciare asset se ciò li porterà a creare debiti inesigibili, e ha affermato che gli sviluppatori dovrebbero fare attenzione quando utilizzano più moduli che potrebbero interagire tra loro in modi inaspettati:
"Lo SlowMist Security Team raccomanda che i protocolli di prestito incorporino i necessari controlli sanitari nelle funzioni che coinvolgono i fondi degli utenti, tenendo anche conto dei rischi per la sicurezza che possono derivare dalla combinazione di diversi moduli. Ciò consentirà la progettazione di modelli sicuri, economici e fattibili che mitighino efficacemente tali attacchi in futuro."
Un rappresentante dello sviluppatore DeFi Spool ha detto a Cointelegraph che il rischio tecnologico è una caratteristica intrinseca dell'ecosistema DeFi. Sebbene non possa essere eliminato, può essere mitigato tramite modelli che valutano correttamente i rischi dei protocolli.
Secondo il white paper sulla gestione del rischio di Spool, viene utilizzata una "matrice del rischio" per determinare la rischiosità dei protocolli. Questa matrice considera fattori quali la percentuale di rendimento annuale (APY) del protocollo, gli audit eseguiti sui suoi contratti, il tempo trascorso dalla sua distribuzione, il valore totale bloccato (TVL) e altri per creare una valutazione del rischio. Gli utenti di Spool possono utilizzare questa matrice per diversificare gli investimenti DeFi e limitare i rischi.
Il rappresentante ha detto a Cointelegraph che la matrice di Spool ha ridotto significativamente le perdite degli investitori derivanti dall'incidente di Euler.
"In questo incidente, gli Smart Vault più colpiti, quelli progettati dagli utenti per cercare rendimenti più elevati (e più rischiosi), sono stati colpiti solo fino al 35%. Il vault meno colpito con esposizione alle strategie di Euler (tramite Harvest o Idle), in confronto, è stato colpito solo del 6%. Alcuni vault avevano esposizione zero e quindi non sono stati colpiti", hanno affermato.
Spool ha continuato: "Sebbene questa non sia la soluzione ideale, dimostra chiaramente la capacità degli Smart Vault di fornire modelli di rischio personalizzati e di distribuire i fondi degli utenti tra più fonti di rendimento".
Cointelegraph ha ricevuto una risposta simile da SwissBorg, un altro protocollo DeFi che mira ad aiutare gli utenti a limitare il rischio attraverso la diversificazione. Il CEO di SwissBorg, Cyrus Fazel, ha dichiarato che l'app SwissBorg ha "diverse strategie di rendimento basate su rischio/tempoAPY".
Alcune strategie sono elencate come “1: core = basso”, mentre altre sono elencate come “2: avventuroso = rischioso”. Poiché a Euler è stata assegnata una valutazione “2”, le perdite dal protocollo sono state limitate solo a una piccola parte del valore totale bloccato di SwissBorg, ha affermato Fazel.
Nicolas Rémond, responsabile dell'ingegneria di SwissBorg, ha chiarito ulteriormente che il team impiega criteri sofisticati per determinare quali protocolli possono essere elencati nell'app SwissBorg.
"Abbiamo un processo di due diligence per tutte le piattaforme DeFi prima di entrare in qualsiasi posizione. E poi, una volta che siamo lì, abbiamo procedure operative", ha detto, aggiungendo, "La due diligence riguarda TVL, team, audit, codice open source, TVL, attacco di manipolazione dell'oracolo, ecc. [...] La procedura operativa riguarda il monitoraggio della piattaforma, il monitoraggio dei social media e alcune misure di emergenza. Alcune sono ancora manuali, ma stiamo investendo per automatizzare tutto in modo da poter essere estremamente reattivi".
In un thread su Twitter del 13 marzo, il team di SwissBorg ha affermato che, nonostante il protocollo avesse perso il 2,2% dei fondi da un pool e il 29,52% da un altro, tutti gli utenti sarebbero stati risarciti da SwissBorg nel caso in cui i fondi non fossero stati recuperabili da Euler.
L'attacco Euler è stato il peggior exploit DeFi del Q1 2023. Fortunatamente, l'attaccante ha restituito la maggior parte dei fondi e la maggior parte degli utenti non dovrebbe avere perdite quando tutto sarà detto e fatto. Ma l'attacco solleva interrogativi su come sviluppatori e utenti possano limitare i rischi mentre l'ecosistema DeFi continua a espandersi.
Una combinazione di diligenza degli sviluppatori e diversificazione degli investitori potrebbe essere la soluzione al problema. Ma indipendentemente da ciò, l'hack di Euler potrebbe continuare a essere discusso per molto tempo in futuro, se non altro per le sue dimensioni e l'illustrazione dei rischi degli exploit DeFi.
