Post-mortem Analysis of OneRing Incident
On March 21, 2022, according to the SlowMist Intelligences Zone, OneRing Finance was the victim of an exploit, resulting in the loss of over $1.4 million. This is our post mortem analysis of the incident.
One Ring is a Multi-Chain Cross-Stable Yield Optimizer Platform. The incident happened on the fanthom network by using a flash loan to malitupate the price of their Oshare tokens.
Attack transaction: https://ftmscan.com/tx/0xca8dd33850e29cf138c8382e17a19e77d7331b57c7a8451648788bbb26a70145
Root of the problem
OneRing directly uses the reserves in the pair to calculate the price of the OShare token. The attacker was able to trigger a slippage in price when they used the swap operation on the OneRingValut. This caused the pair’s reserves to unexpectedly increase, raising the price of OShare to create artificial collateral.
1.The attacker first created a contract to borrow 80,000,000 USDC from Solidity via a flashloan.
2.Convert USDC into miMatic tokens, the token exchange rate was 1:1.001109876698508218.
3.Call the depositSafe function to deposit 79,999,997 ( $80,079,997.00 ) USDC into the contract.
As you can see here, the depositSafe function calls the _deposit function, and it is called by the _doHardWorkAll function. Within this function, a for loop is used to convert all USDC deposited into other tokens.
The depositSafe function then mints about 41,965,509.691846094312718922 OShare tokens for the attacker. We can see that the price of OShare is the value of 1062758591235248117.
The exchange rate has changed significantly when the attacker used two USDC to exchange for miMATIC tokens again after the swap, as shown in the image below.
4.Looking at the withdrawal function, we can see that it also calls the getSharePrice function from the OShare price calculation.
Let’s follow this path and see where it leads us:
The balanceWithInvested function is called here, and we can see that it is follow up with the investedBalanceInUSD function.
In the end, it’s the getUSDBalanceFromUnderlyingBalance function that ultimately affects the price.
In the getUSDBalanceFromUnderlyingBalance function, we can see that the function uses the two values of the two tokens in the contract, _reserves0 and _reserves1, for calculation. Due to the previous swap, a large amount of USDC remained in the pool, so a significant amount of USDC remained in the pool. If the amount of USDC grows, the _amount will also grow, which causes the current OShare price obtained by the getSharePrice function to also increase.
Looking at the figure below, we can see that the current price of OShare is 1136563707735425848.
Next, we can see from the withdrawal function below that the final withdrawal amount is calculated by _withdraw.
After additional investigation, we discovered that _toWithdrawl is also used to calculate balanceWithInvested, which also causes the price to rise.
The 41,965,509 OShares obtained is then exchanged for 81534750101089 USDC.
5.Finally, they repaid the loan and kept the difference.
According to the analysis by MistTrack, the attacker exchanged most of the stolen funds for ETH and FTM. They then bridge it back to Ethereum before finally depositing over 521 ETH to TornadoCash. The initial 0.1 Eth used to fund the smart contract was also transferred in from TornadoCash.
As of right now, the hacker still has around $45,000 or close to 15 ETH in their ETH address. We will continue to monitor and track any movements from this address.
This incident was caused by instant price calculation of the getUSDBalanceFromUnderlyingBalance function within the MasterChefBaseStrategy contract. The hacker used a flash loan to take advantage of an exploit in the contract that allowed them to manipulate the price of OShare. The SlowMist security team recommends projects to not use instant price calculation in the future to avoid price manipulation.