找回密码
 立即注册
首页 业界区 安全 奖励计算公式不要轻易采用 balanceOf 做参数呀! ...

奖励计算公式不要轻易采用 balanceOf 做参数呀!

表弊捞 2025-11-5 12:04:18
背景信息

Equilibria Finance 是一个为 $PENDLE 代币持有者提高收益的 DeFi 协议。其主要功能包括将 PENDLE 代币转换为 ePENDLE(PENDLE --lock--> vePENDLE --mint--> ePENDLE),将 ePENDLE 进行 stake 后获得 stk-ePENDLE 等,目的是提升流动性提供者的收益。除此以外,Equilibria 还为 stk-ePENDLE 的持有者提供了 xEQB 和 vlEQB 代币激励。
本次攻击的原因是 stk-ePENDLE 相关的奖励计算逻辑错误,在 stk-ePENDLE 代币可以转移的前提下,根据用户持有的 stk-ePENDLE 代币余额来进行奖励计算。使得攻击者可以通过一笔 stk-ePENDLE 代币在多个账户间重复利用来领取超额的奖励。

  • 攻击交易:https://app.blocksec.com/explorer/tx/eth/0x185a16017fb4d9b2fefdf5935435253d53d4758238275426b507fe54eb4fe97a
  • 漏洞合约:https://etherscan.io/address/0xd30d6fd662c0d92b49f3c3e478e125ba1d968059#code
  • Alert:

    • https://x.com/Equilibriafi/status/1959296722930483668
    • https://x.com/BlockscopeCo/status/1959287312283496854

Trace 分析

1.png


  • 攻击合约通过一系列的代币转换获取价值 0.01 ETH 的 ePENDLE 代币
  • 调用 stk-ePendle.harvest() 从 ePENDLE 奖励池中收集奖励代币,将收集到的 WETH 和 PENDLE 兑换成 ePendle 代币后进行 stake。
2.png
  1. 此时可以看到 stk-ePendle 合约中存在 13.6 ETH
复制代码
3.png


  • 随后通过闪电贷 Balancer.receiveFlashLoan() 发起攻击。
Balancer.receiveFlashLoan()

先通过闪电贷获取了大量的 ePENDLE,然后 deposit 获得 stk-PENDLE,所有准备工作已经完成。
4.png

执行攻击部分,

  • 创建一个新的合约
  • 将 stk-PENDLE 发送到该合约
  • 调用 getReward() 函数获取 EQB,xEQB 和 ETH 等奖励代币
  • 把 ETH 汇总到主攻击合约
  • 把 stk-PENDLE 发送到主攻击合约
  • 把 EQB,xEQB 返还给 stk-PENDLE 合约
5.png

随后将这个攻击流程重复进行了 20 次,每次获利约 0.664 ETH,总计获利 13.27 ETH。
攻击者通过漏洞获取到奖励代币后,只要 ETH,把 EQB,xEQB 返还给 stk-PENDLE 合约,是为了重复 20 次的奖励获取能够正常运行下去。因为合约中持有 EQB 的数量是 5538 个,而每次获取 EQB 383 个,20 次就是 7660 个。所以需要每次都将获得的 EQB 和 xEQB 返还给 stk-PENDLE 合约。
6.png

代码分析

在 Trace 分析中可以了解到,攻击者利用同一笔 stk-PENDLE 发送到不同的合约中进行重复的奖励领取,多半是计算奖励的逻辑中采用了 balanceOf 的方法来计算奖励权重。
stk-PENDLE 合约:https://etherscan.deth.net/address/0xd30d6fd662c0d92b49f3c3e478e125ba1d968059
在 getReward() 函数中利用 updateReward() 计算用户奖励。
7.png

而在 earned() 函数中,通过 balanceOf 获取目标账户 stk-PENDLE 的余额,余额越大,奖励越多。所以攻击者可以通过同一笔 stk-PENDLE 代币重复获取大量的奖励。
8.png

后记

漏洞修复

对于这个漏洞修复方案,看到社区也存在一些讨论,主要是围绕着以下几个方面

  • 避免直接采用 balanceOf 来计算收益。
  • 如果需要采用 balanceOf 来计算收益,需要限制 stk-PENDLE 代币不允许 transfer。
  • stk-PENDLE 代币可以 transfer 的场景下,则需要在代币转移前后,更新 sender 和 recipient 的奖励累计情况。
如果想要较为优雅地解决这个问题,推荐是选择第三个方法,在 _beforeTokenTransfer() 和 _afterTokenTransfer() 中设计好奖励的更新逻辑。
stk-ePendle.harvest() 的作用

在攻击之前,攻击者专门调用了一次 stk-ePendle.harvest() ,其主要目的是为了通过 _queueNewRewards() 函数累加 rewardInfo.rewardPerTokenStored 的值,以谋求更多的收益。但是在实际执行的 Trace 中,由于 harvestAmount = 0 ,所以 continue 跳过了 _queueNewRewards() 函数的执行步骤。虽然从事后的角度来看这个操作并没有生效,但是漏洞利用的设计与执行上存在这个环节还是必要的。
9.png


来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

5 天前

举报

您需要登录后才可以回帖 登录 | 立即注册