Conic uses the Curve protocol for trying to earn rewards. It has a concept of
omnipools where the same underlying asset is distributed among multiple Curve pools. Currently, I'm not seeing the benefit of this from reading their docs.
First,
Immunefi spotted an exploit that occurred in the function
_airdrop(). The code takes in three parameters:
from,
to and
amount.
These parameters have calculations done on them to determine the airdrop address. This includes an XOR with the block number, from address and to address. Eventually, this is used for the address of a balance call with the amount provided by amount in the function.
It should be noted, there is no check on who the airdrop address is besides the manipulations that occur. The bug is that an attacker can set this to be an arbitrary user. Most importantly, they can set the address to be the address of the pairContract used for a pool. By setting this to 1 and calling sync() the pools price is very messed up, leading to an opportunity to make money.
The second vulnerability exists in the integration between Curve and Conic. The reentrancy protection on the Omnipool was only turned in in the case of ETH pools being used. This was checked by calling checking CurveHandlerV3() to see if the pool had interacted with ETH. The check was made by seeing if it was 0xeee...ee, which is a standard for ETH address. However, in reality, this used the WETH address.
Since the wrong address was being validated against, the reentrancy protection was broken. There is a
known bug in Curve pools, which is read-only reentrancy. By manipulating the Curve pool then calling Omnipool contract for ETH allowed for an attacker to trick the pool into minting more cncETH LP tokens than they should have been rewarded. It's weird that this wasn't found in testing...
The protocol had reentrancy protections in place. On top of this, they also had a mechanism to ensure that imbalanced Curve pools could not be interacted with. However, the threshold was not tight enough, which allowed the attacker to slowly drain the pool. I thought this was a great idea that just did not work because of the ability to preform this attack several times.
Overall, two really interesting bugs! Manipulation of a pool by setting the amount of a particular contract to 1. Then, a known read-only reentrancy vulnerability exploit in Curve by finding a flaw in the prevention of this exact attack. What's the takeaway? Test your code to ensure it works!