VETH 合约被黑分析【通过】

VETH 合约被黑分析

背景

2020年7月1日,VETH 合约遭遇黑客攻击。慢雾安全团队在收到情报后对本次攻击事件进行了全面的分析,下面为大家就这次攻击事件展开具体的技术分析。

攻击细节

本次攻击交易 0xdd1120a90ed4112b634266d6a244b93ca86785317bc75f0e170ab0cd97c65224

通过交易概览可以看到攻击者在 Uniswap 中使用 0.9 ETH 兑换成 VETH,然后使用 VETH 在 Vether 合约中进行操作,最终盗走巨额的 VETH

1

现在使用 OKO 合约浏览器对具体的攻击细节进行分析(下图只展示一部分) https://oko.palkeo.com/0xdd1120a90ed4112b634266d6a244b93ca86785317bc75f0e170ab0cd97c65224/

2

通过分析交易内具体的细节可以发现: 攻击者先创建了一个合约 0x47Ed415006C6F8052Fff05fe983f31D6D24B8fDB 通过此合约对 Vether 合约中的 changeExcluded(unknown37217349) 函数与 transferFrom 函数进行了调用。

接下来对这两个函数的具体代码进行分析:

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;
}

可以看到在 transferFrom 函数中,先对 mapAddress_Excluded[msg.sender] 进行了 if 判断,具体逻辑是 mapAddress_Excluded[msg.sender] 为 false 时,将会检查对攻击者合约的授权额度,然后调用 _transfer 函数进行转账。而这个逻辑显然是走不通,攻击者合约是没有任何授权额度的。因此 mapAddress_Excluded[msg.sender] 只能为 true 然后直接调用 _transfer 函数进行转账。

接下来具体分析该如何将 mapAddress_Excluded[msg.sender] 设置为 true,通过查看合约可以发现:

3

合约在初始化时只将 address(this)burnAddressmapAddress_Excluded 置为 true,那么可以肯定还有其他逻辑可以设置 mapAddress_Excluded ,通过分析 Vether 合约可以发现 changeExcluded 函数可以实现对 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;
}
}

通过分析 changeExcluded 函数可以发现其可见性为 external ,因此攻击者合约可以直接调用 changeExcluded 函数,此时攻击者合约的 mapAddress_Excluded 为 false,所以会进入 if 的逻辑中,接下来对 if 逻辑内的代码进行具体分析:

在进行 if 逻辑后需要先支付手续费,具体为上方代码块中的第 3 行,那这个手续费是从哪里来呢?答案就是攻击者最初转入合约中的 0.9 ETH。

4

通过计算代码中的 mapEra_Emission[1]/16 我们可以得到攻击者需要支付的手续费: 我们读取合约中的 mapEra_Emission 可以知道 mapEra_Emission[1] 为 2048

5

此时计算 mapEra_Emission[1]/16 可得手续费为 2048/16 = 128 VETH,而攻击者兑换了约138 VETH 是足够用来支付手续费的,因此便可以通过上方代码块中的第 4 行将攻击者合约的 mapAddress_Excluded 置为 true

完整的攻击流程如下:

  1. 创建攻击合约,通过 Uniswap 将 0.9 ETH 兑换成约138 VETH(此处换币为了后续支付手续费)
  2. 调用 Vether 合约中的 changeExcluded 函数并利用先前在 Uniswap 兑换的约 138 VETH 支付 128 VETH 的手续费,然后将 mapAddress_Excluded 置为 true
  3. 调用 transferFrom 函数,利用 mapAddress_Excluded 为 true,直接进行转账操作
  4. 拿钱走人
黑客地址:

0xfa2700e67065bc364136b5e7f57112083cb2a0cd

攻击交易:

0xdd1120a90ed4112b634266d6a244b93ca86785317bc75f0e170ab0cd97c65224

VETH 合约地址

0x75572098dc462f976127f59f8c97dfa291f81d8b

修复建议

此次攻击主要利用 Vether 合约中 changeExcluded 函数的可见性为 external 且未有权限限制,用户可以直接进行外部调用为攻击创造了必要的条件。因此应做好对 changeExcluded 函数的权限或可见性的限制,从而避免任意用户可以直接外部调用 changeExcluded 函数。

  • 通过
  • 未通过

0 投票者