可能對 ERC-777 智能合約和 UniswapV2Pair 進行重入攻擊,導致 104 ETH 流動性流失
我的ERC-777 智能合約(Schnoodle,符號 SNOOD)昨天遭到攻擊,導致UniswapV2Pair 代幣的全部流動性被耗盡(104 ETH)。攻擊是通過攻擊者合約進行的,該合約在創建過程中與流動性代幣和我的智能合約進行了一系列互動(此處為 txn )。
通過點擊內部交易列表上的👁圖示,我可以看到以下輸入/輸出數據:
Input: 0x022c0d9f000000000000000000000000000000000000000000000005a3f13b802bf25f800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000180ea08644b123d8a3f0eccf2a3b45a5820755380000000000000000000000000000000000000000000000000000000000000080 Input: 0x0902f1ac Output: 0x000000000000000000000000000000000000000000000005a3f13b802bf25f8100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000062ad7934 Input: 0xa9059cbb0000000000000000000000000f6b0960d2569f505126341085ed7f0342b67dae0000000000000000000000000000000000000000686558904b462764f122c4e1 Input: 0xfff6cae9 Input: 0x23b872dd0000000000000000000000000f6b0960d2569f505126341085ed7f0342b67dae000000000000000000000000273521f6582076a5fc54da9af9bfca5435ffe9ec0000000000000000000000000000000000000000686558904b462764f122c4e1 Input: 0x70a082310000000000000000000000000f6b0960d2569f505126341085ed7f0342b67dae Output: 0x0000000000000000000000000000000000000000686558904b462764f122c4e2
我已經破譯了這個,它轉化為這些函式呼叫:
- 1. UniswapV2Pair.swap(amount0Out, amount1Out, to)
- amount0Out: 104047009087796436864 或 104.xxx…4 ETH
- 金額1出:0
- 至:0x180ea08644b123d8a3f0eccf2a3b45a582075538(消息發送者)
- 2. UniswapV2Pair.getReserves()
- 輸出
- Reserve0:104047009087796436865 或 104.xxx…5 ETH
- Reserve1:1 或 1E-18 SNOOD
- blockTimestampLast: 1655535924
- 3. Schnoodle.transfer(收件人,金額)
- 收件人:0xf6b0960d2569f505126341085ed7f0342b67dae(流動性代幣)
- 金額:32308960759206669952686933217 或 32.3b SNOOD
- 4. UniswapV2Pair.sync
- 5. Schnoodle.transferFrom(持有人、收款人、金額)
- 持有人:0xf6b0960d2569f505126341085ed7f0342b67dae(流動性代幣)
- 收件人:0x273521f6582076a5fc54da9af9bfca5435ffe9ec(攻擊者合約)
- 金額:32308960759206669952686933217 或 32.3b SNOOD
- 6. Schnoodle.balanceOf(賬戶)
- 賬戶:0xf6b0960d2569f505126341085ed7f0342b67dae(流動性代幣)
- 輸出
- 32308960759206669952686933217 或 32.3b SNOOD
它們都發生在同一秒,所以它們在 Etherscan 上沒有以正確的順序列出。但很明顯,#2 (
getReserves
) 的輸出被用作amount0Out
#1 (swap
) 的參數,儘管減去了 1 這很有趣。並且#6 (balanceOf
) 的輸出用作amount
#3 和#5 (transfer
andtransferFrom
) 的參數。因此,攻擊者合約似乎獲得了流動性代幣的 SNOOD 餘額,以及流動性代幣儲備中的 ETH 數量,然後同時進行以下操作:
transferFrom
將所有 SNOOD 從流動性代幣轉移到攻擊者合約transfer
將所有 SNOOD 從消息發送者轉移到流動性代幣swap
將 SNOOD 換成 104 ETH 給消息發送者消息發送者在任何時候都不會收到任何 SNOOD。然而,它能夠將 SNOOD 轉移到流動性代幣。將 SNOOD 轉移到攻擊者合約的呼叫
transferFrom
表明這裡可能發生了重入攻擊,但我無法進一步弄清楚這一點。我使用這個反編譯器和攻擊者合約地址 (0x273521F6582076a5FC54da9Af9bFca5435ffE9eC)反編譯了字節碼,但這超出了我的舒適區。這可能是對 SNOOD 或 UniswapV2Pair 合約的重入攻擊嗎?我做了一些研究,發現以前使用 Uniswap v1 的 ERC-777 令牌存在可重入漏洞。請參閱此處指向GitHub 上的漏洞利用範例的連結,以及表明該漏洞已在 Uniswap v2 中修補的Uniswap 白皮書。
我想知道的是,這次攻擊是如何發生的,漏洞在哪裡?我該如何防範呢?如果這是 SNOOD 程式碼中的一個漏洞,那麼我該如何修復它?如果它是與 ERC-777 代幣相關的 UniswapV2Pair 程式碼中的一個漏洞,這就是 SNOOD,那麼我想我將不得不將我的合約更改為 ERC-20,或者使用 UniswapV3Pair,或者完全使用其他 DEX。
還有 1500 美元的賞金(可協商)可用於解決此漏洞,可以通過我們的 Dework 平台在此處查看。
在我看來,你的錯誤就在這裡。通常這種計算是使用定點算術或使用
reflection * totalSupply / reflectedSupply
計算來完成的。在事務 0x9a6227ef97d7ce75732645bd604ef128bb5dfbc1bfbe0966ad1cd2870d45a20e 的情況下,在呼叫 期間_spendAllowance
,_getStandardAmount
呼叫返回0
,即使轉移的金額很大。很難說這段程式碼的意圖是什麼,但結果是反映的金額沒有轉換為代幣金額,而是簡單地設置為零,因為_getReflectRate
返回的值很大。因此,即使 UniswapV2 交易對沒有設置限額,攻擊者也可以將交易對transferFrom
的總餘額添加到他們的攻擊合約中。隨後,攻擊者呼叫sync
迫使該貨幣對將其新的、大幅減少的餘額作為儲備金。之後,只需將被盜的 SNOOD 代幣換成對中剩餘的 WETH 即可。