Zora空投漏洞利用:深入研究12.8万美元的申领合约攻击

Zora的NFT空投系统中的一个漏洞允许攻击者通过利用薄弱的声明检查来窃取代币。攻击者利用0x Settler合约的basicSellToPool功能,使得ZoraTokenCommunityClaim合约将0x的ZORA代币分配转移到了攻击者的地址。这次攻击暴露了智能合约设计中安全性的重要性,并强调了严格的访问控制的必要性。

Zora空投漏洞:深入技术解析价值12.8万美元的Claim合约攻击

Zora的NFT空投系统中的一个漏洞允许攻击者通过利用薄弱的claim检查来窃取token。 这表明了安全智能合约设计至关重要的原因。

Zora空投漏洞:深入技术解析价值12.8万美元的Claim合约攻击

Zora简介

Zora是一个去中心化的内容创作者协议,专注于NFT和创作者驱动的市场。在Zora的模式中,创作者在一个开放的市场中铸造和销售带有内置版税的NFT。最近在Base上推出的“$ZORA”token被定位为社区的内容币:一个100亿token的“为了乐趣”的meme token(没有治理权),将追溯空投给Zora协议的早期用户。理论上,符合条件的用户(创作者、收藏家、开发者等)可以通过官方claim合约(ZoraTokenCommunityClaim),地址为0x0000000002ba96C69b95E32CAAB8fc38bAB8B3F8,来claim他们分配到的ZORA。Zora团队表示,必须通过官方网站(claim.zora.co)与该合约进行claim,该合约会将用户分配到的ZORA token转移给他们。

架构概述

ZoraTokenCommunityClaim(Base空投分发)

ZoraTokenCommunityClaim合约的部署是为了持有和分发ZORA供应量的10%,这部分token被预留用于追溯空投。在实践中,ZORA团队将分配的token转移到这个合约中,并在链下设置了每个符合条件的钱包的分配额。该合约的作用是强制只有符合条件的用户才能在claim处理启用后claim预先分配的数量。在内部,它跟踪诸如allocationSetupComplete(一个布尔值,一旦所有分配加载完成,该值就会变为true),claimStart(允许claim的时间戳或区块),以及一个映射accountClaims来记录哪些账户已经claim过。(规模:空投总计约1,000,000,000 ZORA,分发给约240万个地址。)

关键功能包括:

  • setAllocations(...) – 一个仅所有者可调用的函数,用于注册批量的接收者地址及其token数量(在设置期间使用)。
  • completeAllocationSetup() – 最终确定分配阶段(例如,设置allocationSetupComplete=true和/或记录claimStart时间),以便可以开始claim。
  • claim() – 供符合条件的用户认领其token;它检查分配是否已设置,发送者尚未认领(accountClaims[msg.sender] == false),然后将他们标记为已认领并将token转移到指定地址。
  • claimWithSignature(...) – 类似于claim(),但允许第三方通过提供用户的EIP-712签名来代表用户claim。此函数采用额外的_claimTo地址参数,以便token可以发送到任何指定的接收者。

Basic (0x Settler) 合约basicSellToPool

0x 的“Settler”Basic流程是一种通用的一步式交换程序,用于许多链上流动性来源。 在这种设计中,Settler合约首先确保它可以转移用户的token,然后直接调用目标DEX/Pool:Pool合约提取卖方token并返回买方token。 在代码中,函数basicSellToPool(IERC20 sellToken, uint256 bps, address pool, uint256 offset, bytes memory data) 编排了这一点。 参数sellToken是正在出售的token(为原生ETH使用特殊的ETH sentinel)。 bps(基点)参数指示要出售的合约当前余额的百分比。 pool是要调用的DEX合约的地址,data是该pool的swap函数的编码调用数据。 offset 告诉 Settler 在 data 中覆盖金额字段的位置。

image

