Fairyproof’s Analysis of Attack on Visor Finance
Visor Finance’s RewardsHypervisor contract deployed on Ethereum was attacked on Dec-21–2021, 02:18:15 PM +UTC. The attacker exploited 150…
Visor Finance’s RewardsHypervisor contract deployed on Ethereum was attacked on Dec-21–2021, 02:18:15 PM +UTC. The attacker exploited 150 ETHs from this attack.
Here is the basic information:
The address of the contract that had a vulnerability was:
0xC9f27A50f82571C1C8423A42970613b8dBDA14ef
The attacker’s address was:
0x8Efab89b497b887CDaA2FB08ff71e4b3827774B2
The attack transaction’s hash value was:
0x69272d8c84d67d1da2f6425b339192fa472898dce936f24818fda415c1c1ff3f
The whole process:
The attacker exploited a vulnerability in the contract and initiated two mint transactions. With each mint transaction, the attacker minted 97.62 million vVISRs.
The attacker then used 195 million vVISRs to withdraw 8.81 million VISORs, converted the VISORs to ETHs via Uniswap V2, sent 152 ETHs to Tornado.Cash.
Then, done with the attack.
What was the vulnerability? Let’s check the deposit function of the RewardsHypervisor contract.
From the above code, we can see that the “from” parameter was a sender. However, the implementation didn’t check the right of “from”, this vulnerability was used to launch the attack.
Let’s check the following code:
Here “from” was used as a contract address by IVisor. Therefore, an attacker could organize an attack as follows:
- Creates a malicious contract, implements a delegatedTransferERC20 function in the contract, and assigns the address of this contract to “from”.
- Sets return value of the malicious contract’s owner() to the contract’s address such that “require(IVisor(from).owner() == msg.sender)” would hold true.
- Assigns an arbitrary value to “visrDeposit” defined in the deposit function and the vvisr.mint(to, shares) function would subsequently send an arbitrary number of vVISRs to an address specified by the attacker.
- After the attacker gets the vVISRs he/she could call the withdraw function to withdraw VISORs.
Two big lessons we can learn from this attack:
1. Don’t pass an external contract’s address as a parameter to a function.
2. When an external contract is called, make sure to check the status both before the call and after the call with great care.