A motivação por trás deste artigo sou eu tentando aprender algumas das vulnerabilidades em smart contracts. Sou grato ao programador de smart contract por me ajudar nessa jornada. Dê uma olhada no canal dele.
Então. Deixe-nos começar!
Tenho certeza de que você já deve ter ouvido falar sobre o famoso ataque DAO, que levou à criação do Ethereum Classic. A vulnerabilidade explorada pelo invasor é chamada de “Reentrância”.
O que é o ataque de reentrância?
Considere que existem dois Contratos A e B, onde o Contrato A chama o Contrato B. Nesse ataque, o que acontece é que, quando a primeira chamada ainda está em execução, o Contrato B chama o Contrato A, e isso meio que resulta em um loop.
Tentaremos entender melhor o ataque com a ajuda do exemplo abaixo. Temos um smart contract chamado EtherStore, onde se pode depositar, sacar e verificar o saldo atual do smart contract.
EtherStore.sol
Vemos que a função withdraw tem um controle para não permitir que o usuário retire mais fundos do que tem, mas o bug está na linha 16. Sempre que enviamos ether para um endereço de smart contract, definimos o que chamamos de fallback. Na maioria dos casos, esta é apenas uma função vazia, mas o invasor é inteligente o suficiente e é aqui que o código de exploração real é colocado.
O Ataque
O invasor chama o exploit, na qual ele deposita 1 ether no contrato EtherStore para passar na verificação da Linha 14 do contrato EtherStore. Quando o código atinge a Linha 16, a fallback do contrato do invasor é invocada onde o invasor chama a função withdraw na EtherStore, até ele drenar os fundos.
Reentrancy.sol
A Solução
Este ataque é possível porque o código nunca chega à Linha 20 do EtherStore onde subtraímos o valor sacado do EtherStore. Para corrigir isso, temos duas soluções que podem ajudar. A primeira é a reposição da lógica para subtrair o saldo do usuário antes de transferi-lo.
função retirada() modificada
A segunda solução seria usar um noReentrancy guard modifer que bloqueia o contrato durante a execução e o desbloqueia no final da execução.
noReentrancy guard modifer
Tentei explicar o problema usando uma linguagem simples e exemplos práticos. Espero que tenha gostado de lê-lo.
Tchau!!!
Artigo escrito por Zuhaib Mohammed e traduzido por Arnaldo Campos . Você pode encontrar o artigo original aqui.
Oldest comments (1)
Show de bola, agora para evitar alguma falha de lógica é interessante usar a lib da Openzeppelin (Reentrancy Guard).