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!

C3 Linearization in Solidity- 1135

bytes032    Reference →Posted 2 Years Ago
  • Inheritance is straight forward until its not. What do you do when a diamond is created from inheritance. For instance, if we have contract A, contract B & C which inherit from contract A and contract D which inherits from B & C. Weird problem to have. The solution to this in Solidity is C3, which is also used by Python.
  • The algorithm guarantees that the method of resolution is uniform throughout the inheritance hierarchy. Additionally, it's expected that method calls and attribute lookups work in this scenario as well.
  • The goal of the Linearization is to make this a linear hierarchy. As a result, the inheritance flow will turn into [D,C,B,A]. Crazy enough, C is now a direct descendant of B! Although this is not the EXACT interruption that you would expect, it's better than the program not compiling.
  • Constructors for the parent contracts are always executed in the C3 order. Changing the order of constructor execution within the child constructor doesn't effect this at all. Additionally, a parent with a constructor and no arguments is automatically invoked, even if it's not explicitly invoked by the child. There is an example in the code of this for the Ownable contract.
  • Overall, a pretty interesting article on how inheritance works in Solidity. Probably been a few bugs in the past as a result of this.

Digging into Compound- 1134

Bytes032    Reference →Posted 2 Years Ago
  • Compound is a borrowing and lending protocol built on Ethereum. Naturally, Compound needs funds to lend out. This is done via liquidity providers (LP). When an LP deposits funds, they are put into a huge pool and receive the ERC-20 token cToken. This cToken represents a portion of the total pool. As the pool earns interest, the amount of funds a user can claim grows.
  • cTokens represent ownership of a loan to be taken out. The value of the cTokens increases over time as borrowers make payments. The cTokens allow a user to take loans by using them as collateral. This means that the funds a user deposits as an LP to get cToken can directly be used to get another asset.
  • cTokens are generic. For instance, cDAI is the DAI token cToken. How does it know how much a token is worth or what the exchange rate is? They use a Chainlink pricefeed in order to do this. This oracle is used to determine collateral requirements and all of the other fund work.
  • The Controller manages risk within the protocol. This is done by setting collateral requirements and liquidation thresholds based on risk weights, user balances and prices from the oracle. Naturally, loans need to be overcollaterized in DeFi in order to work. This logic ensures that the protocol never loses funds on a loan when the market goes down.
  • How does the protocol remain solvent - or have enough funds? Either too many people are borrowing or there are not enough funds being lent. To solve this problem, Compound has a formula known as the utilization rate for a pool. The higher the current utilization rate, the higher the interest on the loan is. Naturally, if the utilization rate is high, less loans will be taken out. Additionally, it will have high interest rates, leading to more LPs to provide value.
  • The interest rate is calculated using the utilization rate, the profits to the protocol and the general borrowing interesting rate. This final value is calculated using an interest rate model to determine the cost of it. In particular, it has a flat fee and a yearly multiplier. This makes the interest linear. The graphs in the article use the purple line as what the borrower pays and the green line as what the LP receives.
  • Most borrowed assets use the Jump Rate model. It's exactly like the previous model with two additional parameters: kink and jump multiplier. The kink is the point on the graph that the jump multiplier is used. The jump multiplier is the rate of increase once the kink has been hit. This makes a very steep climb once a particular threshold of utilization has been hit.
  • The goal is that a high APY will incentivize users to deposit more to ensure there is always liquidity for withdrawal. With these values in mind, it is possible to calculate the amount of interest that would be paid for a loan over a given time period.
  • Overall, good explanation on Compound! I had a lot of misconceptions cleared up.

XSS and cache poisoning via upload.twitter.com on ton.twitter.com- 1133

