Blockchain CTF Challenges
Solve Ethereum and Solidity smart contract CTF challenges - reentrancy, overflows, delegatecall, and more.
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
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 ethersExploit 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 - 1Exploit:
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_URLChecklist
- 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.originfor 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