数字变武器:Osmosis数学库中的DoS漏洞
Trail of Bits公开披露了Osmosis链中的一个漏洞,攻击者能够构造一种交易,使其在Osmosis节点上消耗的计算时间与所支付gas费用严重不匹配。利用该漏洞,攻击者可通过向验证节点发送大量此类交易使整个Osmosis链陷入瘫痪。在我们向Osmosis开发团队报告此漏洞后,他们通过硬分叉修复了该问题,成功避免了攻击发生。
Osmosis是基于Cosmos的区块链,原生支持兑换池功能。用户每日在该平台的资金池中进行数十万美元价值的交易。这些资金池需要执行大量高精度计算,而这正是漏洞所在之处。
漏洞详情
漏洞发现于Osmosis的数学库中,该库用于提供数学函数的近似计算结果。具体而言,漏洞影响其指数函数实现。该函数使用泰勒级数近似计算a^b:
需要注意的是末尾的"…":由于计算机计算能力有限,必须设置计算终止条件。直观的做法是当追加项足够小时停止计算,此时即可认为已接近真实值。Osmosis开发团队正是采用这种方法。以下是其实现的伪代码:
|
|
然而此实现存在缺陷:while循环仅在term足够小时终止,但未设置最大迭代次数限制。通过精心选择a和b的取值,可使循环需要极多次迭代才能终止。具体而言,使用PowApprox计算1.99999999999999^0.1需要超过200万次迭代,在M1处理器上耗时超过800毫秒。
此超长运行时间未体现在使用PowApprox函数的交易gas成本中。这意味着攻击者可通过构造调用PowApprox(1.99999999999999, 0.1)的交易,仅支付极少gas费用即可占用Osmosis节点近1秒的计算时间。通过重复此操作,攻击者可使整个链陷入停滞。
攻击向量
幸运的是(对攻击者而言),此类交易确实存在。以下代码片段中调用了PowApprox函数,该代码用于计算用户向兑换池存入代币时应获得的份额:
|
|
因此如果攻击者创建权重为0.1的tokenA资金池,初始存入1.0个tokenA,随后再存入0.99999999999999个tokenA,即可触发PowApprox中的长时间计算。通过反复存取这0.99999999999999个tokenA,攻击者可使Osmosis节点陷入重复计算PowApprox的循环,最终导致链停止运行!
解决方案
该问题的修复方案非常简单:限制循环迭代次数,并在达到限制时回滚交易。Osmosis最近的硬分叉推送了此修复,有效预防了攻击。对于如何防止类似漏洞再次出现,我们的建议很明确:模糊测试。使用gofuzz对PowApprox函数进行100毫秒超时测试即可快速发现此漏洞。Go原生模糊测试器在使用10毫秒超时设置时也能检测到该漏洞。
我们于2023年9月6日向Osmosis团队报告此漏洞。包含修复方案的PR于2023年10月6日合并,应用此修复的硬分叉于2023年10月23日执行。
我们感谢Osmosis团队与我们快速合作解决这些问题。