WEB3DEV

Cover image for Vulnerabilidade de Downcasting de Inteiros: Demonstração e Correção Eficaz
Panegali
Panegali

Posted on

Vulnerabilidade de Downcasting de Inteiros: Demonstração e Correção Eficaz

Este artigo foi originalmente publicado em https://www.buildbear.io/resources/guides-and-tutorials/Downcasting_Vulnerability


Nas versões 0.8 e superiores do Solidity, a verificação de overflow e underflow é habilitada por padrão. No entanto, essa verificação não se aplica a conversões entre tipos inteiros, incluindo conversões de tipo de dados.

Como resultado, as conversões podem levar ao overflow sem acionar uma reversão.

Permita-nos demonstrar este problema:

Para ajudá-lo a começar imediatamente, já preparamos um repositório que mostra essa vulnerabilidade. Vamos começar fazendo uma cópia do repositório.

Etapa 1: Clonar o repositório do tutorial

1.1 Bifurcando o repositório do tutorial:

  • Visite nosso Repositório do Tutorial e clique no botão “Fork” para duplicar o repositório em sua própria conta. Aguarde até que o processo de bifurcação seja concluído antes de prosseguir.

1.2 Clonando o repositório localmente:

  • Acesse seu repositório bifurcado no GitHub.
  • Clique no botão “Code” (Código) e copie o URL fornecido (seja HTTPS ou SSH).
  • Abra seu terminal ou Git Bash.
  • Navegue até o diretório onde deseja colocar o repositório clonado.
  • Use o seguinte comando para clonar o repositório:
git clone <cole o URL copiado aqui>
Enter fullscreen mode Exit fullscreen mode
  • Aguarde o processo de clonagem terminar. Depois de concluído, você deverá ver um novo diretório com o nome do repositório no diretório escolhido.
  • Para acessar o repositório clonado, use o comando cd <Nome do repositório clonado> e navegue até a pasta DownCastingError executando cd DownCastingError.

Etapa 2: Vamos examinar os contratos.

2.1 Contrato unsafeDownCasting.sol

Aqui está um detalhamento do código:

  1. O SPDX-License-Identifier especifica a licença sob a qual o contrato é lançado. Neste caso, é a licença MIT.
  2. A declaração pragma solidity ^0.8.15; define a versão do compilador Solidity que deve ser usada. Este contrato requer Solidity versão 0.8.15 ou superior.
  3. O contrato é nomeado unsafeDownCasting. Possui uma variável de estado chamada LuckyNumber do tipo uint, que armazenará o número da sorte.
  4. A função setLuckyNumber é uma função pública que recebe um parâmetro uint256 chamado amount. É usada para definir o número da sorte. Dentro dessa função, o valor amount é convertido para um uint8 usando a sintaxe uint8(amount). Essa operação de downcasting (conversão de uma referência de uma superclasse (classe pai) para uma de suas subclasses (classes filhas)) pode levar a resultados inesperados se o valor amount for maior que o valor máximo de uint8, que é 255. Se o amount exceder esse valor, apenas os 8 bits menos significativos serão armazenados na variável number, descartando os bits excedentes. Isso pode resultar em perda de dados e comportamento incorreto.
  5. O valor number convertido é então atribuído à variável LuckyNumber de estado.
  6. A função getLuckyNumber é uma função de exibição pública que retorna o valor atual da variável LuckyNumber. Permite que outros contratos ou entidades externas recuperem o número da sorte sem modificar o estado do contrato.

2.2 Contrato safeDownCasting.sol

  1. O contrato importa a biblioteca SafeCast dos contratos do OpenZeppelin. Essa biblioteca fornece funcionalidade segura de downcasting.
  2. A instrução using SafeCast for uint256; permite que o contrato use a biblioteca SafeCast para o tipo uint256.
  3. A função setLuckyNumber é uma função pública que recebe um parâmetro uint256 chamado _amount. É usada para definir o número da sorte. Dentro dessa função, o valor _amount é convertido com segurança para uint8 usando a função toUint8()da biblioteca SafeCast. Se o valor _amount for maior que o valor máximo de uint8, o downcast será revertido, garantindo que apenas downcasts válidos sejam executados. O valor uint8 resultante é então atribuído à variável LuckyNumber de estado.

