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