20210308 DODO Hacked Event TLDR
4 min readMar 10, 2021
DODO 在這次 Hack 事件中共損失了大約快 200 萬 USD。想說去瞭解了一下這次攻擊事件,是否有可以借鑑的地方。紀錄一下這次的攻擊手法,當成是筆記。
這次是利用 DODO 自己寫的 flashLoan() 和 init() 所產生的漏洞來進行攻擊。使用 flashLoan() 借出 wCRES 和 USDT,然後用攻擊者所建立的 FDO 和 FUSDT 歸還。主要的 FLOW 如下:
- 攻擊者呼叫 Attack Contract 的某個 function (這裡簡稱 Attack())
- Attack()中先把 FDO 從 Attacker 帳號轉到 DVM (DODO Pool) 底下
- Attack()中再把 FUSDT 從 Attacker 帳號轉到 DVM 底下
- Attack() 接著呼叫 DVM 的 flashLoan(),參數中 assetTo 指向 Attack Contract,目的是希望在 flashLoan 可以去呼叫 Attack Contract 的 DVMFlashLoanCall()。
- flashLoan() 先把 _BASE_TOKEN_ Transfer 到 assetTo(Attack Contract)。此時 _BASE_TOKEN_ 還是 wCRES
- flashLoan() 再把 _QUOTE_TOKEN_ Transfer 到 assetTo(Attack Contract)。此時 _QUOTE_TOKEN_ 還是 USDT
- flashLoan() 接著呼叫 Attack Contract 的 DVMFlashLoanCall()
- DVMFlashLoanCall() 中會去呼叫 DVM 的 init()。在 init() 中可以重新設定 _BASE_TOKEN_ 和 _QUOTE_TOKEN_,呼叫目的就是把 _BASE_TOKEN_ 設定成 FDO 和 _QUOTE_TOKEN_ 設定成 FUSDT。 init() 執行完畢後 DVMFlashLoanCall() 也就執行完畢了。
- 回到 flashLoan() 接著就是去檢查有沒有把借出去的 asset 還回來。使用的方法是呼叫 _BASE_TOKEN_ 的 balanceOf(address(this)) 來看目前 DVM 的 balance 有多少。但現在因為 _BASE_TOKEN_ 已經被修改成 FDO,而 FDO 在前面就已經 transfer 到 DVM 底下,所以通過檢查。
- 接下來檢查 _QUOTE_TOKEN balance。此時_QUOTE_TOKEN_ 也變成了 FUSDT。如上述一樣通過檢查。
- 最後flashLoan()呼叫結束。借出去的 wCRES 和 USDT 仍留在 Attack Contract 中,完成攻擊。
這次攻擊發生最主要的原因是在於 init() 沒有做權限管理和允許多次呼叫,導致攻擊者可以藉由更改 BASE Token 和 QOUTE Token 來完成這次攻擊。更細節的部分可以去看 Reference 中 慢霧的分析,裡面講得還蠻詳細。