Introdução
Dado o crescimento do ecossistema de NFTs no Ethereum e o aumento de problemas de segurança relacionados, publicaremos uma série de artigos para apresentar esses problemas de segurança e oferecer algumas sugestões para que os desenvolvedores protejam seus contratos. Neste artigo, apresentaremos o problema de reentrância em contratos NFT e como mitigar a vulnerabilidade relacionada.
O que é Reentrância
De acordo com a wikipedia
Em computação, um programa de computador ou sub-rotina é chamado de reentrante se múltiplas invocações puderem ser executadas com segurança de forma concorrente em múltiplos processadores, ou em um sistema com processador único, onde um procedimento reentrante pode ser interrompido no meio de sua execução e, então, ser chamado novamente com segurança ("reentrando") antes que suas invocações anteriores completem a execução.
Em um contrato inteligente, a reentrância pode ocorrer quando uma função executa uma chamada externa a outro contrato, que por sua vez invoca 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), isso pode levar a um resultado inesperado. Isso ocorre 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 utilizará o estado antigo em vez do atualizado.
A reentrância tem sido um problema prevalente em contratos inteligentes, como o ataque ao MakerDAO, o ERC777 na Uniswap, e outros (pesquise por Reentrancy na BlockSec Academy).
Reentrância em NFT

Para contratos NFT, existem algumas chamadas externas de funções implícitas que podem ser negligenciadas pelos desenvolvedores. Elas incluem as funções onERC721Received e onERC1155Received. A função onERC721Received foi projetada para verificar se o contrato receptor consegue lidar com NFTs (para evitar que os NFTs fiquem bloqueados para sempre). Essa função é invocada em safeTransferFrom e _safeMint do contrato ERC721. Uma similar existe no contrato ERC1155. Devido a essas chamadas de funções externas, a reentrância pode acontecer sem ser percebida pelos desenvolvedores de contratos.
Reentrância em Função Única
A reentrância em função única é a forma mais simples de ataque de reentrância. Nesse tipo de ataque, a função reinvocada é a mesma que a função original. Um atacante pode invocar a função repetidamente antes que a primeira invocação da função seja concluída. Em contratos NFT, isso geralmente acontece em funções relacionadas à operação de mint.
Por exemplo, alguns projetos NFT podem dar a cada usuário a oportunidade de criar NFTs gratuitamente, definir o fornecimento máximo de todo o projeto, ou definir a quantidade máxima de NFTs que um usuário pode possuir. Normalmente, essas restrições são verificadas antes da operação de mint propriamente dita. Mas se os estados relacionados a essas restrições forem atualizados após a função safeMint, o atacante pode reentrar nessa função de mint e contornar as restrições, pois os estados relacionados são os mesmos que na primeira invocação dessa função. O ataque de reentrância ao HypeBears publicado em nosso artigo anterior é um exemplo.
Uma reentrância em função única mais complexa ocorre quando a função safeMint é usada em um loop e as restrições são verificadas antes de o loop começar. Nesse cenário, mesmo que alguns estados sejam atualizados automaticamente antes da chamada externa, as chamadas restantes da função safeMint no loop ainda podem contornar a validação, pois o loop já foi iniciado e a validação ocorre antes de ele começar.
Por exemplo, no caso apresentado em outra publicação, a função mintNFT verifica se o número de NFTs que o usuário deseja criar somado ao fornecimento atual pode exceder o fornecimento máximo. A função safeMint atualiza o fornecimento total antes da chamada externa onERC721Received. Um atacante ainda pode explorar isso, pois a função safeMint aumenta o fornecimento total em apenas 1 a cada vez. Portanto, se o atacante reentrar na função mintNFT na primeira chamada da função safeMint no loop, o fornecimento total se torna o fornecimento antigo mais 1, em vez do fornecimento antigo mais a quantidade de NFTs que serão criados pela primeira chamada de mintNFT.
Reentrância entre Funções
Em vez de entrar na mesma função, o atacante pode entrar em outra função que compartilha ou depende dos estados da função de origem. Detalhamos alguns casos em nossos artigos anteriores sobre o caso Revest e o caso OMNI.
Resumo e Sugestões
Aqui estão algumas sugestões para desenvolvedores de contratos inteligentes NFT mitigarem a ameaça de reentrância.
- Use o Padrão Checks-Effects-Interactions em seu código.
- Tenha cuidado ao usar qualquer biblioteca de terceiros que introduza chamadas externas. Para contratos NFT, tome precauções com o callback implícito das funções
onERC721ReceivedeonERC1155Received.
Leia os Outros Artigos desta Série
Sobre a BlockSec
A BlockSec é uma empresa pioneira em segurança de blockchain, fundada em 2021 por um grupo de especialistas em segurança de renome mundial. A empresa está comprometida em aprimorar a segurança e a usabilidade para o emergente mundo Web3, a fim de facilitar sua adoção em massa. Para isso, a BlockSec oferece serviços de auditoria de segurança de contratos inteligentes e chains EVM, a plataforma Phalcon para desenvolvimento seguro e bloqueio proativo de ameaças, a plataforma MetaSleuth para rastreamento e investigação de fundos, e a extensão MetaSuites para construtores web3 navegarem com eficiência no mundo cripto.
Até o momento, a empresa atendeu mais de 300 clientes ilustres, como MetaMask, Uniswap Foundation, Compound, Forta e PancakeSwap, e recebeu dezenas de milhões de dólares americanos em duas rodadas de financiamento de investidores proeminentes, incluindo Matrix Partners, Vitalbridge Capital e Fenbushi Capital.
Site oficial: https://blocksec.com/
Conta oficial no Twitter: https://twitter.com/BlockSecTeam



