On June 12, 2023, Sturdy Finance was hacked on Ethereum Mainnet. The hackers were able to exploit a vulnerability in the protocol’s borrowing pool, which allowed them to steal around $800K worth of ETH.
Sturdy Finance is a decentralized finance (DeFi) protocol that allows users to borrow and lend assets without paying interest. Instead of charging borrowers interest, Sturdy stakes their collateral and passes the yield to lenders. This model changes the relationship between borrowers and lenders to make Sturdy the first positive-sum lending protocol.
To learn more about the Project, check out the official documentation.
Attacker Address : 0x1e8419e724d51e87f78e222d935fbbdeb631a08b
Attack Transaction : 0xeb87ebc0a18aca7d2a9ffcabf61aa69c9e8d3c6efade9e2303f8857717fb9eb7
Attack Contract : 0x0b09c86260c12294e3b967f0d523b4b2bcdfbeab
Sturdy Exploited Contract : 0x46beA99d977F269399fB3A4637077bB35F075516
The root cause of the exploit was a read-only reentrancy present in Balancer's PoolBalances.sol smart contract. The vulnerable function was _joinOrExit(...) which was marked protected with non-Reentrant modifier but was still vulnerable. Since there was an external call involved in the function, this caused the exploit to happen.


1. Attacker took a flashLoan of 50,000
wstETHand 60,000WETHfrom AAVE.

2. Attacker minted 1023
steCRVtokens usingCurve steCRVPool by depositing 1100ETH
![--> add_liquidity[1100.0 ETH]](https://img.paragraph.com/cdn-cgi/image/format=auto,width=3840,quality=85/https://storage.googleapis.com/papyrus_images/af5b2e8601f59c8f12dc6c0e8fd58124717ac2d450b505899443abfb5b2e2205.png)
3. 109,517
B-stETH-STABLEtokens were also minted by depositing 50,000wstETHand 57,000WETHin Balancer Pool.

4. Attacker borrowed 513 WETH from Sturdy Lending Pool using two tokens as collateral. (1000
steCRV& 233B-stETH-STABLE)
9

5. Increase the price of the
B-stETH-STABLE, so thatsteCRVcan be set as non collateral. Since now the price ofB-stETH-STABLEis increased,PoolBalances.sol/exitPool()is called.

This function calls
PoolBalances._joinOrExit()function which is vulnerable to read only vulnerability and does an external call indirectly.

further call-graph is as follows :
PoolBalances._joinOrExit() --> PoolBalances._callPoolBalanceChange() --> AssetTransferHandler._sendAsset() --> Address.sendValue()sendValue() is the function using the solidity native call.

The call made by the function then used by fallback of the malacious contract to call Sturdy contract
LendingPool.setUserUseReserveAsCollateral()to set thesteCRVas non-collateral as after the price manipulation, the protocol considers that only 233B-stETH-STABLEare able to cover the debt. This function then calls the read functionSturdyOracle.getAssetPrice()which gives false output due to the reentrancy present in the function we discussed above The false output is due to the fact that the value comes directly from the BalancerPoolTokens.getPoolTokens()contract.
7. Withdraw the 1000
steCRVtokens from pool.

8. Now, since the price of
B-stETH-STABLEhas come to normal, liquidate the position in Sturdy Pool with 236WETHto get back 233B-stETH-STABLE.

9. Give the FlashLoan back.
Steps 3-8 are repeated 5 times and are contained in in the exploiter contract as a single function maybe named as "yoink()" This function is called 5 times and contains the logic for steps 3-8.
Immediately after the exploit the exploiter sent the funds to the tornado cash. So, the current owner of the funds is unknown.


On the same day of exploit (June 12, 2023) : Sturdy Finance acknowledged the exploit and tweeted:

They also published a report related to the exploit on June 14, 2023.

Proper implementation of the function doing external call should be done.
Tests covering each and every possibility should be written.
There should be consistency while viewing the state of the blockchain through any source.
Functions viewing the state of blockchain should utilize more than one source.

