DEV Community

Cover image for Technical Analysis of VETH Contract Attack Event
infinite_cycle
infinite_cycle

Posted on

Technical Analysis of VETH Contract Attack Event

Infinite's technical analysis of the VETH contract attack event, this attack transaction is as follows:
0xdd1120a90ed4112b634266d6a244b93ca86785317bc75f0e170ab0cd97c65224 ,Through the transaction overview, we can see that the attacker used 0.9 ETH to convert to VETH in Uniswap, and then used VETH to operate in the Vether contract, and finally stole a huge amount of VETH.

Alt Text

Now use the OKO contract browser to analyze the specific details of the attack (the figure below only shows a part) https://oko.palkeo.com/0xdd1120a90ed4112b634266d6a244b93ca86785317bc75f0e170ab0cd97c65224/

Alt Text

By analyzing the specific details of the transaction, it can be found that the attacker first created a contract 0x47Ed415006C6F8052Fff05fe983f31D6D24B8fDB and called the changeExcluded(unknown37217349) function and transferFrom function in the Vether contract through this contract.

Next, analyze the specific code of these two functions:
function transferFrom(address from, address to, uint value) public override returns (bool success) {
if(!mapAddress_Excluded[msg.sender]){
require(value <= _allowances[from][msg.sender], 'Must not send more than allowance');
_allowances[from][msg.sender] -= value;
}
_transfer(from, to, value);
return true;
}

It can be seen that in the transferFrom function, mapAddress_Excluded[msg.sender] is first judged if, the specific logic is that when mapAddress_Excluded[msg.sender] is false, the authorization limit to the attacker's contract will be checked, and then the _transfer function will be called Make a transfer. And this logic obviously doesn't work. The attacker's contract does not have any authorization quota. Therefore, mapAddress_Excluded[msg.sender] can only be true, and then directly call the _transfer function to transfer.

Next, analyze in detail how to set mapAddress_Excluded[msg.sender] to true:

Alt Text

By looking at the contract, you can find:
When the contract is initialized, only the mapAddress_Excluded of address (this) and burnAddress is set to true, then it is certain that there are other logics to set mapAddress_Excluded. Through analysis of the Vether contract, it can be found that the changeExcluded function can realize the setting of mapAddress_Excluded.

function changeExcluded(address excluded) external {

if(!mapAddress_Excluded[excluded]){
_transfer(msg.sender, address(this), mapEra_Emission[1]/16);

mapAddress_Excluded[excluded] = true;

excludedArray.push(excluded); excludedCount +=1;

totalFees += mapEra_Emission[1]/16;

mapAddress_BlockChange[excluded] = block.number;

} else {
_transfer(msg.sender, address(this), mapEra_Emission[1]/32);

mapAddress_Excluded[excluded] = false;

totalFees += mapEra_Emission[1]/32;

mapAddress_BlockChange[excluded] = block.number;

}

}
By analyzing the changeExcluded function, it can be found that its visibility is external, so the attacker contract can directly call the changeExcluded function. At this time, the attacker contract’s mapAddress_Excluded is false, so it will enter the logic of if.

Next, make a specific analysis of the code in the if logic:

After the if logic is executed, a handling fee needs to be paid first, specifically in line 3 in the code block above. Where does this handling fee come from? The answer is that the attacker initially transferred 0.9 ETH into the contract.

Alt Text

As you can see in the figure, 0.9 ETH is converted into about 138 VETH.

By calculating mapEra_Emission[1]/16 in the code, we can get the fee that the attacker needs to pay: we read the mapEra_Emission in the contract to know that mapEra_Emission[1] is 2048.

Alt Text

At this time, the calculation fee for mapEra_Emission[1]/16 is 2048/16 = 128 VETH, and the attacker exchanged about 138 VETH, which is enough to pay the fee, so you can use the 4th line in the code block above The mapAddress_Excluded of the attacker's contract is set to true.

The complete attack process is as follows:

  1. Create an attack contract and exchange 0.9 ETH into approximately 138 VETH through Uniswap (the currency exchange here is for subsequent payment of handling fees)
  2. Call the changeExcluded function in the Vether contract and use the 138 VETH previously exchanged in Uniswap to pay a handling fee of 128 VETH, and then set mapAddress_Excluded to true
  3. Call the transferFrom function and use mapAddress_Excluded as true to directly perform the transfer operation
  4. Take money and leave

Discussion (0)