filedescriptor - HackerOne    Reference →Posted 2 Years Ago
  • This bug report is a doozy! It combines various vulnerability classes to create a horrifying exploit in Twitter.
  • Twitter allows users to upload files. If a known file type is sent, then the response for the file will contain the proper Content-Type. If it's a malicious file extension, such as HTML, it's rejected though. So, what happens if the file type is not known? No Content-Type is sent!
  • The web browser does not trust file extensions; it only likes the Content-Type. If this header is not included, it attempts to deduce the type of the file based upon the content! This is called MIME Sniffing. By sending a file with a random file type, the browser will sniff the type of it based upon the content. This allows for malicious content, such as HTML, to be included in the file that will be executed!
  • Sadly, this was a self-attack though; we need another bug to make this hit other users. The author found out that an HTML5 AppCache manifest file can be uploaded to website. This allows a malicious user to control the caching behaviors over ton.twitter.com in the browser. What can an attacker do with this?
  • The appcache manifest file has crazy capabilities. For instance, it can change the HTML on the page! Worse yet, it will stick in your browser, giving a user permanent XSS. Overall, a combination of MIME sniffing and clever usage of the appcache manifest file lead to permanent XSS. Pretty rad!

Hacking Brightway scooters: A case study- 1132

Von - robocoffee    Reference →Posted 2 Years Ago
  • Electric scooter hacking!? Sign me up! In this article, the author takes a look into the Brightway Scooters made for NAVEE and Xiaomi. The scooter has a Controller in the bottom that communicates with a motor and a battery. In the top of the scooter is a dashboard that communicates with the Controller uses UART. The Dashboard communicates with cell phones using BLE.
  • To pair a scooter, the app must be downloaded and a QR code is scanned. To activate the scooter, a home video must be watched. The 'Mi Home' API is integrated with the vendors app. By looking into this internal application, we find the locations of important registers (such as put the scooter into drive mode) and more.
  • The format for an packet for the scooter is as follows:
    • TYPE: The command type. Write, read, MCU (controller) read/write and a few others.
    • ADDRESS: The register address mentioned above.
    • REST: The package being used.
    • LEN: The length of the payload.
    • PAYLOAD: The hex values to transmit.
  • They decided to take apart the scooter and map out all of the hardware. While doing this, they noticed that Single Wire Debug (SWD) pins were left on! All they had to do to access JTAG was connect via OpenOCD. With this, they have complete access to the system memory, control flow and anything else they want.
  • Another oversight they noticed was that the firmware updates (OTA) for BLE are unencrypted. This allowed for reverse engineering of the system as a whole.
  • Recently, Xiaomi introduced firmware signing to secure the BLE firmware from tampering. However, the MCU firmware is still not signed. This allows for some tampering of the device still. They tried uploading their own firmware to various components for fun using this issue.
  • The device has BLE encryption and a secure chip. However, using these does not mean security by default. Protections still need to be put in place for other things. Overall, fun post on reverse engineering!

Carbon - Source Code Imager- 1131

Carbon    Reference →Posted 2 Years Ago
  • Carbon is a source imaging tool that supports a variety of languages. Just wanted to document it here to use in the future. bytes032 uses this all the time and things look great using it.

ERC4626 Inflation Attack Protection- 1130

