数字变武器:Osmosis数学库中的DoS漏洞
Trail of Bits公开披露了Osmosis链中的一个漏洞,攻击者可以构造一种交易,使其在Osmosis节点上占用的计算时间与消耗的gas量不成比例。利用该漏洞,攻击者可通过向验证者发送大量此类交易来停止Osmosis链的运行。在我们向Osmosis开发团队报告此漏洞后,他们通过硬分叉修复了该问题,避免了攻击发生。
Osmosis是一个具有原生交换池功能的Cosmos链。用户每天在Osmosis的池中交换数十万美元的价值。自然,这些池需要执行大量相当精确的计算,而这正是我们发现的漏洞所在。
漏洞详情
我们在Osmosis的数学库中发现了这个漏洞,该库用于提供数学函数的近似解。具体来说,该漏洞影响了他们的指数函数。他们使用泰勒级数近似来计算a^b:
|
|
然而,这个实现存在一个问题。while循环会一直运行直到term足够小,但没有设置最大迭代次数的限制。如果我们精心选择a和b的值,可以使这个循环需要非常多的迭代才能终止。特别是,使用PowApprox计算1.99999999999999^0.1需要超过200万次迭代,在M1处理器上运行超过800毫秒。
这种长时间运行在调用PowApprox函数的交易gas成本中并未考虑。这意味着如果攻击者能够构造一个调用PowApprox(1.99999999999999, 0.1)的交易,他们可以在Osmosis节点上占用近一秒的运行时间,而只需支付很少的gas费用。通过反复执行此操作,他们可以使整个链停止运行。
幸运的是(对攻击者而言),这样的交易确实存在。在以下代码片段中有一个对PowApprox的调用,该代码用于计算当有人向交换池存入代币时应给予的份额:
|
|
因此,如果攻击者创建一个tokenA权重为0.1的池,用1.0 tokenA初始化它,然后存入0.99999999999999更多的tokenA,他们就可以触发PowApprox中的长时间计算。通过反复存入和提取这0.99999999999999 tokenA,攻击者可以使Osmosis节点反复计算PowApprox,从而停止整个链的运行!
简单解决方案
幸运的是,这个问题的修复非常简单:限制循环迭代次数,如果达到限制就回滚交易。Osmosis最近的硬分叉推送了这个修复,防止了攻击。至于如何防止类似漏洞在其他地方出现,我们的建议很简单:模糊测试。使用gofuzz以100ms超时测试PowApprox函数会很快发现这个漏洞。使用10ms超时替代时,Go的原生模糊测试器也能检测到这个漏洞。
我们于2023年9月6日向Osmosis团队报告了这个漏洞。包含修复的PR于2023年10月6日合并,应用此修复的硬分叉于2023年10月23日执行。
我们要感谢Osmosis团队迅速与我们合作解决这些问题。