透過交易概覽可以看到攻擊者在 Uniswap 中使用 0.9 ETH 兌換成 VETH,然後使用 VETH 在 Vether 合約中進行操作,最終盜走鉅額的 VETH。
現在使用 OKO 合約瀏覽器對具體的攻擊細節進行分析(下圖只展示一部分)https://oko.palkeo.com/0xdd1120a90ed4112b634266d6a244b93ca86785317bc75f0e170ab0cd97c65224/
透過分析交易內具體的細節可以發現:攻擊者先建立了一個合約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);
returntrue;
}
可以看到在 transferFrom 函式中,先對 mapAddress_Excluded[msg.sender] 進行了 if 判斷,具體邏輯是mapAddress_Excluded[msg.sender]為 false 時,將會檢查對攻擊者合約的授權額度,然後呼叫_transfer函式進行轉賬。而這個邏輯顯然走不通,攻擊者合約是沒有任何授權額度的。因此mapAddress_Excluded[msg.sender]只能為 true ,然後直接呼叫_transfer函式進行轉賬。
接下來具體分析該如何將mapAddress_Excluded[msg.sender]設定為 true:
透過檢視合約可以發現:
合約在初始化時只將address(this)和burnAddress的mapAddress_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。
圖中可以看到,透過 0.9 ETH 兌換成約 138 VETH。
透過計算程式碼中的mapEra_Emission[1]/16我們可以得到攻擊者需要支付的手續費:我們讀取合約中的 mapEra_Emission可以知道 mapEra_Emission[1]為 2048。
此時計算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函式。