非常有趣的一道区块连CTF题目的思考————king

区块连CTF题目


前言

这道题目在于处理接受函数的知识,另外我们结合selfdestruct函数进行分析


一、题目以及解答

这是一个非常有意思的问题:
首先下面的solidity代码是本次的题目,我们要求的是
1,拿到king,把king作为我们的地址。
2,让king无法再被下一个人拿到。

contract King {
    address king;
    uint256 public prize;
    address public owner;

    constructor() payable {
        owner = msg.sender;
        king = msg.sender;
        prize = msg.value;
    }

    receive() external payable {
        require(msg.value >= prize || msg.sender == owner);
        payable(king).transfer(msg.value);
        king = msg.sender;
        prize = msg.value;
    }

    function _king() public view returns (address) {
        return king;
    }
}

关于这个问题的第一步,可以很显然使用receive()函数对该合约转发prize数量的代币即可:

contract Hack{
    constructor(address payable target) payable {
        uint256 prize = King(target).prize();
        (bool ok,)=target.call{
            value:prize
        }("");
        require(ok,"call failed");
    }
}

此时,我们还要注意,拿到king之后不能被别人得到king,由于这里面的King合约没有设置receive,fullback。所以我们不用担心对其进行转账。但接下来的一个关键的问题是,如果对方合约使用selfdestruct()函数强行转至合约King会如何?其实,不管有没有触发receive()函数,都无法成功,因为转钱

二、题目分析

1.进攻receive()函数

让我们分解一下这段代码:

(bool ok,):这是一个元组,用来存储函数调用的结果。ok是一个布尔值,表示函数调用是否成功。

target.call:这里target是一个合约地址或者合约实例,call是一个低级操作符,用来调用目标合约的call函数。call函数可以执行任意的字节码,但不会改变状态,也不会创建日志。

{value:prize}:这是传递给call操作符的输入数据,value字段指定了要发送的以太币数量。

(""):这是call操作符的参数,表示要调用的函数标识符。空字符串""通常用于调用没有参数的函数,比如receive()。

prize:这是一个变量,代表要发送的以太币数量。

这段代码的意图可能是尝试通过call操作符来模拟发送以太币到一个合约的receive()函数。但是,实际上,receive()函数是自动被调用的,当以太币发送到合约地址时,不需要手动调用。

solidity

receive() external payable {

}

这里的payable关键字表明这个函数可以接收以太币。当以太币发送到合约地址时,receive()函数将自动执行。如果你需要在接收以太币时执行特定的逻辑,你可以在receive()函数内部添加代码。

2.守护king

在Solidity中,如果你想要让智能合约能够接收以太币(ether),确实需要定义一个可以接受以太币的特殊函数。这些函数包括:

receive():这是一个特殊的函数,用于接收以太币,没有参数,也没有返回值。它不能有任何可见性修饰符,如public或private,因为它是由以太坊虚拟机(EVM)在向合约发送以太币时自动调用的。

fallback():这个函数在合约没有接收到匹配的函数调用时被调用。它也可以接收以太币,并且可以有参数和返回值。从Solidity 0.4.0版本开始,fallback()函数已经被废弃,推荐使用receive()函数。

payable修饰符:如果你想要一个普通的函数能够接收以太币,你可以在函数声明时添加payable修饰符。例如:

solidity

function myFunction() public payable {
// 函数体
}

如果你没有定义receive()、fallback()或者带有payable修饰符的函数,合约将无法接收以太币。这是因为以太坊虚拟机在执行交易时,如果合约没有定义receive()或fallback()函数,它将不知道如何处理接收到的以太币。

然而,如果你的合约需要在接收以太币时执行特定的逻辑,你仍然需要定义一个receive()函数或者带有payable修饰符的函数。例如:

solidity

contract MyContract {
function receive() external payable {
// 接收以太币的逻辑
}
}

或者,如果你想要一个普通的函数能够接收以太币:

solidity

contract MyContract {
function deposit() public payable {
// 存款逻辑
}
}

请注意,自Solidity 0.8.0版本起,receive函数已经被移除,取而代之的是receive和fallback都被废弃,所有的以太接收逻辑都应该使用带有payable修饰符的函数来实现。这意味着,如果你正在使用Solidity 0.8.0或更高版本,你应该确保你的合约中有至少一个带有payable修饰符的函数,以便能够接收以太币。


强行selfdestruct转入为什么拿不到king

当以太币被发送到一个没有定义接收机制的智能合约时,这笔资金将无法被合约所接受。即使在合约中定义了receive函数,如果该函数尝试将收到的资金通过payable(king).transfer(msg.value);的方式转发给另一个地址,但该地址(在本例中为king)没有适当的接收函数,那么这笔资金将不会成功转移。相反,资金将被原路退回给最初的发送者,因为智能合约的receive函数无法处理没有接收机制的转账目标。

在编写智能合约时,开发者需要确保如果合约需要接收以太币,就必须定义相应的接收函数,并且考虑到所有可能的资金流向,确保资金能够按照预期的方式被接收和转移。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值