C.R.E.A.M. Finance Post Mortem: AMP Exploit
Dear C.R.E.A.M. community, partners & friends, we firstly want to reassure you that we’ve stopped the exploit. Thank you to everyone who has helped us in handling this exploit.
C.R.E.A.M. Finance remains committed to our community, partners, users and our vision of a trustless, automated & capital efficient financial market.
Our community and users are our priority. We are working with authorities to trace the attacker and have created a plan to restore funds lost.
See below the complete post-mortem of the exploit:
At approximately 12pm on 31st August (UTC +8), C.R.E.A.M. Finance was exploited for 462,079,976 in AMP tokens and 2,804.96 ETH tokens.
There was a main exploit along with a smaller copy-cat. The copy-cat exploit address has withdrawal history from Binance. We are working with Binance to identify the second perpetrator. We will forward all relevant information to law enforcement authorities and prosecute to the fullest extent of the law.
The first transaction of the exploit is here.
The transaction of the copy-cat exploit is here.
This is the first time C.R.E.A.M. Finance has been exploited directly.
How did it happen?
The AMP token contract implements ERC777, which has the _callPostTransferHooks hook that triggers tokensReceived() function that was implemented by the recipient. The reentrancy opportunity related to ERC-777-style transfer hooks allowed the exploiter to nest a second borrow() function inside the token transfer() before the initial borrow() was updated. This was used over 17 transactions.
We are working closely with the Flexa team in understanding the details of the exploit and we are both confident that their contracts worked exactly as designed. To be clear, the exploit was not the result of a bug or issue with AMP’s code.
With the assistance of PeckShield, we have determined that the root cause of the exploit was an error in the way C.R.E.A.M. Finance integrated AMP into our protocol. While unfortunate and disappointing, we take ownership of the error.
What happened after?
We paused the AMP supply and borrow functions. We will re-enable the AMP market when a patch can be safely deployed. We are working with auditors and technical advisors to ensure that we can safely protect against similar attacks in the future.
What about the impacted parties?
While the Schadenfreude is often loud during exploits such as this, no one within the broader DeFi ecosystem wins when a protocol is exploited. We are committed to the industry, our partners and most importantly our users.
We will be replacing the stolen ETH and stolen AMP so that there’s no liquidity issues for users. We will commit to allocating 20% of all protocol fees toward repayment until this debt is fully paid. In the meantime, we will post a CREAM collateral with the Flexa/AMP team to secure this debt.
If you are an impacted user, please submit your details through this google form.
We are committed to making this right for those negatively impacted by the exploiter. We are committed to this industry and building innovative DeFi products. We appreciate the support of our partners and community and will move forward together.
Are there any bounties for the recovery of the funds?
Yes. If the main exploiter is willing to send back the stolen funds, we will honor our normal 10% bug bounty and allow the exploiter to keep 10% of the funds as a bug bounty.
However, if anyone is able to identify and provide information leading to the arrest and prosecution of the exploiter, we will share 50% of all funds returned. We are working with the relevant authorities to pursue all avenues available to us.
C.R.E.A.M. Finance will continue to innovate
We have long term goals, and C.R.E.A.M. Finance will continue to build and innovate. We will learn from this exploit and use it as an opportunity to further strengthen the C.R.E.A.M. protocol. While certainly a setback, we remain driven in our mission to bring capital efficiency decentralized lending markets, fulfilling the financial needs of individuals, institutions and protocols.
Appendix — Diving into the exploit
The vulnerability is a result of listing AMP token on C.R.E.A.M. Finance as one of the collateral assets on Feb 10th 2021. It has not been exploited until now due to the low amount of AMP supplied since crAMP’s inception. Yet 5 days ago an influx of AMP supplied to the crAMP market made it profitable for the attacker to launch an exploit.
Since the execution of this attack vector would result in the protocol holding bad debts against the attacking contract address, each attacking contract could only be used once. The attacker repeated the attack 7 times with deployments of duplicated attacking contracts before 10 revised version of the attack were launched.
# nested borrow https://etherscan.io/tx/0xba468e260588e659d308413bf14c5b466fb13ee6423a96587ad1eee4a81bb802 https://etherscan.io/tx/0x8b4ec34be08527e549b7fc4863f23ca8a9c65824ac62a4327bd803f8cbb83fc2 https://etherscan.io/tx/0xf5a3225fd62ed183af9df48dd9b725727f8975d251165b40972cf54b3198fd70 https://etherscan.io/tx/0x51fd83401f2be2e16fed9c02c7f7df683e1f0c4bcc7cdccf58a1d810824c4992 https://etherscan.io/tx/0x55692ccc8ccf81b155044ed4109155ec7714dfae541fe4c4be23da8b18240248 https://etherscan.io/tx/0x77e2d72bd9d94f20b051f0a629a79e9a316b3ee3c6bf7495236f43bc24d379d8 https://etherscan.io/tx/0x0016745693d68d734faa408b94cdf2d6c95f511b50f47b03909dc599c1dd9ff6# nested borrow, then liquidate and seize https://etherscan.io/tx/0xa9a1b8ea288eb9ad315088f17f7c7386b9989c95b4d13c81b69d5ddad7ffe61e https://etherscan.io/tx/0x1d20ea6596943a38376bef5d3b68d67db275061257c7af5a05334212563c2028 https://etherscan.io/tx/0x1c3464135a0d7b0e770d53afe57b9ff0de70803bbf2e8f7714ea71022447f288 https://etherscan.io/tx/0x6afb3e8e318e221711715c3e2017661ad35ef92e083f7554372ce8ffcaf7da6d https://etherscan.io/tx/0x5452e5ff92a628bbebe732441e2b10cf428d7e0170004665c6b689180642533f https://etherscan.io/tx/0xf0f6a07e0d27b00b972ccdfa500cb53f87ff3e079a3746afb3af6ca84a186043 https://etherscan.io/tx/0x6f3bc128724bdae00f328e300d74103d0adcf988720b0b02f65b6f258af276fa https://etherscan.io/tx/0x487364b6de9e00015c571017c00fd5078c795822a4387af4d95962e50112bc06 https://etherscan.io/tx/0xd7ec3046ec75efbd04b3eea8752a8a6373a92c0dd813d08b655661054d3239c5 https://etherscan.io/tx/0xc90468d698700757f33543039c7cb10d4ca49d57b5417789e7656e73019de674
In the first wave of the attacks, the attacker started with supplying ETH as collateral in crETH market, and then borrowed AMP from crAMP market. Within the execution of transferring AMP to the attacking contract,
_callPostTransferHooks was called, which in turn executed an external contract call that then re-entered crETH market to borrow ETH against the very same collateral that was supposed to be posted for borrowing AMP.
To be more specific, the vulnerability is present within our borrow function when executed in combination with $AMP token’s ERC777 implementation, which calls the tokenReceived hook.
This allowed the attacker to nest a second borrow() function before the initial borrow() completed its execution, the effect of which allowed the attacker to borrow more than normally they would have been allowed.
First wave of the attacks
We use the transaction to illustrate the first wave of the attacks:
- Attacking contract A deposited 100 ETH for 4,834.46565933 crETH
- Attacking contract A borrowed 3,896,000 AMP, and nested borrowed 71 ETH (by now the attacking contract was undercollateralized and liquidatable)
The net effect of this attacking transaction:
C.R.E.A.M. lost 38,960,000 AMP
C.R.E.A.M. gained 100–71 = 29 ETH.
However after the transaction is completed, the attacking contract’s debts had become undercollateralized and flashbots would then repay and seize 8% of the liquidation rewards.
Second wave of the attacks
In the second wave of the attacks, the attacker revised the contracts and liquidated their own undercollateralized debts. We use the transaction below to illustrate.
- Attacking contract A deposited 2,000 ETH for 96,689.19905008 crETH
- Attacking contract A borrowed 77,920,000 AMP, and nested borrowed 1,420 ETH (by now the attacking contract was undercollateralized and liquidatable)
- Attacking contract A sent 38,960,000 AMP to attacking contract B
- Attacking contract B liquidates attacking contract A by repaying 38,960,000 AMP back to crAMP market, and seized 35,529.572 crETH from attacking contract A’s collateral
- Attacking contract B withdraws 734.923 ETH with 35,529.572 crETH.
The net effect of this attacking transaction:
C.R.E.A.M. lost 2,000–1,420–734.923 = 154.923 ETH
C.R.E.A.M. lost 77,920,000–38,960,000 = 38,960,000 AMP
Results and Improvements
Total funds lost: 462,079,976 AMP + 2,804.96 ETH
- After we discovered this exploit, we quickly scanned through all markets on C.R.E.A.M. and Iron Bank to make sure there are no ERC777-like tokens.
- After this incident, we will enhance our protocol security by
- Enhancing the standard operating procedure regarding listing new tokens on C.R.E.A.M. Finance’s platform by applying stringent checks on token contract implementations, including scanning for CALL opcode in test transactions that execute core actions on the protocol, and studying potential impacts of all non-vanilla transfer / transferFrom function implementation.
- Implement a protocol-level non-reentrancy guard that prevents reentrancy within the protocol, as the existing reentrancy guard only protects against reentrancy at a contract level.