Started at 00:47:19 AM +UTC, Nov-17–2020, the Origin protocol was attacked by exploiting its flawed handling of the mint logic in its
VaultCore smart contract. The hack results in a loss of approximately $7.7M (11,809 ETH and 2,249,821 DAI) from the affected vault. Here we elaborate the technical details in this blog post.
This incident was due to a bug in the protocol without (1) validating the transferred-in assets and (2) enforcing reentrancy protection on the mint logic. The exploitation leads to a greatly inflated totalSupply of the rebasing token, i.e., OUSD. The attacker then makes use of the inflation to redeem and drain about $7.7M of assets from the OUSD vault.
The Hack Walk-through
We started the analysis from the transaction behind the hack: 0xe1c7…8401. This hack is initialized from a malicious ERC20-like contract (located at 0x47c3). This malicious contract implements a hook that will be invoked whenever the transferFrom() (function signature: 0x23b872dd) is being called.
With this preparation, the bad actor launches the attack by firstly applying 70K ETH flashloans from dYdX, then swapping 17.5K ETH to 7.85M USDT (on Uniswap) and other 52.5K ETH to 20.99M DAI (also on Uniswap). After the preparation, the malicious actor starts minting OUSD twice. The first minting operation is via
mint() with 7.5M USDT while the second minting is via
mintMultiple() with 20.5M DAI. However, the
mintMultiple() routine does not properly validate the transferred-in assets.
As shown in the figure above, if the prepared malicious ERC20 assets are transferred in, the
FakeToken.transferFrom() function is called, invoking the hook function that then re-enters the
VaultCore contract again.
VaultCore.mint() dramatically inflates the
totalSupply of OUSD by at least 20.5M (from the
mintMultiple()). The above code snippet shows that the
rebase() function derives the
newTotalSupply by calculating the assets in the vault and strategies. Because of the previously transferred-in 20.5m DAI, the
newTotalSupply is greatly increased and the following
oUSD.changeSupply() applies it to the OUSD token contract. This inflates OUSD by 20.5M. When the execution returns to
VaultCore.mintMultiple(), those 20.5M DAI corresponding OUSD would be normally minted again, which inflates OUSD by another 20.5M.
Due to the rebasing nature of OUSD, every OUSD owner accordingly gets an inflated balance. After that, the bad actor immediately redeems her share of 33.269M OUSD for profit. In total, the actor performs three valid mints: 7.5M USDT (via
mint()), 20.5M DAI (via
mintMultiple()) and 2K USDT (via reentered
mint() due to the reentrancy), leading to 28M + 2K OUSD. However, because of the inflated totalBalance, the actor can walk away with 33.269M OUSD. The detailed attack sequence is as follows:
- dYdX flashloan 70K ETH
- swap 17.5K ETH to 7.85M USDT on Uniswap
- swap 52.5K ETH to 20.99M DAI on Uniswap
- VaultCore.mint(7.5M USDT) -> 7.5M OUSD
- VaultCore.mintMultiple(20.5M DAI, 0 fakeToken) -> 20.5M OUSD (hijacked)
* VaultCore.mint(2K USDT) -> 2K OUSD
* inflate OUSD totalSupply by 20.5M
- swap 300K OUSD to 158.55K USDT on Uniswap
- swap 1M OUSD to 520.756K USDT on Uniswap
- VaultCore.totalValue() -> 35M
- VaultCore.redeem (33.269M OUSD) and gets following assets:
* 19.5M DAI
* 9.4M USDT
* 3.9M USDC
- swap 10.45M USDT to 22.898K ETH on Uniswap
- swap 3.9M USDC to 8.305K ETH on Uniswap
- swap 19.0M DAI to 47.976K ETH on Uniswap
- payback dYdX flashloan 70K ETH
Once again, the classic reentrancy attack allows the hacker to walk away with
11,809 ETH + 2,249,821 DAI, which is around $7.7M loss. As a common mitigation mechanism to block such reentrancy attacks, the so-called Checks-Effects-Interactions design pattern always helps. In addition, whitelist the supported asset to avoid control flow hijacking and apply reentrancy guard if necessary.
PeckShield Inc. is an industry leading blockchain security company with the goal of elevating the security, privacy, and usability of the current blockchain ecosystem. For any business or media inquiries (including the need for smart contract auditing), please contact us at telegram, twitter, or email.