Ethernaut题库闯关连载的第17篇题解。
今天这篇是Ethernaut 题库闯关连载的第17篇,难度等级: 有点难。
欢迎大家订阅专栏:Ethernaut 题库闯关,坚持挑战下去,你的 Solidity代码能力肯定大有提高。
合约创建者构建了一个非常简单的代币工厂合约。任何人都可以轻松地创建新的代币。部署第一个代币合约后,创建者发送0.001
来获得更多代币。但是创建者犯了一个错误,他们忘记保存创建代币合约地址。
本次的挑战的目标是检索出代币工厂创建的第一个token的合约地址,并掉用destroy清空已发送给它的0.001
ETH,则此关完成。
合约源码如下:
/ SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
import '@openzeppelin/contracts/math/SafeMath.sol';
contract Recovery {
//generate tokens
function generateToken(string memory _name, uint256 _initialSupply) public {
new SimpleToken(_name, msg.sender, _initialSupply);
}
}
contract SimpleToken {
using SafeMath for uint256;
// public variables
string public name;
mapping (address => uint) public balances;
// constructor
constructor(string memory _name, address _creator, uint256 _initialSupply) public {
name = _name;
balances[_creator] = _initialSupply;
}
// collect ether in return for tokens
receive() external payable {
balances[msg.sender] = msg.value.mul(10);
}
// allow transfers of tokens
function transfer(address _to, uint _amount) public {
require(balances[msg.sender] >= _amount);
balances[msg.sender] = balances[msg.sender].sub(_amount);
balances[_to] = _amount;
}
// clean up after ourselves
function destroy(address payable _to) public {
selfdestruct(_to);
}
}
在查看解题思路之前,可以先自己想一想,自己会怎么做?
这一关的关键是了解合约的地址是如何生成的。
合约本身很容易理解,但解决方案的难点并不在于如何利用它。让我们回顾一下代码并理解我们需要做什么。
Recovery
合约是一个允许msg.sender
创建代币的工厂合约。发送者通过每次调用generateToken
来部署一个新的SimpleToken
合约。
一旦我们找到检索已部署的SimpleToken
地址的方法,我们就可以调用destroy
函数,该函数将执行一个selfdestruct(_to)
,将所有合约余额发送到_to
地址。
SimpleToken
合约至少有两个不同的问题:
transfer
函数总是重置_to
余额// allow transfers of tokens
function transfer(address _to, uint256 _amount) public {
require(balances[msg.sender] >= _amount);
balances[msg.sender] = balances[msg.sender].sub(_amount);
balances[_to] = _amount;
}
这个函数msg.sender
的余额被正确更新,_to
的余额将被重置为amount
。恶意行为者只需调用transfer(受害地址,0)
就可以将受害者余额完全重置为0。
destroy
函数没有权限限制// clean up after ourselves
function destroy(address payable _to) public {
selfdestruct(_to);
}
合约的destroy
功能执行了自毁操作码。该操作码销毁合约...
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!