Vamos implantar esses contratos e ver a vulnerabilidade em ação.

Etapa 3: Configurando a infraestrutura para implantar o contrato inteligente

3.1. Visite o aplicativo BuildBear. (Bem, podemos implantar este contrato no nó Hardhat local, mas usaremos o BuildBear, você poderá entender o motivo no final deste tutorial).

3.2. Crie sua Rede de Testes Privada. Você tem a opção de bifurcar das redes principais ou criar uma nova rede de testes do zero, usando a rede principal como base. A bifurcação da rede principal da Ethereum nos permite utilizar convenientemente NFTs e tokens existentes.

3.3. Adicione sua rede de testes privada à sua carteira MetaMask usando o botão “Add to Metamask” (Adicionar a Metamask):

Etapa 4: Implantando o Contrato Inteligente

Para começar, execute o seguinte comando para instalar os pacotes necessários:

npm install
Enter fullscreen mode Exit fullscreen mode

4.1 Atualize o arquivo hardhat.config.js:

  • Acesse seu Dashboard (painel) e clique em “verify contract” (verificar contrato).

  • Copie os objetos BuildBear e Etherscan e atualize o arquivo hardhat.config.js com os novos valores.

4.2 Para implantar os contratos inteligentes safeDownCasting.sol e unsafeDownCasting.sol, execute o seguinte comando: npx hardhat deploy. Isso executará os scripts de implantação localizados na pasta deploy e salvará os detalhes da implantação, incluindo a ABI e o endereço do contrato, na pasta deployments.

4.3 Testando a Vulnerabilidade

Como estamos usando o BuildBear, podemos interagir convenientemente com os contratos diretamente do explorer, eliminando a necessidade de escrever um script.

Clique em “Open Faucet” (abrir torneira) no painel e conecte sua carteira para cunhar tokens nativos. Com o BuildBear, temos nossa própria torneira, então não precisamos solicitar tokens como fazemos quando usamos redes de testes públicas.

Clique no link fornecido no terminal do contrato unsafeDownCasting. Você será direcionado para a página Contract. Vá para a seção "Write Contract" (Escrever contrato).

Clique em “Connect to Web3”(Conectar à Web3). Agora o explorador está conectado à sua carteira. Digite qualquer número maior que 255 e clique em “Write”(Escrever) para assinar a transação na MetaMask.

Agora vá para a seção "Read Contract" (ler contrato). Você notará que o número da sorte é 44. Como o valor máximo que pode ser representado por um uint8 é 255, a operação de downcast causa um overflow. No Solidity, quando ocorre um overflow durante uma operação aritmética, o valor "dá a volta" e começa a partir do valor mínimo do tipo de dados. Neste caso, os 8 bits menos significativos de 300 (que é 44 em binário) serão armazenados na variável number.

Como resultado, a variável LuckyNumber de estado receberá o valor de 44.

4.4 Testando o Contrato com a Biblioteca SafeCast.

Agora vá para a página do explorador do contrato safeDownCasting a partir do link comprovado no Terminal, conecte a carteira e digite 300 e clique em write, como você pode ver, a transação falhou. Clique em "View Transaction" (Exibir transação). Como você pode ver, a transação falhou pelo motivo SafeCast: value doesn't fit in 8 bits, porque a função SafeCast está verificando se o inteiro é menor que uint8 antes de convertê-lo em uint8.

Mitigamos com sucesso a vulnerabilidade de DownCasting usando a biblioteca SafeCast dos contratos do OpenZeppelin.

Se você apoia nossos esforços, siga-nos no Twitter e no LinkedIn. Se ainda não o fez, convidamos você a entrar em nosso grupo do Telegram clicando aqui.

Repositório do Github: Tutoriais do Buildbear

Sobre o BuildBear:

O BuildBear oferece aos desenvolvedores uma plataforma conveniente para criar uma rede de testes privada personalizada para testar seus DApps. Com a capacidade de bifurcar cadeias EVM, os desenvolvedores podem criar uma rede privada adaptada às suas necessidades.

Use o BuildBear.io e crie sua rede de testes privada agora!


Artigo escrito por BuildBear Team. Traduzido por Marcelo Panegali

Top comments (0)