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!

Mushrooms Finance Theft Of Yield Bugfix Review- 919

Immunefi    Reference →Posted 3 Years Ago
  • Maximal/Miner Extractable Value (MEV) is a measure of the profit that a miner can make by ordering the blocks they produce. For an attacker, this can be includes, excluding or reordering the transactions altogether.
  • Mushroom Finance has built in protections in place that make flash loans attacks not possible; only externally owned accounts (EOA) cannot make a call to the contract. However, the concept of the arbitrary ordering of blocks is still important here.
  • A sandwich attack is when a miner orders their transaction, a victim transaction then another controlled transaction. This bundle of transaction within a block could make the miner block very profitable, given the proper sequence of events. Sandwich attacks are are version of frontrunning.
  • In the case of the Mushroom Finance contract, there is a function called harvest(). When this is triggered, the yields for the earned funds will be distributed pro-rata (based upon the amount of inserted funds.
  • The attacker can manipulate the harvest function call but sandwiching two other transactions. First, an attacker would need to use their own funds in order to distort the price of the Uniswap pool. Then, in the sandwich, the put the harvest() call. The final transaction has the the Uniswap pool go back to its undistorted state, taking some of the harvest funds.
  • To fix this problem, which had been exploited by several bots in the past, the fix is calling harvest more frequently. If there's no money to be gained, then there's no attack.
  • The malicious ordering of transactions within a block is a fascinating attack. I wonder if it's possible to simulate this on a local fork for demonstration purposes?

Sovryn Loan Vulnerability Bugfix Review- 918

Immunefi    Reference →Posted 3 Years Ago
  • Sovryn is a decentralized trading and lending protocol. It is deployed on RSK, a sidechain of the Bitcoin blockchain. When lending give out money, they earn interest on their BTC being used for lending.
  • In the DeFi world, most loans are over-colleateralized in order to ensure they can be paid off. This is because the blockchain does not have the means to ruin the users life via bad credit score and other things if they do not pay back the money.
  • When takes out the money for a loan, the function borrow can be used to specify information about the loan, such as the pool to take the collateral on and the loan id to use. Additionally, a different receiver that be sent as a parameter as well.
  • By specifying the loanid on the call, an attacker can take out loans for other users. According to the article, this is ONLY possible when the loanid has unused collateral. However, it may have been possible to race the removal of a loan from the contract as well.
  • To launch this attack, first, an attacker needs to identify a loan with unused collateral (theoretically). Next, they need to call borrow() with the receiver that they control. Since they have a loan using someone else's collateral, there is no penalty for paying back the loan! They do not have to pay this back.
  • The same vulnerability happens within the marginTrade() function. A malicious user can put someone else in a bad position but specifying that user. In particular, the function call allowed for the setting of the trader on the call, when it should have been msg.sender.

Yield Skimming: Forcing Bad Swaps on Yield Farming- 917

Dedaub Team    Reference →Posted 3 Years Ago
  • Yield farming is lending or staking cryptocurrency in exchange for a percentage of interest. By providing some funds as an individual, you can take some of the groups profit.
  • In yield farming, a common code pattern is upon harvesting the yields (taking your share of money from the work done) that the tokens are swapped at an exchange, such as Uniswap. This is done in order to rebalance the contracts tokens in the event that too many funds are taken away. Additionally, it is common for the harvest() function to be public, meaning that anybody can decide when the yields can be harvested. Why is this a problem though?
  • An attacker can abuse this feature in order to manipulate the pool. An example flow is shown below:
    1. Distort the pool being purchased from. For instance, take out a flash loan to make one asset expensive and the other much cheaper. Sell a ton of asset A to the pool.
    2. Call harvest(). The pool does the swap at the very bad prices for Asset A.
    3. The attacker will then trade Asset B they got from the original swap in order to get back a profit.
  • To protect against this type of manipulation, a few things can be done. First, limiting the callers of the yield function. Secondly, the harvest function can be called with extremely regularity to make the fees of the swap to expensive to perform this attack. Finally, check for slippage and reject to price if it has swayed too much.

Vesper Rebase Vulnerability Bugfix Review And Bug Bounty- 916

Immunefi    Reference →Posted 3 Years Ago
  • Vesper is a DeFi platform that should work and make money for you. This money is called yield from using your DeFi in various places.
  • When the function rebalance() is called, it takes the underlying assets of a user and buys VSP. By doing this, the price of VSP is increased; VSP holders are entitled to a percentage of the yield based upon the use of the underlying asset produces. This is done by a Vesper's Rebalancing bot in order to distribute yield to holders through inflating the price of Vesper.
  • The function rebalance appears to have been callable by anyone and not just the bot. This is part of the where the problem lies.
  • An attacker could exploit the distribution function being callable by taking out a flash loan. First, an attacker would need to take out a loan in WETH and swap the WETH for VSP on Uniswap. Now, the pool has significantly more WETH than VSP, drastically inflating the price of VSP.
  • Call rebalance() manually. Now, the triggering of this call will perform a swap to get VSP. But, because of the inflated price from the flash loan, the swap gets a much smaller amount of VSP than it should. As a result, most of the WETH from the rebalance() goes back into the hands of the flash loaner even though they did not participate in the farming at all.
  • There is a cooldown period of the rebalance() call. So, this was not the most likely attack to occur. Additionally, they claim this attack would have been discovered through monitoring... but, I think that relying on this for security is a bad precedent to set.
  • To fix this vulnerability, the frequency of rebases called by the bot from sped up dramatically. By doing this, the cost of the flash loan and swap fee makes the attack no longer viable. If there's no profit, then there is not attack. It appears that the whitehat hacker got no funds from this.

Zapper Arbitrary Call Data Bugfix Review- 915

Immunefi    Reference →Posted 3 Years Ago
  • Zapper is a wallet platform that helps make the platform easy to use. When joining a pool, you need several different types of assets. If a user wanted to join this pool, it would require many different transactions to do. In order to solve this, Zapper will swap the coins for you and deposit them into the liquidity pool.
  • With Uniswap and SushiSwap liquidity pools, you can get positions by depositing funds into pools, known as zapping in. Additionally, you can withdraw your funds from the pool, known as zapping out. In order to do this, a user had to allow the Zapper to perform these operations. For this to be possible, Zapper allowed users to specify an arbitrary call to any liquidity pool.
  • This call allowed for a controlled address and a controlled call data. As a result, an attacker could setup transferFrom() to force the contract to transfer all LP tokens from any victim to the attacker. Since, at this point, a user has allowed the contract access to the coins. This allows for a cross account zap out, in terms of the service being used.
  • To fix this vulnerability, Zapper removed the ability to send over arbitrary call data. Regardless, interesting bug!

PancakeSwap Content Injection Bugfix Review- 914

Immunefi    Reference →Posted 3 Years Ago
  • PancakeSwap uses Crowdin for localization management. This is making the website available in many different languages.
  • The API key on the website for Crowdin had bad permissions though. Instead of only having read only permissions it had writable permissions as well. This means a user could have changed the localization, such as English, to change the content of the website. This could have allowed phishing to take place to steal a bunch of money from the platform.
  • Web bug in a cryptocurrency project that was quite bad. Good find!

Bitswift Race Condition Bugfix Review- 913

Immunefi    Reference →Posted 3 Years Ago
  • Bitswift only allows people to interact with the blockchain via their web client. This puts in classic web vulnerabilities into the mix.
  • When claiming a voucher (for a coin), a user makes a POST request to /claim. Since this happens in web server code, there is a small window where multiple web requests can be made on the voucher. So, a claim can be made multiple times with something like Turbo Intruder. Nice!

88mph Function Initialization Bugfix Review- 912

Immunefi    Reference →Posted 3 Years Ago
  • 88mph had an initialization function without the onlyOwner() modifier. Additionally, there was no check to ensure that a contact wasn't double initialized. Three of the pool contracts were vulnerable to this.
  • This means that ANYBODY could have became the owner of the contract. Using this, an attacker could steal other users NFTs and deposits as well as call mint() and burn() to add value to themselves.
  • To do fix this bug, they had to steal all of the funds, upgrade the contract then fix the money back. Yikes... I hate this world. Regardless, a very simple access control bug from an apparently unaudited contract.

Nomad Bridge Hack- 911

samczsun    Reference →Posted 3 Years Ago
  • Nomad bridge is a cross-chain protocol between Cosmos compatible blockchains, such as Moonbeam, and Ethereum. Being able to transfer ERC-20 coins between chains is amazing for scalability but is really hard to do correctly. 4 out of the 5 biggest hacks on rekt.news have been on bridges.
  • When moving stuff across chain, there appears to be two functions for this: prove() and process(). The process() function is used for uses a transaction from one chain to another after proving it.
  • To validate if the message hash is valid, the following line of code is ran:
    require(acceptableRoot(messages[_messageHash]); 
    
  • The following code can be broken into a few steps:
    1. The variable _messageHash is the keccak hash of the data being added to the blockchain.
    2. The map (dictionary in Python) is used to find the matching hash for this message. If it's valid, it will the expected root hash. Otherwise, it will return 0x0, since that's the default for a bad map find in Solidity.
    3. acceptableRoot() is called to ensure that the root hash of this message is valid. If it is, the transaction continues. Otherwise, the contract reverts.
  • So, this looks like good code, what's the problem? During an update of the smart contract, the hash 0x0 was made into a valid root! Since a Solidity map defaults to 0x0, any fake transaction will pass. Wait, how is this repeatable?
  • It turns out that the function acceptableRoot() had been updated to handle an ENUM in legacy code. Instead of having PROVEN and PROCESSED (which return true and false respectively) the legacy code checks to see if the time for the data passed in is 0. Since the structure will return a hash time that is not 0, this ALWAYS passes. Thanks to Zellic_io for tracing this down.
  • For the repeatable effect, I'm still not 100% sure about it. According to source code the 0x0 hash would be set to a value of 2 (PROCESSED) then would never be usable again. The state to update does messages[_messageHash], making it so the specific call cannot be used again. However, we can remake this call with slightly different values over and over again!
  • What is super crazy about this, is that the QuantStamp audit called this out as a potential issue. I never would have called this out, since it seemed like it was part of the design.
  • The attack lost 190 million but it appears that several of these people are whitehats who will give the money back. Regardless, I'm sure that 75% is gone forever. All of the other platforms that rely on this bridge, such as Moonbeam and EVMO, drastically sank in value from this attack.

Pods Finance Bugfix Review- 910

Immunefi    Reference →Posted 3 Years Ago
  • Pods Finance has a rewards system built into the protocol. If you decide to put issue options, then the contract will mint rewards for you.
  • The vulnerability, which was present in both rewards system, allowed a malicious attack to claim rewards for other users. If a user had minted at least one option in the pat, they could repeatedly call unmintWithRewards() in order to claim the same share over and over again. By doing this, all of the funds from the contract could be stolen.
  • The fix for this was calculating the reward based upon the options being unminted and NOT the shares that the user possesses. Even though this could steal all of the funds from the contract, it was rated as "high" instead of "critical" since just the theft of rewards was possible. Regardless, being able to drain the contract of all the money seems like a critical finding.