該死的脆弱 DeFi 是一個 DeFi 智能合約攻擊挑戰系列。內容包括了閃電貸攻擊、借貸池、鏈上預言機等。在開始之前你需要具備 Solidity 以及 JavaScript 相關的技能。針對每一題你需要做的就是保證該題的單元測試能夠通過。
題目鏈接:https://www.damnvulnerabledefi.xyz/challenges/3.html
題目描述:
有一個借貸池合約提供 DVT 代幣的閃電貸功能,其中有 100 萬個代幣。而你一個都沒有,你需要做的就是在一筆交易中取光該借貸池的代幣。
同樣首先看下借貸池合約的源碼
TrusterLenderPool.sol
通過智能合約可以看出,想通過 flashLoan 方法拿出所有 token 是沒有辦法的。因為合約最後會校驗餘額,不滿足的話會回滾交易。
換個思路,如果能夠調用 token 合約的 transferFrom 方法,即
將借貸池合約中的 token 轉到 attacker 地址,就能達到目的了。
但要使 transForm 成功執行,就需要 token 合約的授權。在 ERC20 標準中有方法
即同意 spender 花費調用者賬戶 amount 數量的 token。
在本題中,就可以在借貸池合約中調用類似下面的方法:
即調用者(借貸池合約)同意 attacker 地址花費其 amount 數量的 token。
然而,借貸池合約中並沒有可以調用的地方,但我們注意到 flashLoan 方法內部有行代碼 target.functionCall(data);,其內部核心就是進行底層調用 target.call(data)
智能合約之間的交互都是通過 calldata, 形如:
0x6057361d000000000000000000000000000000000000000000000000000000000000000a
前 4 個字節(6057361d)是函數 selector(函數的標識符),其餘是傳遞給函數的輸入參數。
在合約內部通過構造 calldata,可以通過 abi.encodeWithSignature ("函數名 (... 參數類型)", ...params)
所以在本題 target 是 token 合約的地址,data 是 approve 方法,在 js 中通過下面的方法構造 data
之後就可以調用 flashLoan 方法並傳入對應的參數。成功執行後就意味著借貸池合約中的餘額可以隨意供 attacker 操作。代碼如下
運行 yarn truster, 測試通過!
然而題目要求進行一筆交易,顯然我們的代碼是不滿足要求的,所以可以通過智能合約執行一筆交易
TrusterAttack.sol
之後在測試用例中部署合約,執行 attack 方法
最後運行 yarn truster, 測試通過!