科技 > 区块链 > 区块链技术

重入攻击是什么?Curve池内的7000万美元如何丢的?

21人参与 2026-07-29 区块链技术

近期 curve 的 vyper 编译语言漏洞导致超过 7000 万美元被盗,此次的漏洞被称为「重入攻击」,本文将深入介绍重入攻击。本文源自 cyberpunkmetalhead 于 medium 所着文章 《a deep dive into how curve pool’s $70 million reentrancy exploit was possible》,由 星球日报odaily 编译、整理。

近期的 curve 池漏洞与我们在过去几年里看到的大多数加密货币黑客事件有所不同,因为与之前的许多漏洞不同,这一次并不直接与智能合约本身的漏洞有关,而是与它所使用的语言的底层编译器有关。

在这里,我们谈论的是 vyper:一个面向智能合约的、具有pythonic风格的编程语言,旨在与以太坊虚拟机(evm)交互。我对此次漏洞的背后原因非常感兴趣,所以我决定深入研究。

随着这次漏洞的发展,每天的新闻头条都在报告新的数字。现在看来,情况终于得到了控制,但在此之前已经有超过 7000 万美元被盗。根据 llamarisk 的事后评估,截止到今天,有几个 defi 项目的池子也被黑客攻破,包括pegd 的 peth/eth: 1100 万美元;metronome 的 mseth/eth: 340 万美元;alchemix 的 aleth/eth: 2260万美元;和curve dao: 大约2470万美元。

这次漏洞被称为重入错误,它是在 vyper 编程语言的某些版本上出现的,特别是 v0.2.15、v0.2.16 和 v0.3.0。因此,使用这些特定版本的 vyper 的所有项目都可能成为攻击的目标。

什么是重入(reentrancy)?

为了理解这次漏洞为什么会发生,我们首先需要了解什么是重入以及它是如何工作的。

如果一个函数在运行过程中可以被中断,并且在其之前的调用完成运行之前可以安全地再次被调用「重新进入」,则称该函数为可重入的。可重入函数在硬件中断处理、递归等应用中都有使用。

为了使一个函数变得可重入,它需要满足以下条件:

这里有一个实际的例子:

i = 5
def non_reentrant_function():
return i**5
def reentrant_function(number:int):
return number**5

函数 non_reentrant_function:

函数 reentrant_function:

值得注意的是,许多智能合约函数都不是可重入的,因为它们访问如钱包余额之类的全局信息。

什么是锁(lock)?

锁本质上是一种线程同步机制,某个进程可以声称或「锁定」另一个进程。

最简单的锁类型被称为二进制信号量。这种锁为被锁定的数据提供独占访问。还有更复杂的锁类型,可以提供对读数据的共享访问。在编程中误用锁可能导致死锁或活锁,进程持续互相阻塞,状态不断改变但没有进展。

编程语言在后台使用锁来优雅地管理和共享多个子程序之间的状态更改。但是,某些语言,如 c# 和 vyper 允许在代码中直接使用锁。

@nonreentrant(‘lock’)
def func():
assert not self.locked, “locked”
self.locked = true
# do stuff
# release the lock after finishing doing stuff
raw_call(msg.sender, b””, value=0)
self.locked = false
# more code here

在上面的例子中,我们希望确保如果 msg.sender(合约调用者)是另一个合约,它不会在运行时调用代码。如果在 raw_call() 下面还有更多的代码,而没有锁,msg.sender 可能会在我们的函数运行完毕之前调用上面的所有代码。

因此,在 vyper 中,nonreentrant(‘lock’) 装饰器是一种控制对函数的访问的机制,以防止调用者在它们完成运行之前反复运行智能合约函数。

在许多 defi 黑客事件中,通常都是合约开发者没有预见到的智能合约错误,一个聪明但恶意的利用者发现了某些函数或数据暴露的方式中的弱点。但这次的情况独特之处在于,curve 的智能合约以及所有其他成为攻击受害者的池和项目在代码本身中都没有已知的漏洞。合约是稳固的。

nonreentrant(‘lock’)是存在的。

由于 vyper 语言在处理重入锁的方式上出现了问题,导致了这个问题的发生。所以,合约创建者可能部署了看似合理的代码,但由于编译器没有正确处理锁,使得攻击者能够利用这个有缺陷的锁进行利用,导致合约行为出现意料之外的结果。

让我们看看真正受到重入攻击的合约。注意 @nonreentrant(‘lock’) 修饰符吗?通常情况下,这应该可以防止重入,但实际上并未能防止。攻击者能够在函数返回结果之前反复调用 remove_liquidity()。

@nonreentrant(‘lock’)
def remove_liquidity(
_burn_amount: uint256,
_min_amounts: uint256[n_coins],
_receiver: address = msg.sender
) -> uint256[n_coins]:
“””
@notice withdraw coins from the pool
@dev withdrawal amounts are based on current deposit ratios
@param _burn_amount quantity of lp tokens to burn in the withdrawal
@param _min_amounts minimum amounts of underlying coins to receive
@param _receiver address that receives the withdrawn coins
@return list of amounts of coins that were withdrawn
“””
total_supply: uint256 = self.totalsupply
amounts: uint256[n_coins] = empty(uint256[n_coins])
for i in range(n_coins):
old_balance: uint256 = self.balances[i]
value: uint256 = old_balance * _burn_amount / total_supply
assert value >= _min_amounts[i], “withdrawal resulted in fewer coins than expected”
self.balances[i] = old_balance – value
amounts[i] = value
if i == 0:
raw_call(_receiver, b””, value=value)
else:
response: bytes[32] = raw_call(
self.coins[1],
concat(
method_id(“transfer(address,uint256)”),
convert(_receiver, bytes32),
convert(value, bytes32),
),
max_outsize=32,
)
if len(response) > 0:
assert convert(response, bool)
total_supply -= _burn_amount
self.balanceof[msg.sender] -= _burn_amount
self.totalsupply = total_supply
log transfer(msg.sender, zero_address, _burn_amount)
log removeliquidity(msg.sender, amounts, empty(uint256[n_coins]), total_supply)
return amounts

这是如何被利用的?

到目前为止,我们知道重入攻击是一种反复调用智能合约中的某个函数的方法。但这是如何导致资金被盗和在curve 攻击中损失 7000 万美元的呢?

注意智能合约末尾的 self.balanceof[msg.sender] -= _burn_amount 吗?这告诉智能合约池中 msg.sender 的流动性,减去燃烧费。接下来的代码行为 message.sender 调用 transfer()。

因此,一个恶意合约可以在金额更新之前不断地调用提现,几乎让他们可以选择提取池中的所有流动性。

这样的攻击通常的流程是这样的:

这将重复,直到池中没有更多的流动性。

vyper 语言中的这个问题已经被修复,在 0.3.0 版本之后不再存在。如果您是开发人员,或使用 vyper 的 web3 组织,请确保立即更新您的版本。

(0)

您想发表意见!!点此发布评论

推荐阅读

2026年Polymarket与Hyperliquid全面对比:加密交易者应该选哪个?

07-29

加密货币混币器是什么?工作原理&类型、洗钱监管风险、代表项目全整理

07-29

mETH混合模型揭秘:为什么流动性质押的时间溢价比收益率更致命?

07-29

链上美股热潮来袭:定义、架构与税务要点拆解

07-29

区块链上的“交易确认”需要等多久?新手指南

07-29

SeerDex:它是什么?为什么现在有这么多人抢购预售版?

07-29

猜你喜欢

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论