Reino: Code Quality

Una mala calidad del código lleva a un comportamiento no predecible. Desde la perspectiva de un usuario, muchas veces también supone una usabilidad limitada. Pero para un atacante es una oportunidad para atacar al sistema de formas insospechadas.

Code Correctness: Reentrancy

Abstract
Una función rompe el patrón comprobaciones-efectos-interacción o no protege contra ataques de reentrada.
Explanation
Un ataque de reentrada ocurre cuando un contrato malicioso vuelve a llamar al contrato de llamada antes de que finalice la primera invocación. Esto sucede cuando el contrato vulnerable expone una función que interactúa con contratos externos antes de llevar a cabo localmente el efecto de la llamada actual. Esto puede llevar a que el contrato externo asuma el flujo de control de la interacción.

Si un contrato malicioso llama a la función expuesta de una víctima que interacciona de manera insegura con el contrato de llamada, el contrato atacante recibirá y procesará la interacción (por ejemplo, a través de una función alternativa) e inmediatamente volverá a llamar a la función expuesta de la víctima para entrar en un bucle de llamada-interacción-llamada. Este estado recursivo evita que se ejecute más código en la víctima y puede provocar un drenaje parcial o total de activos o valores dependiendo de la naturaleza de la interacción.

El patrón comprobaciones-efectos-interacción se usa comúnmente en contratos inteligentes para evitar una lógica incorrecta. El patrón designa que el código compruebe primero las condiciones requeridas, luego lleve a cabo el cambio de estado relacionado (el efecto) y finalmente interactúe con el contrato externo en relación con ese efecto.

Ejemplo 1: El siguiente ejemplo permite un ataque de reentrada realizando una comprobación, una interacción y luego un efecto sin seguir el patrón comprobaciones-efectos-interacción.

El código:

1. Comprueba el saldo del remitente (Comprobaciones).
2. Envía Ether a la persona que llama a través de msg.sender.call.value (Interacción).
3. Realiza un cambio de estado disminuyendo el saldo del remitente (Efectos).


function withdraw(uint amount) public{
if (credit[msg.sender] >= amount) {
require(msg.sender.call.value(amount)());
credit[msg.sender]-=amount;
}
}


El código en el Example 1 rompe el patrón comprobaciones-efectos-interacción haciendo comprobaciones-interacción-efectos en su lugar. Esto puede conducir a una reentrada si un contrato inteligente atacante recibe Ether en una función alternativa e inmediatamente vuelve a llamar a withdraw, creando una situación recursiva en la que Ether se agota porque la línea de código que disminuye el saldo (también conocida como el efecto) nunca se ejecuta.
References
[1] Enterprise Ethereum Alliance External Calls and Re-entrancy
[2] Standards Mapping - CIS Azure Kubernetes Service Benchmark 4
[3] Standards Mapping - CIS Amazon Elastic Kubernetes Service Benchmark 4
[4] Standards Mapping - CIS Amazon Web Services Foundations Benchmark 3
[5] Standards Mapping - CIS Google Kubernetes Engine Benchmark normal
[6] Standards Mapping - Common Weakness Enumeration CWE ID 841
[7] Standards Mapping - Smart Contract Weakness Classification SWC-107
desc.structural.solidity.swc107