這一關的目標是偷走合約的所有資產。
這題目標是偷走合約裡的所有資產,所以先找到可以轉帳的 function
19 行的 withdraw(uint256 _amount)
中有使用 msg.sender.call
來轉帳:
提款函示 withdraw(uint256 _amount)
的流程:
balances[msg.sender]
)是否大於轉出的金額(_amount
)那我們可以動手腳的地方,就是在第 2 步把錢轉給我們的時候。因為 Solidity 在轉錢到別的合約時,會觸發接受方合約的 receive()
或是 payable fallbakc()
,所以我們只要在 receive()
中再次呼叫題目的 withdraw(uint256 _amount)
就可以產生新的提款請求,且上一筆也還沒扣除金額;造成不斷提款的效果。攻擊合約如下(會先朝關卡轉進一些錢以通過餘額判斷):
這種攻擊的思路有點像是 Recursive Functions 的概念,讓合約不斷重複呼叫導致流程沒有照著預期進行,這種攻擊手法在智能合約中被稱做 Reentrancy attacks,關於這個攻擊手法更多詳細可以參考: