Caçar bugs em contratos inteligentes pode ser um trabalho ridiculamente bem remunerado e também é parte integrante da proteção do ecossistema contra hacks. Recentemente, tive o prazer de entrevistar um desenvolvedor que encontrou um bug de US$7 bilhões – e recebeu US$2,2 milhões por reportá-lo.
Neste blog, vamos analisar o bug que esse desenvolvedor encontrou e como ele tinha o potencial de comprometer US$7 bilhões em valor antes de oferecer algumas estratégias e ferramentas que ajudarão você a encontrar bugs.
Vamos mergulhar.
Exemplo de bug em um contrato inteligente da Polygon
Construção
Em 31 de maio de 2020, a blockchain Matic foi ativada (que mais tarde seria renomeada para Polygon). Polygon é uma blockchain compatível com a EVM conhecida por suas baixas taxas de gás e curto tempo de bloco. A cadeia começou recentemente a explorar a tecnologia zk-rollup.
Se você der uma olhada no bloco 0 da Polygon, o primeiro bloco absoluto da blockchain, também conhecido como bloco “gênesis”, você verá 10 transações. Uma dessas transações criou um contrato chamado MRC20.
Bloco Gênesis da Polygon
O que é este contrato?
Quando enviamos um token nativo da blockchain, temos que gastar gás para isso. Assim, a equipe da Polygon implantou um contrato que permite que você assine uma transação para enviar ETH a alguém, tendo outra pessoa com capacidade de pagar a taxa de gás por essa transação. Conhecido como uma “metatransação”, esse recurso foi popularizado com a introdução do EIP-712.
Você pode ver que este contrato recebeu quase 10 bilhões de tokens MATIC para ajudar a facilitar essas transações sem gás. No entanto, este contrato inteligente continha uma vulnerabilidade que poderia ter sido potencialmente explorada para drenar todo o saldo!
Em 3 de dezembro de 2021, o herói da história, o desenvolvedor com o pseudônimo de Leon Spacewalker, enviou um relatório ao programa de recompensas de bugs Immunefi, detalhando essa função exata. Um segundo herói, que chamaremos apenas de Whitehat2, também relatou a vulnerabilidade um dia depois.
Cerca de 800.000 tokens MATIC foram roubados antes que a cadeia fosse finalmente bifurcada, revertida e corrigida em 5 de dezembro de 2021.
Isso nos deixa com mais algumas perguntas: Qual era a vulnerabilidade? Como ela permaneceu desconhecida por tanto tempo? Como foi encontrada?
A Exploração
Abaixo está a função que facilita essas transações sem gás.
function transferWithSig(
bytes calldata sig,
uint256 amount,
bytes32 data,
uint256 expiration,
address to
) external returns (address from) {
require(amount > 0);
require(
expiration == 0 || block.number <= expiration,
"Assinatura está expirada"
);
bytes32 dataHash = getTokenTransferOrderHash(
msg.sender,
amount,
data,
expiration
);
require(disabledHashes[dataHash] == false, "Assinatura Desativada");
disabledHashes[dataHash] = true;
from = ecrecovery(dataHash, sig);
_transferFrom(from, address(uint160(to)), amount);
}
À primeira vista, parece inofensiva: leva a assinatura do usuário, quantos tokens e para quem ele deseja enviá-los e quaisquer outros dados, juntamente com uma data de validade para a transação.
Ele executa alguns requisitos, obtém o hash dos dados para enviar a metatransação, garante que o hash de dados não foi usado e executa a função ecrecovery
.
Esta função é essencialmente um empacotador para a função Solidity ecrecover.
Empacotador da função Solidity ecrecover.
Esta função nos permite verificar de onde vêm as transações assinadas. Você notará que, mesmo na documentação do Solidity, é dito que “retornará zero em caso de erro”. A função ecrecovery
copiou isso e, se tivesse um problema, retornaria 0. O que, como muitos desenvolvedores sabem, pode ser assustador. Se retornar zero em caso de erro, isso significa que devemos verificar se o endereço retornado não é zero, certo?
Aqui está o código real:
Aqui está o que provavelmente deveria estar lá:
Portanto, não verificamos o endereço para garantir que não resultou em um erro. Não é um problema. A última linha de código em nossa função transferWithSig
faz a transferência real, e certamente faremos algum tipo de verificação lá, certo?
function _transfer(address sender, address recipient, uint256 amount)
internal
{
require(recipient != address(this), "não consegue enviar para MRC20");
address(uint160(recipient)).transfer(amount); // Ele só envia o dinheiro!
emit Transfer(sender, recipient, amount);
}
A função _transferFrom
acabou de chamar nossa função _transfer
, como mostrado acima. Você notará que ela não verifica se o endereço from
(remetente) tem dinheiro suficiente.
Isso significa que alguém poderia enviar uma assinatura inválida, o que resultaria em um endereço zero retornado da função ecrecovery, mas o contrato MRC20 ainda enviaria ao endereço to
(destino) uma quantia em dinheiro. É assim que esses 9.999.993.000 MATIC poderiam ser drenados, já que o contrato MRC20 envia o dinheiro diretamente de si mesmo!
Uma verificação para garantir que o endereço from
tenha dinheiro suficiente para essa transação assinada teria evitado esse problema.
Como o Bug do Contrato Inteligente se esquivou da descoberta por tanto tempo?
O que é estranho para mim é que, após a vulnerabilidade ficar adormecida por quase um ano e meio, ela foi descoberta por Leon, por outro hacker de chapéu branco e por um hacker de chapéu preto dentro de um período de poucos dias.
Parece suspeito. Mas a equipe da Immunefi me disse que isso pode acontecer com frequência. Algumas explorações podem se tornar populares com base em um artigo, publicação ou desafio, e as pessoas começam a procurar essa vulnerabilidade, resultando em várias pessoas a encontrando ao mesmo tempo.
Mas o mais provável é que a Polygon tenha verificado o contrato no Polygonscan nessa época – então foi quando as pessoas realmente começaram a olhar para ele.
Talvez haja mais na história, mas talvez não.
De qualquer forma, vamos usar esse bug como um momento de aprendizado e ver algumas das habilidades que Leon e outros caçadores de bugs usam para encontrar bugs, ajudando a proteger o ecossistema Web3.
As 7 principais estratégias
Agora, vamos aprender as habilidades que Leon e outros caçadores de bugs usam para encontrar essas vulnerabilidades e reivindicar recompensas de bugs. Esta lista de dicas pressupõe que você já conhece o básico dos contratos inteligentes, então sim, aprender Solidity é um pré-requisito.
Use esses superpoderes para hacks éticos e lembre-se de divulgar com responsabilidade quaisquer vulnerabilidades que encontrar.
Muito do trabalho de encontrar vulnerabilidades vem de olhar para o código e executar ferramentas como o slither. Para este pagamento de US$2,2 milhões, Leon disse que conseguiu encontrar o bug olhando linha por linha no código do contrato inteligente, então lembre-se, encontrar vulnerabilidades geralmente é um grande esforço manual!
Além das dicas práticas abaixo, a maior lição de Leon foi para que os caçadores de bugs de contratos inteligentes “encontrem sua vantagem”, mas o que ele quer dizer com isso? Normalmente, isso significa encontrar algo que o diferencia de outros hackers. Nós, como comunidade, precisamos cobrir todos os cantos do espaço do contrato inteligente, então encontre uma seção em que você seja especificamente bom e se destaque.
Aqui estão as sete estratégias e dicas para ajudar a encontrar sua vantagem, para torná-lo um caçador de bugs de contrato inteligente bem-sucedido.
1. Encontre um projeto e procure por bugs
A primeira maneira de encontrar bugs é conhecer cada centímetro de como um protocolo funciona. Essa é uma das primeiras habilidades que todo caçador de bugs de contrato inteligente precisa aprender: a capacidade de entender um protocolo de ponta a ponta.
Percorra os documentos, tente reimplementar um protocolo você mesmo e visualize as transações por meio desse protocolo em um explorador de blocos.
Leon disse que essa estratégia funciona para outros caçadores, mas não para ele. Ele se concentra nos próximos três, mas é importante que todo caçador de bugs seja capaz de fazer isso.
2. Encontre um Bug e Procure Projetos
Uma abordagem mais fácil para caçar bugs é encontrar um bug que poucas pessoas conhecem e tentar ver quais protocolos o implementaram.
Essa estratégia exige muita pesquisa, pois há muitas pessoas trabalhando na exposição de bugs ao público em geral.
Primeiro, você precisa entender todas as explorações básicas de contrato inteligente e, em seguida, suas versões avançadas. Você precisa estar ciente das melhores práticas e ver se existem protocolos que não as seguiram.
Depois de encontrar um bug de contrato inteligente que você acha que muitos projetos podem não ter protegido, comece a procurar por esse bug. Familiarize-se com este novo bug e como encontrá-lo. E não deixe de escrever um blog ou algum tipo de post para ajudar outros desenvolvedores de contratos inteligentes que podem se deparar com esse bug a se protegerem.
3. Seja Rápido
Os projetos que desejam que os caçadores de bugs analisem seus contratos inteligentes precisam se inscrever em programas de recompensas de bugs como o Immunefi. E você vai querer ser um dos primeiros desenvolvedores a encontrar as novas recompensas. Se você começar a analisar um contrato antes de outros caçadores, terá mais tempo para encontrar um bug antes de outros caçadores.
Existem algumas maneiras de ser rápido - uma das maneiras pelas quais Leon conseguiu encontrar a vulnerabilidade do contrato inteligente antes de outros foi ativando notificações para o canal de atualizações do Discord do Immunefi. Ele recebia uma notificação sempre que um novo projeto chegava ou um projeto era atualizado. Ferramentas como essa podem ajudá-lo a ir fundo no código antes de qualquer outra pessoa.
4. Seja criativo
Outra maneira pela qual Leon conseguiu uma vantagem, foi percorrendo os fóruns de comunidades e descobrindo se eles estavam pretendendo submeter uma recompensa por bug. Ele então começaria a olhar para os contratos inteligentes antes mesmo que a recompensa fosse aprovada. Isso deu a ele muito mais tempo para analisar um contrato do que outros desenvolvedores, pois eles esperariam que uma recompensa de bug fosse publicada.
5. Conheça suas ferramentas
Os caçadores de bugs usam ferramentas como a extensão do VSCode para Solidity, Visual Developer, Hardhat, Foundry, Brownie, Dune, Etherscan, além de várias outras.
Uma estratégia típica de caça a bugs pode ser carregar o VSCode, adicionar o código ao VSCode com a extensão visual Solidity e ir linha por linha procurando por bugs comuns ou práticas recomendadas ruins.
Depois de encontrar um ponto fraco, configurar um ambiente de teste para executar testes no contrato é um bom próximo passo. Muitas vezes você pode reutilizar muitos dos testes que os desenvolvedores do protocolo usaram originalmente.
6. Não tenha medo de projetos auditados
Não há muito mais a dizer aqui. As firmas de auditoria cometem erros. Muitos dos projetos para os quais Leon encontrou vulnerabilidades foram auditados por grandes empresas.
Usar as habilidades que falamos neste blog pode ser o diferencial para você encontrar esses problemas!
7. Conhecimento específico do setor
Uma das maiores vantagens em encontrar seu diferencial é se especializar em um nicho específico. Se você entender uma área incrivelmente bem, terá a vantagem de saber como todas as funções interagem entre si. Se você é um especialista fenomenal em vulnerabilidades de contratos inteligentes, mas não sabe nada sobre DeFi, será difícil encontrar vulnerabilidades em contratos DeFi. Por exemplo, muitos desenvolvedores entendem código, mas não entendem conceitos básicos financeiros.
Você pode ficar incrivelmente bom em entender exchanges descentralizadas, protocolos de empréstimo ou talvez apenas NFTs!
Se você puder se tornar um mestre em segurança e um mestre de uma certa vertical na Web3, estará bem posicionado para ter uma grande vantagem sobre todos os outros que procuram bugs.
Resumo
Espero que esta publicação seja útil para você em sua jornada de caça a bugs em contratos inteligentes. Se você quiser saber mais sobre segurança ao escrever seus contratos inteligentes, confira as dez melhores práticas de segurança DeFi.
E, como sempre, espero vê-los por aí construindo e mantendo o ecossistema um pouco mais seguro.
Links
Mudança nos contratos da Polygon
Contratos anteriores da Polygon
As opiniões expressas neste post são exclusivamente do autor e não refletem as opiniões e crenças da Chainlink Foundation ou Chainlink Labs.
Artigo original escrito por Patrick Collins. Traduzido por Paulinho Giovannini.
Latest comments (0)