函数逻辑和安全检查:

  • 首先,它通过检查_isRestrictedTarget(pool)并触发还原(通过ConfusedDeputy()错误)来阻止任何受限目标调用。这通过禁止某些地址来防止滥用。
  • 如果sellToken是ETH,它计算value = (address(this).balance * bps) / BASIS。如果提供的data为空(即,没有calldata),它需要offset==0,然后执行简单的pool.call{value: value}(""),直接发送ETH。否则,它将32添加到offset,并将value存储到该位置处的data中,以便pool调用将使用正确的ETH金额。
  • 如果sellToken是一个ERC-20 token(address != 0),它计算amount = sellToken.balanceOf(address(this)) * bps / BASIS。然后,它将amount写入offset+32处的data中。如果token的地址与pool不同,它会调用sellToken.safeApproveIfBelow(pool, amount),以便pool可以提取token(这是approval逻辑)。
  • 最后,合约执行调用:(success, returnData) = pool.call{value: value}(data)。它在失败时还原。在调用返回后,它会检查是否没有返回数据(这意味着可能调用了非合约),然后它会还原并显示InvalidTarget()

安全审计状态

虽然Zora的claim网站的FAQ声明“合约是否经过审计?是的,由Zellic审计。”,但尚未发布公开的审计报告。Zellic自己的已发布审计列表没有Zora的条目,并且BaseScan上ZoraTokenCommunityClaim的已验证源页面显示“未提交合约安全审计。”因此,社区无法审查审计的范围、发现或补救状态。

image

攻击分析

ZORA社区claim合约中的一个缺陷允许攻击者劫持分配给0x地址的token。攻击者构造了一个对0x Settler(execute())的调用,该调用触发了一个以ZORA claim合约为目标的basicSellToPool操作。由于claim合约的内部_claimTo(address user, address to)函数不要求msg.sender == user,因此Settler调用导致合约将分配给0x的ZORA token发行给攻击者的地址。换句话说,攻击者向Settler的execute()发送了一个交易,导致Settler将ZORA“出售”给claim合约,而claim合约又执行了隐藏的_claimTo(attacker, attacker)。结果是,原本给0x的ZORA token最终进入了攻击者的钱包。

攻击的详细分解

1) 攻击者调用Settler.execute(): 攻击者向0x Settler V1.10合约(地址0x5C9bdC80...)发送了一个交易,调用了execute(...)函数。该交易输入数据编码了一个操作:basicSellToPool。在此payload中,sellToken被设置为ZORA token地址,pool被设置为ZoraTokenCommunityClaim合约地址,而data字段是对ZoraTokenCommunityClaim._claimTo(attacker, attacker)的ABI编码调用。

image

2) _dispatch 和 basicSellToPool: 当execute()运行时,Settler的内部_dispatch逻辑将此操作路由到basicSellToPool(...)。在Settler代码中,basicSellToPool检查pool地址是否允许,然后执行低级调用:

image

3) 在这里,pool是ZORA claim合约,而data是编码的_claimTo(attacker, attacker)。由于Settler合约不限制调用任意合约,因此它转发了该调用。

image

4) Claim合约执行_claimTo: 低级调用调用了ZoraTokenCommunityClaim._claimTo(attacker, attacker)。 在claim合约内部,_claimTo授权将用户的ZORA分配转移到指定地址。 因为_claimTo不检查msg.sender是否等于用户,所以它只是处理了claim。 结果是,ZORA token 从claim合约转移到了攻击者的地址

image

如何防止这种攻击

核心问题是claim合约中缺乏访问控制。一个简单的修复方法是要求_claimTo的调用者是受益于claim的帐户。例如,在_claimTo(user, to)中添加require(msg.sender == _user, ...)检查将确保只有实际接收者才能触发他们的claim。或者,claim合约可能只暴露一个用于发送者自己地址的claim()函数,或者要求接收者签名的有效Merkle证明。正如它所说的那样,Settler可以作为任意调用者调用_claimTo

在0x Settler方面,该合约是一个通用的执行器,因此其行为本质上没有错误——它完全按照编程执行。(原则上,Settler可以将已知的“claim”合约列入受限目标黑名单,但这对于每次空投来说都难以维护。)简而言之,漏洞在于claim合约的设计中。在claim逻辑中严格执行msg.sender将阻止漏洞利用,因为Settler的调用会失败。

