For now only consists of those that I was personally involved with and that are missing by cmichel's impressive writeup.
This was the problem we spent by far the most time on. It consists of a Challenge
contract without source code, with an internal flag that has to be set to true
.
We ended up manually annotating the entire opcode-level path from contract start to the only contract SSTORE
. You can find our annotated version here.
In total, we annotated 521 opcodes with 5078 stack items.
At the end, we were able to reconstruct the logic of the solve(uint256)
function responsible for setting the contract flag:
With that, we were able to calculate the input value required for the xor'd base string to equal the target string.
This was my personal favorite - when else do you have the chance to (ethically) steal $200M?
The challenge consists of an upgraded FiatTokenV3
version of the USDC
token contract, introducing a new lending mechanism.
The way the lending mechanism works is rather simple:
Importantly, the lend function results in a normal transfer of funds to the borrower. For contracts not aware of the functionality, it looks like they are now the proper owner of these funds. However, the lender can unilaterally reclaim the loan at any time, as long as the borrower has sufficient funds in their account.
This can be easily exploited via flash loans (remember, we are on a fresh fork of mainnet). Importantly, for it to be exploitable, the flash loan has to use a push pattern where the user actively re-pays the funds at the end of the transaction (as opposed to a pull pattern where the user only authorizes the repayment and the calls into the flash loan contract to close the position). Aave v1 used such a push pattern, but does not quite have the required $200M USDC liquidity anymore. Aave v2 and dYdX use a pull pattern. Luckily, Uniswap v2 uses a push pattern, and across its largest 3 USDC pairs offers sufficient liquidity. We ended up with the following Exploiter
contract:
With this, the steps for the exploits were:
Exploiter
swap
to fund the exploiter with some USDCexploit
to steal (most of) the pair's USDC reserves