Ataque de reentrância (Reentrancy attack)
O ataque de reentrância foi responsável por diversos hacks, incluindo o da DAO em 2016. Esse tipo de ataque ocorre quando um contrato realiza uma chamada externa para um endereço não confiável sem antes modificar seu próprio estado. O contrato malicioso pode então invocar recursivamente a função vulnerável. Por exemplo, uma função de saque que envia ETH antes de atualizar o saldo do usuário pode ser explorada se o endereço do destinatário for um contrato com uma função fallback que chame novamente a função de saque.
Exemplo: Vamos ver um exemplo onde um ataque de reentrância é possível.
Neste exemplo, usando a função withdraw()
, um usuário pode sacar seu saldo em ether, o mesmo que foi previamente depositado no contrato. A função lê o saldo do usuário, envia o valor correspondente em ether para o endereço que realizou a chamada e, por fim, redefine o saldo desse endereço.
Como sabemos, é possível criar uma função fallback que receba ether e execute determinado código. Assim, um atacante pode implantar um contrato que inclua uma função fallback do seguinte tipo:
No contrato anterior, attackedAddress
é o endereço do contrato que contém ether e que será alvo do ataque. Um invasor pode implantar esse contrato e iniciar um ataque utilizando a função attack()
, que drenará todos os fundos do contrato vulnerável.
Mitigação:
Utilizar o padrão de "Retirada" (withdraw pattern) em vez do padrão de "Envio" (send pattern).
Atualizar o estado interno antes de realizar chamadas externas.
Limitar o uso de chamadas externas e utilizar bibliotecas de segurança, como a OpenZeppelin.
Referência:
Last updated
Was this helpful?