Athena Wiki

Blockchain CTF Challenges

miscadvanced

Solve Ethereum and Solidity smart contract CTF challenges - reentrancy, overflows, delegatecall, and more.

miscblockchainethereumsolidityweb3reentrancyoverflowfoundry

Blockchain CTF Challenges

Blockchain CTF challenges typically involve Ethereum smart contracts written in Solidity. You're given a contract and must exploit a vulnerability to drain funds, change ownership, or meet a specific win condition.

Attack Flow

Mermaid diagram

Setup

# Install Foundry (Solidity development toolkit)
curl -L https://foundry.paradigm.xyz | bash
foundryup

# Install web3.py (Python interaction)
pip3 install web3

# Install ethers.js
npm install ethers

Exploit Methodology

Read the Contract Source

Identify all state variables, their types, and storage slots. Read every function - especially fallback() and receive(). Find the win condition (isSolved(), owner == attacker, balance == 0).

Identify the Vulnerability

Check Solidity version first: < 0.8 means possible integer overflow. Look for external calls before state updates (reentrancy), tx.origin auth, delegatecall with user-controlled targets, and block-based randomness.

Write the Exploit

Write either a Solidity exploit contract (for reentrancy, delegatecall) or a script (for simple tx.origin, overflow, or randomness attacks).

Deploy and Execute

Use Foundry (forge create, cast send) or web3.py. Verify the win condition after each step.

Common Vulnerabilities

Before Solidity 0.8, arithmetic overflowed silently.

// vulnerable: uint256 wraps at 2^256
uint256 balance = 0;
balance -= 1;  // → 2^256 - 1

Exploit:

contract Exploit {
    function attack(Target target) external {
        // Underflow: balance becomes type(uint256).max
        target.transfer(address(this), 1);
    }
}

Solidity 0.8+

Solidity 0.8+ reverts on overflow by default. Use unchecked {} blocks to see if the CTF intended unsafe arithmetic.

Interaction Tools

# Deploy exploit contract
forge create --rpc-url $RPC_URL --private-key $PRIVATE_KEY \
  src/Exploit.sol:Exploit \
  --constructor-args $TARGET_ADDRESS

# Send transaction
cast send --rpc-url $RPC_URL --private-key $PRIVATE_KEY \
  $CONTRACT_ADDRESS "attack()" --value 1ether

# Read contract state
cast call $CONTRACT_ADDRESS "owner()(address)" --rpc-url $RPC_URL

# Check win condition
cast call $TARGET_ADDRESS "isSolved()(bool)" --rpc-url $RPC_URL

Checklist

  • Read the contract - understand storage layout and slot assignments
  • Identify win condition (isSolved, owner change, balance drain)
  • Solidity version < 0.8? → integer overflow/underflow possible
  • External calls before state updates? → reentrancy
  • tx.origin for auth? → trick original owner via intermediate contract
  • delegatecall? → check storage collision between proxy and implementation
  • Block-based randomness? → predict or reproduce in same block
  • Need to force-send ETH? → selfdestruct
  • Practice: Ethernaut, Damn Vulnerable DeFi

Last updated on

On this page