carte-su-un-tavolo

BadReveal – Exploit NFT

Una nuova famiglia di vulnerabilità

Un nuovo exploit trovato dai ricercatori di Sayfer e @rugpullfinder team consente agli aggressori di sapere qual è l'NFT più raro prima della rivelazione del progetto. Ciò consente a un utente malintenzionato di ottenere un vantaggio irregolare tra gli investitori nell'acquistare il pezzo più raro e costoso. In alcuni progetti, il più raro può avere un prezzo 50 volte superiore al prezzo del pezzo standard.

La vulnerabilità si verifica a causa di cattive pratiche di codifica. Abbiamo trovato la vulnerabilità in dozzine di progetti. Possibilmente esistenti in migliaia che non abbiamo ancora testato manualmente.

Non c'è modo di testarlo automaticamente, quindi se vuoi sapere se un progetto in cui vuoi investire o in cui hai già investito è vulnerabile a BadReveal, taggaci su Twitter @SayferSecurity con #BadReveal e i nostri ricercatori verificheranno.

Colpisce più progetti attivi

Per comprendere l'entità del problema abbiamo analizzato oltre 100 diversi progetti e abbiamo scoperto che 12 erano vulnerabili all'attacco. Questi sono alcuni dei progetti vulnerabili: 

Capsula PUMA CatBlox (tempo di sfruttamento: 2 giorni 18 ore, capitalizzazione di mercato: 628.19 ETH)

Eroi Everai: duo (tempo di sfruttamento: 4 giorni 2 ore, capitalizzazione di mercato: 1,905.37 ETH)

Degen Toonz (tempo di sfruttamento: 3 giorni 13 ore, capitalizzazione di mercato: 6,221.6 ETH)

Maggiori dettagli come tempi di transazione specifici sono nel appendice.

Dettagli tecnici della vulnerabilità

sfondo 

Come lo sono gli NFT Token ERC721, ogni token è univoco con i propri metadati. Di solito, in un progetto NFT con una fase di rivelazione, i token vengono coniati alla cieca e, una volta che tutto è stato coniato, gli NFT vengono rivelati e i loro metadati vengono resi pubblici. Gli NFT con metadati rari potrebbero valutare 50 volte rispetto ad altri NFT nei progetti. Il più raro di tutti è chiamato "Leggenda".

Ma cosa succede se un utente malintenzionato riesce in qualche modo a ottenere i metadati prima che vengano rivelati e utilizza questi dati per acquistare la legenda? L'attaccante ottiene un vantaggio ingiusto e ottiene più profitto di tutti gli altri acquirenti sfruttando questi dati per acquistare la legenda.

Cos'è un token URI?

L'URI del token di un NFT è un identificatore univoco di come "appare" il token. Un URI potrebbe essere un indirizzo HTTP, un hash IPFS o persino un BLOB JSON mantenuto on-chain. Punta a un file JSON che contiene i metadati del token.

Quando crei il tuo progetto NFT, devi assicurarti che gli URI dei token non siano accessibili o indovinabili prima della rivelazione NFT. In caso contrario, ciò potrebbe potenzialmente consentire agli aggressori di ottenere il controllo degli NFT più preziosi del progetto. In effetti, potrebbero utilizzare questi URI per verificare la presenza di alcune proprietà rare nei metadati prima che chiunque possa vederle.

La vulnerabilità 

Abbiamo scoperto che molti progetti impostano l'URI del token in una transazione e poi lo rivelano in un'altra transazione. Nel tempo che intercorre tra queste due transazioni, che a volte possono durare ore, un utente malintenzionato può scansionare tutti gli NFT nel progetto e trovare qual è il più raro, quindi acquistarlo in base al suo tokenID.

Esempio di sfruttamento

Qui abbiamo un esempio di una funzione che restituisce l'URI del token se the reveal flag è vero (è falso per impostazione predefinita) o un URI che punta a un'immagine nascosta comune per ogni token se il flag è falso.

function tokenURI(uint256 tokenId) public view virtual override
       returns (string memory)
   {
       require(_exists(tokenId), "Nonexistent token");
       if (reveal == false) {
           return hideURI;
       }
       string memory URI = baseURI;
       uint256 randomId = ((randomNumber + tokenId) % supplyMax) + 1;
       return
           bytes(URI).length > 0
               ? string(abi.encodePacked(URI, randomId.toString(), ".json"))
               : "";
   }

L'URI viene creato con quattro elementi: baseURI, tokenId, supplyMaxe randomNumber. Questi quattro elementi sono pubblici nel nostro codice e conosciamo facilmente i primi tre elementi ma non sappiamo quando randomNumber è inizializzato.

Ora vediamo la funzione where reveal diventa vero.

function revealNFT() external onlyOwner {
    require(randomNumber != 0);
       reveal = true;
   }

Comprendiamo che ogni URI è accessibile una volta che gli NFT vengono rivelati. Prima di allora, avevamo solo un'immagine generica per ogni NFT. Ma prima di chiamare revealNFT(), il proprietario deve accertarsene randomNumber è stato inizializzato.

Quindi vediamo dove il codice assegna un valore a randomNumber.

function requestRandomNumbers() external onlyOwner {
       requestId = COORDINATOR.requestRandomWords(
           keyHash,
           s_subscriptionId,
           requestConfirmations,
           callbackGasLimit,
           numWords
       );
   }
 
   function fulfillRandomWords(
       uint256, 
       uint256[] memory randomNumbers
   ) internal override {
       randomNumber = randomNumbers[0];
   }

