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!

Explained: The XCarnival Hack- 889

Rob Behnke    Reference →Posted 3 Years Ago
  • XCarnival is an NFT lending platform in which a user can deposit an NFT as collateral against loans. By depositing NFTs are collateral, tokens and other assets can be purchased.
  • When a user deposits an NFT into the platform, they are assigned an orderID. This should have been valid as long as the collateral (NFT) was still in the system.
  • However, there was a mistake in this logic. The orderID was still valid, even if the collateral had been taken out of the contract. This allows for the using of the receipt to take out loans, while the contract not longer possessed the collateral necessary to force the payback of the loan.
  • To launch the attack, they created several contracts and put NFT as collateral. The reason they used multiple contracts was that there was a limit on the size of loans that could be taken out. As a result, they did this attack multiple times to steal 3.8 million ETH.
  • Apparently, they had passed an audit from Certik. Interesting how this either got missed by the audit or the functionality was changed after. From my perspective, this feels like something I would check quickly. Overall, good bug!

Exploiting Spartan Protocol’s LP-Share Calculation Flaws- 888

Amber Group    Reference →Posted 3 Years Ago
  • Spartan is a DeFi protcol for assets running on BSC/BNB. This is mostly the same as the UniswapV2 protocol with some small differences. This is an AMM.
  • When putting funds into a pool, a user is able to remove (liquidate) these funds. When a user removes these funds, the amount of the funds they are entitled to must be calculated. When taking funds out of the pool, the user must send back LP tokens, which are essentially receipts for putting funds into the pool.
  • The simple way to do this is returning LP tokens/total LP tokens. This allows them to obtain a total for the underlying assets proportional to what they put in. At this point, the tokens will be burned (destroyed). This math is where the vulnerability occurs at because of bad state handling.
  • The vulnerability occurs when syncing costs between the reserves and the pools contributions. Since these values are not being updated properly, they were able to exploit the slippage between the two prices. This desync between the amount of total funds and the assets put into the pool makes it possible to take out more funds than expected.
  • To perform this attack, the following steps have to be done:
    1. Add liquidity to the pool and get LP tokens back.
    2. Transfer assets into the pool. This amplifies the amount of assets in the LP token, which allows the attack be possible.
    3. Remove the liquidity. Since there are more assets (from step 2), we get more liquid returned than what we put in.
    4. Put the assets into the contract as liquidity then remove it.
    5. Perform this operation multiple times.
  • This took me a while to understand. The important nuance here is that asset and liquid are slightly different concepts. Adding assets to the pool would amplify the price of the liquidity in an unfair way. Eventually, when the liquidity was removed, we get some assets back than we put in. Neat!

Astroport Audit by Halborn & Oak- 887

Halborn    Reference →Posted 3 Years Ago
  • Astroport is a decentralized trading platform. Prior to being released fully, it went under two security audits on multiple features. A few of these bugs are interesting and worth calling out!
  • In the AMM (Automated Market Maker), there is a function to set configuration parameters, such as other deployed contracts to use. However, these functions are not backed by access control! This means that anybody cab trivially change these parameters and potentially steal funds. This same issue was found by both Oak and Halborn.
  • When creating a pool, there is no check that the same assets are being used to create this. As a result, we have a classic double spending problem. A user could take out more money from the pool than there fair share. This can be triggered again because of a case sensitive check for an address.
  • In the Oak audit, there are a few more severe issues. The first issue is a rounding problem when taking out assets with division. When taking out funds in the pool compared to one another, the division gets rounded up instead of rounded down. This resulted in money being easy to siphon from the contract.
  • The second major vulnerability is a gas exhaustion attack. There is an iteration through a map with an attacker controlled size. By putting in many small amounts into this, it would make the funds forever locked.
  • A lot of the other findings are simply "X doesn't work and user could lose funds". It is shocking how some things do not work as expected with this much money on the line. Overall, fairly good audits with good bugs!

Port Finance Logic Error Bugfix Review- 886

Immunefi    Reference →Posted 3 Years Ago
  • Lending in the real world is a complicated subject. If you are attempting to start up a business, then you need capital backing or to take out a loan yourself. When you take out a loan, you must provide some collateral to guarantee you will pay it back. While something is up for collateral, it cannot be used for anything else.
  • The value of the asset you want to borrow is called the Loan To Value (LTV). For instance, if you borrow $60 worth of some cryptocurrency and you provide $100 as collateral, your LTV is $60/$100 = 0.6.
  • Liquidation is a way to protect lenders from a negative price fluctuation. If the value of your collateral is insufficient, the liquidators may purchase your collateral at a discount. Lending protocols usually set target LTVs for their lending pools, and as a borrower, your main risks involve losing your collateral through mismanagement of your position’s LTV.
  • Port Finance is a non-custodial money market protocol on Solana. The purpose of this app was to create a large listing of interest rate and lending protects for Solana. Port Finance has a number of lending pools, which are called Reserves in their context.
  • Todo...

Sense Finance Access Control Issue Bugfix Review- 885

