Constantinopla habilita un nuevo ataque de reentrada

La próxima actualización de Constantinople para la red ethereum introduce un costo de gas más económico para ciertas operaciones de SSTORE . Como efecto secundario no deseado, esto permite ataques de reentrada cuando se usa address.transfer (...) o address.send (...) en contratos inteligentes de Solidity. Anteriormente, estas funciones se consideraban seguras para la reentrada, pero ya no lo son.

¿Qué le pasa a este código?

A continuación se muestra un contrato inteligente breve que no es vulnerable a un ataque de reentrada antes de Constantinopla, pero sí vulnerable después. Puede encontrar el código fuente completo, incluido el contrato del atacante, en nuestro GitHub: https://github.com/ChainSecurity/constantinople-reentrancy

Este código es vulnerable de una manera inesperada: simula un servicio seguro de intercambio de tesorería. Dos partes pueden recibir fondos de manera conjunta, decidir cómo dividirlos y recibir un pago si están de acuerdo *. Un atacante creará un par de este tipo donde la primera dirección es el contrato del atacante que se enumera a continuación y la segunda dirección es cualquier cuenta de atacante. Por este par, el atacante depositará algo de dinero.

El atacante llamará a la función attack en su propio contrato, de modo que los siguientes eventos se desarrollen dentro de una transacción :

En resumen, el atacante acaba de robar el ether de otras personas del contrato de PaymentSharer y puede continuar haciéndolo.

¿Por qué se puede atacar ahora?

Antes de Constantinopla, cada operación de almacenamiento costaba al menos 5000 gas. Esto superó con creces el estipendio de gas de 2300 enviado al llamar a un contrato usando transfer o send .

Después de Constantinopla, las operaciones de almacenamiento que están cambiando las ranuras de almacenamiento “sucias” cuestan solo 200 gas. Para que una ranura de almacenamiento se ensucie, debe cambiarse durante la transacción en curso. Como se muestra arriba, esto a menudo se puede lograr mediante un contrato de atacante llamando a alguna función pública que cambia la variable requerida. Posteriormente, al hacer que el contrato vulnerable llame al contrato del atacante, p. con msg.sender.transfer (...) , el contrato del atacante puede usar el estipendio de gasolina 2300 para manipular la variable del contrato vulnerable con éxito.

Deben cumplirse ciertas condiciones previas para que un contrato sea vulnerable:
1. Debe haber una función A , en la que un transferir / enviar sea seguido por una operación de cambio de estado . Esto a veces puede no ser obvio, p. Ej. una segunda transferencia o una interacción con otro contrato inteligente.
2. Tiene que haber una función B accesible desde el atacante que (a) cambie de estado y (b) cuyos cambios de estado entren en conflicto con los de la función A .
3. La función B debe ser ejecutable con menos de 1600 gas
(2300 gas estipendio – 700 gas para el CALL ).

¿Mi contrato inteligente es vulnerable?

Para probar si es vulnerable:
(a) verifique si hay alguna operación después de un evento de transferencia .
(b) verifique si esas operaciones cambian el estado de almacenamiento, con mayor frecuencia asignando alguna variable de almacenamiento. Si está llamando a otro contrato, p. Ej. un método de transferencia de tokens, compruebe qué variables se modifican. Haga una lista.
(c) verifique si algún otro método accesible desde no administradores en su contrato utiliza una de estas variables
(d) verifique si estos métodos cambian el estado de almacenamiento por sí mismos
(e) verifique si el método está por debajo de 2300 en gas, teniendo en cuenta que las operaciones de SSTORE son potencialmente solo 200 gas.

Si todo esto es el caso, es probable que un atacante pueda hacer que su contrato entre en un estado indeseable. En general, este es otro recordatorio de por qué el Patrón de Verificaciones-Efectos-Interacciones es tan importante.

¿Existen contratos inteligentes vulnerables?

Un escaneo de la cadena de bloques principal de ethereum utilizando los datos disponibles de eveem.org no descubrió contratos inteligentes vulnerables . Estamos trabajando junto con miembros del grupo de trabajo ethsecurity.org para expandir este análisis a los contratos inteligentes complejos que aún no se han descompilado. Especialmente los intercambios descentralizados que con frecuencia llaman funciones de transferencia de éter a cuentas que no son de confianza, seguidas de cambios de estado posteriores, pueden ser vulnerables. Nuestro analizador estático en https://securify.chainsecurity.com puede detectar posibles ataques de reentrada y hemos abierto el patrón relevante en https://github.com/eth-sri/securify. Tenga en cuenta que una advertencia de un ataque de reentrada en muchos casos no es explotable, pero necesita un análisis cuidadoso.

Gracias

Un agradecimiento especial para Ralph Pichler por las discusiones iniciales que destacaron este nuevo vector de ataque.

Sin el trabajo de Tomasz Kolinko en la descompilación de contratos inteligentes mediante la ejecución simbólica, no hubiéramos podido escanear rápidamente la mayoría de los contratos inteligentes de Ethereum. Abriremos el proyecto tan pronto como se hayan asegurado todos los contratos.

* Durante esta parte, el contrato verificaría firmas nuevas de ambas partes para evitar problemas de ejecución inicial y otros. Omitimos esta parte para facilitar la lectura, ya que no influye en el ataque real.