People often ask me "How did you learn how to hack?" The answer: by reading. This page is a collection of the blog posts and other articles that I have accumulated over the years of my journey. Enjoy!
allocate is made, this takes the PCV value and puts it into the Uniswap pool at the market rate. However, this should be done with the ETH/USD oracle price instead. Why is this? purchase function can be used to purchase FEI at a standard (stable) $1.01. allocate again. This deposits the PCV (in ETH) into the pool. The counterpart quantity of FEI is minted/burned directly by the protocol. With the distorted market (from the flash loan), more ETH is deposited than should be. msg.sender is the same as the tx.origin alongside the check the no code being at the address. Interesting!blocknumber will be different. So, the solution to this problem is OVM replacing context-dependent opcodes in the OVM to be similar to those in on the L1 blockchain. StateDB to store the native balances in an ERC20 token. This means the ETH balance will always be 0 but the users balance is within the specific contract. selfdestruct function, the ETH at this location triggers the ERC20 token to send money to the specific address. Afterwards, it needs to 0 out the money for this contract in the ERC20 as well. selfdestruct setting the contract to 0. For more information on this bug and the internals of Optimism, read here. transferFrom allows users to get money from other users. Of course this requires the approval of the user whose funds is being taken away. This is common in the real world, with situations like bills from comcast and things. transfer will ensure that the operation is allowed.approve function to subtract the amount of tokens from the current transfer of allowed tokens. For instance, if I'm allowed to take 5 apples total but only take 2, I still have 3 apples I can take. This is the logic that the code is trying to do for the tokens. recipient of the data, it allows the msg.sender or the CALLER of the request. This malicious user was never allowed to access these tokens, which creates a major problem. transferFrom to send 0 tokens. This is because we need the call to succeed in order to change the approval on our account. Once the approval has been made, we can transfer tokens from their account. transferFrom for 0 ETH still worked, even when our user was not authorized to do this. Interesting! burn() function removing the tokens from circulation. ExitToNear. This records the sender, destination and amount of this exit. call and delegateCall. With call, the internal state variables cannot be changed from the other contract. However, delegateCall is designed exactly for this. Even with this for delegateCall, the AMOUNT of ether for msg.value is forwarded to the contract, even if the contract does not really have the money. ExitToNear can be called directly. If we use delegateCall, we can send Ether to OUR contract without sending it to the bridge. delegateCall retains the msg.value without actually having the money, ExitToNear will log that is received a bunch of ETH, when it never did. As a result, the owner keeps the money but makes the bridge believe that they need to wrap the coin on the other platform for them. This allows infinite creation of money!ExitToNear must be called by the bridge contract itself. Overall, a great find in complex software that led to a 6 million payout. swap and swapUnderlying. swap is used to swap the LP token and the pool stablecoin. swapUnderlying is used to seap the pool stablecoin and the other underlying stable coins. swap but not the swapUnderlying function. swap with fUSDT tokens, they would get an inflated number of LP tokens. Then, they could remove liquidity from the pool to call swapUnderlying to get more tokens of fUSDT than they started with. Again, they can create money out of thin air with this. public function like this is completely unacceptable. repay function. safeTransferFrom of ERC20 had a reentrancy vulnerability in it. Once the transfer occurred, a callback to the address (contract) was made._pool amount is set the current balance of the pool, not what has been taken out by the recursive call beforehand. Additionally, it would mint 5 times the expected shares as well. GroupSize property is used to keep track of the amount of transactions in play that are signed. However, this is not checked and is assumed to be 5. If this was larger than 5 then additional transactions can be included to drain other pools.