Two vulnerabilities in one function — the analysis of Visor Finance exploit
The attackers exploited the vulnerabilities in Visor Finance via a malicious contract, and forged a transaction to deposit 200 million tokens into Visor Finance’s stake mining contract (0xc9f27a50f82571c1c8423a42970613b8dbda14ef), thereby acquiring 195,249,950 vVISR stake certificates. The 8,812,958 VISR were then withdrawn from the stake mining contract using the stake certificates.
The exploit process:
1. Deploy the attack contract 0x10c509aa9ab291c76c45414e7cdbd375e1d5ace8；
2. Call the deposit function of the stake mining contract through the attack contract, and specify the amount of tokens deposited (visrDeposit) to be 100 million , from the attack contract to the attacker’s address 0x8efab89b497b887cdaa2fb08ff71e4b3827774b2;
3. In line 53, the amount of stake certificates shares is calculated as 97,624,975 vVISR.
4. Since from is an attack contract, the deposit function executes the if branch from line 56–59 and calls the specified function of the attack contract;
(1) In line 57, call the owner function of the attack contract. As long as the attack contract sets the return value to the contract address, it can pass the check in line 57;
(2) In line 58, call the delegatedTransferERC20 function of the attack contract. Here reentrancy is executed, and the deposit function of the stake mining contract is called again, with the parameters unchanged, so the stake mining contract executes the process of step 3 again;
(3) When the second execution reaches line 58, the attack contract will not perform any operations;
5. Due to reentrancy, the stake mining contract issues two staking certificates of 97,624,975 vVISR to the hacker, and the total number of staking certificates is 195,249,950 vVISR.
The hacker swaps 195,249,950 vVISR to 8,812,958 VISR through a withdrawal transaction (0x6eabef1bf310a1361041d97897c192581cd9870f6a39040cd24d7de2335b4546). At that time, there is 9,219,200 VISR in the stake mining contract.
7. Through UniswapV2, the hacker exchanges 5,200,000 VISR for WETH. This operation almost empties the ETH liquidity of the ETH/VISR trading pair in UniswapV2, and then the obtained 133 ETH is sent to Tornado.
This attack exploits two vulnerabilities in the stake mining contract RewardsHypervisor of Visor Finance:
1. The call does not restrict the target contract, and the hacker can call any contract and take over the execution process of the stake mining contract. This is the primary vulnerability, causing the root cause of this exploit.
2. The function is not protected against reentrancy attacks. This is the minor vulnerability, leading to a miscalculation of the amount of staking credentials, which is not the main exploit of this attack, but can also be exploited to launch a separate attack.
In response to these two issues, it is suggested for the project party:
1. When conducting external contract calls, it is recommended to add a whitelist to prohibit arbitrary contract calls, especially the key contract calls that can control the contract execution process;
2. The function should be designed to prevent reentrancy, it is recommended to use the ReentrancyGuard contract of openzeppelin.