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!

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.

Multichain Contract Vulnerability Post Mortem- 869

Multichain (AnySwap)    Reference →Posted 3 Years Ago
  • Multichain, formerly known as AnySwap, is an infrastructure for a multi-blockchain ecosystem. As with cross-chain protocols, it is simply a bridge that allows the transferring of tokens from one chain to another by creating their own token on each platform.
  • A white hat hacker reported a vulnerability in the platform. The issue was immediately fixed but the users needed to revoke permissions in order to completely fix the problem.
  • What was the issue? AnyswapERC20 and AnyswapRouter assume that the function permit is implemented for all token contracts. This function is used to make the gasless approval of token transfers. Since some of these contracts had fallback functions, that was triggered instead of the permit code.
  • Since permit checks to see if a user is able to send the funds, the complete removal of this code bypasses a very important security check. Hence, an attacker can steal all funds being used from permits. This is possible if two situations are met:
    • Permit is NOT implemented.
    • There is a generous fallback function on the token.
  • Why only permits though? The check that gets broken is validating the permit or from of the code. As a result, if there are ANY permits about an address, an attacker is able to steal these funds. To launch the attack, they need to trade a token that meets the criteria above. When they attempt to run this code for transferring funds from another user, there is no limitation on the amount of funds sent.
  • To me, it is interesting to note that the logic for a smart contract reverting is from the Solidity compiler itself. If a function exists, it is sane to think that the code wouldn't run - but the fallback breaks this assumption. If you try to call code at an address that has no code, this will run STOP (which is a success) instead of REVERT as well.
  • This researcher was paid out 2 million dollars (1M to each contract with this bug). The niceness of the smart contracts is fascinating to me; why wouldn't a function that cannot be resolved just revert? Hmmm, such as weird eco-system. An additional exploit link is here.

Qubit Finance Hack- 868

CertiK    Reference →Posted 3 Years Ago
  • Qubit Finance is a money market platform for lenders and borrowers. This functionality includes a Ethereum - BSC bridge (blockchain connector). In the case of Qubit Finance’s bridge, you deposit your ERC-20 tokens to the bridge and receive BEP-20 tokens in return.
  • The function safeTransferFrom is used to send tokens from the depositor and into the contract. When doing this, the user needs to provide an ERC20 token address.
  • When passing in this address, the contract attempts to use transferFrom to remove funds of the user to put into the contract. Then, on the other blockchain, the user gets newly minted tokens. However, if no code was at this address, the transfer of funds would never occur but the minting would still take place.
  • When no code exists at an address, the call return successfully. This is a weird quirk of this language! The attacker entered in 0 as the address. By using the attack over and over again, an infinite amount of qXETH could be minted. This drained an estimated $80 million from the protocol
  • This was a simple case of bad error handling and bad input validation. The usage of a custom ERC20 library, instead of the OpenZepplin, caused them issues as well. It is very strange how the address returns a success when there is no code there. An additional link can be found at here

The Wormhole Hack- 867

Certik    Reference →Posted 3 Years Ago
  • Solana Wormhole is a communication enabling the transfer of tokenzied assets from different blockchains. Wormhole has a set of guardians that sign off on transfers between the different chains.
  • A bridge works by having two contracts: one on each chain. In this case, there was a contract on Solana and another on Ethereum. What was the attack? Simply put: the attacker submitted transaction showed that it contained valid signatures from the guardians. They created 120K ETH out of thin air!
  • In order to do things cross chain, the guardians must sign off on it. Or do they? Four functions down in the call stack, a change to use load_instruction_at_checked instead of load_instruction_at was made. One of them makes the assumption that the verification has been done while the other does not.
  • Once the attacker realized the mistake in the code (removed the signature check), they provided their own smart contact to be used for verification. At this point, it was trivial to mint their own tokens.
  • The validation was passed down several times. This is an excellent case where a unit test or integration test for security based issues would have helped a ton.

The Meter.io Hack- 866

Rob Behnke    Reference →Posted 3 Years Ago
  • Meter.io is cross-chain bridge. A Wrapped token is a token that is tied to the value of another currency, such as the USD. In this case, it was wrapped ETH vs. unwrapped (regular) ETH handling.
  • For wrapped tokens, there are assumptions being made. For instance, wrapped tokens should not be able to burn (remove coins from circulation) or locked while wrapped.
  • A user could make a deposit to the contract with two different functions: depositEth and the ETH20 deposit function. One of the functions validates that the callData and msg.value are the same. However, the other does not make this check in a require statement.
  • Why is this bad? An attacker can specify how much money to deposit in the callData without sending over any money. Then, they can withdraw this money, draining the contract of funds.
  • This was an open source project that got forked into this. Unknown code and assumptions can lead to major security flaws, when not handled correctly.

