Fairyproof’s Comprehensive Analysis of the Attack on Bent Finance
In our previous post, we gave a brief analysis of the attack on Bent Finance. Technically more details and thoughts can be drawn and good…
In our previous post, we gave a brief analysis of the attack on Bent Finance. Technically more details and thoughts can be drawn and good lessons can be learned from this incident.
The attacked contract in this incident was Bent Finance’s BentBasePool contract deployed at 0x270B6AFF561284ef380cDD6d8B036f4981049A86 on Ethereum.
The BentBasePool contract used the proxy mechanism i.e. it had a proxy contract deployed at:
0x270B6AFF561284ef380cDD6d8B036f4981049A86 and an implementation contract deployed at: 0x21D54b4418f010C18d3165Fb00cBD6dE05db308a
The implementation contract had the following code section:
Based on this implementation, when “balanceOf[msg.sender] >= _amount”, a withdrawal operation would succeed. After we went deeper into the implementation of “balanceOf” we could find out that the value of “balanceOf” would be changed only when “deposit” were to happen.
After reviewing the above two attack/withdrawal operations, the input value of both operations was greater than 0. Therefore, it was unlikely this incident was caused by this implementation.
Would it be possible that something went wrong during a contract upgrade?
Following this clue, we discovered two suspicious transactions both of which were initiated by Bent Finance: Deployer whose address was:0x8E0b94A789C26F21b141F99c888b84a8cd21A5Dd. And both transactions were calling an “updateVersion” function in the BentBasePool contract.
The first happened at 01:09:27 PM on Nov-30–2021 +UTC and the hash value was:
0xf711641ea9814d78780c8a51ad734ad44d58baf3f97256a3f5ec3200a29eadc7
The second happened at 01:12:31 PM on Nov-30–2021 +UTC and the hash value was:
0xf8dff6712395e9cabfc58ae65a68e750a556d0bd5d0985af6108df3be03b92e7
An “udpateVersion” function is a commonly used function to update a version number after a contract upgrade happens. This function in general is called only once. However, both of the above two function calls took an input parameter value of 2 and they seemed to be repeated transactions.
This was suspicious. Therefore, we went further and checked what both calls did.
We found out that the first “updateVersion” call modified two states:
The first state was at slot 42 and the value was 2.
The second state was at:
0xcbea793df26de3cd6c734b5ee573e01005ceb67e5cbd7b7479894cded0f1519b
And the value was 1e26 which pretty much seemed to be a token’s quantity.
We discovered more details about the first “updateVersion” call:
We found out that the contract that was executed was not the one that got verified on etherscan, but the one that was not open-source and was deployed at 0xb45d6c0897721bb6ffa9451c2c80f99b24b573b9. And this non-open-sourced contract was deployed by Bent Finance: Deployer as well.
Obviously, the attacker obtained the private key of the Bent Finance: Deployer. He/she deployed a malicious contract and called the “udpateVersion” function in the malicious contract to change the balance of his/her address. And after that the attacker upgraded the malicious contract with a normal implementation contract to cover up.
Again, the root cause of this attack is the admin’s private key was compromised. Thus, keeping a project admin’s private key safe needs greater attention than ever in a project’s daily operation and maintenance. Moreover, a team who still has an admin that possesses full access control needs to transfer the access control to a multi-sig wallet or DAO as soon as possible.