Quem Realmente Chamou: A Falha de Autenticação com tx.origin
O desafio
O vault on-chain da Pembrook permite que apenas o owner faça saques, e a chave do owner nunca vazou. Mesmo assim, o vault foi esvaziado depois que o owner usou um novo site de airdrop que pedia para clicar em Claim. A proteção do saque está fazendo o que o autor escreveu; o autor só fez a pergunta errada sobre quem está chamando. Leia o contrato e indique a expressão na verificação de owner que permitiu que um contrato com o qual o owner apenas interagiu gastasse em nome dele.
O que você vai aprender
- Distinguir msg.sender (chamador imediato) de tx.origin (assinante da transação)
- Explicar como um contrato de phishing mantém tx.origin igual à vítima
- Identificar tx.origin em uma checagem de acesso como a vulnerabilidade
- Comparar com uma checagem correta de propriedade usando msg.sender
- Enunciar a regra: autorize com msg.sender, não com tx.origin
Habilidades testadas
Pré-requisitos
- Leitura de Solidity
- O que é uma cadeia de chamadas entre contratos
Como funciona
Toda chamada em Solidity enxerga duas identidades. msg.sender é quem chamou esta função diretamente, o que pode ser outro contrato. tx.origin é a conta externa (EOA) que assinou a transação inteira, sem mudar, não importa por quantos contratos a chamada passe.
Autorizar com tx.origin é passível de phishing. Se o dono é induzido a chamar um contrato malicioso, e esse contrato chama o vault, então dentro do vault msg.sender é o contrato malicioso, mas tx.origin continua sendo o dono. Uma checagem de tx.origin == owner passa, e o código do atacante gasta como se fosse o dono sem nunca tocar na chave do dono.
O transferOwnership do mesmo contrato mostra a forma correta, comparando msg.sender, que não pode ser conduzido através de um intermediário.
Erros comuns
- Responder
msg.sender. Essa é a checagem segura, usada corretamente emtransferOwnership. - Culpar uma chave vazada. Nenhuma chave vazou; o dono foi enganado para originar a transação.
- Apontar para
transferou para a checagem de saldo. Essas partes estão corretas; a falha está na forma como o dono é identificado. - Chamar de reentrancy. Nada reentra; a chamada única simplesmente passa por uma proteção vulnerável a phishing.
Como se proteger
Identifique os chamadores com msg.sender.
- Substitua
tx.origin == ownerpormsg.sender == ownerem toda checagem de acesso. - Evite
tx.originpara autorização por completo. Seus poucos usos legítimos são desencorajados, e a account abstraction corrói ainda mais a noção de uma origem única. - Adicione testes que chamem funções privilegiadas por meio de um contrato intermediário, para que uma proteção vulnerável a phishing falhe no CI.