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!

Enzyme Finance Price Oracle Manipulation Bugfix Review- 881

Immunefi    Reference →Posted 3 Years Ago
  • A price oracle is used to view the price information of a given asset. This is commonly used for trading platforms.
  • These oracles come in two flavors: on chain and off chain. Automated Market Makers (AMM - also known as a Decentralized Exchange) such as Uniswap and PancakeSwap. For constant-product AMMs, like UniswapV2, the users rely upon a ratio between two tokens. This solution has a problem with price fluctuations.
  • For off chain, such as Chainlink, the data is calculated off chain, then added to a contract periodically. This has the problem of speed of support of other tokens, safeness and scalability.
  • A loan is simply money given in advance. A flash loan is borrowing a large amount of money (for a fee) for a short period of time without collateral. In particular, it has to be returned within transaction; otherwise, it will be reversed. Why is this useful? Arbitrage! The idea is to buy something you cannot afford then sell it in another market for a little bit more to make a profit, eventually paying back the loan.
  • Enzyme Finance is an Ethereum baed protocol used for asset management. User can create and invest into various funds, with the rules defined by the ruler of the fund. Once money is put into a fund, they get a share for this fund, based upon the assets added.
  • How much does a share cost? This is calculated via the function calcGav() to mint tokens based upon the cost. The cost of the share is based upon the cost of the Idle Tokens, such as idleUSDCYield.
  • The unit price of the Idle token is calculated strictly between the net asset value of the pool divided by the supply. The code is simply price = totNav.div(totSupply0;. If we control the total supply, then we could manipulate the cost of assets in the pool. How can this be done? The contract has internal flashloan functionality, which can drastically change the price of the IdleToken.
  • How do we actually make money from this?
    1. Make a flashloan from a smart contract for IdleUSDCYield tokens. This will affect the GAV calculations for the pool.
    2. Buy shares with the ETH/USDC in the smart contract. Since the price has dropped from our flashloan, we get these at a discount.
    3. Repay the flashloan.
    4. Redeem the shares that we bought. Now, we can sell them at a huge gain.
  • To fix this problem, the idle tokens were delisted. Additionally, the flashloan functionality was removed entirely. Overall, price oracle manipulation is a scary concept without trivial fixes. With a decentralized markets, this is an inherit problem of how it's designed.

APWine Incorrect Check of Delegations Bugfix Review- 880

Immunefi    Reference →Posted 3 Years Ago
  • APWine protocol is used to tokenize future fields. This is done by storing an Interest Bearing Token (IBT). Or, any other asset yield bearing asset in a smart contract with a Future Yield Token (FYT) in exchange.
  • The smart contract receives the yield from the assets directly. However, the FYT holders are the only ones allowed to withdraw the yields. The division of these yields is done via Principal Tokens (PTs). The FYT to PT is a 1 to 1 ratio.
  • In the ERC20 implementation, there is a function called _beforeTokenTransfer that does some validation steps when transferring out yield to an externally allowed entity. After the transfer occurs, there is an if statement to update the state of the contract.
  • This if statement confirms that the from and to are neither 0x0 or the vault contract itself. Is it possible to perform the transfer without updating the state?
  • When burning (removing) a token, the standard says that these tokens should be transferred to the zero address. However, there is usually a hook that prevents the sending of tokens to this address, which is what the vulnerable code it trying to do.
  • This becomes a problem when _burn is called. When the code is called with _beforeTokenTransfer(account, address(0), amount), the address is sent to zero. In particular, delegated funds being removed do not update the main state. This means we can arbitrarily increase the delegated funds!
  • To exploit this, we need to perform the following steps:
    1. Deposit money into the FutureVault vault.
    2. Create a fresh account (to bypass a sanity check) and delegate some funds to a smart contract address.
    3. Call withdraw to redeem on Principal Tokens for the interest gained. This works because the redeem balance for a user compared to their delegated amount is not run.
    4. Repeat these steps multiple times.
    5. Generate yield from the inflated delegation amount.
    6. Redeem a bunch of money!
  • To fix this vulnerability the delegation funds amount is put into the _withdraw function. Overall, great bug that was from the over-reuse of code. ERC20 is hard to implement correctly with all of the custom logic needed for specific applications.

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.