Skip to content
On this page

丢失的Ether何处寻?CTF挑战“Recovery”带你踏上区块链寻宝之旅

在区块链的世界里,智能合约就像一台精密的机器,一旦部署就难以修改。而今天,我们将一同探索一个名为“Recovery”的CTF(Capture The Flag)挑战,它将带领我们深入理解智能合约的运作机制,并学会如何从一个“丢失”的合约中“捞出”宝贵的Ether。

故事的开端:简单的代币工厂与遗失的地址

想象一下,一位开发者创建了一个名为 Recovery 的代币工厂合约。这个工厂非常简单,任何人都可以调用 generateToken 函数,轻松创建一个新的代币。在部署了第一个代币合约 SimpleToken 后,开发者为了获得更多的代币,向这个 SimpleToken 合约发送了 0.001 Ether

然而,不幸的是,开发者随后 丢失了 SimpleToken 合约的地址。这0.001 Ether就如同沉入了大海,再也无法直接访问。我们的任务,就是成为一名区块链侦探,找回(或者说转移) 这个隐藏在遗失合约地址中的0.001 Ether。

深入源码:揭秘RecoverySimpleToken

让我们来仔细看看这两份合约的源码:

Recovery.sol (代币工厂)

solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Recovery {
    // generate tokens
    function generateToken(string memory _name, uint256 _initialSupply) public {
        new SimpleToken(_name, msg.sender, _initialSupply);
    }
}

Recovery 合约非常直观,它只提供了一个 generateToken 函数,用于部署新的 SimpleToken 合约。SimpleToken 的创建者(_creator)和初始供应量(_initialSupply)会在部署时被记录。

SimpleToken.sol (代币合约)

solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract SimpleToken {
    string public name;
    mapping(address => uint256) public balances;

    // constructor
    constructor(string memory _name, address _creator, uint256 _initialSupply) {
        name = _name;
        balances[_creator] = _initialSupply;
    }

    // collect ether in return for tokens
    receive() external payable {
        balances[msg.sender] = msg.value * 10;
    }

    // allow transfers of tokens
    function transfer(address _to, uint256 _amount) public {
        require(balances[msg.sender] >= _amount);
        balances[msg.sender] = balances[msg.sender] - _amount;
        balances[_to] = _amount;
    }

    // clean up after ourselves
    function destroy(address payable _to) public {
        selfdestruct(_to);
    }
}

SimpleToken 合约则更具看点:

  • constructor: 记录代币名称、创建者以及创建者拥有的初始代币数量。
  • receive() external payable: 这是关键!当有人向 SimpleToken 合约发送Ether时,这个函数会被触发。它会将接收到的Ether 乘以10,并将其作为代币数量奖励给发送者。开发者就是通过向合约发送0.001 Ether,获得了0.01个代币。
  • transfer: 允许代币的转移。
  • destroy(address payable _to): 这个函数允许任何人调用,并将合约本身以及合约中剩余的 Ether 全部转移到指定的地址 _to

寻宝的线索:selfdestruct 的魔力

通过阅读 SimpleToken 合约,我们看到了一个非常强大的函数:destroy。它的作用是调用 selfdestruct(_to)selfdestruct 函数是Solidity中一个非常特殊的操作码,它会销毁当前合约,并将合约中剩余的Ether全部发送到指定的地址。

这意味着,只要我们能够找到那个“丢失”的 SimpleToken 合约地址,并且拥有调用 destroy 函数的权限,我们就能将合约中存储的0.001 Ether转移出来。

难题:如何找到“丢失”的合约地址?

CTF 挑战的核心往往在于找到那个隐藏的细节。在这个挑战中,最棘手的问题就是 如何找到 SimpleToken 合约的地址

Solidity 合约的地址并非完全随机生成,而是与部署者的地址以及一次性随机数(nonce)有关。通过一种称为 “地址预测” 的技术,我们可以根据部署者的地址和部署的顺序来推算出合约的地址。

解决方案:AddressRecovery.sol 与地址预测

题目提供的答案中,AddressRecovery.sol 合约正是解决了这个问题:

solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract AddressRecovery {
    constructor() {}
    function cAddrRecover(address _creator) external pure returns (address) {
        return address(
            uint160(
                uint256(
                    keccak256(
                        abi.encodePacked(
                            bytes1(0xd6),
                            bytes1(0x94),
                            _creator,
                            bytes1(0x01) // This is the nonce, indicating the first contract deployed by the creator
                        )))));
    }
}

这个 AddressRecovery 合约中的 cAddrRecover 函数,正是利用了Solidity的地址生成算法。它接收 _creator(代币工厂的部署者)的地址,然后通过 keccak256 哈希算法,结合特定的字节(0xd6, 0x94, _creator, 0x01),计算出一个预期的合约地址。这里的 0x01 可以理解为是部署者创建的第一个合约的 nonce。

通关之路:一步步找回Ether

  1. 部署 AddressRecovery 合约: 首先,你需要部署 AddressRecovery 合约。
  2. 获取 Recovery 合约的部署者地址: 在实际的CTF环境中,你需要知道部署 Recovery 合约的那个账户地址(在测试代码中通常称为 CREATOR)。
  3. 预测 SimpleToken 合约地址: 调用 AddressRecovery 合约的 cAddrRecover 函数,传入 Recovery 合约的部署者地址,即可预测出 SimpleToken 合约的地址。
  4. 获取 SimpleToken 合约实例: 使用预测出的地址,以及 SimpleToken 合约的ABI(Application Binary Interface),创建一个 SimpleToken 合约的实例。
  5. 调用 destroy 函数: 调用 SimpleToken 合约实例的 destroy 函数,并将你的地址作为参数传入,这样 SimpleToken 合约中剩余的0.001 Ether就会被转移到你的地址。

总结

“Recovery”挑战巧妙地结合了Solidity的 receive 函数、 selfdestruct 操作码以及合约地址的生成机制。通过理解这些核心概念,并运用地址预测的技巧,我们就能成功地从一个“丢失”的合约中“捞出”宝贵的Ether,完成挑战。

这不仅仅是一场游戏,更是一次宝贵的学习经历,它让我们更深刻地理解了区块链智能合约的运作原理,以及在实际应用中可能遇到的安全风险和技术挑战。希望这次寻宝之旅,能让你对区块链技术有更深的认识!

Built with AiAda