Resources

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!

Fei Protocol Flashloan Vulnerability Bugfix Review- 879

Immunifi    Reference →Posted 3 Years Ago
  • Fei is a stablecoin that does this through various algorithms. One method is the Protocol Controlled Value (PCV). The protocol itself controls a large amount of the liquidity provider tokens (LP tokens) in the Uniswap V2 pool for the ETH/FEI pair. Liquidity refers to the ability to change one asset into another. The LP is the entity that does this exchange.
  • In order to incentivize LP participation, an LP specific token is used. This gets people in the crypto market to put their assets into the pool. In this case, the token (ETH/FEI pari) represents a proportional share between the pool of tokens deposited.
  • When a call to 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?
  • If a bunch of ETH is deposited into the pool, FEI becomes expensive and ETH becomes cheap. Because of this controlled inflation on the value, the value is FEI is very high. Now, the purchase function can be used to purchase FEI at a standard (stable) $1.01.
  • Now, call 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.
  • If the FEI is swapped back into the pool (from what we bought before), this will be worth MAY more ETH than it should be. By doing this over and over again, 60K ETH could be stolen.
  • To prevent this attack, the bonding curve is no longer supplied to the ETH/FEI Uniswap pool. Instead, the funds for the bonding curve are from a reserve stabilizer, which places a hard floor on the price of ETH. Additionally, a slippage parameter was added in order to prevent mass manipulation from causing so much damage.
  • The final issue was the improper usage of an isContract check. It is possible to do this by ensuring that the msg.sender is the same as the tx.origin alongside the check the no code being at the address. Interesting!

Optimism Infinite Money Duplication Bugfix Review- 878

Immunefi    Reference →Posted 3 Years Ago
  • Ethereum is quite slow. In order to make it faster, several ideas have been proposed. One of these is an Off-Chain solution, commonly referred to as Layer 2 (L2). These L2 solutions execute code off-chain in a separate but similar environment to the EVM
  • When using L2, only a summary of the data executed is stored on Ethereum (L1). The actual computation and storage of the contracts is done on L2, making it much more efficient. This is called a rollup.
  • The term "optimistic rollups" is the batching of rolls. By doing this, we loose some of the security guarantees. The optimistic part is simply assuming that all transactions are valid. There are outside validators to make sure corrupt of the state does not occur.
  • Optimism depends on fault proofs to advance the state of Ethereum with summaries. If there is a dispute between two actors, then the data is re-executed on the Ethereum blockchain.
  • Of course, this causes problems because some data such as 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.
  • The final key to understanding this bug is how ETH is stored in the OVM. Instead of using ETH natively, it is stored in an ERC20 token. To allow this to work, they applied patches to 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.
  • Now, time for the actual vulnerability! When calling the 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.
  • However, the difference between ETH and the ERC20 ETH causes the problem. Instead of setting the balance of the ERC20 token of ETH to 0, the real ETH is set to 0! This means that a selfdestructing contract can send the ERC20 ETH to another location and keep its original balance. This is a money duplication bug!
  • I assume the fix was simply using the ERC20 version of the ETH for the selfdestruct setting the contract to 0. For more information on this bug and the internals of Optimism, read here.
  • This was an insanely complicated exploit which required a very deep understanding of the eco-system to find. I would guess that the author of the post realized that not everything could have been changed from the actual ETH to the ERC20. Then, decided to look for it. Crazy enough this was out of scope, but the company paid out the max bounty anyway!

Redacted Cartel Custom Approval Logic Bugfix Review- 877

Immunefi    Reference →Posted 3 Years Ago
  • ERC20 is a standard used for different tokens in Ethereum. OpenZepplin has a battle tested implementation of this to ensure that nobody has to rewritten these basic but security sensitive functionality.
  • The implementation of 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.
  • Within this function, the funds are first transferred to the sender of the request. Although this sounds strange, this is the proper pattern to prevent reentrancy attacks. transfer will ensure that the operation is allowed.
  • Next, it calls the 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.
  • Here is where the problem comes in: instead of allowing the 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.
  • In order to exploit this, the attacker needs to send a request to 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.
  • The fix was to remove this contract entirely and use the OpenZeppelin implementation instead. Don't roll your own crypto(currency)!
  • Overall, I really enjoyed the bug. It was extremely subtle and easy to miss. I'm surprised that transferFrom for 0 ETH still worked, even when our user was not authorized to do this. Interesting!

Aurora Inflation Spend Bugfix Review:- 876

Immunefi    Reference →Posted 3 Years Ago
  • In the world of blockchain, a bridge is a way for assets to exist between blockchains. Since there are so many different chains, having this allows NFTs and coins to exist in several different places.
  • This is done with the I Owe You approach. This means that users send funds to the bridge protocol on the one chain to be locked by the contract. Then, the equivalent is created on the second network as an IOU token or a wrapped token. For every asset moved from one chain to another, the bridge holds the native version.
  • Aurora is an implementation of the EVM on the NEAR blockchain network. Aurora developed the Rainbow Bridge to allow users to transfer between Ethereum, NEAR and Aurora. In particular, ETH and all ERC20 tokens from Ethereum can be used on the nested layer of NEAR, which is on Aurora.
  • How does this bridge actually work though?
    1. The standard burn() function removing the tokens from circulation.
    2. The money (ETH) is sent to a special hardcoded contract to generate an event to move data off chain.
    3. The contracts event calls ExitToNear. This records the sender, destination and amount of this exit.
    4. The Aurora EVM handles this transaction, from the events logs, to perform actions on the other part of the bridge.
  • The final piece of background knowledge is the difference between 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.
  • The vulnerability comes down to how the event logging was done to trigger the complex chain integration. In step 4 from above, the function ExitToNear can be called directly. If we use delegateCall, we can send Ether to OUR contract without sending it to the bridge.
  • Since 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!
  • To fix this problem, ExitToNear must be called by the bridge contract itself. Overall, a great find in complex software that led to a 6 million payout.

