当前位置: 首页 > news >正文

Ethernaut Level 5: Token - 整数下溢攻击详解

🎯 Ethernaut Level 5: Token - 整数下溢攻击详解

关卡链接: Ethernaut Level 5 - Token
攻击类型: 整数下溢攻击
难度: ⭐⭐⭐☆☆

📋 挑战目标

  1. 获得大量代币 - 从初始的 20 个代币增加到大量代币
  2. 理解整数溢出 - 掌握算术运算的安全问题

请添加图片描述

🔍 漏洞分析

合约源码分析

pragma solidity ^0.6.0;contract Token {mapping(address => uint) balances;uint public totalSupply;constructor(uint _initialSupply) public {balances[msg.sender] = totalSupply = _initialSupply;}function transfer(address _to, uint _value) public returns (bool) {// 🚨 漏洞:没有检查下溢出require(balances[msg.sender] - _value >= 0);balances[msg.sender] -= _value;balances[_to] += _value;return true;}function balanceOf(address _owner) public view returns (uint balance) {return balances[_owner];}
}

漏洞识别

整数下溢问题

  1. 无符号整数特性 - uint 类型不能为负数
  2. 下溢行为 - 当 0 - 1 时,结果变成 2^256 - 1
  3. 检查失效 - require(balances[msg.sender] - _value >= 0) 总是为真

攻击原理

// 假设用户余额为 20
uint balance = 20;
uint transferAmount = 21;// 下溢计算:20 - 21 = 2^256 - 1 (巨大的正数)
uint result = balance - transferAmount;
// result = 115792089237316195423570985008687907853269984665640564039457584007913129639935// require 检查:巨大的正数 >= 0,总是为真
require(result >= 0); // ✅ 通过检查

💻 Foundry 实现

攻击测试代码

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;import "forge-std/Test.sol";// 复制原始有漏洞的合约 (使用 0.6.0 版本行为)
contract VulnerableToken {mapping(address => uint) public balances;uint public totalSupply;constructor(uint _initialSupply) {balances[msg.sender] = totalSupply = _initialSupply;}function transfer(address _to, uint _value) public returns (bool) {// 故意使用不安全的算术运算unchecked {require(balances[msg.sender] - _value >= 0);balances[msg.sender] -= _value;balances[_to] += _value;}return true;}function balanceOf(address _owner) public view returns (uint balance) {return balances[_owner];}
}contract TokenTest is Test {VulnerableToken public token;address public attacker = makeAddr("attacker");address public victim = makeAddr("victim");function setUp() public {// 部署代币合约,初始供应量 1000token = new VulnerableToken(1000);// 给攻击者 20 个代币token.transfer(attacker, 20);}function testTokenUnderflowExploit() public {console.log("=== 攻击前状态 ===");console.log("攻击者余额:", token.balanceOf(attacker));console.log("受害者余额:", token.balanceOf(victim));vm.startPrank(attacker);// 🎯 关键攻击:转账超过余额的代币uint256 transferAmount = 21; // 大于 20 的余额token.transfer(victim, transferAmount);vm.stopPrank();console.log("=== 攻击后状态 ===");console.log("攻击者余额:", token.balanceOf(attacker));console.log("受害者余额:", token.balanceOf(victim));// 验证下溢攻击成功assertGt(token.balanceOf(attacker), 1000000); // 攻击者获得巨额代币assertEq(token.balanceOf(victim), transferAmount);}function testUnderflowMath() public view {// 演示下溢计算uint256 balance = 20;uint256 transferAmount = 21;console.log("=== 下溢计算演示 ===");console.log("原始余额:", balance);console.log("转账金额:", transferAmount);unchecked {uint256 result = balance - transferAmount;console.log("下溢结果:", result);console.log("最大 uint256:", type(uint256).max);console.log("是否相等:", result == type(uint256).max);}}function testSafeVersion() public {// 演示安全版本VulnerableToken safeToken = new VulnerableToken(1000);safeToken.transfer(attacker, 20);vm.startPrank(attacker);// 在 Solidity 0.8.0+ 中,这会 revertvm.expectRevert(); // 期望交易失败safeToken.transfer(victim, 21); // 这在新版本中会失败vm.stopPrank();}
}

运行测试

forge test --match-contract TokenTest -vvv

🛡️ 防御措施

1. 使用 Solidity 0.8.0+

pragma solidity ^0.8.0;contract SafeToken {mapping(address => uint256) public balances;function transfer(address _to, uint256 _value) public returns (bool) {// Solidity 0.8.0+ 自动检查溢出balances[msg.sender] -= _value; // 自动 revert 如果下溢balances[_to] += _value;return true;}
}

2. 使用 SafeMath 库 (旧版本)

pragma solidity ^0.6.0;import "@openzeppelin/contracts/math/SafeMath.sol";contract SafeTokenV6 {using SafeMath for uint256;mapping(address => uint256) public balances;function transfer(address _to, uint256 _value) public returns (bool) {balances[msg.sender] = balances[msg.sender].sub(_value); // 安全减法balances[_to] = balances[_to].add(_value); // 安全加法return true;}
}

3. 显式检查

contract ExplicitCheckToken {mapping(address => uint256) public balances;function transfer(address _to, uint256 _value) public returns (bool) {require(balances[msg.sender] >= _value, "Insufficient balance");balances[msg.sender] -= _value;balances[_to] += _value;return true;}
}

📚 核心知识点

整数溢出类型

类型描述示例
上溢超过最大值type(uint256).max + 1 = 0
下溢低于最小值0 - 1 = type(uint256).max

Solidity 版本对比

// Solidity 0.7.x 及以下
function unsafeAdd(uint a, uint b) public pure returns (uint) {return a + b; // 可能溢出,无自动检查
}// Solidity 0.8.0+
function safeAdd(uint a, uint b) public pure returns (uint) {return a + b; // 自动检查溢出,溢出时 revert
}// 显式不安全操作 (0.8.0+)
function explicitUnsafe(uint a, uint b) public pure returns (uint) {unchecked {return a + b; // 显式跳过溢出检查}
}

安全数学运算

// ✅ 安全的余额检查
function safeTransfer(address _to, uint256 _value) public {require(balances[msg.sender] >= _value, "Insufficient balance");balances[msg.sender] -= _value;balances[_to] += _value;
}// ✅ 使用 SafeMath (旧版本)
function safeTransferLegacy(address _to, uint256 _value) public {balances[msg.sender] = balances[msg.sender].sub(_value);balances[_to] = balances[_to].add(_value);
}

🏛️ 历史案例

著名的整数溢出攻击

  1. PoWHCoin (2018)

    • 攻击者利用整数溢出获得巨额代币
    • 导致项目完全崩溃
  2. BeautyChain (BEC) (2018)

    • BatchOverFlow 漏洞
    • 造成代币价值归零
  3. SMT Token (2018)

    • 类似的批量转账溢出漏洞
    • 交易所暂停交易

🎯 总结

Token 关卡揭示了早期 Solidity 的重要安全隐患:

  • 整数溢出的严重后果 - 可以完全破坏代币经济学
  • 版本升级的重要性 - Solidity 0.8.0+ 提供内置保护
  • SafeMath 的历史价值 - 在旧版本中提供安全保护
  • 显式检查的必要性 - 总是验证关键假设

这个看似简单的算术错误,实际上影响了无数 DeFi 项目的安全性设计。


🔗 相关链接

  • 系列目录: Ethernaut Foundry Solutions
  • OpenZeppelin SafeMath
  • GitHub 项目
http://www.dtcms.com/a/395361.html

相关文章:

  • 正向代理 vs 反向代理
  • SNN论文阅读——spikformer
  • 【论文阅读】Robix:机器人交互、推理与规划的统一模型
  • 【论文阅读】AutoDrive-R^2: 激励自动驾驶VLA模型的推理与自我反思能力
  • [UnrealEngine] 虚幻引擎UE5下载及安装(UE4、UE5)
  • AI原生安全架构的提出与落地路径:来自南凌科技的实践观察
  • ELK企业级日志分析系统
  • EasyDSS一站式点播方案如何提升企业视频门户的用户体验?
  • MARSIM仿真平台部署安装及FUEL部署-Ubuntu20.04
  • 16-留言板案例
  • ubuntu22.04配置ip
  • VMware ubuntu开机后黑屏
  • ubuntu运行项目:音乐解锁-unlock-music-master,安装依赖报错问题
  • vim操作
  • 【AI编程】四大规范驱动开发Spec工具助力AI编程从“即兴创作“向“工程化“转变
  • IDEA中print(“)输出中文乱码
  • 一站式报修软件:破解高校、物业等机构报修难题的高效方案
  • mobaxterm解决无法在vim中复制
  • 深度解析 CUDA-QX 0.4 加速 QEC 与求解器库
  • 深度解析通义DeepResearch:阿里开源的300亿参数深度研究智能体
  • 关于OpenCV无法进行h264视频转码的问题
  • KingbaseES 四维操控:索引、视图、用户与事务的实战密码
  • 大模型强化学习-PPO应用
  • 惠普打印机连接电脑完整指南:方法与故障排除
  • 轻松加载外部Jar,实现SpringBoot功能灵活扩展
  • MCGS COM口MODBUS转发
  • Elasticsearch面试精讲 Day 22:机器学习与异常检测
  • 仓颉语言中的 `Some` 类型解析
  • spring-boot--redis调整token过期时间
  • 树形表格示例