【CTF】paradigm-CTF babysandbox
前言:找Ver👴想復現下qwb final的區塊鏈。Ver👴給我發了這個比賽下面的一道題,發現這個比賽里面有很多高質量的智能合約題。從這里開始寫一些不錯的題目。
babysandbox
看到題目名字就知道了題目考點: 沙盒
給出合約
BabySandbox.sol
Setup.sol
pragma solidity 0.7.0;import "./BabySandbox.sol";contract Setup {BabySandbox public sandbox;constructor() {sandbox = new BabySandbox();}function isSolved() public view returns (bool) {uint size;assembly {size := extcodesize(sload(sandbox.slot))}return size == 0;} }Setup.py中的isSolved()進行了是否成功解決challenge的check.
這里我不是很熟悉.slot這種用法,所以自己隨便部署了一個進行試驗。
應該就是取了題目合約的整個字節碼。要求把合約變成一個賬戶。或者直接讓合約自毀應該也可以。
然后我們分析下Sandbox中的各種方法
這里說的是如果caller也就是調用者是自己的話。那么就會直接調用。
delegatecall,也就是如果這里能設置出一些東西那么就可以成功改變合約狀態了。
第一行檢測了gas是否夠用,然后calldatacopy
從調用數據的位置 f 的拷貝 s 個字節到內存的位置 t
之后他就會利用staticall繼續進行檢測,但是我們可以發現,他從這里進入的staticcall 是進入了 自己的合約。 相當于對自己進行了一次重入。重入之后的調用方,就是msg.sender了。也就是可以正常進入delegatecall了。
但是他利用的是staticcall在外層,所以還是不能改變合約的原有狀態。
但是通過之后 他利用call進行了第二次的合約使用。也就是這里的delegatecall就可以完成任何想做的事情了。也就是我們想要的合約銷毀。
那么到這里 整體的思路就很清晰了:
首先進入run(address target)中,delegatecall無法進入,進入staticcall
staticall中進入delegatecall 完成一次調用。
call中進入delegatecall完成一次調用。
需要一個函數在staticcall中不改變合約狀態,在call中改變。
delegatecall的target只需要直接selfdestruct就可以了。
那么現在就考慮怎么給出一個辦法,使得兩次調用所執行的方法不同?
嘗試思路:
也就是利用類似上述的偽代碼。這里是不可做的。
所以這個方法也很難進行bypass。
考慮使用call外部變量進行改變,這種是可行的一個辦法。我們可以通過在外部合約設置一個方法 我們利用內部的call方法進行請求,如果能正確返回狀態值則代表當前狀態就是call了。
因為外部Call方法的狀態即使revert()他也會只返回一個狀態碼0,并不會直接阻斷整個交易的正常運行。
fallback()external payable{bool success;(success,)=address(0x3c725134d74D5c45B4E4ABd2e5e2a109b5541288).call("");if(!success){return;}else{selfdestruct(address(0));}}
這樣就成功繞過了沙箱
這個是從github的官方wp中學到的 ,感覺應該和3的意思相同? 用等同于python的語法try catch 這樣可以直接避免直接revert()
contract Setup {BabySandbox public sandbox;constructor() {sandbox = new BabySandbox();}function isSolved() public view returns (bool) {uint size;assembly {size := extcodesize(sload(sandbox.slot))}return size == 0;} }學到了很多opcode以及call staticcall delegatecall的知識。
有自學網絡安全的朋友可以關注私信我哦!!!
總結
以上是生活随笔為你收集整理的【CTF】paradigm-CTF babysandbox的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Parallels高危漏洞的奇葩修复指南
- 下一篇: 反击CobaltStrike