The analysis of Nerve Bridge Security Incident- 875

BlockSec    Reference →Posted 3 Years Ago
  • Curve provides two kinds of stablecoin swap pools: standard and meta. The metapool allows coin to be pooled with another pool without diluting its value.
  • There are two main functions for this security issue: 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.
  • The price calculation between these two functions was inconsistent. In particular, the LP token failed to include the virtual price (no idea what this means) into the calculation for swap but not the swapUnderlying function.
  • By calling 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.
  • A simple mistake in the calculation and swapping of tokens caused this problem. Apparently, this mistake was programmed into a Solidity rewrite from Vyper then used in multiple places. A shared library bug is worth more than a single contact bug. Thanks Log4Shell!
  • The attacker performed this on Synapse for 8 million dollars but was unable to get this through for some reason. They performed this on a different location with the same vulnerability to steal 500K.

The Zenon Network Hack- 874

Rob Behnke    Reference →Posted 3 Years Ago
  • Zenon Network (ZNN) is some sort of blockchain network that interfaces with the BNB chain.
  • Their ERC20 contract for wrapped ZNN (wZNN) had a public burn function. Since the price of the coin is dedicated by the amount of coins in circulation, this is horrible. A link to this is on Twitter from Peckshield.
  • The attacker took out a very large loan (commonly referred to as a flash loan) to invest in a massive amount of wZNN tokens. They called the burn function to destroy 26K wZNN tokens. Since this decreased the amount of available tokens, the price skyrocketed.
  • Since the price of the token was so high, the selling back of the tokens (wZNN) to the contract made them way more valuable than they actually were. As a result, they drained the entire contract of WBNB tokens to use for other purposes.
  • This was caused by a very simple access control bug. A public function like this is completely unacceptable.

Full Report of the Lever Hack- 873

Lever    Reference →Posted 3 Years Ago
  • Lever is a AMM-Based trading protocol built on Ethereum. Luckily for us, the Github repo is public and online, including the contracts.
  • The bug is a logic vulnerability coming down to how collateral's (down payment assets for loans) are handled. When making a loan to Lever for BNB, they deposited xBNB. However, these same tokens could still be SPENT on the vault to pay back a different loan with the repay function.
  • Essentially, the collateral was not validated to be used for the loan and for paying back a separate loan. As a result, once the first loan was paid off, the collateral from the previous loan could be paid back as well. This creates a double spend issue with the tokens.
  • According to Halborn, this had seen three professional reviews. From looking at these audits, only minor issues (except a single medium severity finding) and non-security related things were called out. I'm unsure of the quality of these auditors.
  • The one medium severity finding was interesting though! When performing a liquidation (selling everything from pool of assets) the slippage (price difference between decision and actual execution) is not accounted for. This could lead to arbitrage techniques to steal small amounts of money.
  • Overall, a set of interesting logic bugs. It does matter who is auditing your code!

DeFi Security Lecture 5-Overflow and Underflow Vulnerability- 872

Beaver Finance    Reference →Posted 3 Years Ago
  • PIZZA is some sort of financial blockchain company on EOS. eCurve is an exchange liquidity pool for stable coins. Sadly, no code snippets were shown on this. But the impact is interesting.
  • The attackers took advantage of an integer overflow vulnerability within eCurve to mint an infinite amount of Tripool tokens. Once they got these tokens, they deposited them into PIZZA to drain 5 million.

The Grim Finance Hack- 871

Rob Behnke    Reference →Posted 3 Years Ago
  • Grim fianance is a compounding yield optimizer built on top of the Fantom Opera blockchain. The code for safeTransferFrom of ERC20 had a reentrancy vulnerability in it. Once the transfer occurred, a callback to the address (contract) was made.
  • The reentrancy attack could only occur 5 times, because of the limited amount of gas. On each call, the _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.
  • The attacker was able to perform this attack many times in order to steal 30 million dollars. A simple reentrancy attack made this possible, even if the amount transactions was limited by the gas.

The Tinyman Hack- 870

Rob Behnke    Reference →Posted 3 Years Ago
  • Algorand is another blockchain solution. Tinyman is a marketplace for trading, liquidity providers, and developers. It uses an Automated Market Maker (AMM) algorithm over liquidity pools (a collection of assets). This service is similar to Uniswap on Ethereum.
  • When using Tinyman's burn (token remove) function, it will give back the user two different tokens. The amounts of each token depend on the amount stored within the protocol, which is key to this. For instance, they wanted to burn (remove) some of coin 1 and some of coin 2, they would get the real assets back of both.
  • The attacker found a vulnerability that allowed them to retrieve only a single token back. Since one of them would be much more valuable than the other, this allowed them to take more money out of the pool than expected.
  • The attacker performed this attack over and over again (17 times) in order to team 3 million dollars. The contracts are written in teal, no good code snippets were shown. Regardless, they probably let you choose which tokens to return, not realizing the implications of this.
  • If you look at the public pentest report, almost the same exact issue occurs when taking out money (withdraw). Teal is a very low level language, meaning they don't have variables but scratch memory slots. The wrong slot was used for a comparison, making it possible to take money out.
  • The other bugs in the report was interesting was well. For instance, the 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.
  • Another one is integer division being performed prior to multiplication. Since integers automatically round down, a drift in the protocol fee would occur. They found an integer error in the handling of 64-bit vs. 128 bit numbers as well.
  • Overall, a subtle design decision that was exploited by the attacker led to a lot of lost money. Sadly, this protocol was tested prior to release with 6 critical findings and this still happened. The bugs from the report were interesting to look at as well.