Antecedentes
No último post, aprendemos sobre ataques de DoS contra contratos inteligentes. Desta vez, veremos os ataques de phishing baseados em tx.origin em contratos inteligentes.
Conhecimento prévio
Vamos começar examinando dois métodos comuns para verificar o endereço de um remetente em Solidity.
msg.sender: msg.sender lerá apenas o endereço do chamador de nível superior
tx.origin: tx.origin lerá o endereço original em que a transação foi iniciada
Como vemos no diagrama abaixo, Bob chama o contrato B através do contrato A, que chama o contrato C.
Para o contrato B: tx.origin = Bob e msg.sender = contrato A.
Para o contrato C: tx.origin = Bob e msg.sender = contrato B.
Para o contrato A: Bob é tx.origin e msg.sender
Portanto, tx.origin é sempre um endereço EOA, embora o msg.sender possa ser um EOA ou um endereço de contrato.
Exemplo de vulnerabilidade
Suponho que você já esteja familiarizado com a distinção entre msg.sender e tx.origin, mas vamos nos aprofundar um pouco mais na seguinte vulnerabilidade do contrato.
// 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, "Not owner");
(bool sent, ) = _to.call{value: _amount}("");
require(sent, "Failed to send Ether"); }}
Análise de Vulnerabilidade
Evidentemente, um contrato de carteira é uma carteira de contrato que permite ao criador depositar Ether no contrato após a implantação.
Quando você deseja gastar seus fundos, pode transferir qualquer quantia chamando Wallet.transfer ( ). Naturalmente, os fundos na carteira não podem ser acessados por ninguém; portanto, você deve passar no cheque do proprietário tx.origin = = para poder transferir esses fundos. É aqui que o problema surge. Como mencionado anteriormente, tx.origin lê o endereço original em que a transação foi iniciada, portanto, podemos construir um contrato de phishing para induzir a vítima a iniciar uma transação que nos permita obter sua identidade e transferir seu Ehter. Indo além, examinaremos como o contrato de ataque é utilizado para realizar esse roubo de identidade.
Suponho que usuários astutos já tenham identificado a falha no contrato da Carteira, que é a vulnerabilidade de reentrada que introduzimos anteriormente. Referência: quando tx.origin corresponde ao endereço EOA do chamador original, a função à prova de falhas (failsafe) de retorno de chamada é invocada. Não entraremos em mais detalhes aqui; se você estiver com problemas para entender, consulte o nosso artigo intitulado
“Introduction to Smart Contract Security Audits | Reentrancy Attack.”
Contrato de Ataque
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); }}
Vamos começar analisando primeiro o processo de ataque:
Alice implanta o contrato da Carteira e transfere dez Ether para que ele possa funcionar.
Eve descobre fundos no contrato de Carteira, implanta o contrato de Ataque e passa o endereço do contrato de Carteira para o construtor.
Eve usa engenharia social para investigar o interesse de Alice como o de compras bolsas online; implanta um site de compras falso e envia um link para Alice por e-mail.
Alice recebeu o e-mail e sua curiosidade a levou a clicar no link, onde descobriu uma seleção de bolsas baratas que ela gostava. Quando tentou comprá-las, descobriu que precisava conectar sua carteira e fornecer autorização de assinatura para se registrar com sucesso.
Após assinar com sucesso, Alice descobriu que todo o seu Ether no contrato da Carteira havia sido transferido.
A lógica por trás desse ataque é realmente bastante direta, então vamos examinar o que aconteceu.
A assinatura de Alice durante o registro nunca foi usada para registro, mas sim para assinar uma transação que invocava Attack.attack ( ). ataque.attack ( ) chamado pela Wallet.transfer ( ) e passada para um novo proprietário, por meio do endereço EOA de Eve, bem como seu saldo em Ether do contrato de carteira.
O endereço usado para assinar a transação era o endereço EOA de Alice e o tx.origin também era o endereço EOA de Alice para o contrato da Carteira. Eve agora pode transferir o Ether no contrato da Carteira para sua própria conta usando um golpe de phishing e obter acesso com sucesso à conta de Alice.
Sugestões para reparo
Como desenvolvedor: o uso de tx.origin para autorização representa um risco de phishing porque o tx.origin empilha as chamadas recursivamente e depois encontra o endereço do originador ( EOA ) da chamada da transação. Consequentemente, atualmente o tx.origin é usado apenas para determinar se o msg.sender é o endereço EOA e não para verificação de autorização, requerendo o uso do msg.sender.
Como auditor: Durante uma auditoria, você deve examinar os locais no código em que tx.origin é usado para autenticação e avaliar se há risco de phishing.
Este artigo foi escrito por SlowMist e traduzido por Adriano P. de Araujo. O original em inglês pode ser encontrado aqui.
Top comments (0)