WEB3DEV

Cover image for Desenvolvimento Seguro de Contratos Inteligentes (1) - Reentrância de Código em Contratos NFT
Panegali
Panegali

Posted on

Desenvolvimento Seguro de Contratos Inteligentes (1) - Reentrância de Código em Contratos NFT

Introdução

Dada a prosperidade do ecossistema NFT na Ethereum e o aumento dos problemas de segurança relacionados, publicaremos uma série de blogs para apresentar esses problemas de segurança e dar algumas sugestões para os desenvolvedores garantirem contratos. Neste blog, apresentaremos o problema de reentrância em contratos NFT e como mitigar a vulnerabilidade relacionada.

O que é Reentrância

De acordo com a Wikipédia

Em computação, um programa de computador ou sub-rotina é chamado de reentrante se várias invocações podem ser executadas simultaneamente em vários processadores, ou em um sistema de processador único, onde um procedimento reentrante pode ser interrompido no meio de sua execução e então ser chamado novamente com segurança (“re-entrada”) antes que suas invocações anteriores concluam a execução.

Em um contrato inteligente, a reentrância pode ocorrer quando uma função executa uma chamada externa de outro contrato, que invoca ainda mais a função original (ou outras funções) antes que a invocação original retorne. Se a chamada externa for controlada por uma entidade não confiável (por exemplo, um contrato malicioso), pode levar a um resultado inesperado. Isso porque, em algumas funções, o resultado depende do estado do contrato. O estado do contrato será atualizado após a chamada externa. No entanto, a invocação reentrante da função usará o estado antigo em vez do atualizado.

A reentrância tem sido um problema predominante em contratos inteligentes, por exemplo, o ataque MakerDAO, o ERC777 na Uniswap e outros (pesquise Reentrancy (Reentrância) na BlockSec Academy).

Reentrância em NFT

1

Para contratos NFT, existem algumas chamadas de funções externas implícitas que podem ser negligenciadas pelos desenvolvedores. Elas incluem a função onERC721Received e onERC1155Received. A função onERC721Received foi projetada para verificar se o contrato receptor pode lidar com NFTs (para evitar que as NFTs sejam bloqueadas para sempre). Essa função é invocada no safeTransferFrom e _safeMint do contrato ERC721. O similar existe no contrato ERC1155. Devido a essas chamadas de funções externas, a reentrância pode acontecer sem ser notada pelos desenvolvedores do contrato.

Reentrância de Função Única

A reentrância de função única é a forma mais simples de ataque de reentrância. Nesse tipo de ataque de reentrância, a função reinvocada é a mesma da função original. Um invasor pode invocar a função repetidamente antes que a primeira invocação da função seja concluída. Nos contratos NFT, isso geralmente acontece nas funções relacionadas à operação mint.

Por exemplo, alguns projetos de NFT podem dar a cada usuário a chance de criar NFT livremente, definir o fornecimento máximo de todo o projeto ou definir a quantidade máxima de NFTs que um usuário pode manter. Normalmente, essas restrições são verificadas antes da operação de cunhagem real. Mas se os estados relacionados a essas restrições forem atualizados após a função safeMint, o invasor poderá reinserir essa função mint e ignorar as restrições, pois os estados relacionados são os mesmos da primeira invocação dessa função. O ataque de reentrância do HypeBears postado em nosso blog anterior é um exemplo.

Uma reentrância de função única mais complicada ocorre quando a função safeMint é usada em um loop e as restrições são verificadas antes do início do loop. Nesse cenário, mesmo alguns estados serão atualizados automaticamente antes da chamada externa, as chamadas de função safeMint restantes no loop ainda podem ignorar a validação, pois o loop já foi iniciado e a validação acontece antes do início do loop.

Por exemplo, no exemplo mostrado em outro post, a função mintNFT verificará se o número de NFTs que o usuário deseja cunhar mais o fornecimento atual pode exceder o fornecimento máximo. A função safeMint atualiza o fornecimento total antes da chamada externa onERC721Received. Um invasor ainda pode explorá-lo, pois a função safeMint só aumenta a oferta total em 1 a cada vez. Portanto, se o invasor reinserir a função mintNFT na primeira chamada de função safeMintdo loop, a oferta total se tornará a oferta antiga mais 1, em vez da oferta antiga mais a quantidade de NFTs que serão cunhadas pela primeira chamada de mintNFT.

Reentrância entre funções

Em vez de inserir a mesma função, o invasor pode inserir outra função que compartilhe ou dependa dos estados com a função de origem. Detalhamos alguns casos em nossos blogs anteriores para o caso Revest e o caso OMNI.

Resumo e sugestões

Aqui estão algumas sugestões para desenvolvedores de contratos inteligentes NFT para mitigar a ameaça de reentrância.

  1. Use o padrão Checks-Effects-Interactions em seu código.
  2. Tenha cuidado ao usar qualquer biblioteca de terceiros que introduzirá chamadas externas. Para contratos NFT, tenha cuidado com o retorno de chamada implícito da função onERC721Receivede onERC1155Received.

Sobre nós

A equipe BlockSec se concentra na segurança do ecossistema blockchain e na pesquisa de monitoramento e bloqueio de hacks de criptomoedas, auditoria de contratos inteligentes.

Saiba mais sobre a BlockSec:

Twitter: https://twitter.com/BlockSecTeam

Github Academy: https://github.com/blocksecteam/blocksec_academy


Artigo escrito por BlockSec e traduzido por Marcelo Panegali

Oldest comments (0)