This repository collects blockchain challenges in CTFs and wargames.
These challenges are categorized by topic, not by difficulty or recommendation.
Also, there are my writeups and exploits for some challenges (e.g., Paradigm CTF 2022).
Please be aware that these contain spoilers.
If there are any incorrect descriptions, I would appreciate it if you could let me know via issue or PR!
Since contract bytecodes are publicly available, it is easy to predict pseudorandom numbers whose generation is completed on-chain (using only states, not off-chain data).
It is equivalent to having all the parameters of a pseudorandom number generator exposed.
If you want to use random numbers that are unpredictable to anyone, use a decentralized oracle with a random number function.
For example, Chainlink VRF, which implements Verifiable Random Function (VRF).
Forced Ether transfers to contracts via selfdestruct
If a contract does not have a receive Ether function and a payable fallback function, it is not guaranteed that Ether will not be received.
When a contract executes selfdestruct, it can transfer its Ether to another contract or EOA, and this selfdestruct transfer can be forced even if the destination contract does not have the receive Ether function and the payable fallback function.
If the application is built on the assumption that the Ether is 0, it could be a bug.
In case a function of contract A contains interaction with another contract B or Ether transfer to B, the control is temporarily transferred to B.
Since B can call A in this control, it will be a bug if the design is based on the assumption that A is not called in the middle of the execution of that function.
For example, when B executes the withdraw function to withdraw Ether deposited in A, the Ether transfer triggers a control shift to B, and during the withdraw function, B executes A's withdraw function again. Even if the withdraw function is designed to prevent withdrawal of more than the limit if it is simply called twice, if the withdraw function is executed in the middle of the withdraw function, it may be designed to bypass the limit check.
To prevent reentrancy attacks, use the Checks-Effects-Interactions pattern.
Flash loans are uncollateralized loans that allow the borrowing of an asset, as long as the borrowed assets are returned before the end of the transaction. The borrower can deal with the borrowed assets any way they want within the transaction.
By making large asset moves, attacks can be made to snatch funds from DeFi applications or to gain large amounts of votes for participation in governance.
A solution to attacks that use flash loans to corrupt oracle values is to use a decentralized oracle.
Challenge
Note, Keywords
Damn Vulnerable DeFi: 1. Unstoppable
Simple flash loan with a single token. Failure to send the token directly.
Damn Vulnerable DeFi: 2. Naivereceiver
The flashLoan function can specify a borrower, but the receiver side does not authenticate the TX sender, so the receiver's funds can be drained as a fee
Damn Vulnerable DeFi: 3. Truster
The target of a call is made into the token and the token can be taken by approving it to oneself
Damn Vulnerable DeFi: 4. Sideentrance
Flash loan that allows each user to make a deposit and a withdrawal. The deposit can be executed at no cost at the time of the flash loan.
Governance attacks by executing flash loans during snapshots
If the algorithm distributes some kind of rights using the token balance at the time of a snapshot, and if a malicious user transaction can trigger a snapshot, a flash loan can be used to obtain massive rights.
A period of time to lock the token will avoid this attack.
Challenge
Note, Keywords
Damn Vulnerable DeFi: 5. Therewarder
Get reward tokens based on the deposited token balance.
Damn Vulnerable DeFi: 6. Selfie
Get voting power in governance based on the deposited token balance.
Bypassing repayments of push architecture flash loans
There are two architectures of flash loans: push and pull, with push architectures represented by Uniswap and Aave v1 and pull architectures by Aave v2 and dYdX.
For example, if there is a transaction by another party to sell token A and buy B, the attacker can put in a transaction to sell A and buy B before the transaction, and later put in a transaction to sell the same amount of B and buy A, thereby ultimately increasing the amount of A at a profit.
In general, such "revenue earned by selecting, inserting, and reordering transactions contained in a block generated by a miner" is referred to as Miner Extractable Value (MEV). Recently, it is also called Maximal Extractable Value.
In general, a same-nonce attack is possible when the same nonce is used for different messages in the elliptic curve DSA (ECDSA), and the secret key can be calculated.
In Ethereum, if nonces used to sign transactions are the same, this attack is feasible.
The address is the public key applied to a keccak256 hash, and the public key cannot be recovered from the address.
If even one transaction has been sent, the public key can be back-calculated from it.
Specifically, it can be recovered from the Recursive Length Prefix (RLP)-encoded data [nonce, gas_price, gas, to, value, data, chain_id, 0, 0] and the signature (v,r,s).
Bypassing bots and taking ERC-20 tokens owned by wallets with known private keys
If a wallet with a known private key has an ERC-20 token but no Ether, it is usually necessary to first send Ether to the wallet and then transfer the ERC-20 token to get the ERC-20 token.
However, if a bot that immediately takes the Ether sent at this time is running, the Ether will be stolen when the Ether is simply sent.
In this situation, we can use Flashbots bundled transactions or just permit and transferFrom if the token is EIP-2612 permit friendly.
Constructors that is just functions by typos (< Solidity 0.5.0)
In versions before v0.4.22, the constructor is defined as a function with the same name as the contract, so a typo of the constructor name could cause it to become just a function, resulting in a bug.
Since v0.5.0, this specification is removed and the constructor keyword must be used.
Bypassing PoW of other applications using Bitcoin's PoW database
Bitcoin uses a series of leading zeros in the SHA-256 hash value as a Proof of Work (PoW), but if other applications are designed in the same way, its PoW time can be significantly reduced by choosing one that matches the conditions from Bitcoin's past PoW results