In questo esempio, usano VRF di Chainlink, un generatore di numeri casuali off-chain, per creare un offset negli URI con randomNumber. Queste due funzioni sopra mostrano come funziona. Il proprietario dovrà chiamare requestRandomNumbers() che assegnerà un numero casuale a randomNumber con una chiamata interna di fulfillRandomWords() di Chainlink.

Cosa sta succedendo nella vita reale quando il proprietario vuole rivelare gli NFT?

Il proprietario inizierà chiamando requestRandomNumbers() a cui assegnare un valore casuale randomNumber. Perché randomNumber ha ora un valore diverso da zero, il proprietario può chiamare revealNFT() per accendere il reveal flag in true, quindi tutti gli URI sono pubblici con tokenURI().

Ma ricorda che per prevedere gli URI, abbiamo solo bisogno di quattro elementi di cui tre già noti e randomNumber che è anche pubblico e ha il suo valore assegnato quando requestRandomNumbers() è chiamato.

Quindi nel frattempo tra requestRandomNumbers() ed revealNFT() vengono chiamati, gli URI non sono ancora pubblici ma abbiamo tutti gli elementi per prevederli.

Esiste un'altra versione di questa vulnerabilità. Anche se più comune, è più difficile da sfruttare. Se non c'è una fase di rivelazione, il baseURI viene spesso impostato all'inizio o nel mezzo della fase di mint. Quindi, non appena un NFT viene coniato, viene rivelato, ma i token rimanenti rimangono sconosciuti. Possiamo quindi recuperare l'URI e usarlo per conoscere gli NFT più rari tra quelli rimanenti. Quindi devi provare a coniare al momento giusto per trovarli.

Come abbiamo detto sopra, il risultato è che gli aggressori possono ottenere il controllo degli NFT più preziosi nel progetto in quanto potrebbero utilizzare questi URI per verificare la presenza di alcune proprietà rare nei metadati prima che chiunque possa vederli.

Per evitare di avere lo stesso tipo di vulnerabilità, puoi verificarle Strategie di randomizzazione per cadute NFT Di William Entrike. Ti aiuterà a randomizzare gli URI dei token in modo sicuro.

Mitigazione

Quindi cosa dovresti fare se possiedi un progetto NFT e vuoi mitigare i rischi e proteggere la base di codice da BadReveal?

Poiché l'essenza della vulnerabilità BadReveal si basa sul vantaggio che l'attaccante ha tra l'impostazione della transazione URI del token sulla transazione di rivelazione (o mint), la mitigazione sarebbe quella di combinare i due in un'unica transazione.

Se prevedi di rivelare gli NFT, imposta contemporaneamente l'URI del token di base:

 function reveal(string memory baseURI) public onlyOwner {
     revealed = true;
     baseTokenURI = baseURI;
 }

Nell'esempio che abbiamo visto in precedenza la soluzione potrebbe anche essere quella di spostare il reveal in modo che venga impostato automaticamente dalla transazione di Chianlink:

function fulfillRandomness(bytes32, uint256 _randomness) internal override {
     revealed = true;
     randomNumber = randomNumbers[0];
}

Sfruttando questo approccio, potresti prendere in considerazione l'idea di scartare il file revealed boolean dal tuo codice e sostituendolo con la verifica al volo di Chainlink randomNumber Incarico:

function someMintingFunction(uint256 _quantity) internal {
     require(!randomNumber, "Not revealed yet");
     //…
}

L'utilizzo di questo meccanismo è il modo più semplice per mitigare BadReveal in quanto non introduce il divario tra le transazioni che consente a un utente malintenzionato di acquistare prima che altri acquirenti ottengano le informazioni sui metadati.

Sommario

I rischi informatici dei progetti NFT possono assumere molte forme e forme, è opinione comune che se il tuo NFT non è stato rubato non sei stato violato, ma cosa succederebbe se dovessi ottenere l'NFT più raro nel mazzo, ma un attaccante è stato abbastanza intelligente da comprarlo prima di te? Sei stato hackerato senza nemmeno saperlo.

È importante stabilire requisiti affinché i progetti NFT investano in audit di alta qualità e utilizzino buone pratiche di sicurezza. 

Crediamo fermamente che questa vulnerabilità sia comunemente sfruttata in natura sotto il radar degli investitori e delle comunità NFT. Si prega di condividere queste informazioni con il maggior numero possibile di progetti in modo che ne garantiscano la sicurezza.

Vorremmo ringraziare tappetopullfinder @rugpullfinder l'aiuto nell'indagare e verificare con noi la vulnerabilità. Abbiamo usato la loro esperienza e conoscenza nello spazio NFT per approfondire la tana del coniglio di BarReveal

Appendice – Progetto interessato

Dettagli di CatBloxPUMACapsule

https://etherscan.io/address/0x8b8D1225bB21CA07812FF3c2ee9358f7b5d90EcA

Everai Heroes: dettagli del duo

https://etherscan.io/address/0x9a38dec0590abc8c883d72e52391090e948ddf12

Degen Toonz Dettagli

https://etherscan.io/address/0x19b86299c21505cdf59ce63740b240a9c822b5e4

Scritto Da
Avigdor Sason Cohen

Avigdor è un ricercatore di sicurezza web3 presso Sayfer. È appassionato delle nuove tecnologie blockchain e di come possiamo assicurarci di svilupparle in modo sicuro.

 

Salta al contenuto