No se puede replicar el ataque de dirección corta

Estaba leyendo sobre el ataque de dirección corta y decidí replicar y probar las posibles soluciones.

Lo que sé sobre el ataque de dirección corta es que si omite n caracteres de su dirección, termina proporcionando 68-(n/2) bytes a su transferfunción y el evm agrega ceros para hacer 68 bytes. Y el resultado final es que su valor cambia por n<<8. Esto fue solo una descripción general de alto nivel.

Ahora trato de probar lo mismo con un token de prueba (con decimales = 2). La función de transferencia del contrato pasa por:

 function transfer(address _to, uint256 _value) {
        require (balanceOf[msg.sender] > _value) ;
        require (balanceOf[_to] + _value > balanceOf[_to]);
        balanceOf[msg.sender] -= _value;
        balanceOf[_to] += _value;
        Transfer(msg.sender, _to, _value);                                  
    }

Usé remix conectado a mi red de prueba privada para verificar este ataque.

yo tenia una 0x7ecd024742458287b9cd97015ff265d04a316f20direccion Llamé a la función de transferencia del contrato con argumentos:

transfer("0x7ecd024742458287b9cd97015ff265d04a316f2", 1);

Según tengo entendido, esperaba que la dirección proporcionada obtuviera 256 monedas (si se replica el ataque de dirección corta). Pero en lugar de eso, obtuve el error:

transact to browser/TestShortAddAttack.sol:MyToken.transfer error: El gas requerido excede el límite de gas del bloque: 6000000. Una estimación de gas importante también podría ser el signo de un problema en el código del contrato. Verifique los bucles y asegúrese de no enviar valor a una función no pagadera (esa también es la razón de una estimación de gas sólida).

¿Por qué la transacción consume tanto gas? ¿Evm se ha ocupado de este problema o necesitamos implementar la verificación (Comprobación de la longitud de msg.data)?

Sé que es un usuario experimentado, pero tal vez el mensaje de falta de combustible se esté produciendo debido a un lanzamiento. ¿Has probado con la dirección correcta? Quiero decir, ¿con el 0 al final?
Con 0 al final, la dirección será de 20 bytes y no podré replicar el problema. Para replicar este problema, necesito proporcionar una dirección con una longitud inferior a 20 bytes.
Probablemente necesitará crear el mensaje de transacción para asegurarse de que sea más corto, el remix puede tener algún código que valide y asegure que las direcciones sean de 20 bytes.
Hmm... esto puede ser posible. déjame intentar lo mismo con geth.

Respuestas (1)

Traté de replicar también. Sin embargo, no obtuve el error que obtuviste, pero tampoco obtuve una réplica perfecta del ataque. Tengo una implementación de la biblioteca safemath, pero de otra manera como la tuya.

function transfer(address _to, uint _amount) public returns (bool success){
    balances[msg.sender] = balances[msg.sender].sub(_amount);
    balances[_to] = balances[_to].add(_amount);
    Transfer(msg.sender,_to,_amount);
    return true;
}

Intenté usar la dirección:

0xe9f341c1b12912b1594afa3885c873c91ec66920

Si ejecuto la transferencia como lo haría normalmente

transfer("0xe9f341c1b12912b1594afa3885c873c91ec66920",1);

obtendría

0x40c10f19000000000000000000000000e9f341c1b12912b1594afa3885c873c91ec6692000000000000000000000000000000000000000000000000000000000000000000000000

como entrada de la transacción firmada. Si en su lugar usé la dirección abreviada

transfer("0xe9f341c1b12912b1594afa3885c873c91ec6692",1);

obtendría

0x40c10f190000000000000000000000000e9f341c1b12912b1594afa3885c873c91ec669200000000000000000000000000000000000000000000000000000000000000000000000

Rellenando la entrada con un cero, pero como el encabezado de la dirección, y no detrás como se pretendía. Esto simplemente transferiría los fondos a una dirección a la que no tengo acceso.

¿Encontraste una manera de replicar el ataque?

El problema suele ser del lado del cliente, si usa una biblioteca que hace el relleno de argumentos, solucionará el problema antes de que llegue al contrato. Para demostrar el problema, debe usar un mensaje codificado, por ejemplo, eliminando a mano dos ceros 0x40c10f1900000000000000000000000e9f341c1b12912b1594afa3885c873c91ec66920000000000000000000000000000000000000000000000000000000000000064.
Usé geth directamente, pero supongo que debería hacerse a través de rawtransaction en su lugar. Ambos problemas eran no poder reproducir el ataque, así que pensé que estaría bien.