Como um contrato malicioso esconde seu script

porMatheusem26/06/2022

Nesse artigo iremos aprender a como um contrato malicioso consegue ocultar seu script malicioso e como previnir um ataque em seu contrato inteligente.

Vulnerabilidade

No Solidity qualquer endereço pode ser convertido em contrato específico, mesmo que o contrato no endereço não seja o que está sendo lançado.
Isso pode ser explorado para ocultar códigos maliciosos. Vamos ver como.

Como funciona:
Digamos que Alice possa ver o código de Foo e Bar, mas não de Mal. É óbvio para Alice que Foo.callBar() executa o código dentro de Bar.log().
No entanto, Eve implanta Foo com o endereço de Mal, de modo que chamar Foo.callBar() irá realmente executar o código em Mal.

  1. Eve implanta Mal
  2. Eve implanta Foo com o endereço de Mal
  3. Alice chama Foo.callBar() depois de ler o código e julgar que é seguro para interagir.
  4. Embora Alice esperasse que Bar.log() fosse executado, Mal.log() foi executado.

O que aconteceu?
Alice foi levada a interagir com o contrato Mal, mesmo após revisar o contrato Bar e entender que o script estava correto.
Devido a tática de Eve de esconder o contrato Mal atrás do contrato Bar, ocasionando assim uma interação com possível script malicioso como podemos ver abaixo.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
contract Foo {
Bar bar;
constructor(address _bar) {
bar = Bar(_bar);
}
function callBar() public {
bar.log();
}
}
contract Bar {
event Log(string message);
function log() public {
emit Log("Bar foi chamado");
}
}
// Este código está oculto em um arquivo separado
contract Mal {
event Log(string message);
// function () external {
// emit Log("Mal foi chamado");
// }
// Na verdade podemos executar o mesmo exploit mesmo que esta função
// não exista usando o fallback
function log() public {
emit Log("Mal foi chamado");
}
}

Técnicas Preventivas

  • Inicialize um novo contrato dentro do construtor
  • Fazer com que o endereço do contrato externo seja public para que o código do contrato externo possa ser revisado
Bar public bar;
constructor() public {
bar = new Bar();
}

Testar no Remix