bytes032 and others    Reference →Posted 2 Years Ago
  • ERC4626 is a specification for a vault. This vault gives out shares in return for assets. The shares determine the underlying assets that can be redeemed (in terms of assets) from the protocol.
  • The number of shares that are gained is dependent on the vaults exchange rate. This rate is dependent on the vaults liquidity. For instance, if 100 tokens give 200 shares, then the share is worth 0.5 of a token.
  • When depositing tokens, the user receives a slightly rounded down number of shares. This often doesn't matter... but, in the case where small amounts of assets and shares are being used, this can cause major havoc. For instance, if the exchange rate for is 1 share for 100 tokens. Then depositing 99 tokens would result in a drastic loss with the user getting zero shares.
  • When the vault is empty, an attacker can abuse this rounding to steal money from other users. For instance, take the following scenario:
    1. The attacker buys a single share for virtually no money.
    2. A regular user decides to add in a large amount of the asset. They send the transaction.
    3. The transaction is frontran by an attacker who donates the same amount of funds as the user is about to add in.
  • Why does this matter? The contract currently has 1 share for a large amount of assets. So, the cost of 1 share is the amount of assets added in (assets worth/1 share). The user deposits in the token. If it's less than the worth of the one share, then they will get 0 shares even though they liquidity is added. The attacker can then withdraw their share for a massive profit.
  • This is a known limitation of the specification that was first realized by a Trail of Bits audit of Yearn. How do we prevent this? Two obvious ways are forcing a large deposit at the beginning of the contract and forcing a minimum amount of shares.
  • The new concept being used to prevent this by Amxx and Open Zeppelin is a virtual offset. The issue occurs because of an inflation attack on the contract and rounding errors with a small amount of shares. The goal of the virtual offset is to artificially increase the number of shares by adding more decimals to the shares. This mitigates the attack since the rounding error is what made the attack possible
  • The second remediation strategy is including the virtual shares and virtual assets in the exchange rate computation. By doing this artificial increase, the donation is somewhat put into the virtual components, making it not profitable.
  • Overall, an interesting attack that is possible because of frontrunning and the EVM not supporting floating point numbers. The solution to the problem is clever and does cost very much money for the users of the vault.

Voting Vulnerability of SUSHI Token - 1129

Phuwanai Thummavet    Reference →Posted 2 Years Ago
  • The SUSHI token is a governance token with voting power. The SUSHI holders can delegate their votes to other users to gang vote on proposals as well. This entity is known as the representative.
  • The protocol had some design flaws in it. The function _moveDelegates is executed during the voting delegation process to give the votes to a representative. Although the voting power is moved to the representative, the delegator's tokens are NOT. So, they can transfer the tokens to another user who can now vote or delegate further these further. This is known as a sybil or double spend attack.
  • The second vulnerability is a logic flaw in changing representatives. During the redelegation process, the previous delegates voting tokens are subtracted from and the new delegates tokens are added to. However, the previous delegate token amount subtracts with the current token amount instead of the previous. This means that we can subtract votes from a representative by simply delegating, buying SUSHI and changing representatives.
  • The previous vulnerability can also cause a denial of service (DoS). A user may want to redelegate their funds to another. However, since the current SUSHI token count is used instead of the previous one, the arithmetic can underflow.
  • Interestingly, these are known bugs by the SUSHI team. In the contract code, there is a comment saying to NOT use this token for security reasons. I'm sure when people assumed the code worked fine though. Why wouldn't they just patch the bugs then? So weird. Overall, impactful and simple logic bugs.

RouteProcessor2 has been exploited on Sushi Swap- 1128

Slowmist    Reference →Posted 2 Years Ago
  • Sushi Swap is a popular trading platform with the ability to take out loans, perform leverage trading and more.
  • When a user wants to allow an address to spend money on their behalf, they use the approve ERC20 function. Since we trust Sushiswap and they need the approval to spend our money in the smart contract call, this is a pretty standard thing to do.
  • A router contract allows for a high level call to be made and the smart contract will do the rest for you. For instance, if you wanted to trade USDC for wETH, you would need to find the pool to perform the trade. The router can be used as a lookup in order to find this pool. Additionally, it may be able to perform multiple operations in one transaction.
  • The Sushiswap router was a little too generous with user provided data. The function processRoute took in a variable called route, which was generated off chain. This route is used for the path of tokens to be traded, with the first token being the sold and the final being the bought token.
  • The route variable had no verification performed on it though. When using the swap command code with a UniswapV3 pool, the user can provide an arbitrary address.
  • The attackers contract calls back to the uniswapV3SwapCallback function. There is validation that the sender is the pool, which is true since an attacker controls the contract address! Now, the smart contract thinks that the caller is a UniswapV3 pool.
  • In the code, there is a safeTransferFrom call, where the attacker controls the from parameter. Since the router has approvals from other users to spend their money, an attacker can use this to send the money to themselves! Additionally, all of the funds of a token can be drained from the router itself, since it has a call to safeTransfer on itself.
  • This is why large approvals are horrible... you must be careful, since a protocol may have a vulnerability that will allow them to drain the funds of its users. Overall, a super interesting and impactful bug in a popular trading platform. In practice, be careful on the external contract calls and privileges you allow.

