零时科技 || Cetus 攻击事件分析

admin 2025年5月27日20:00:45评论34 views字数 2399阅读7分59秒阅读模式
零时科技 || Cetus 攻击事件分析

背景介绍

2025年5⽉22⽇,我们监控到 SUI 上针对 Cetus 的攻击事件:

https://suiscan.xyz/mainnet/tx/DVMG3B2kocLEnVMDuQzTYRgjwuuFSfciawPvXXheB3x

攻击共造成 223M USD 的损失。

攻击及事件分析

攻击者⾸先通过 flash_swap 来将 haSUI 兑换为 SUI , flash_swap 是 swap 和 flashloan 的变体,在 token0 对 token1 的 flash_swap 中,可以先获得 token1 ,再通过 repay_flash_swap 来⽀付 token0 。

零时科技 || Cetus 攻击事件分析

通过上述操作,攻击者获得了 5,765,124.79 SUI ,需要在同⼀个 transaction 中⽀付 10,024,321.29 haSUI 。且该池⼦的 haSUI 的 sqrtPriceX64 由 18,956,530,795,606,879,104 , tick = 545 ,变为了 18,425,720,184,762,886 , tick =-138185 ,相当于价格由原先的 1.056 降低到了 0.0000009977 ,价格⼤幅降低⾄原来的 0.00009% 。

随后,攻击者通过 open_position 创建了⼀个 Liquidity Position ,其中该 Position 的 tickLower 为 300000 , tickUpper 为 300200 。

零时科技 || Cetus 攻击事件分析
零时科技 || Cetus 攻击事件分析

tick 区间对应的 price 的区间为:

零时科技 || Cetus 攻击事件分析

随后,攻击者在该价格区间内添加流动性 10,365,647,984,364,446,732,462,244,378,333,008 。

零时科技 || Cetus 攻击事件分析

我们看⼀下添加流动性的代码:

零时科技 || Cetus 攻击事件分析

可以看出,添加流动性需要的 amount_a 和 amount_b 由 get_amount_by_liquidity 得出,接下来,我们看⼀下get_amount_by_liquidity 的具体实现和对应的参数。

零时科技 || Cetus 攻击事件分析

由于 arg2 为 currentTick ,且 currentTick = -138185 ⼩于 arg0 lowerTick 。所以,接下来代码会走到

零时科技 || Cetus 攻击事件分析

由于 arg0 为 lowerTick ,所以 cetus::tick_math::get_sqrt_price_at_tick(arg0) = 60257519765924248467716150 ,且 arg1 为 upperTick , cetus::tick_math::get_sqrt_price_at_tick(arg1) = 60,863,087,478,126,617,965,993,239 。

函数 get_delta_a 的具体实现如下:

零时科技 || Cetus 攻击事件分析

Cetus 的核⼼问题出在 checked_shlw 函数上,我们看该函数的具体代码:

零时科技 || Cetus 攻击事件分析

该函数的逻辑很简单,将⼀个数左移动⼀个 word ,就是64位。如果发⽣溢出,就返回0,如果没发⽣溢出就返回左移后的数。所以,检测左移后是否溢出需要判断 input > 2 ^ (256 - 64) - 1 ,然⽽,代码中却判断 input > 0xffffffffffffffff <<192 ,由于 (0xffffffffffffffff << 192) > 2 ^ (256 - 64) ,所以该代码会导致 input 在 2 ^ (256 - 64) < input <(0xffffffffffffffff << 192) 的数字被截断返回,且溢出检测失效。此时,攻击者构造的数据为:

零时科技 || Cetus 攻击事件分析

所以, input = 10365647984364446732462244378333008 * 605567712202369498277089 =6277101735386680763835789423207666416102355444464034512896 , input ⼤于 2^(256-64) ,但是 input ⼩于 0xffffffffffffffff << 192 。所以,左移时必然发⽣溢出,但是程序的溢出检测失败。发⽣溢出后, v1 = liquidity * (upperSqrtPriceX64 - lowerSqrtPriceX64) - 2 ^ (256 - 64) =491983144293873864340816 。

由于,该值远⼩于 lowerSqrtPriceX64 * upperSqrtPriceX64 ,最终 get_delta_a 的返回值为0。因此,攻击者需要⽀付的token_a 为1(p + 1),即可添加 10365647984364446732462244378333008 的 liquidity 。

零时科技 || Cetus 攻击事件分析

随后,攻击者通过 remove_liquidity 将添加的流动性移除,并通过 repay_flash_swap ⽀付 flash_swap 未⽀付的 token 后完成攻击,攻击者获利 5,765,124 SUI 和 10,024,321 haSUI 。最后,Cetus团队通过两个PR完成了对该漏洞的修复:

https://github.com/CetusProtocol/integer-mate/pull/6/files

零时科技 || Cetus 攻击事件分析

第⼀次修复没有完全修复该漏洞, mask = 1 << 192 = 2 ^ 256 ,所以只有 n >= mask 或 n > mask - 1 ,才能完全修复,避免左移64位后发⽣溢出截断:

https://github.com/CetusProtocol/integer-mate/pull/7/files

零时科技 || Cetus 攻击事件分析

总结

本次漏洞的成因是函数在针对左移溢出检测时, mask 的值选择错误,导致溢出检测失败,对应的值被截断。最终,导致攻击者以不符合代码逻辑的极⼩的 token 添加了极⼤的流动性。建议项⽬⽅在设计经济模型和代码运⾏逻辑时要多⽅验证,合约上线前审计时尽量选择多个审计公司交叉审计。

若需了解更多产品信息或有相关业务需求,可扫码关注公众号或移步至官网:

零时科技 || Cetus 攻击事件分析

微信号noneage

官方网址https://noneage.com/

推荐阅读

REVIEW

零时科技 || Cetus 攻击事件分析

零时科技 || Cetus 攻击事件分析

零时科技 || Cetus 攻击事件分析

零时科技 || Cetus 攻击事件分析

END

零时科技 || Cetus 攻击事件分析

点击阅读全文 立刻直达官网

/www.noneage.com/

零时科技 || Cetus 攻击事件分析

原文始发于微信公众号(零时科技):零时科技 || Cetus 攻击事件分析

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年5月27日20:00:45
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   零时科技 || Cetus 攻击事件分析http://cn-sec.com/archives/4102755.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息