¿Cómo escapar de los contratos inteligentes del embrague de los ataques de reentrada? Inteligencia de datos PlatoBlockchain. Búsqueda vertical. Ai.

¿Cómo escapar de los contratos inteligentes del embrague de los ataques de reentrada?

Tiempo de lectura: 6 minutos

Si echamos un vistazo más de cerca a los hacks criptográficos más grandes y las cifras deslumbrantes que perdieron, se habrían arraigado profundamente en las fallas de codificación.

Uno de esos casos comunes de vulnerabilidad de seguridad es el ataque de reentrada. Sin embargo, el efecto destructivo causado por la reentrada mal manejada puede no parecer tan simple como lanzar el ataque en sí.

A pesar de ser un problema conocido y muy publicitado, la aparición del error Reentrancy en los contratos inteligentes siempre es inevitable. 

¿Con qué frecuencia los piratas informáticos explotaron la vulnerabilidad de reentrada en los últimos años? ¿Como funciona? ¿Cómo evitar que los contratos inteligentes pierdan fondos debido a errores de reingreso? Encuentre respuestas a estas preguntas en este blog.

Entonces, en poco tiempo, repasemos los ataques de reentrada más grandes que se recuerdan. 

Algunos de los trucos de reentrada en tiempo real más infames 

Los ataques de reingreso que causaron los efectos más devastadores en los proyectos terminaron haciendo uno de estos dos o incluso ambos. 

  • Drene completamente el Ether de los contratos inteligentes
  • Los piratas informáticos se infiltran en el código del contrato inteligente

Ahora podemos observar algunos casos de ataques de reentrada y su impacto. 

Junio ​​de 2016: ataque DAO – 3.54M o $150M Ether

Abr 2020: Truco Uniswap/Lendf.Me – $25 millones

Mayo 2021: El truco BurgerSwap – $7.2M

Ago 2021: Hack de CREMA FINANCE – $ 18.8M

Mar 2022: Finanzas Ola - $ 3.6M

Jul 2022: Protocolo OMNI – $1.43M

Está muy claro que los ataques de reentrada nunca han pasado de moda. Obtengamos una visión profunda de esto en los siguientes pasajes. 

Descripción general del ataque de reentrada

A partir del nombre “Reingreso”, que implica “Reingresar una y otra vez”. El ataque de reentrada implica dos contratos: el contrato de la víctima y el contrato del atacante. 

El contrato del atacante explota la vulnerabilidad de reingreso en el contrato de la víctima. Utiliza la función de retiro para lograrlo. 

El contrato del atacante llama a la función de retiro para drenar los fondos del contrato de la víctima haciendo llamadas repetidas antes de que se actualice el saldo en el contrato de la víctima. El contrato de la víctima verificará el saldo, enviará fondos y actualizará el saldo. 

Pero dentro del marco de tiempo de enviar los fondos y actualizar el saldo en el contrato, el contrato del atacante hace una llamada continua para retirar fondos. Como resultado, el saldo no se actualiza en el contrato de la víctima hasta que el contrato del atacante agota todos los fondos.

La gravedad y el costo de la explotación de reingreso alarman la necesidad imperiosa de realizar auditorías de contratos inteligentes para descartar la posibilidad de pasar por alto tales errores. 

Vista ilustrativa del ataque de reentrada

Analicemos el concepto de ataque de reentrada a partir de la siguiente ilustración simplificada. 

Aquí hay dos contratos: el contrato vulnerable y el contrato Hacker

El contrato hacker hace una llamada para retirarse del contrato vulnerable. Al recibir la llamada, el contrato vulnerable verifica los fondos en el contrato del hacker y luego transfiere los fondos al hacker. 

El hacker recibe los fondos e implementa la función de respaldo, que llama nuevamente al contrato vulnerable incluso antes de que se actualice el saldo en el contrato vulnerable. Repitiendo así la misma operación, el hacker retira los fondos por completo del contrato vulnerable. 

¿Cómo escapar de los contratos inteligentes del embrague de los ataques de reentrada?

Características de la función de respaldo utilizada por el atacante 

  • Son exigibles externamente. Es decir, no pueden llamarse desde dentro del contrato en el que están escritos.
  • Función sin nombre
  • La función de reserva no incluye lógica arbitraria en su interior.
  • El respaldo se activa cuando se envía ETH a su contrato inteligente adjunto y no se declara ninguna función de recepción ().

Análisis del ataque de reentrada desde una vista técnica 

Tomemos un contrato de muestra y comprendamos cómo ocurre el ataque de reingreso.

Contrato malicioso