Immunifi    Reference →Posted 3 Years Ago
  • Sense is a framework that allows the building of new yield primitives. This would include bonds, yield tokens and tranch-like (pools of assets) instruments.
  • The first app (made by Sense) was a yield stripping app called Sense Space. This means that users can lend at a fixed rate and make gains on this. Additionally, they make short/long bets on the future yields of existing yield-bearing assets.
  • Sense Space is an Automated Market Maker (AMM). This is built upon the Balancer contract, which implements yieldspace invariants and a market for principal and yield token trading. Balancer is automated portfolio, liquidity provider and price sensor.
  • When the Balancer vault handles a swap between tokens, it does this by making a callback to the onSwap() function of the Space AMM pool.
  • The AMM pool function onSwap() would update the prices of the token depending on the actions performed on the actual swap. In particular, updating the amount of tokens available.
  • The issue is that the onSwap() method does NOT validate who makes this call. As a result, an attacker could provide arbitrary values to this to control the oracle. By controlling the oracle, the price of tokens could be set, giving an attacker an easy time stealing money.
  • The simple fix for this was to ensure that the sender of the call was the vault contract. Overall, a simple vulnerability that came from the complexity of integrating multiple pieces together.

The Inverse Finance Hack- 884

Rob Behnke    Reference →Posted 3 Years Ago
  • Price oracles are being in used to calculate how much a token costs. This is similar to exchanging currencies at the airport for USD to Euros. How is this cost set?
  • In the land of crypto, this is commonly done based upon algorithms from the amount of assets in circulation. If there are more coins in circulation, then they cost less. If there was less coins, then they cost more.
  • If the users of the token are not careful, then the cost of the token can be manipulated. For instance, an attacker could buy a ton of tokens to make the token cheap. Then, buy something using this new cheaper price. Finally, return all of the tokens to make the price stable again. This is known as oracle manipulation.
  • In the case of Inverse Finance, it was a bit more complicated. The attacker took out a flash loan then put collateral in a pool. By performing a swap with the flash loan, the price of their collateral rose drastically!
  • Because of the rise in price, they were able to take out a large loan from the pool. After performing some conversions, they were able to pay off the flash loan as well. This resulted in 150 million being stolen from the contract.
  • This token manipulation required a deep understanding of how the system worked in order to exploit. If there is any calculation going on then it must be carefully vetted.

Wormhole Uninitialized Proxy Bugfix Review- 883

Immunifi    Reference →Posted 3 Years Ago
  • Wormhole is a communication bridge between Solana and other blockchains. As such a big service, it needs to be updated. The issue, is that blockchains are immutable. So, how is this done? In some complicated and convoluted ways that have some weird negatives.
  • The goal is to change the code in use at a specific address but keep the state of the contract. To make this possible, there is one address that acts as the proxy and the other that acts as the contract code itself. The proxy holds the state of the contract. This is done via making a call to delegateCall() from the proxy to the contract. A final point is that the initialization function has to be a regular function instead of a constructor.
  • There are two common patterns for this: TPP and UUP. Transparent Proxy Pattern (TPP) ensures that all calls by a user execute the implementation logic and all calls by the admin implement the proxy contracts logic. TPP has to store information about the admin on the proxy side, making it much so efficient.
  • To combat this problem, the prevailing pattern is Universal Upgradeable Proxy Standard (UUPS). The main difference is that the upgrade logic is in the implementation contract instead of the proxy contract. This makes the cost of updating cheaper and we no longer have name collisions. For more on these patterns, read Transparent vs UUPS Proxies.
  • OpenZeppelin's (smart contract templates that are widely used) UUPS implementation had an access control problem. The init function set the caller to be the owner of the contract; this is another constructor related problem! With this, the attacker could upgrade the contract to their own malicious values, then set the new location to be their own contract. Finally, calling selfdestruct would drain the funds and make the proxy useless.
  • In the case of Wormhole, they had the same exact problem. An initialization function was never called and left open to the world. Using SELFDESTRUCT would have bricked the contract and stolen all of the money. To fix this, they simply had to call initialize themselves.
  • Overall, the proxy pattern is interesting but adds a lot of complexity. Good find for 10 million dollars.

Polygon Double-Spend Bugfix Review- 882

Immunefi    Reference →Posted 3 Years Ago
  • Polygon is a blockchain platform. They have implemented a bridge called the Plasma Bridge. A user can go from one blockchain to another with their funds using this bridge.
  • Transferring funds between blockchains is complicated. Tokens must be locked in one place then appear in another. In order to do this securely, the authors have created an implementation of a Merkle Proof. In particular, the burn transaction (exit) receipt is verified this way.
  • Within a Merkle proof, the branchMask is used to keep the system secure and must be unique. This is important, since this was the ID that was being confirmed for a exit being executed or not.
  • The branch mask is decoded by the MerklePatriciaProof.verify and once again at WithdrawManager.verifyInclusion. The decoding of the second function ignores several values while decoding it. Since the branch mask id can have many different variations from this bad decoding and this is used for an ID we have a problem.
  • The uniqueness of this ID is not 100% true then. The replay attack can be a completely valid receipt but with a separate branch mask. In particular, this lead to 224 ways to execute the same ID. This allows the stealing of money from the contract when going between chains.
  • The branch mask should always be 0x0 for the mask. Since this was not check, the particular attack mentioned above was possible. Overall, a fascinating bug from the improper validation of cryptography.

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.