Ethernaut 20 級拒絕可能不再可解決。為什麼?
我解決了除 20 級拒絕之外的所有級別的Ethernaut遊戲:https ://ethernaut.openzeppelin.com/level/0xcE1BB92eeb71AF5Fec09D38B0c854d55285f6e04
最終還是放棄了,在作者的部落格上查找了解決方法:https ://github.com/sigp/solidity-security-blog#dos-vuln
我使用 Remix 在 Rinkeby 測試網路上部署了以下合約:
pragma solidity ^0.8.7; contract DenialAttack { fallback() external payable { assert(false); } }
該聯繫人的地址是:
0x828F2073947a6d3De9caeEf48c7eCa989436a14B
然後我在 Ethernaut 上創建了一個新的 Denial 實例。接下來我打電話(來自開發工具):
contract.setWithdrawPartner("0x828F2073947a6d3De9caeEf48c7eCa989436a14B")
我確保
partner
已成功將其設置為我的攻擊契約。我送出了我的實例,但它告訴我我還沒有完成關卡。然後我執行(在我的 Brave 瀏覽器的開發工具中):contract.withdraw()
並且交易成功完成。這是它在 Etherscan 上的外觀。
預期的行為是我在送出實例後完成關卡並呼叫
withdraw
失敗並出現氣體不足錯誤。好的,所以這應該足以重現該問題。
這裡的想法是將所有(或大部分?) gas
partner.call.value(amountToSend)("");
傳遞給被呼叫者合約(在我的情況下是傳遞給的執行。因此,我們實現了拒絕服務。DenialAttack``Denial``withdraw()
然而,似乎實際發生的事情是
call
沒有將所有的氣體傳遞給被呼叫者合約,並且留下了足夠的氣體來完成withdraw()
.我還嘗試了其他方法來燃燒所有氣體,例如在循環中多次迭代或執行類似於此處描述的操作。沒有任何效果。
我的假設是,這個解決方案曾經有效,但乙太坊中發生了一些變化,在
call
沒有指定氣體限制的情況下使用氣體時如何通過氣體,並且這個水平不再可解決。也許https://github.com/ethereum/EIPs/issues/114是相關的?我的問題是:我是對的嗎?這個水平還可以解決嗎?如果不是,為什麼?究竟發生了什麼變化?什麼時候?
謝謝!
多虧了賞金,我才看到了這個問題,並且非常好奇為什麼它不可能……我離 20 級並不遠,所以我跳了幾步嘗試一下。
這個問題似乎只存在於solidity > 0.8.5(使用松露測試),我測試了0.6.0到0.8.5(排除)範圍內的幾個版本,行為完全正常。
有了一個簡單的契約:
pragma solidity ^0.8.0; contract TargetCall { fallback() external payable { assert(false); } }
我看到了和你一樣的行為,它是呼叫內部的恢復而不是斷言,所以執行可以繼續……
查看字節碼,我看到了一些奇怪的東西:
0x60806040526000601057600f6012565b5b005b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fdfea264697066735822122022ef0b693779530b61308a11d0037e0882593e0cda55eb30d234198773a38f6464736f6c634300080a0033
斷言位於:
fdfe
但在 OPCODE 視圖中是:
- 0xFD:恢復
- 0xFE:無效(斷言錯誤)
我認為這
assert(false)
是“優化”到一個簡單的revert()
但無論我放入什麼條件(即使是一些不應該優化的..)它都會產生類似的字節碼(也許我錯過了一些東西)。如果真的是優化,為什麼會有 0xFE 無效操作碼呢?我的解決方案是強制使用無效的 OPCODE 而不是
revert()
:因此,修改
fdfe
為fefe
wich 轉換為:
- 0xFE 無效(斷言錯誤)
- 0xFE 無效(斷言錯誤)
部署這個字節碼解決了這個挑戰。
該合約目前部署在 Rinkeby 網路上:0x2C68B51837c38B5f9B1e20acf607efed175B9BC7
這個水平還可以解決嗎?
是的 !
究竟發生了什麼變化?
我想關於 assert() 的solidity >0.8.5 行為發生了變化,但我找不到具體資訊讓我想出一個不那麼骯髒的解決方案。如果有人有適當的解釋/連結來更改摘要,我也會很好奇!
PS:如果我發現任何東西,我將繼續尋找解釋該行為的更改日誌並相應地編輯我的答案。