Cosmos IBC传输通道升级漏洞分析:通过转发功能使v2通道无法升级

本文详细分析了Cosmos IBC协议中一个关键安全漏洞,攻击者可通过转发功能在合法通道上创建永久未确认的数据包承诺,导致传输v2通道无法完成升级流程,影响系统可维护性。

Cosmos报告#2914705 - 通过转发功能使传输v2通道无法升级

影响摘要

升级功能中存在特定检查HasInflightPackets,它会查找通道的已提交数据包。如果存在任何数据包,则不会将通道设置为FLUSHCOMPLETE状态(在handleFlushStateWriteUpgradeAckChannelWriteUpgradeConfirmChannel中)。如果通道不处于FLUSHCOMPLETE状态,升级就无法完全完成(在ChanUpgradeOpen中会报错,阻止进入WriteUpgradeOpenChannel)。

数据包承诺可以通过两种方式删除:确认和超时。但转发功能在收到目标通道的确认之前,不会为转发的数据包写入确认。这导致合法通道可能依赖于恶意通道,而恶意通道可以选择不确认数据包,从而使合法通道无法进入FLUSHCOMPLETE状态,最终无法完成当前或未来的升级。

重现步骤

  1. 首先创建合法的传输v2通道:ibc-0上的channel-0 <-> ibc-1上的channel-0(这部分由中继器处理)
  2. 在应用中打开另外两个通道:ibc-0上的channel-1 <-> 本地链 ibc-1 || 本地链 ibc-0 -> ibc-1上的channel-1
  3. 提交接收数据包,其结构包含转发信息:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
ibc0Cw.ReceivePacketV2(ibc0Path, types.FungibleTokenPacketDataV2{
    Tokens: []types.Token{
        {
            Amount: "1",
            Denom:  types.Denom{Base: "x"},
        },
    },
    Memo:     "",
    Sender:   ibc1Cw.Address(),
    Receiver: ibc0Cw.Address(),
    Forwarding: types.ForwardingPacketData{Hops: []types.Hop{
        {ChannelId: legitChannel, PortId: port}, {ChannelId: ibc0Path.Dest.ChanId, PortId: port},
    }, DestinationMemo: ""},
})

数据包在ibc-0的channel-1上接收后,会通过channel-0转发到ibc-1的channel-0,然后再次转发到ibc-1的channel-1。由于这种转发机制,系统不会写入任何确认(但会写入收据),导致无法超时。最终结果是ibc-0上的合法channel-0将一直保持已提交(传输中)的数据包状态,直到恶意channel-1收到确认(这不会发生)。

技术细节

该漏洞的核心在于转发功能的实现方式:

  1. 转发功能等待目标通道的确认后才写入原始通道的确认
  2. 如果目标通道是恶意的且不发送确认,原始通道将永远保持未确认状态
  3. 这种设计意外引入了通道间的危险依赖关系

解决方案

Cosmos团队最终通过撤回传输v2功能并移除通道升级能力来解决此问题。虽然该漏洞被评定为低严重性,但仍获得了2000美元的漏洞赏金。

相关材料

  • lock_upgrade.go - 漏洞验证代码
  • upgrade.mov - 验证过程视频
  • GitHub问题跟踪:#7947(撤回传输v2功能的问题)
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计