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>
- 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 executandocd DownCastingError.
Etapa 2: Vamos examinar os contratos.
2.1 Contrato unsafeDownCasting.sol
Aqui está um detalhamento do código:
- O SPDX-License-Identifier especifica a licença sob a qual o contrato é lançado. Neste caso, é a licença MIT.
- 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. - O contrato é nomeado
unsafeDownCasting. Possui uma variável de estado chamadaLuckyNumberdo tipouint, que armazenará o número da sorte. - A função
setLuckyNumberé uma função pública que recebe um parâmetrouint256chamadoamount. É usada para definir o número da sorte. Dentro dessa função, o valoramounté convertido para umuint8usando a sintaxeuint8(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 valoramountfor maior que o valor máximo deuint8, que é 255. Se oamountexceder esse valor, apenas os 8 bits menos significativos serão armazenados na variávelnumber, descartando os bits excedentes. Isso pode resultar em perda de dados e comportamento incorreto. - O valor
numberconvertido é então atribuído à variávelLuckyNumberde estado. - A função
getLuckyNumberé uma função de exibição pública que retorna o valor atual da variávelLuckyNumber. Permite que outros contratos ou entidades externas recuperem o número da sorte sem modificar o estado do contrato.
2.2 Contrato safeDownCasting.sol
- O contrato importa a biblioteca
SafeCastdos contratos do OpenZeppelin. Essa biblioteca fornece funcionalidade segura de downcasting. - A instrução
using SafeCast for uint256; permite que o contrato use a bibliotecaSafeCastpara o tipouint256. - A função
setLuckyNumberé uma função pública que recebe um parâmetrouint256chamado_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çãotoUint8()da bibliotecaSafeCast. Se o valor_amountfor maior que o valor máximo deuint8, o downcast será revertido, garantindo que apenas downcasts válidos sejam executados. O valoruint8resultante é então atribuído à variávelLuckyNumberde 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
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.jscom 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)