0x 文档 明确警告:

image

后果

攻击者有效地将 ZORA token从 0x 的社区分配转移到他们自己的钱包中(根据一些估计,大约 $128k)是从 0x 的分配中获得的。 除了经济损失之外,此事件也削弱了对空投的信心。 混乱的发布(在此期间甚至 BaseScan 都短暂关闭)。

image

随后的漏洞利用导致价格波动——ZORA 的市值在空投发布后的几个小时内暴跌超过 60%。

image

协议的响应

截至撰写本文时,Zora Labs 尚未发布正式的公开事后分析或补丁公告。

0x 团队在社交媒体上澄清说,Settler 合约本身没有被“黑客入侵”或存在缺陷——它只是在token存在时按设计执行。 实际上,0x 的人员指出,该漏洞是由于token分配造成的,而不是 Settler 代码错误。

image

地址

  • Settler V1.10 (0x 协议) – 0x5C9bdC801a600c006c388FC032dCb27355154cC9 (Base 上 0x: Settler v1.10 合约)
  • ZORA Token – (Base 上的 ZORA ERC20;用于空投)
  • ZoraTokenCommunityClaim – 0x0000000002ba96C69b95E32CAAB8fc38bAB8B3F8 (Zora 的 Base claim 合约)
  • 攻击者的地址 – 0xC834496f208f0D2929f7aaFDDa7b0f66Fd616f70(接收了被盗的 ZORA)
  • 0x: 部署者 (Zora) – 0xBEBE537eFb8377629A1dFB1aC5c0568036E32712(部署了 claim 合约)

常见问题 (FAQ)

  1. 0x Settler 合约中是否存在错误? 没有。 0x Settler 执行器按设计工作。 只有因为 ZORA claim 合约本身允许任何人代表任何用户调用 _claimTo(...) 才有可能利用该漏洞。 换句话说,0x 的代码没有问题——问题在于空投合约接受了 Settler 的调用并转移了token,就好像它是有效的claim一样。
  2. 攻击者是如何触发claim的? 攻击者在 Settler execute() 调用中编码了一个 basicSellToPool 操作,其中 ZORA token和 claim 合约地址作为参数。 这导致 Settler 对 claim 合约执行了一个低级 pool.call(...),该合约执行了隐藏的 _claimTo(attacker, attacker) 调用。 因为合约没有检查调用者,所以不需要权限或签名。
  3. 有多少被盗? 确切的总数仍在统计中。 每次claim只转移几个 ZORA token,但攻击者可以重复它。 链上证据显示攻击者重复接收 ZORA(例如,在一笔交易中为 4.2417 ZORA)。 报告表明,大约价值 10 万至 20 万美元的 ZORA 最终进入了攻击者的钱包(相当于 0x 的整个空投分配)。
  4. 这会发生在其他人身上吗? 仅当其他项目的claim合约有类似的错误时。 任何允许外部调用者“claim to”任意地址而不检查 msg.sender 的智能合约都容易受到攻击。 事实上,空投合约通常应该_要求_只能claim接收者自己的地址。 项目应审查其claim逻辑以防止这种情况发生。
  5. 被盗token会被追回吗? 链上不太可能。 区块链交易是不可逆转的。 除非攻击者自愿返还token或被链下行为强迫,否则被盗的 ZORA 可能会丢失。 受影响的项目 (Zora) 可能会决定补偿 0x 或销毁/mint额外的token以平衡损失,但这是一种治理决策,而不是智能合约修复。
  6. 主要教训是什么? 辅助合约(如空投claim合约)的安全性至关重要。 即使核心协议合约是安全的,它也可能因与设计不佳的外部代码交互而被欺骗。 在这种情况下,claim合约中的权限模型是根本问题。 开发人员应假定他们公开的任何调用都可能由合约而不是用户钱包调用,并据此进行编码(例如,强制执行 msg.sender == 所有者检查)。
  • 原文链接: threesigma.xyz/blog/expl...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Three Sigma
Three Sigma
Three Sigma is a blockchain engineering and auditing firm focused on improving Web3 by working closely with projects in the space.