【漏洞分析】Reflection Token 反射型代幣攻擊事件通用分析思路

2023-12-06 18:00:49

在本篇文章中,我將通過一個攻擊事件引出 Reflection Token 攻擊事件的一個通用分析思路。
關於 Reflection Token 的其他案例分析,可以參考BEVO代幣攻擊事件分析及復現一文。

TomInu 攻擊事件

TomInu Token 是一個反射型代幣 reflection token,於2023-01-26遭到駭客攻擊,攻擊者獲利35577美元。

TomInu(被攻擊合約): 0x2d0e64b6bf13660a4c0de42a0b88144a7c10991f
攻擊交易: https://phalcon.blocksec.com/tx/eth/0x6200bf5c43c214caa1177c3676293442059b4f39eb5dbae6cfd4e6ad16305668

攻擊過程較為簡單,攻擊者通過幾個常規操作就完成獲利。

  1. 攻擊者借出閃電貸
  2. 用 WETH swap 出 1465904852700232013011 TINU
  3. deliver 1465904852700232013011 TINU
  4. skim 得到 1733770910894426471783 TINU(在這一步已經完成了獲利)
  5. 把 TINU swap 為 WETH
  6. 歸還閃電貸

本次攻擊事件通過推文告警並且進行了分析,但是很可惜分析的結論略顯含糊的。紅框標註的部分並不是攻擊者獲利的真正原因。(為什麼不是真的)

推文:https://twitter.com/QuintenDes/status/1618730379447508998

並且,目前在在網路上搜尋到的所有關於 reflection token 攻擊事件的成因分析中提到:「由於攻擊者 deliver 了一筆 token ,導致了 pair 中的 token 升值,從而能夠 skim 出更多的 token 進行獲利」。這類分析大多是理所當然地下結論,沒有通過實際的計算推導,妄下結論誤導讀者。(為什麼這麼說)

攻擊過程很簡單,先 deliver 然後 skim,就能夠獲利了。根據這個攻擊過程的特徵,我們直接找 rToken增發程式碼,定位漏洞點。(為什麼可以這麼做)

以上的幾個為什麼都將會在後面「為什麼」這一章節進行解釋,讀者可以先帶著疑問進行閱讀。

漏洞分析

_transferStandard 函數中可以看出,TomInu 代幣在進行轉賬 rAmount 時需要收取 teamfee 兩種手續費,並將扣除了手續費後的 rTransferAmount 轉給收款人。

其中 team 手續費 rteam 留存在本合約中,fee 手續費 rfee 則是直接銷燬。

此時他們的數量關係應該為:rTransferAmount = rAmount - rteam - rfee

問題出現在 _getRValues 函數中,該函數在計算 rTransferAmount 的過程中忽略了 rteam 引數,計算 rTransferAmount = rAmount - rfee 得到的結果比實際結果要大,造成了 rToken 的增發。也就是說,因為這個計算問題,市場上實際流通的 rAmount 總和是要大於 rTotal 的值的。

代幣合約在執行 _transfer() 函數的時候,會將本合約的代幣 swap 成 ETH,這個操作使得增發的代幣一直累計在 pair 中。

為什麼

在這個章節中,會對前面的暴言暴論進行解釋

  1. 為什麼推文中的關於漏洞成因的結論是含糊的不準確的。
  2. 什麼說關於 reflection token 攻擊事件的成因分析中提到「由於攻擊者 deliver 了一筆 token ,導致了 pair 中的 token 升值,從而能夠 skim 出更多的 token 進行獲利」的分析結論都是錯誤的。
  3. 為什麼看到攻擊過程先 deliver 然後 skim 就完成獲利之後,我得出的結論是直接找 rToken增發程式碼定位漏洞點。

首先我將舉幾個例子來模擬整個 deliver-skim 的過程,為了使得這個例子儘可能的簡單,這個過程中將不考慮任何手續費的收取。

場景1:

只有 attacker 和 pair 持有所有的 token

rTotal 1000, tTotal 100, rate 10

pair: rAmount 500, tAmount 50
attacker: rAmount 500, tAmount 50

attacker deliver 500 rAmount

rTotal 500, tTotal 100, rate 5

