Um aplicativo descentralizado (dApp) Ethereum é um aplicativo que interage com um protocolo de consenso por trás dele. No nosso caso, analisamos um dos casos de uso mais comuns de um dApp: um aplicativo web comum que interage com um ou vários contratos inteligentes.
Quando você visita um dApp pela web (com uma extensão como a MetaMask), você pode interagir com o site com sua chave privada e assinar transações por meio de sua interface web.
Aqui está o exemplo de um dApp, onde eu uso sua interface web e minha extensão do Chrome contendo minha carteira Ethereum para comprar um Cryptokitty:
Quando seu navegador interage com um aplicativo web comum, o aplicativo web pode falar com outros servidores internos, bancos de dados ou uma nuvem. No final, a interação é simples:
Em um dApp, a maioria das interações são as mesma. Mas há um terceiro elemento: o contrato inteligente, que é acessível ao público.
Algumas interações com o aplicativo da web levarão a uma leitura ou gravação em um ou vários contratos inteligentes na blockchain Ethereum.
Abordagem multifacetada
O dApp existe, em parte, para simplificar a interação com seus contratos inteligentes para o usuário final. Mas não há regra que declare que devemos interagir com os contratos inteligentes do dApp por meio da interface web do dApp. Como os contratos inteligentes são acessíveis publicamente, podemos interagir com eles diretamente, sem impedimentos pela lógica do servidor web que pode restringir quais transações podemos emitir.
Até agora, temos uma abordagem em duas frentes para o nosso teste de invasão:
- Um teste de invasão de aplicação web padrão explorando autenticação, controles de acesso e gerenciamento de sessão.
- Uma auditoria de contrato inteligente.
Em outras palavras, verificamos erros lógicos no aplicativo Web e na lógica do contrato inteligente.
No entanto, devido aos modificadores, há na verdade um terceiro aspecto que podemos considerar em nosso ataque.
Modificadores
Na Ethereum, você pode escrever funções que só são executadas se chamadas de um endereço Ethereum específico. onlyOwner
é um exemplo comum de um modificador que, quando implementado corretamente, permite apenas que o proprietário do contrato execute determinadas funções.
contract mortal {
/* Defina o proprietário da variável do tipo endereço */
address owner;
modifier onlyOwner {
require(msg.sender == owner);
_;
}
function writeData(bytes32 data) public onlyOwner returns (bool success) {
// só será executado se o proprietário enviou a transação
}
...
}
Embora possamos interagir diretamente com o contrato inteligente, não podemos executar funções quando modificadores como onlyOwner
são implementados corretamente. Entretanto, quando se trata de um dApp, as chaves privadas para esses endereços privilegiados quase certamente existem no servidor web. E a aplicação web quase certamente tem uma lógica que leva a entrada do usuário pela web e chama uma função privilegiada no contrato inteligente usando uma dessas chaves.
Como o dApp tem acesso a esses endereços privilegiados da Ethereum, o terceiro ponto se torna: “como podemos fazer com que o dApp escreva funções privilegiadas no contrato inteligente em nosso nome?”
Tudo isso considerado, temos nossa base de ataque:
- Uma avaliação padrão de aplicativos web (autenticação, controle de acesso, gerenciamento de sessões). Isso pode não envolver contratos inteligentes. Escalonamento de privilégios horizontal/vertical, injeção de banco de dados, XSS, etc.
- Uma auditoria de contrato inteligente. Problemas de permissão, overflows/underflows, race conditions, etc.
- Tentativa de forjar gravações privilegiadas no contrato inteligente por meio da interface web. Você pode fazer com que o aplicativo web interaja com o contrato inteligente de uma maneira que ele não esperava?
Interceptando pedidos com Burp
Quando você vai se inscrever para uma conta no Cryptokitties, a lógica do aplicativo web obtém seu endereço Ethereum que você expõe de sua extensão MetaMask. Em seguida, ele solicita que você insira seu endereço de e-mail e apelido para sua conta.
A próxima parte é fundamental: como os dApps negociam com suas contas Ethereum, elas são baseadas na autenticação da chave pública. Não há autenticação de senha.
Para este efeito, Cryptokitties solicita que você assine uma mensagem (“Cryptokitties”) para garantir que você possui a chave privada associada ao seu endereço.
Se interceptarmos a solicitação, veremos:
Em teoria, o site Cryptokitties verificaria se os dados no parâmetro sign (sua mensagem “Cryptokitties” assinada) correspondem ao parâmetro address, seu endereço Ethereum.
Essa validação ocorre na lógica da aplicação web. Encontrei vários dApps que não validam a assinatura corretamente, permitindo que eu troque meu endereço Ethereum de inscrição por um que não corresponda à minha assinatura, assim:
Cryptokitties valida assinaturas corretamente, mas quando um dApp não o faz, eu produzi negação de serviço para o proprietário do endereço Ethereum falsificado e forjei sua identidade nesse aplicativo.
Assinando
Aqui está um exemplo de autenticação de manipulação de um dApp. Depois de cadastrar para uma conta, qualquer login subsequente de seu endereço Ethereum exige que você assine uma detalhada mensagem contendo sua intenção (estou me cadastrando), seu endereço de e-mail e a hora atual.
Por que esse dApp quebra a assinatura nesses campos?
- Intenção: Assinar algo e enviar essa assinatura para algum lugar é perigoso se o usuário não entender o que está assinando. Isso deixa clara a intenção da assinatura no texto da mensagem.
- Endereço de e-mail: recupera o endereço de e-mail da sua assinatura e vê se esse endereço de e-mail foi usado para se inscrever com o endereço Ethereum que assinou a mensagem. Se for uma correspondência, a tentativa de login é válida (até o momento).
- Timestamp: Isso evita um ataque de repetição (Replay Attack). Se a hora atual não foi incluída na assinatura, um invasor que visse a assinatura poderia reproduzi-la a qualquer momento para autenticar como esse usuário. Em vez disso, ele só considera a assinatura válida se o aplicativo da web a receber dentro de alguns minutos do carimbo de data/hora indicado da assinatura.
A alteração de qualquer um desses campos deve causar um erro.
Vulnerabilidades de contratos inteligentes
Discutimos um dos pontos do nosso ataque, como a auditoria direta de vulnerabilidades do contrato inteligente. Vamos examinar algumas vulnerabilidades vistas no mundo selvagem.
batchOverflow
Este foi apelidado de batchOverflow
. Veja se você consegue descobrir como os invasores exploraram essa vulnerabilidade antes de analisar algumas dessas respostas.
Uma análise mais detalhada pode ser encontrada aqui.
Reinicializando o dono da carteira
A Parity sofreu uma grande perda por não implementar um modificador adequado, conforme discutimos anteriormente. Qualquer um poderia chamar a função initWallet
, o que permitia definir seu próprio endereço como o proprietário dessa carteira.
Tipicamente, o proprietário de uma carteira (ou contrato) é definido no construtor do contrato, que é chamado apenas uma vez. Qualquer alteração subsequente nesse endereço ocorreria em uma função que exigisse a assinatura do proprietário inicial. Aqui, esse modificador não existia e initWallet
podia ser chamado sempre.
Uma análise mais detalhada pode ser encontrada aqui.
Ferramentas de auditoria de contratos inteligentes
Existem ferramentas poderosas de código aberto para auditar o código de contratos inteligentes. Entre eles estão Manticore da Trail of Bits e Mythril da ConsenSys. Vou deixar os detalhes dessas ferramentas para outro post.
Finalizando
Espero que este post tenha lhe dado uma melhor compreensão sobre a base de ataque de um dApp e como ele difere de um aplicativo web padrão.
Para mais conteúdo sobre segurança Ethereum e blockchain, siga meu Twitter, onde eu posto sobre esses tópicos com frequência.
Este artigo foi escrito por Brandon Arvanagui e traduzido por Marcelo Panegali. O original pode ser encontrado aqui.
Oldest comments (0)