The Paraluni Hack- 865

Rob Behnke    Reference →Posted 3 Years Ago
  • Paraluni is a financial project in the metaverse. The function depositByAddLiquidity contains a reentrancy vulnerability in it.
  • When calling depositByAddLiquidity, an internal call is made that transfers the caller deposit into a new pool. However, the pool contract can be controlled by an attacker. Once the flow is sent to the attacker contract, we can reenter this contract again.
  • The funds have already been transferred to the other pool put the internal state has not been updated. As a result, an additional call to this contract to deposit can allow for moving the money TWICE. This can be repeated indefinitely to drain the contract of money. A twitter thread showing the code is at here from PeckShield.
  • Typically these reentrancy bugs are only within the fallback functions. So, it was cool to see this vulnerability happen in a place that is impossible to fully fix in Solidity. Cool bug!
  • Another write up, from Slowmist, has good analysis on it as well. The main new insight is that the incoming array of tokens was not validated to against the pool. This resulted in the controlling of our own ERC20 token.

Fantasm Finance Post Mortem- 864

Fantasm Finance    Reference →Posted 3 Years Ago
  • The Fantasm Fianance Protocol had its own coin (just like everything else!). The code for minting (creating) these tokens had a brutal flaw in it.
  • In a require statement, there is a validation that the user deposits enough other tokens in order to mint the new token. However, we are dealing with FSM, FTM and ETH are input, all at the same time. These require statements must be on point in order for this to work.
  • The code compares ONLY the value of msg.value (ETH) and not the minimum amount of FTM tokens. As a result, an attacker could ONLY send ETH and FSM tokens but send NO FSM tokens. This error allowed an attacker to mint XFTM without depositing any FTM.
  • In this case, _minFtmIn variable contains ETH instead of FTM token minimum amount. Since this already passed, it was a major problem. The code is shown below:
    require(_minFtmIn < ftmIn, "Pool::mint: Not enough FTM input");
    
  • As a result, an attacker could mint XFTM without ever entering in any FTM. So, here is how they stole 2 million dollars:
    1. Mint XFTM token without entering in FTM tokens.
    2. Collect XFTM token.
    3. Sell XFTM token to FTM. Remember, we created these out of thin air.
    4. Do this process over and over again with more and more money.
  • Overall, writing concise code for each edge case is hard. In this case, the check is there but not working properly. This would have passed a code review but failed dynamic testing. An additional link for this is at Halborn.

Cashio Hack- 863

Rob Behnke    Reference →Posted 3 Years Ago
  • Cashio is a stable coin (CASH) that is linked to USB. This runs on the Solana blockchain.
  • To mint new tokens, a user needs to deposit collateral for the token. The collateral can only be deposited if the account goes through a series of checks first.
  • An attacker could create a new account with worthless collateral tokens. Because of a lack of checks on the account and collateral, this allowed for infinite tokens to be minted.
  • Damn, this seems quite obvious to me. If you are going to take in collateral, it better be legitimate. Otherwise, you are going to be robbed blind. No wonder banks want so much information on you!

The Beanstalk Hack- 862

Rob Behnke    Reference →Posted 3 Years Ago
  • Beanstalk uses a decentralized governance protocol. The smart contract contains a 2/3 vote emergancyCommit function that happens in 24 hours.
  • Voting in the Beanstalk protocol is determine based upon the donations to the contract itself. Right before the time for the vote was about to happen, they performed a flash loan or took out an insane loan for a short period of time.
  • This flash loan gave them 79% control of the protocols votes. With this power, they could approve their proposal with the emergancyCommit(). Since the proposal was just sending the money to the Ukraine and the attacker, the money was gone. At this point, the attacker used the money to pay back the Flash loan.
  • Flash loans are part of the eco-system and must be accounted for. Otherwise, attackers will steal all of the money then pay back their flash loan.
  • This contract was audited by a security firm, shockingly. However, they were not allowed to audit the governance functionality of Beanstalk.