pair: rAmount 500, tAmount 100
attacker: rAmount 0, tAmount 0

此時,pair 的 tAmount 從 50 變成了 100。接下來 attacker 將呼叫 skim 來獲利了是不是?

attacker calls pair.skim()

rTotal 500, tTotal 100, rate 5

pair: rAmount 250, tAmount 50
attacker: rAmount 250, tAmount 50

attacker 如願以償獲利了嗎?沒有,attacker 和 pair 又回到了最初的 50 tAmount,並不能通過這個操作來進行獲利。

場景2:

attacker, pair 以及一些其他使用者共同持有所有的 token

rTotal 1000, tTotal 100, rate 10

pair: rAmount 250, tAmount 25
attacker: rAmount 500, tAmount 50
others: rAmount 250, tAmount 25

attacker deliver 500 rAmount

rTotal 500, tTotal 100, rate 5

pair: rAmount 250, tAmount 50
attacker: rAmount 0, tAmount 0
others: rAmount 250, tAmount 50

attacker calls pair.skim()

rTotal 500, tTotal 100, rate 5

pair: rAmount 125, tAmount 25
attacker: rAmount 125, tAmount 25
others: rAmount 250, tAmount 50

pair 回到了原始的 25 tAmount,而 attacker 由原來的 50 虧損到了 25 tAmount。堅定持有的 others 由 25 上漲到了 50 tAmount。

通過上面的兩個例子,我們可以得出結論,只有當 attacker 和 pair 所持有的代幣份額合計 100% 的情況下,deliver-skim 的操作 attacker 才不會虧損。而兩者份額不足 100% 的情況下,deliver-skim 的操作反而會導致 attacker 遭受損失。也就是說 attacker 通過 deliver-skim 的操作無論怎麼樣都是不賺的,最好的情況是 attacker 和 pair 所持有的代幣份額合計 100% 的情況下才不至於虧損。

那麼…有沒有更好的情況呢?好到…兩者持有的代幣份額合計起來…超過100%

比如,發生了代幣增發?

場景3:

由於程式碼存在 rToken 相關的計算錯誤,導致代幣增發的發生,具體表現為 rToken 的實際流通量大於 rTotal 的數量。

rTotal 1000, tTotal 100, rate 10

pair: rAmount 400, tAmount 40
attacker: rAmount 800, tAmount 80
others: rAmount 400, tAmount 40

sum_rAmount = 1600 > rTotal = 1000
pair.rAmount + attacker.rAmount = 1200 > rTotal = 1000

attacker deliver 800 rAmount

rTotal 200, tTotal 100, rate 2

pair: rAmount 400, tAmount 200
attacker: rAmount 0, tAmount 0
others: rAmount 400, tAmount 200

attacker calls pair.skim()

rTotal 200, tTotal 100, rate 2

pair: rAmount 80, tAmount 40
attacker: rAmount 320, tAmount 160
others: rAmount 400, tAmount 200

至此,attacker 從原來的 80 tAmount,通過 deliver-skim 操作獲利達到 160 tAmount。

通過這個場景,也就可以解釋為什麼看到攻擊過程中通過 deliver-skim 操作獲利時,首先想到的就是去找程式碼中使得 rAmount 增發的計算操作。因為只有 rAmount 發生了增發,pair 和 attacker 的份額大於 100%,且增發部分需要留存在 pair 合約中,才能夠滿足通過 deliver-skim 操作進行獲利的基礎條件。

後記

在 TomInu 攻擊事件發生的4個月後,存在相同漏洞的 ADU token 再次被攻擊。
ADU token attack tx:https://explorer.phalcon.xyz/tx/bsc/0xc6f6b70e9e35770b699da9b60244d461d02db66859df42319c3207d76931423c

為什麼會寫這篇文章,因為當我想對這些攻擊事件進行學習與分析的時候,我檢視了網路上的分析文章,他們給出的漏洞成因含糊不清毫無根據。我讀了很多篇分析文章,說辭都是大同小異地糊弄。還沒分析清楚就胡亂指點,最終被忽悠的就是真心想研究清楚的人。走了不少彎路,把彎路總結成這篇文章,感謝你的閱讀。