Smart contract security testing and blockchain CTF exploitation. Covers Solidity vulnerability analysis, EVM storage manipulation, delegatecall attacks, CREATE/CREATE2 address prediction, and common DeFi exploit patterns. Use when analyzing Solidity contracts, solving blockchain challenges, or testing smart contract security.
# Get connection info
curl http://$HOST:$PORT/connection_info # -> PrivateKey, Address, TargetAddress, setupAddress
# RPC endpoint
RPC_URL="http://$HOST:$PORT/rpc"
# Win condition: Setup.isSolved() must return true
When contract A does delegatecall to contract B, B's code runs with A's storage.
Contract addresses from CREATE are deterministic: keccak256(rlp([sender, nonce]))[12:]
keccak256(h(key) || uint256(slot_number))
h(k) = abi.encode(k) (left-padded to 32 bytes)h(k) = keccak256(k)eth_getStorageAtWhen a function loops over a user-supplied array to validate items (signatures, approvals, votes), passing an empty array skips the loop entirely. If there's no minimum-length check, validation is bypassed.
for (uint i = 0; i < arr.length; i++) with no require(arr.length >= N)[] to skip all validationRaw ecrecover accepts both (v, r, s) and (v', r, N-s) (where N = secp256k1 order, v flipped 27↔28). If a contract deduplicates signatures by hash of raw bytes, the malleable form has a different hash but recovers to the same signer.
ecrecover used without s <= N/2 enforcement (OpenZeppelin's ECDSA.sol enforces this)new_s = N - s, flip v, submit as "new" signature| Vulnerability | Check |
|---|---|
| Reentrancy | External calls before state updates |
| Access control | Missing onlyOwner / msg.sender checks |
| Integer overflow | Solidity < 0.8.0 without SafeMath |
| Delegatecall injection | User-controlled delegatecall target |
| tx.origin auth | tx.origin instead of msg.sender |
| Selfdestruct | Force-send ETH, reset contract nonce |
| Weak randomness | blockhash/timestamp as entropy source |
| Empty array bypass | Loop validation with no min-length check |
| Signature malleability | Raw ecrecover without s-normalization |
# web3.py essentials
from web3 import Web3
w3 = Web3(Web3.HTTPProvider(RPC_URL))
acct = w3.eth.account.from_key(PRIVATE_KEY)
# Read private storage
w3.eth.get_storage_at(contract_addr, slot)
# Deploy contract
from solcx import compile_source, install_solc
install_solc("0.8.13")
compiled = compile_source(source, output_values=["abi", "bin"], solc_version="0.8.13")
# Send raw bytecode deployment
tx = {'data': bytecode, 'gas': 3000000, 'gasPrice': w3.eth.gas_price, 'nonce': nonce, 'chainId': chain_id}
signed = acct.sign_transaction(tx)
w3.eth.send_raw_transaction(signed.raw_transaction)