Smart contracts and the EVM
Public code, public state, and an execution model where a callback in the middle of your function is a normal event.
Assumes21. Reverse engineering
By the end you can
- Read contract storage directly and explain why 'private' means unindexed rather than secret
- Trace a reentrancy path and name the state update that happened too late
- Distinguish delegatecall from call in terms of whose storage is written
- Recognise an unprotected initialiser or owner-setting function from the bytecode alone
- Follow a transaction trace to the exact call that changed the balance
- Explain why an on-chain source of randomness is an attacker-observable value
1. Read
Smart contract challenges: reentrancy, storage, and the EVM
Blockchain CTF without the jargon. Reading a contract you only have bytecode for, the storage slot that is public whether or not the variable is, reentrancy and delegatecall, and why on-chain randomness is never random.
Thinking like the designer: finding the intended flaw
The hardest CTF challenges have no memory-corruption and no injection - just a system whose logic can be bent. Threat modeling from the attacker's chair: trust boundaries, assumptions, and the questions that find a logic bug.
2. Use the tools
In the order they come up while solving. Read what each one does, or go straight to the workspace tab that runs it.
- EVM bytecode analyzer: disassemble, decode selectors, read storage
Disassemble Ethereum contract bytecode, resolve function selectors, decode ABI calldata, and read a storage slot the way Solidity packs it.
Open it in the workspace - Hex to text converter
Convert hexadecimal to text and back, tolerating whitespace, commas, and `0x` prefixes. Runs entirely in your browser.
Open it in the workspace - MD5, SHA-1 and SHA-256 hash generator
Compute MD5, SHA-1, SHA-256, SHA-384, and SHA-512 of any text in the browser, using Web Crypto. Nothing is sent anywhere.
Open it in the workspace - Struct pack and unpack (p32, p64, u32, u64)
Convert integers to little-endian byte strings and back at 8, 16, 32, and 64 bits - the pwntools p32/p64 helpers without the install.
Open it in the workspace
3. Try one now
Generated in your browser and checked in your browser. No account, nothing to download, and a fresh one whenever you want another.
4. Practise on the real thing
Real picoCTF challenges that use these techniques, easiest first.
Common mistakes
The wrong turns this topic reliably produces. Written as the mistake rather than the rule, because the rule is easy to agree with and easy to walk straight past.
- Reading `private` as confidential. Storage is public by construction; the keyword only stops other contracts reading it through the compiler.
- Looking for the bug inside a single function. Most of these are ordering bugs across an external call, which is why checks-effects-interactions exists as a rule.
- Using block values as randomness in your own solution and then being surprised the challenge does the same. Miners and callers can both see them before they commit.
- Reading a successful transaction as the state change you wanted. A call that reverts inside a try block, a fallback that silently accepts, and a transfer that returns false instead of throwing all produce a receipt marked successful.
- Testing only against a freshly deployed copy. The challenge's contract has a live history - who initialised it, which balances exist, what has already been called - and that accumulated state is frequently the whole vulnerability.
Checkpoint
Given a vulnerable contract, drain it in a single transaction and write down the call sequence, marking the exact point where the contract's own state was stale.
Teaching note
The mental model that unlocks this module is that an external call is a yield point. Draw the stack for a reentrant withdraw once, with the balance update below the call, and the whole bug class becomes obvious rather than exotic.
Go deeper
The lessons above are written to get you through a challenge. These are the chapters to read when you want the subject instead - each one named so you can check it rather than take our word for it. Nothing here is affiliate-linked or sold by us.
Designing Secure Software - Loren Kohnfelder
Chapter 10, Untrusted Input
A contract's caller is untrusted input that can run code, which is the framing that makes reentrancy ordinary.
Designing Secure Software - Loren Kohnfelder
Chapter 6, Secure Design
Invariants and trust boundaries, which is what a contract audit is checking and what a CTF contract violates on purpose.