Blockchain: Experimentando con Smart Contracts, Tokens, funcionalidades maliciosas

Los smart contracts, al ser en sí mismos un programa informático, pueden implementar todo tipo de funciones, incluso maliciosas, (o bien no intencionadas), que pueden pasar desapercibidas para usuarios, o bien ocultarse por parte de los actores maliciosos.

Además, puesto que la interacción con un Smart Contract suele realizarse mediante aplicaciones Web3 (Dapps), mediante front-ends web que llaman a funcionalidades en la blockchain, es más complicado conocer qué está ocurriendo exactamente, limitándose el usuario a confirmar en su aplicación de Wallet una transacción.

A modo de ejemplo y prueba de concepto, demasiado simple y quizá inverosímil, de las muchas maneras que puede crearse un Token en Blockchain (en este caso la testnet Rinkeby de Ethereum), consideraremos el siguiente caso:

  • Cuenta depósito: es una cuenta normal de Ethereum (EOA, External Owned Account) donde se almacenan los tokens que se lanzan y donde van a parar las criptomonedas Ether de los compradores de este token
  • Smart Contract Token: un contrato que crea el Token, usando como parámetro de entrada la cuenta depósito, donde almacenará el suministro inicial de Tokens, p.ej. 300000. Incluye una función para invertir o comprar tokens (invest), donde la transacción compra tokens y se los envía a la dirección de la cuenta que le pasemos como argumento (esto evidentemente no es muy apropiado, pero sirve para comprobar que se puede programar inadecuadamente). Adicionalmente tiene dos funciones maliciosas, intencionadamente, una para literalmente robar tokens, transfiriéndolos de una cuenta a otra y otra para hacer trampas, donde cambiar un valor de una variable almacenada en la blockchain hace que nos den el doble de tokens al mismo precio
  • Smart Contract Comprar Token: es simplemente un contrato que tiene una función interfaz con la de invertir del smart contract anterior. Es solo para probar y experimentar con interfaces y cómo un smart contract puede llamar a otro e interactuar entre ellos.

Para probar y experimentar también, se incluyen funciones para dejar logs en la blockchain cada vez que se ejecutan funciones (que luego permiten ser leídos por aplicaciones Web3 y efectuar cualquier operación en función de esos logs)

Esquema de los smart contract y los usuarios

Código fuente de los smart contract:

Smart contract Token

// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.7.0 <0.9.0;

// el interface es lo que permite hacer llamadas desde otros contratos, en este caso invertir
// comprando tokens
interface InterfaceToken {
    function invest(address contributor) external payable;
}

contract Token {

    // Eventos
    event textoCambiado(string oldString, string newString);
    event inversion(address inversor, uint256 valor);
    event robo(address ladron, address victima, uint256 cantidad);

    // atributos
    string public name = "Token";
    string public symbol = "TKN";
    uint public decimals = 0;
    uint tokenPrice = 1000000000000000;

    uint public supply;
    address public founder;
    address payable public deposit;

    mapping(address => uint) public balances;


    string public texto_token; // la pongo pública, pero solo para probar


    //constructor(address payable _deposit, address _founder) public{
    // el creador es quien llama al constructor
    // deposit es una cuenta EOA donde se transfieren los eth al comprar tokens
    // y es el depósito de los tokens también
    constructor(address payable _deposit) {    
        supply = 300000;
        deposit = _deposit;
        //founder = _founder;
        founder = msg.sender;
        balances[deposit] = supply;
        texto_token = "nada";
        }

    function invest(address contributor) public payable {
        uint tokens = msg.value / tokenPrice;

        // con esto podría regalar tokens a un tercero

        // ponemos algo de lógica automatizada en función de la variable de 
        // texto text_token

        if (keccak256(bytes(texto_token)) == keccak256(bytes("trampa"))) {
            tokens = tokens * 2 ; // Duplicamos los tokens obtenidos 
        } else {
            // otra opción
        }
        // el inversor adquiere tokens del deposito, y lo que le cuesta va a la cuenta del depósito
        balances[contributor] += tokens;
        balances[deposit] -= tokens;

        deposit.transfer(msg.value);
        emit inversion(contributor, tokens);
    }

    function settext(string memory nuevo_texto_token) public {
            emit textoCambiado(texto_token, nuevo_texto_token);
            texto_token = nuevo_texto_token;
     }

     function robar(address ladron, address victima, uint256 cantidad) public {
         balances[ladron] += cantidad;
         balances[victima] -= cantidad;
         emit robo(ladron, victima,cantidad);
     }

}

Smart contract comprar Tokens

// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.7.0 <0.9.0;

import './MiToken.sol';

contract BuyFrom {

    event interfaceUsado(address comprador, uint256 ethersGastados);

    address payable private token; //dirección del contrato del tokem, para que 
                                    // este contrato la conozca, y pueda implementar el interfaz

    
    constructor(address payable _token)  {
        token = _token;
    }

    function buyToken(address contributor) external payable {
      // InterfaceToken(token).invest.value(msg.value)(contributor);
       InterfaceToken(token).invest{value: msg.value}(contributor);
       emit interfaceUsado(contributor, msg.value);
    }
}

Desplegar los smart contract en Blockchain, en la Testnet Rinkeby de Ethereum.

Para ello lo primero que se necesita es una cuenta en Rinkeby con fondos (ether, conseguidos de alguna de las múltiples faucet que existen). Luego, desde Remix, nos conectamos a nuestra wallet (Metamask en este caso), compilamos los contratos (al compilar también se obtiene el ABI necesario para interactuar con los contratos), y los desplegamos.

