智能合约中的重入攻击

智能合约是一种旨在以信息化方式传播、验证或执行合同的计算机协议。智能合约允许在没有第三方的情况下进行可信交易,这些交易可追踪且不可逆转。智能合约概念于1995年由NickSzabo首次提出。智能合约的目的是提供优于传统合约的安全方法,并减少与合约相关的其他交易成本。

漏洞概述:

因为以太坊智能合约中是可以调用外部的合约代码,外部合约可能是攻击者构造的恶意不安全的合约代码,当在转账操作时执行代码,迫使攻击的合约回调包括自身的代码,和绕过源代码的限制发生了重入攻击事件。

发生重入攻击漏洞有两个原因:

1.?调用了外面不安全的合约代码

美SEC就Ripple案件中发布Hinman邮件:6月13日消息,据FOX Business记者Eleanor Terrett发推称,美国证券交易委员会(SEC)就Ripple案件中发布Hinman邮件,这些文件显示了美国贸易和市场部对Hinman 2018年演讲草稿的评论。Ripple反对美国SEC简易判决动议的简报中未经编辑的部分显示,SEC高级官员表示,Hinman演讲细节越少越好。当时的贸易和市场总监Brett Redfearn发表了一份未经编辑的声明,该演讲可能会导致人们对什么是证券产生更大的困惑,因为Hinman的新测试超出了典型的Howey分析。贸易和市场部对Hinman演讲稿回应称,这个演讲是普通公众或市场参与者一直要求的,所以我们非常支持这个演讲及其传达的内容。

Hinman演讲文件指的是美国SEC前财务部主任William Hinman(2017年至2020年))于2018年6月在雅虎金融全市场峰会上发表的演讲,他在演讲中表示以太坊不是证券,Ripple认为该演讲是其与美国SEC正在进行的法律斗争的关键证据,美国SEC指控Ripple的XRP销售违反了美国证券法。[2023/6/13 21:34:33]

2.?外部合约的函数早于状态变量的修改

Ancilia:曾批准任何代币在0x6d89开头地址上交易的用户请立即撤销:金色财经报道,Web3网络安全公司Ancilia提醒称,如果用户曾批准任何代币在0x6d8981847eb3cc2234179d0f0e72f6b6b2421a01上交易,请及时撤销,已检测到多个黑客利用了用户之前对0x6d89的批准。目前共22060个地址曾授权该地址,黑客已利用该漏洞获利超过460枚BNB(约合13.9万美元),已发送至Tornado Cash。[2023/2/28 12:33:25]

Ripple在巴西推出加密按需流动性服务:金色财经报道,Ripple与拉丁美洲数字银行Travelex达成合作,在巴西推出加密按需流动性(ODL)服务,该产品最初计划允许巴西和墨西哥之间法定货币的转移和交易,后续也会将该服务扩展到美国和亚洲。(Coindesk)[2022/8/19 12:35:21]

漏洞分析:

看withdraw函数,我们可以看到它接收了一个_amount参数,将其与发送者的balance进行比较,不超过发送者的balance就将这些_amount发送给sender,同时我们注意到这里它用来发送ether的函数是call.value,发送完成后,它才在下面更新了sender的balances,这里就是可重入攻击的关键所在了,因为该函数在发送ether后才更新余额,所以我们可以想办法让它卡在call.value这里不断给我们发送ether,同样利用的是我们熟悉的fallback函数来实现。

BitMEX:目前停机问题已解决:8月13日消息,随后BitMEX跟进称,团队实现修复的同时,正在通过Support与任何可能受到影响的用户进行沟通,并将为任何受到停机影响的用户采取适当的步骤。最新消息显示,该事件已经解决。

早些时间报道,BitMEX由于交易引擎引发停机,团队正在修复。[2022/8/13 12:23:28]

当然,这里还有另外一个关键的地方——call.value函数特性,当我们使用call.value()来调用代码时,执行的代码会被赋予账户所有可用的gas,这样就能保证我们的fallback函数能被顺利执行,对应的,如果我们使用transfer和send函数来发送时,代码可用的gas仅有2300而已,这点gas可能仅仅只够捕获一个event,所以也将无法进行可重入攻击,因为send本来就是transfer的底层实现,所以他两性质也差不多。

2016年6月以太币组织TheDAO被攻击,攻击者利用两个代码漏洞创建子合约提取了360万个以太币。接下来我们简单说一下这个事件

攻击者利用the?DAO函数智能合约中splitDAO()函数,重复对DAO资产进行重入攻击,不断从项目的资产里面分离出DAO资产并转移到自己的账户中

1.?创建钱包,调用splitDAO函数

2.?创建一个分割提案到一个新的钱包地址

3.?等待再调用splitDAO函数

4.?成功获取了ether

?解决方法:

1.?使用其他转账函数

进行以太坊转账时发送给外部地址时使用Solidity的内置函数,这将不足以调用另一份合约.

2.?先修改状态变量

这种方式就是确保状态变量的修改要早于转账操作,即Solidity官方推荐的检查-生效-交互模式(checks-effects-interactions)。

1.?使用互斥锁

互斥锁就是添加一个在代码执行过程中锁定合约的状态变量以防止重入攻击。

2.?使用OpenZeppelin官方库

OpenZeppelin官方库中有一个专门针对重入攻击的安全合约

??本文作者:权星实验室团队

来源:金色财经

郑重声明: 本文版权归原作者所有, 转载文章仅为传播更多信息之目的, 如作者信息标记有误, 请第一时间联系我们修改或删除, 多谢。

银河链

[0:31ms0-1:507ms