本文主要是介绍非常有趣的一道区块连CTF题目的思考————king,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
区块连CTF题目
区块连CTF题目king
- 区块连CTF题目
- 前言
- 一、题目以及解答
- 二、题目分析
- 1.进攻receive()函数
- 2.守护king
- 强行selfdestruct转入为什么拿不到king
前言
这道题目在于处理接受函数的知识,另外我们结合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函数无法处理没有接收机制的转账目标。
在编写智能合约时,开发者需要确保如果合约需要接收以太币,就必须定义相应的接收函数,并且考虑到所有可能的资金流向,确保资金能够按照预期的方式被接收和转移。
这篇关于非常有趣的一道区块连CTF题目的思考————king的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!