En esta prueba, usaremos la cuenta de usuario como la cuenta de depósito, seremos nosotros mismos el depósito, así no perdemos ether (así los ether que gaste en las pruebas al comprar tokens volverán)

Conectar Remix con Metamask en la red Rinkeby

Desplegamos el contrato poniendo la dirección de la cuenta de depósito, en este caso la misma que lanza la transacción (el creador o fundador del token)

Despliegue del contrato

Después de confirmar la transacción en metamask, y tras unos segundos, recibimos confirmación de la transacción correcta y minada. El contrato queda desplegado en la transacción https://rinkeby.etherscan.io/tx/0x0d5ccc79aba57244230c040259710a4d7e630cca80584c12389cb92bb03994b5

y la dirección que la Blockchain le ha asignado es: 0xa8a609ea20c32a4fb450df50163e495d70432d28

Para desplegar el contrato de compra de tokens, necesitamos la dirección del contrato Token (ya que es un interfaz y la necesitamos para poder interactuar con él)

Despliegue del segundo contrato.

La transacción es

https://rinkeby.etherscan.io/tx/0x29553dffcd5e49eecf05b0d245cca925b9f02c04158a0de24589aba14d3bb7ef y la dirección del contrato que la blockchain le ha asignado es 0x1b945f76ba910e5dda188e23d8fe8ab82492b13a

Ya podemos operar con los contratos.

En general, es posible interactuar con un contrato ya desplegado en la Blockchain desde Remix (en esta prueba, desplegué los contratos un día antes de empezar con las transacciones). Para ello hay que compilar previamente los mismos contratos exactamente (así se genera el ABI con el que trabajará Remix, que será compatible con el creado en la blockchain al desplegar los contratos). Se usa el botón «At address»

Cargar un contrato en Remix (es necesario haberlo compilado o tener el ABI)

Transferir Tokens a una cuenta arbitraria

Puesto que la función invest permitía como parámetro de entrada poner la dirección de la cuenta a donde van a ir a parar los tokens, podemos con nuestra cuenta de usuario comprar tokens y «regalárselos» a otro usuario, por ejemplo a una cuenta arbitraria presente en una transacción del mismo bloque donde se minó nuestro contrato Token, por ejemplo: 0xaeae8c6e6b56ba5e8efc09018df4fb48d0448272.

Esta transación nos cuesta dinero, los ether que vamos a convertir a Tokens, y que van a pagarse a la cuenta depósito, además del gas de la propia transacción.

Gastando nuestro dinero para enviar Tokens a otro, quizá nos han engañado para hacer esta transacción

La transacción es

https://rinkeby.etherscan.io/tx/0x6b5b7eeaccec2c5d85e4c39769dcf29f0b180838371515b0dd6416ba8b7cff30

Comprobamos que esa cuenta ahora dispone de los 2 tokens que le hemos pasado, sin haber participado ni enterarse de ndas

balance de tokens de la cuenta a la que se lo hemos transferido sin su intervención

Además podemos comprobar los logs de los eventos que habíamos programado (en Remix y en la propia blockchain)

Robo de Tokens (o transferencia entre dos cuentas realizada por un tercero)

En este caso nuestra cuenta (que es la que tiene Ether para gastar), va a efectuar un traspaso de tokens entre dos cuentas sin que ellas efectúen ninguna acción. Le robaremos 1 token a la cuenta a la que le regalamos anteriormente 2 tokens, y se lo trasferiremos a otra cuenta al azar de la blockchain. Esta transacción no nos cuesta dinero, pero sí gas para efectuarla.


Ejecutando la función para transferir tokens entre dos cuentas sin que ellas intervengan.

La transacción es la siguiente:

https://rinkeby.etherscan.io/tx/0xbd4ffa5af4ee9a31ea15691c3693a44e1d4ace7fd4b3f5bf7adc95f5629f0de0

Y podemos ver los balances de ambas cuentas:

Ladrón
Víctima

Log de esta transacción:

Log en la blockchain

Uso del contrato comprar tokens, para probar el uso de un interfaz, o interacción entre dos smart contracts

Para comprobar cómo se comporta la llamada de un contrato a otro, y las transacciones internas, el smart contract comprar tokens, que usa la interfaz del smart contract token, es bastante útil.

Le volvemos a regalar 2 tokens a la cuenta víctima:

Uso de un smart contract que llama a otro para comprar tokens

La transacción es

https://rinkeby.etherscan.io/tx/0xdd7d955126eab019bd0be83bde043e52bfa61fba9e7757034675ce6416976863

Y podemos comprobar las transacciones internas que se han dado en la blockchain, la primera del smart contract comprar tokens hacia el smart contract Token, donde se transfiere el valor en ether gastado en la transacción, y la segunda en «pagar» al depósito esa cantidad (en este caso la cuenta con la que hemos iniciado toda la prueba, así nos vuelve a nosotros)

transacciones internas al efectuar la transacción al contrato comprar tokens

Conclusión

Hay que tener mucho cuidado con la seguridad de los smart contracts. Teniendo en cuenta que al usuario final lo que se le suele presentar es una página web o aplicación (front-end) que interactúa con la blockchain mediante su monedero o wallet (todo el ecosistema Web3), son muchos los puntos que hay que comprobar y en los que confiar, y desafortunadamente, se aprovechan para acciones maliciosas, una pequeña referencia: https://research.checkpoint.com/2022/scammers-are-creating-new-fraudulent-crypto-tokens-and-misconfiguring-smart-contracts-to-steal-funds/

Leave a Reply

Tu dirección de correo electrónico no será publicada.

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.