contract Attack {
    DepositFunds public depositFunds;

    constructor(address _depositFundsAddress) {
        depositFunds = DepositFunds(_depositFundsAddress);
    }

    // Fallback is called when DepositFunds sends Ether to this contract.
    fallback() external payable {
        if (address(depositFunds).balance >= 1 ether) {
            depositFunds.withdraw();
        }
    }

    function attack() external payable {
        require(msg.value >= 1 ether);
        depositFunds.deposit{value: 1 ether}();
        depositFunds.withdraw();
    }


}

Este es el contrato del atacante en el que el atacante deposita 2ETH. El atacante llama a la función de retiro en el contrato vulnerable. Una vez que se reciben los fondos del contrato vulnerable, se activa la función de respaldo. 

El respaldo luego ejecuta la función de retiro y drena el fondo del contrato vulnerable. Este ciclo continúa hasta que los fondos se agotan por completo del contrato vulnerable.

Contrato vulnerable

contract DepositFunds {
    mapping(address => uint) public balances;

    function deposit() public payable {
        balances[msg.sender] += msg.value;
    }

    function withdraw() public {
        uint bal = balances[msg.sender];
        require(bal > 0);

        (bool sent, ) = msg.sender.call{value: bal}("");
        require(sent, "Failed to send Ether");

        balances[msg.sender] = 0;
    }


}

El contrato vulnerable tiene 30ETH. Aquí, la función de retiro () envía la cantidad solicitada al atacante. Dado que el saldo no se actualiza, los tokens se transfieren al atacante repetidamente. 

Tipos de ataques de reentrada

  • Reentrada de función única 
function withdraw() external {
   uint256 amount = balances[msg.sender];
   require(msg.sender.call.value(amount)());
   balances[msg.sender] = 0;
}

El msg.sender.call.value(amount)() transfiere los fondos después de lo cual la función de reserva del contrato del atacante llama a retirar() de nuevo antes de que se actualice balances[msg.sender] = 0.

  • Reentrada de funciones cruzadas
function transfer(address to, uint amount) external {
   if (balances[msg.sender] >= amount) {
       balances[to] += amount;
       balances[msg.sender] -= amount;
   }
}
function withdraw() external {
   uint256 amount = balances[msg.sender];
   require(msg.sender.call.value(amount)());
   balances[msg.sender] = 0;
}

La reentrada de funciones cruzadas es mucho más compleja de identificar. La diferencia aquí es que la función alternativa llama a transferir, a diferencia de la reentrada de una sola función, donde llama a retirar.

Prevención contra ataques de reentrada

Patrón de Comprobaciones-Efectos-Interacciones: El patrón de controles-efectos-interacciones ayuda a estructurar las funciones. 

El programa debe estar codificado de manera que verifique primero las condiciones. Una vez pasadas las comprobaciones, se deben resolver los efectos sobre el estado de los contratos, luego de lo cual se pueden llamar a las funciones externas. 

function withdraw() external {
   uint256 amount = balances[msg.sender];
   balances[msg.sender] = 0;
   require(msg.sender.call.value(amount)());
}

El código reescrito aquí sigue el patrón de controles-efectos-interacciones. Aquí el saldo se pone a cero antes de hacer una llamada externa. 

uso de modificador

El modificador noReentrant aplicado a la función asegura que no haya llamadas reentrantes. 

contract ReEntrancyGuard {
    bool internal locked;

    modifier noReentrant() {
        require(!locked, "No re-entrancy");
        locked = true;
        _;
        locked = false;
    }
}

En el final

El paso más efectivo es realizar auditorías de contratos inteligentes de una empresa de seguridad líder como QuillAudits, en la que los auditores vigilan de cerca la estructura del código y verifican cómo funciona la función de respaldo. Con base en los patrones estudiados, se dan recomendaciones para reestructurar el código si parece haber alguna comportamientos vulnerables

La seguridad de los fondos está garantizada justo antes de ser víctima de cualquier pérdida. 

Preguntas Frecuentes

¿Qué es un ataque de reentrada?

Un ataque de reingreso ocurre cuando una función en el contrato vulnerable hace una llamada a un contrato que no es de confianza. El contrato no confiable será el contrato del atacante que realiza llamadas recursivas al contrato vulnerable hasta que los fondos se agoten por completo. 

¿Qué es un reentrante?

El acto de reingresar significa interrumpir la ejecución del código e iniciar el proceso nuevamente, lo que también se conoce como reingresar.

¿Qué es un protector de reingreso?

La protección de reentrada utiliza un modificador que evita que la función se llame repetidamente. Lea el blog anterior para encontrar el ejemplo de guardia de reingreso.

¿Cuáles son algunos de los ataques a los contratos inteligentes?

Los contratos inteligentes están expuestos a numerosas vulnerabilidades, como el reingreso, la dependencia de la marca de tiempo, los desbordamientos aritméticos, los ataques DoS, etc. Por lo tanto, la auditoría es imprescindible para garantizar que no haya errores que colapsen la lógica del contrato.

69 Vistas

Sello de tiempo:

Mas de hachís