Beyond the market risk: a logic bug identified in SushiSwap’s KashiPairMediumRiskV1 contract- 1127

BlockSec    Reference →Posted 2 Years Ago
  • In November of 2022, BlockSec sounded the alarms: funds had been successfully drained from SushiSwap. They contacted the Sushi security team to try to remediate the situation.
  • There are functional bugs within smart contracts, like reentrancy and integer overflows. A large amount of the vulnerabilities are accounting bugs that come from messing up the math.
  • The borrow() function has the modifier solvent to check to see if it's above water. If it's not, then the transaction will revert. This is compared against the exchangeRate. Of particular importance is that this variable is mistakenly NOT upgraded in this function call.
  • In liquidate, the updating for the exchangeRate is done in the beginning of the function. If two prices are different between withdrawal and deposit, this can be a major case for exploitation.
  • The exploit steps are pretty straight forward for this. The attacker used a flash loan to amplify the calculation difference. In particular, the exchange rate in the borrow function was 250 * 10^27. On the liquidate function the exchange rate was 328 * 10^27. By borrowing at one rate then liquidating at another, they were able to make a huge profit off of this. I'm guessing that the hacker was sitting on a large price difference for a while in order to exploit this bug.
  • Overall, an interesting yet simple bug. Gotta do better than this!

Reentrancy Vulnerability in Sentiment.xyz- 1126

0xmikko_eth    Reference →Posted 2 Years Ago
  • Balancer had a read only reentrancy vulnerability. This happens when a read only function, outside of the protocol, calling back into the function within a weird state. The reentrancy checks don't work, since it's normally not put onto view functions.
  • The vulnerability comes from the function _joinOrExit. It invokes the function _callPoolBalanceChange before calling _setMinimalSwapInfoPoolBalances. This is important because _setMinimalSwapInfoPoolBalances updates the token balances for balancer. The interesting part is that the protocol will always send back unused Ether to the user part way through execution via sendValue.
  • The transferring of the ETH is in the middle of the execution of _callPoolBalanceChange but before _setMinimalSwapInfoPoolBalances. This means that the Balancer pool tokens have been minted but the vault has NOT been updated at this stage. This puts the contract into a funky state.
  • So, reentrancy to steal all of the money with consecutive calls, right? Well, not so fast. These functions have reentrancy modifiers on them in order to prevent this. The modifiers are only placed on external functions that modify the state typically. This still means a read only reentrancy is possible though. If an attacker sets up a fallback function where the extra ETH gets sent back to, they could make read only calls to the contract using this exploit. Further analysis of this vulnerability can be found on the Balancer Forums.
  • What even uses these read only calls though? Pricing oracles! In the case of Sentiment.xyz, they were using Balancer as an oracle for how much each token costs. The attacker performed the following steps to exploit this:
    1. Take out a flash loan and put assets into Sentiment.xyz as collateral.
    2. Manipulate the Balancer pool.
    3. Setup a reentrant contract to call the exitPool function.
    4. Call Sentiment.xyz with the manipulated pool prices to obtain collateral back at an extremely high cost.
    5. Profit.
  • I'm a little confused on how Sentiment.xyz got exploited on this, since this is an issue with Balancer and Balancer patched the problems. My hypothesis is that Sentiment.xyz was using an older version of the pool that was vulnerable or was not using the information from the contract properly. Overall, super interesting vulnerability!