Cosmos 生态安全指南:解构 Cosmos 生态不同组件的安全场景

进阶1/28/2024, 10:22:34 AM
本​​文解构 Cosmos 生态不同组件的安全场景。

作为全球最大,最为知名的区块链生态之一,Cosmos 专注于提升区块链互操作性,实现不同区块链之间的高效互通。包括 Celestia、dYdX v4 在内的一系列头部项目都基于 Cosmos SDK 和 IBC 协议进行搭建。

随着 Cosmos 开发组件受到更多开发者青睐,Cosmos 生态的安全问题也势必会带来更广泛的影响。例如,此前 Cosmos SDK 的 Dragonfruit 漏洞就影响了多个主流公链的正常运行。由于 Cosmos 生态系统基础组件的分散性,开发者需要根据不同的功能需求使用或者扩展不同的组件,导致 Cosmos 生态中的安全问题也存在分散、多样的特点。一份帮助开发者结构性了解 Cosmos 生态安全现状与应对方案的研究,也就显得十分必要。

CertiK 团队独家发布的《Cosmos 生态安全指南》通过读者友好的分类细致剖析了 Cosmos 生态不同组件的安全场景。此报告不仅包括 Cosmos 生态以往重大安全漏洞的分析,还将一些常见的安全漏洞根据起因,效果,代码位置等分类,最大程度地为 Cosmos 生态开发者提供安全指引,并为安全审计人员提供学习和审计 Cosmos 安全问题的索引资料。

一直以来,CertiK 团队都在通过持续的研究和挖掘,协助提升 Cosmos 与整个 Web3 的生态安全。我们将定期为大家带来各类项目安全报告和技术研究,欢迎持续关注!如有任何疑问,可随时与我们取得联系。

以下是《Cosmos 生态安全指南》全文👇。

概况

Cosmos 是一款开源、开放、高度可扩展的区块链跨链网络,也是全球最为知名的区块链生态之一。Cosmos 是一个由 CometBFT(原 Tendermint 团队)推出的支持跨链交互的异构网络,由多条独立、并行的区块链组成去中心化网络,其愿景是打破信息的孤岛效应,实现不同区块链之间的互操作性。在当前多链时代,实现跨链交互已经成为区块链行业的迫切需求。

Cosmos 提供了一种高效的跨链模式,特别适用于专注特定垂直领域的公链。通过提供模块化的区块链基础设施,Cosmos 为各应用开发者提供了便利,使其能够选择并使用符合其需求的公链。

Cosmos 生态系统中的应用程序和协议采用IBC(区块链间通信协议)进行连接,实现了各个独立区块链之间的跨链交互,使资产和数据能够自由流通。Cosmos 的愿景是建立一个区块链互联网,为大量自主、易于开发的区块链提供扩展和交互的可能性。

长期以来,CertiK 对 Cosmos 生态环境保持了充分的关注和研究。我们在 Cosmos 生态安全问题上积累了充足的经验,在本研究报告中,将介绍我们对 Cosmos 生态系统安全的探索和研究成果,主要将重点集中在 Cosmos SDK 安全、IBC 协议安全、CometBFT 安全和 CosmWasm 安全四个方向,讨论的对象目标会从 Cosmos 基础组件延伸到 Cosmos 基础链或应用链,通过对类似问题的分析和扩展,以自下而上的方式向读者展现 Cosmos 生态中关于链自身涉及到的安全要点。

由于 Cosmos 生态的复杂多样性,存在的安全问题也具备多样性的特征,因此这份研究报告并没有将所有的安全漏洞类型都涵盖其中,仅探讨更具有典型特征且对 Cosmos 生态链存在更大危害性的漏洞。如果想要了解更多关于其他安全问题的详情,欢迎联系 CertiK 安全工程师交流探讨。

背景

  • CometBFT:跨链可扩展性的基石

CometBFT 是一项创新的共识算法,包括底层共识引擎(CometBFT Core)和通用应用程序区块链接口(ABCI)两个主要组件。其共识算法采用了 PBFT+Bonded PoS 混合共识,确保节点同步记录交易。作为 Interchain 可扩展性的核心组成部分,CometBFT 通过验证者共识,维护 Interchain 生态系统的安全性、去中心化和完整性。

  • Cosmos SDK:模块化和新功能

Cosmos SDK 是一个帮助开发者加速开发进程的工具包,提供了模块化和可插拔的特性,利用 Cosmos SDK,开发者可以基于 CometBFT 共识算法构建自己的区块链或功能组件,实现便捷开发并缩短开发周期。目前已在许多区块链项目中得到采用,如 Cronos、Kava 和最近推出的 dYdX V4。未来的发展计划将专注于模块化和引入新功能,使开发人员能够创建更复杂、模块化的应用程序,培育更广泛、更强大的生态系统。

  • IBC 协议:增强互操作性和可扩展性

IBC 协议(区块链间通信协议)能够在区块链之间实现安全、去中心化且无需许可的数据传输。由于 Cosmos 是由多条独立并行的区块链组成的去中心化网络且利用中继技术实现不同区块链之间的跨链,因此 IBC 可以说是整个项目最核心的部分。Interchain 基金会目前重点关注两个主题:可扩展性和可用性。通过提高 IBC 的可扩展性和互操作性,Cosmos 将进一步增强其生态系统的容量,从而实现区块链、应用程序和智能合约之间的无缝交互。

  • CosmWasm:解锁去中心化、无许可部署

CosmWasm(Cosmos WebAssembly)是一个基于 WebAssembly 的智能合约框架,专为 Cosmos 生态系统设计。它使开发人员能够在没有许可要求的情况下部署去中心化应用程序,同时还允许区块链开发人员将其产品开发周期与区块链开发分开,从而降低验证器升级的成本。除此之外它还具有模块化架构,Cosmos SDK 集成,跨链通信等特性。

截止目前,Cosmos SDK,IBC 协议相对成熟,且在目前的 Cosmos 生态系统中使用最为广泛。

从链开发者的角度考虑,目前 Cosmos 上的生态链所需要大部分自定义化的功能都可以依赖 Cosmos SDK 来完成,而为了实现跨链操作过程中一些特殊操作或是出于优化性能等目的,链开发者会对各自 IBC 模块实现定制化,除此之外,也有少部分的链会对 CometBFT Core 等底层引擎做修改定制化,因篇幅限制暂时不在本研究报告中展开,本研究报告将重点剖析 Cosmos SDK 和 IBC 协议这两者的技术要点和安全问题。

Cosmos SDK 安全指南

Cosmos SDK 是一个强大而灵活的框架,用于构建区块链应用程序和去中心化协议。它由 Interchain 基金会开发,是 Cosmos 网络的核心组件,Cosmos 网络是互连区块链的去中心化网络。

Cosmos SDK 旨在简化自定义区块链应用程序的开发,并实现不同区块链之间的无缝互操作性。Cosmos SDK 主要有以下特点:模块化架构、可定制性、基于 CometBFT、实现 IBC 对应接口、开发者友好。Cosmos SDK 通过利用 CometBFT Core 底层共识引擎确保强大的安全性,保护网络免受恶意攻击,为用户的资产和数据提供保护。此外,其模块化性使用户能够轻松设计定制模块。尽管有这些优点,但当开发人员使用 Cosmos SDK 实现自己的应用程序时,仍然可能存在安全漏洞。

从安全审计角度来讲,我们需要对审计目标做到面面俱到,充分考虑到各个角度的安全隐患问题,但从安全研究角度来讲,我们更需要去关注能够造成重大影响的安全漏洞,在更短的时间内尽可能的避免最大安全隐患,为集成服务方提供更有效的帮助。从这个角度考虑,对一些危险程度高、影响范围大的漏洞做出分类,并分析出其漏洞模型是非常必要且有价值的事情。

在贯穿整个 Cosmos 生态的 ABCI 接口中,我们重点关注 BeginBlock、EndBlock、CheckTx、DeliverTx 这四个接口,前两者直接涉及到单个区块的执行逻辑,而后两者涉及到对 sdk.Msg(Cosmos 生态中传输消息的基础数据结构 ) 的具体处理。

由于 Cosmos 生态上各种应用链的实现逻辑都可按照类似 Cosmos SDK 里的模块和样例,因此在分析理解下文的安全漏洞时,需要对 Cosmos SDK 的模块运行流程有个基本概念。

在 Cosmos 生态里,交易最初在用户代理中被创建,然后会被签名并广播到区块链内的节点。节点利用 CheckTx 方法来验证各种交易细节,如签名、发件人的余额、交易序列和提供的燃料等。如果交易通过验证,它将被添加到内存池,等待被包含在一个区块中。另外,如果交易未通过验证,将向用户发送错误消息,导致交易被拒绝。在区块执行期间,会对交易进行进一步检查,这是通过 DeliverTx 方法完成的,以确保一致性和确定性。

在 Cosmos SDK 中,交易的生命周期可以简要描述为如下流程:

1.交易创建:交易是在客户端使用各种工具、CLI 或在前端创建的。

2.添加到内存池:交易被添加到内存池,其中节点发送一个 ABCI 消息 -CheckTx 到应用层,以检查有效性并接收结果 abci.ResponseCheckTx。在 CheckTx 中,交易从字节格式解码为 Tx 格式,然后在 Tx 的每个 sdk.Msg 上调用 ValidateBasic() 进行初步的无状态有效性检查。如果应用程序存在对应的 anteHandler,则会先执行它的内部逻辑,然后调用 runTx 函数,最终会调用到 RunMsgs() 函数来处理 sdk.Msg 的具体内容。如果 CheckTx 成功,消息将添加至本地内存池作为下一个区块的候选,并将通过 P2P 广播到对等 Peer 节点。

  1. 包含在一个提议区块中:每一轮开始时,提议者创建一个包含最新交易的区块,最后由全节点负责共识的验证者,同意接受该区块或者投票一个空区块。

  2. 状态更改:DeliverTx 被调用来迭代区块中的交易,类似于 CheckTx,但它在 Deliver 模式下调用 runTx,并执行状态的变更。MsgServiceRouter 被调用来路由交易中的不同消息到不同的模块,然后执行 Msg Server 中的每个相应消息。之后,在执行消息后运行检查,如果有任何失败,将还原状态。在执行过程中,使用 Gas 计量器来跟踪使用了多少燃料 (gas)。如果发生任何燃料错误(例如,燃料不足),则与执行失败后的后果相同,状态更改将被还原。

  3. 提交区块:当节点接收到足够的验证者投票时,它就会提交一个新的区块以添加到区块链中,并最终确定应用层中的状态转换。

Cosmos 生态上的交易生命周期图

以下是 Cosmos SDK 的具体执行逻辑,在分析下文漏洞触发路径时可以方便查阅理解:

Cosmos SDK 重点 ABCI 的具体执行逻辑

常见漏洞分类

在了解漏洞分类之前,我们需要对漏洞危险程度有一个基本划分,这样有助于更好地识别出危险性大的安全漏洞,尽可能规避潜在的安全风险。

从危险程度和影响范围考虑,我们主要关注 Critical 和 Major 评级的安全漏洞,它们通常可以造成以下风险:

  1. 链停止运行

  2. 资金损失

  3. 影响系统状态或正常运行

而这些危险的起因往往是以下几种类型的安全漏洞:

  1. 拒绝服务

  2. 错误的状态设置

  3. 验证缺失或者不合理

  4. 唯一性问题

  5. 共识算法问题

  6. 实现上的逻辑漏洞

  7. 语言特性问题

漏洞分析

由于 Cosmos 生态模块化的特殊性,各类链条实现上存在大量模块间相互使用,模块内相互调用的案例,因此存在漏洞触发路径与漏洞触发位置变量的可控路径不一致的情况,我们在分析漏洞具体触发原因时不应只关注触发路径,还应该关注漏洞关键变量的可控路径,这样才能帮我们更好地划分定义漏洞模型。

链停止运行

链停止运行的罪魁祸首大多情况下是单个区块执行过程中产生的问题,但在 Cosmos 的历史发展过程中也出现过共识安全漏洞而导致链不得不主动停止来修复的情况,因此这里把影响共识类型的安全漏洞也放到导致链停止运行效果里来讨论,我们会分别来讲这两类问题。

第一类情况常见的是拒绝服务类型的漏洞,其具体原因主要是不当的崩溃处理与循环边界可被用户影响的遍历操作。此类漏洞往往会使得链暂停运行,或者减缓其运行速度等。

前文中有提到 Cosmos SDK 和 CometBFT 作为 Cosmos 生态中关键的基础设施,它们不仅被 Cosmos 中的基础链使用,各类的应用链也都基于其架构实现各自逻辑,因此它们都会遵从 CometBFT 的 ABCI 接口规则,其攻击面重点也是在其 ABCI 接口上,而能够造成的 Chain halt 的安全漏洞大多是可以直接影响到区块代码执行的问题,因此其发生的路径基本都可溯源到 BeginBlock 和 EndBlock 两个接口。

第二类情况是属于影响到共识的漏洞,通常和各类链的实现相关,目前已知的常见于一些逻辑处理验证,时间校准和随机性问题。此类漏洞从本质上会影响到区块链的去中心化原则,直观上看可能并没有太大影响,但假如经过有心者恶意设计,那么依然会产生较大的安全风险。

第一类情况

  • 案例一:SuperNova 项目

漏洞背景:铸币分发操作中缺乏地址验证,从而导致操作失败,资金流失。在铸币模块中,每次 token 铸造都取决于抵押金额。然而,如果池不存在或者合约地址输入错误,铸币模块可能会发生意外情况,导致区块链停止运行。在奖励池模块中,池合约地址没有经过验证。如果分发操作失败,链将直接停止运行。

漏洞位置:https://github.com/Carina-labs/nova/blob/932b23ea391d4c89525c648e4103a3d6ee4531d5/x/mint/keeper/keeper.go#L175

漏洞代码片段:


漏洞触发路径:

BeginBlocker (/x/mint/keeper/abci.go)

Keeper.DistributeMintedCoin

Keeper.distributeLPIncentivePools

PoolIncentiveKeeper.GetAllIncentivePool (/x/mint/keeper/keeper.go)

漏洞补丁:

https://github.com/Carina-labs/nova/commit/538abc771dea68e33fd656031cbcf2b8fe006be0

补丁位于 poolincentive 的消息处理模块 (x/poolincentive/types/msgs.go),而非 mint 模块。

对处理 MsgCreateCandidatePool(即创建 pool)时的消息做了地址校验,是想从根源上杜绝错误地址的可能。

  • 案例二:Cosmos Interchain Security 项目

项目地址:https://github.com/cosmos/interchain-security

漏洞背景:验证者可以通过在同一个区块中提交多个 AssignConsumerKey 消息来减缓提供链的速度。在 x/ccv/provider/keeper/key_assignment.go 中定义的 AssignConsumerKey 函数使验证者能够为经批准的消费链分配不同的 consumerKey。为了执行此操作,consumerAddrsToPrune AddressList 会增加一个元素。由于在 x/ccv/provider/keeper/relay.go 中的 EndBlocker 中会遍历这个 AddressList,攻击者可以利用它来减慢提供链的速度。为执行这种攻击,恶意行为者可以创建具有多个 AssignConsumerKey 消息的交易,并向提供链发送这些交易。consumerAddrsToPrune AddressList 的基数将与发送的 AssignConsumerKey 消息相同。因此,EndBlocker 的执行将花费比预期更多的时间和资源,导致提供链运行速度减缓,甚至停止。

漏洞位置:https://github.com/cosmos/interchain-security/blob/6a856d183cd6fc6f24e856e0080989ab53752102/x/ccv/provider/keeper/key_assignment.go#L378

漏洞代码片段:

漏洞触发路径:

msgServer.AssignConsumerKey

Keeper.AssignConsumerKey

AppModule.EndBlock

EndBlockCIS

HandleLeadingVSCMaturedPackets

HandleVSCMaturedPacket

PruneKeyAssignments

  • 案例三:Quicksilver 项目 -Airdrop 模块

漏洞背景:BeginBlocker 和 EndBlocker 是模块开发人员可以在其模块中实现的可选方法。它们分别在每个区块的开始和结束时触发。在 BeginBlock 和 EndBlock 方法中使用崩溃来处理错误可能会导致链在出现错误时停止。EndBlocker 清算未完成的空投时未考虑模块是否有足够的代币从而触发崩溃的可能,导致链停止运行。

漏洞位置:https://github.com/quicksilver-zone/quicksilver/blob/b4aefa899e024d‍60f4047e2f2f403d67701b030e/x/airdrop/keeper/abci.go#L15

漏洞代码片段:

漏洞触发路径:

AppModule.EndBlock

Keeper.EndBlocker

Keeper.EndZoneDrop

漏洞补丁:https://github.com/quicksilver-zone/quicksilver/blob/20dc658480b1af1cb323b4ab4a8e5925ee79a0ed/x/airdrop/keeper/abci.go#L16

直接去掉了 panic 的处理代码,换成了记录错误日志。

  • 案例四:Cosmos Interchain Security 项目

项目地址:https://github.com/cosmos/interchain-security

漏洞背景:攻击者可以通过向提供链的奖励地址发送多个代币来可以实现拒绝服务攻击。

在消费链的 EndBlocker 执行流程中,在 x/ccv/consumer/keeper/distribution.go 中定义的 SendRewardsToProvider 函数获取 tstProviderAddr 中所有代币的余额,并将它们发送到提供链。为了实现这一点,它必须遍历奖励地址中找到的所有代币,并逐个通过 IBC 发送到提供链。由于任何人都可以向奖励地址发送代币,攻击者可以创建并发送大量不同 denom 的代币,例如使用具有 token 工厂模块的链,来发起拒绝服务攻击。因此,EndBlocker 的执行将花费比预期更多的时间和资源,导致消费链运行速度减缓,甚至停止。

漏洞位置:https://github.com/cosmos/interchain-security/blob/6a856d183cd6fc6f24e856e0080989ab53752102/x/ccv/consumer/keeper/distribution.go#L103

漏洞代码片段:

漏洞触发路径:

AppModule.EndBlock

EndBlock

EndBlockRD

SendRewardsToProvider

第二类情况

这一类共识问题可能并不能带来直观的严重危害,但是从整个区块链本质原则和体系考虑,亦或是从具体的场景去看这些漏洞的话,它们带来的影响和危害并不见得比其他常规漏洞危害小,除此之外,这类漏洞也有存在着共同点。

  • 案例一

漏洞背景:Cosmos SDK Security Advisory Jackfruit

Cosmos SDK 的 x/authz 模块中 ValidateBasic 方法的非确定性行为容易导致共识停止。x/authz 模块的 MsgGrant 消息结构包含一个 Grant 字段,其中包括用户定义的授权所授予的到期时间。在 Grant 结构的 ValidateBasic() 验证处理中,比较其时间信息与节点本地的时间信息而不是区块时间信息,由于本地时间是非确定性的,各个节点的时间戳可能存在差异,因此会导致共识问题。

漏洞公告:

https://forum.cosmos.network/t/cosmos-sdk-security-advisory-jackfruit/5319

https://forum.cosmos.network/t/cosmos-sdk-vulnerability-retrospective-security-advisory-jackfruit-october-12-2021/5349

https://github.com/cosmos/cosmos-sdk/security/advisories/GHSA-2p6r-37p9-89p2

漏洞代码片段:

漏洞补丁:

https://github.com/cosmos/cosmos-sdk/compare/v0.44.1...v0.44.2

像关于时间戳这样的问题不仅会出现在 Cosmos SDK 这样的基础组件中,在各类应用链中也曾出现过类似的漏洞。

  • 案例二

漏洞背景:SuperNova,nova 项目

项目地址:https://github.com/Carina-labs/nova/tree/v0.6.3

使用 time.Now() 返回操作系统的时间戳。本地时间是主观的,因此是非确定性的。由于各个节点的时间戳可能存在小的差异,因此链可能无法达成共识。在 ICAControl 模块中,交易发送函数使用 time.Now() 来获取时间戳。

漏洞位置:https://github.com/Carina-labs/nova/blob/932b23ea391d4c89525c648e4103a3d6ee4531d5/x/icacontrol/keeper/send_msgs.go#L14

漏洞代码片段:

漏洞补丁:

将使用本地时间戳改为了使用区块时间。

timeoutTimestamp := time.Now().Add(time.Minute * 10).UnixNano() _, err = k.IcaControllerKeeper.SendTx(ctx, chanCap, connectionId, portID, packetData, uint64(timeoutTimestamp))

timeoutTimestamp := uint64(ctx.BlockTime().UnixNano() + 10*time.Minute.Nanoseconds()) _, err = k.IcaControllerKeeper.SendTx(ctx, chanCap, connectionId, portID, packetData, uint64(timeoutTimestamp))

  • 案例三

漏洞背景:BandChain 项目的预言机模块

项目地址:https://github.com/bandprotocol/bandchain/

代码库中的注释表明,预言机模块必须在质押之前执行,以便实现违反预言机协议者的惩罚措施。代码中出现的顺序是:在 SetOrderEndBlockers 函数中,质押模块在预言机模块之前运行。如果质押模块在预言机模块之前执行,那么基于预言机模块中完成的验证来惩罚验证者质押等操作将是不可能实现的。

漏洞位置:https://github.com/LeastAuthority/bandchain/blob/master/chain/app/app.go#L221-L225

漏洞代码片段:

可以看到漏洞具体实现和漏洞注释完全是反过来的,预言机模块应该排在质押模块之前。

  • 案例四

漏洞背景:Sei Cosmos 项目的 accesscontrol 模块

项目地址:https://github.com/sei-protocol/sei-cosmos

在 Cosmos 各类代码库的多个实例中,go map iteration 都有使用 go 语言的 map 类型,并对其进行了迭代。由于 go 语言的 map 的迭代是非确定性的,这将导致节点达到不同的状态,这可能会导致共识问题,从而导致链停止运行。比较合适的处理方法是将映射键排序到一个切片中,并迭代排序后的键。此类问题比较普遍,属于是语言特性在运用上引入的问题。

在 x/accesscontrol/keeper/keeper.go 的 BuildDependencyDag 的实现中,节点迭代 anteDepSet。由于 Go 中映射迭代的非确定性行为,ValidateAccessOp 可能会出现两种不同类型的错误,这可能会导致共识失败。

漏洞位置:https://github.com/sei-protocol/sei-cosmos/blob/afe957cab74dd05c213d082d50cae02dd4cb6b73/x/accesscontrol/keeper/keeper.go#L314C9-L314C9

漏洞代码片段:

根据这些案例可以发现,对于使得链被动停止运行的漏洞危害性往往最大,其漏洞起因的逻辑关系都可追溯到直接影响区块链中单个区块运行的执行流程。而像一些共识安全漏洞,往往是链主动停止运行去修复,其漏洞起因的逻辑关系都可追溯到影响区块链整体的运行流程和状态。与我们接下来讨论的造成资金损失类型的漏洞关注点不同,资金损失类型的漏洞通常不会去根据其问题出现的逻辑路径来判断其具体危险影响程度,而是更关注其资金的拥有者、资金量的大小、影响资金的范围以及影响资金的方式等。

资金损失

资金损失类问题常见于对 sdk.Msg 和 IBC 消息的逻辑处理中,当然在能够造成链停止运行的原因中也存在有部分漏洞可以造成链资金损失的效果,具体影响还得看具体漏洞,这里着重讨论前者。此外由于 IBC 是 Cosmos 生态中非常重要的一环,因此难免会涉及到 IBC 的部分漏洞,具体关于 IBC 的攻击面与相对应的漏洞我们放到下一章节去探讨。

资金损失常见于 gas 消耗、资金被锁无法取出、资金传输过程中丢失、计算逻辑错误导致资金损失和资金存储 ID 未保证唯一性等逻辑情况。

这里我们以 SuperNova 项目为例,分析下和它相关的三个漏洞。

  • 漏洞背景:SuperNova 项目

项目地址:https://github.com/Carina-labs/nova

如果区域(zone)的小数位数高于 18,资金可能会被锁定。在该项目代码中,区域的小数位数没有上限,可以超过 18 位。在 ClaimSnMesssage 中,当用户希望索取他们的份额代币时,使用了 ClaimShareToken。然而,如果区域的小数位数高于 18,那么转换将失败,无法从系统中提取资产。因此通过控制区域小数位数,可以直接触发交易崩溃失败。

漏洞位置:https://github.com/Carina-labs/nova/blob/v0.6.3/x/gal/keeper/claim.go#L167

漏洞代码片段:


漏洞触发路径:

msgServer.ClaimSnAsset

Keeper.ClaimShareToken

Keeper.ConvertWAssetToSnAssetDecimal

precisionMultiplier

  • 漏洞背景:SuperNova 项目

项目地址:https://github.com/Carina-labs/nova/

区域的唯一性未经验证。在已注册的区域上,使用区域 ID 来检查基础代币(BaseDenom)的唯一性,每个区域的 BaseDenom 应该是唯一的,如果基础代币的值设置错误,将导致资金损失。该项目在 RegisterZone 中设置基础代币之前,并未确保 BaseDenom 在所有主区域中都是唯一的,否则会存在用户向另一含有同名 BaseDenom 的恶意 zone 存储资金的可能性,从而造成资金损失。

漏洞位置:https://github.com/Carina-labs/nova/blob/v0.6.3/x/icacontrol/keeper/msg_server.go#L99

漏洞代码片段:

漏洞补丁:多了 DenomDuplicateCheck 检查

除此之外上文链停止运行第一种情况中的案例一,是由于崩溃导致铸币失败,也是资金损失的一种形式。

  • 漏洞背景:Supernova 项目

项目地址:https://github.com/Carina-labs/nova/

缺少状态更新。在 IcaWithdraw() 方法中,如果交易失败,版本状态没有修改,会导致 WithdrawRecord 无法访问,对应的资金也无法提取。更通俗的理解就是 state 设置在 SendTx 前,失败后未修改 state,导致该资金回撤失败并且下次无法再次回撤。

漏洞位置:https://github.com/Carina-labs/nova/blob/932b23ea391d4c89525c648e4103a3d6ee4531d5/x/gal/keeper/msg_server.go#L356

漏洞代码片段:

根据这部分的案例可以发现,与资金相关的操作主要实现逻辑,还是取决于对各类消息的处理,当然也存在如第一类情况的案例一在 BeginBlock 执行流程中涉及到的铸币操作,当这些操作失败时也会导致资金损失。整体来说,我们将审计重点放在涉及资金操作的代码模块就可以大幅提高发现此类漏洞的可能性。

影响系统状态或正常运行

此类问题范围比较宽泛,刚才讨论的前两者危害其实也可以认为是影响系统状态或正常运行的漏洞类型的子集。除此之外,危险性更大的更多是一些逻辑类型的漏洞,很大程度上,这类漏洞会根据项目的业务逻辑而产生不同的安全风险,但是由于 Cosmos SDK 组件构造的相似性以及模块化的特点,在具体代码实现时候往往会犯下类似的错误,这里给大家列举下常见的漏洞类型:

sdk.Msg 类型中变量校验不完全

由于各项目基于 sdk.Msg 实现了各式各样的派生类型,但是在 Cosmos SDK 中其实并未对所有已有类型的各个元素做相应的检测,导致疏漏了一些关键的内嵌变量检测,从而存在一定的安全风险。

  • 案例一:Cosmos SDK Security Advisory Barberry

漏洞背景:MsgCreatePeriodicVestingAccount.ValidateBasic 验证机制缺失对账户的存活等状态的判断。在 x/auth 中定义的 PeriodicVestingAccount,攻击者可以将受害者的账户初始化为恶意归属账户,该账户允许存款但不允许取款。当用户将资金存入其账户时,这些资金将被永久锁定,并且用户无法提取。

漏洞补丁:

https://forum.cosmos.network/t/cosmos-sdk-security-advisory-barberry/10825

https://github.com/cosmos/cosmos-sdk/security/advisories/GHSA-j2cr-jc39-wpx5

https://github.com/cosmos/cosmos-sdk/compare/v0.47.3-rc.0...v0.47.3

https://github.com/cosmos/cosmos-sdk/pull/16465

漏洞代码片段:

除此之外,Cosmos-SDK Security Advisory Elderflower、Cosmos-SDK Security Advisory Jackfruit,其实都是在 ValidateBasic 环节出现的问题,前者是直接缺失了对 ValidateBasic 的调用,后者则是在消息内部关于时间戳变量校验出现的问题。而在应用链,此类的问题更是常见,像 ethermint,pstake-native,quicksilver 等项目在处理消息的验证措施上都出现过类似的安全漏洞。

除了验证类型,在 sdk.Msg 的处理逻辑中,也会遇到如涉及到大量 gas 消耗的循环操作,不合理的崩溃处理等,由于针对消息的处理链上具备相应的 recovery 机制,因此它们的危险程度相对于链停止运行会低一些,但依然可以影响到系统的正常运行或是导致链上资金的损失。

常见类型漏洞

除去根据项目业务特有的安全漏洞,还存在一些比较常见的漏洞模型,比如资金损失案例三,就是一个在发送消息前改变状态的操作,这类漏洞和智能合约中的漏洞很相似,在传输资金之前先改变了自身的状态,往往会带来如重入或者遗留的错误状态等问题,像这种状态设置和消息传输紧密结合的场景在区块链中其实十分常见,很多造成重大危险的漏洞都是源于此类问题。除此之外,还有一些计算上的安全漏洞类似于除零漏洞、gas 消耗绕过、使用有漏洞的版本等,这类漏洞都会影响到系统状态或系统正常运行。

唯一性问题

由于区块链上涉及到大量的查找读取存储操作,因此在某些功能实现中,命名的唯一性非常重要。例如前文资金损失案例二,就是唯一性问题,除此之外一些代表 key 等重要因素的 string 或者 byte 数组类型的变量,有时候它们的前缀组成也会存在一定的风险,比如是否存在「/」作为每次命名的结尾等,稍有不慎就可能会导致命名被伪造成另一种含义的字符串,从而导致一系列如资金损失、共识出错等问题。

语言特性问题

这类问题更加宽泛一些,但是比较有特征可循,因此较为容易被发现,比如 golang 的 map 迭代问题、rust 中的一些 panic 机制问题等,建议在使用对应语言前,将这些语言特性本身可能会导致对应风险的点列举出来,在使用或者审计时单独关注即可最大程度上避免此类错误。

小结

根据我们对 Cosmos 生态底层安全问题的探索,其实不难发现,此类问题不仅适用于 Cosmos 生态,有很多漏洞模型同样可以运用在其他的生态链中,以下是有关研究 Cosmos 生态系统安全问题的一些建议和总结:

  • 关注基础设施漏洞:CometBFT 和 Cosmos SDK 的核心组件也可能存在漏洞,因此需要对这些组件进行定期更新和维护,以确保安全性。
  • 及时审查第三方库:Cosmos 开发者通常使用第三方库来扩展其应用程序的功能。然而,这些库可能包含潜在的漏洞,因此需要审查和更新这些库以降低风险。
  • 注意恶意节点攻击:在 Cosmos 生态系统中,共识节点是网络的关键组成部分。节点的拜占庭容错算法可能会受到攻击,因此需要确保节点的安全性以防止不良行为。
  • 注意物理安全:对于运行 Cosmos 节点的硬件和服务器,需要采取物理安全措施以防止未经授权的访问和潜在的攻击。
  • 必要的代码审查:由于 Cosmos SDK 和 CometBFT 生态系统的开放性,开发者和审查员应该对核心代码以及在自定义模块中编写的代码进行审查,以识别和纠正潜在的安全问题。
  • 留意生态系统工具:Cosmos 生态系统包括许多工具和应用程序,这些工具也需要进行安全审查和定期更新,以确保其安全性。

IBC 协议安全指南

本模块将重点探讨 IBC 协议 (The Inter-Blockchain Communication protocol) 方面相关的安全问题。IBC 协议是 Cosmos 中极其重要的一环,它的作用是架起各链之间的交互桥梁,假如说其他各类跨链桥是为一些较为独立的问题提供解决方案,那么 IBC 协议可以说是为链之间的交互问题提供了统一的基础解决方案和底层技术支持。IBC 是一种允许异构区块链以可靠、有序和信任最小化的方式传递任何数据的协议。

自比特币问世以来,区块链领域经历了爆炸性的增长。数不清的新网络纷纷涌现,它们各自拥有独特的价值主张、共识机制、意识形态、支持者和存在理由。在引入 IBC 之前,这些区块链大都处于独立运作的状态,就像存在于封闭的容器中,无法相互通信,然而这种封闭的模式从根本上是不可持续的。

假如将区块链视为各个人口不断增长并充满商业活动的国家,有的区块链擅长农业,而有的在畜牧业方面表现出色,它们自然而然地希望进行互利的贸易和合作,各自发挥自身优势。毫不夸张地说,IBC 开辟了一个充满无限可能性的新世界,使不同的区块链能够互操作、传递价值、交换资产和服务,并建立连接,而不受今天大型区块链网络固有的可扩展性问题所限制。

那么 IBC 是如何满足这些需求,并起到至关重要的作用呢?根本原因在于 IBC 是:

  1. 无需信任的

  2. 可支持异构区块链的

  3. 可在应用层进行自定义的

  4. 经过检验的成熟技术

IBC 协议的基础是轻客户端(light clients)和中继器(relayers)。通过 IBC 进行通信的链 A 和链 B 互相具有对方账本的轻客户端。链 A 无需信任第三方,只需通过验证区块头就可以对链 B 的状态达成共识。通过 IBC(尤其是模块)进行交互的链彼此间不会直接传送消息。相反,链 A 将数据包中的一些消息同步至其状态。随后,中继器会对这些数据包进行检测,并将它们传送给目标链。

总的来说,IBC 协议可分为两层,分别是IBC TAO 和 IBC APP。

IBC TAO:定义数据包的传输、身份验证和排序的标准,即基础设施层。在 ICS 中,这由核心、客户端和中继器类别组成。

IBC APP:定义通过传输层传递的数据包的应用程序处理程序的标准,这些包括但不限于同质化代币转账 (ICS-20)、非同质化代币转账 (ICS-721) 和链间账户 (ICS-27),并且可以在应用程序类别的 ICS 中找到。

IBC 图表 ( 来自 Cosmos Developer Portal)

IBC 协议是 Cosmos 坚持的区块链互联网(Internet of Blockchains)愿景的支柱。从这个意义上说,IBC 的设计选择受到了 TCP/IP 规范的影响。与 TCP/IP 为计算机通信制定标准的方式类似,IBC 也指定了一组通用抽象,通过将其实现可以允许区块链进行通信。TCP/IP 对通过网络中继的数据包的内容不设限制,IBC 也是如此。此外,与 HTTP 和 SMTP 等应用协议在 TCP/IP 上搭建的方式类似,同质化资产 / 非同质化资产传输或跨链智能合约调用等应用实例也将 IBC 协议作为基础层。

目前 IBC 协议出现的主要问题都是在关于通道传输和数据包的处理上,当然也不乏在证明验证等环节出现过比较大的问题,但那些问题相对较少,本文重点讨论 IBC 协议的常见问题。由于 IBC 协议的模块化设计,IBC 应用程序开发人员可以无需关注客户端、连接和证明验证等底层细节。但他们需要实现 IBCModule 接口,以及相对应的 Keeper 处理方法等,因此较多 IBC 协议相关的问题都出现在 IBCModule 关于接收和处理数据包的接口(onRecvPacket, OnAcknowledgementPacket, OnTimeoutPacket 等)代码路径中。

常见漏洞分类

在 Cosmos 生态中,IBC 协议作为连接枢纽,从漏洞种类上来说IBC 协议相关的漏洞更为丰富,出现漏洞的位置更加复杂,由于 IBC 协议的相关实现和 Cosmos-SDK,CometBFT 等模块结合密切,下文中难免会提到一些 Cosmos 生态其他模块的实现。此外,目前 IBC 主要运用在 Cosmos 生态系统中,因此其主流使用语言还是 Golang,详情可见 ibc-go 相关文档。

由于篇幅限制,这里不再针对 IBC 协议中各个环节和组件做细致的分析,只对现有的一些安全漏洞做分类探讨,如果想了解更为细致和全面的分析,欢迎联系我们 CertiK 的安全工程师交流探讨。

常见漏洞分类:

1.命名漏洞

① 字符串处理漏洞

② 字节码处理漏洞

  1. 传输过程漏洞

① 数据包顺序漏洞

② 数据包超时漏洞

③ 数据包认证漏洞

④ 其他数据包漏洞

  1. 逻辑漏洞

① 状态更新漏洞

② 投票共识等漏洞

③ 其他逻辑漏洞

  1. Gas 消耗漏洞

现有的 IBC 协议,在审计和分析其安全性的流程上和 Web2 协议的审计流程上具有较多相似性,这次我们将从协议的制定、实现和运用扩展这样一个完整流程的角度来剖析 IBC 协议上的部分安全问题和潜在风险。由于协议的制定往往是由少数人员和组织去完成的,对于各类区块链组织来说,更多的工作是围绕在协议的实现和运用扩展上,因此本文也将重点讨论这两者的安全问题。这是出于对 IBC 协议安全风险涵盖范围广的考虑,能更好地把协议上不同类型的安全问题划分到对应的环节和模块中。

漏洞分析

IBC 协议的制定

  • 案例一:ICS-07 协议,逻辑漏洞

漏洞背景:解绑期限的错误使用

在代码中存在如下校验:

if currentTimestamp.Sub(consState.Timestamp) >= clientState.UnbondingPeriod {

根据 Tendermint 安全模型来看,时间为 t 的区块(标头)的 NextValidators 中的验证器需要在 t+TrustingPeriod 之前正确运行,在那之后,它们可能会有其他行为。然而这里检查的是 UnbondingPeriod,而不是 TrustingPeriod,其中 UnbondingPeriod>TrustingPeriod。如果 consState 的期限介于 TrustingPeriod 和 UnbondingPeriod 之间,那么将接受该标头作为用于验证构成不当行为的其中一个冲突标头的基准。在此期间,consState.NextValidators 中的验证器不再被认为是值得信任的,敌对的前验证者可以在不冒任何风险的情况下关闭客户端。

项目地址:https://github.com/cosmos/ibc/tree/e01da1d1346e578297148c9833ee4412e1b2f254/spec/ics-007-tendermint-client

漏洞位置:https://github.com/cosmos/ibc/tree/e01da1d1346e578297148c9833ee4412e1b2f254/spec/ics-007-tendermint-client#misbehaviour-predicate

https://github.com/cosmos/cosmos-sdk/blob/6344d626db1fbdba5e0f67425703c1584021bf5b/x/ibc/light-clients/07-tendermint/types/misbehaviour_handle.go#L96

漏洞代码片段:

协议定义函数

代码实现

IBC 协议的实现

IBC 协议的实现环节是比较容易出现问题的地方,因为这个环节起到了承上启下的作用,既要尽可能的避免协议规范中的歧义问题,又需要为了协议后续的运用和扩展实现提供更为基础便捷的接口。因此这里将 IBC 协议实现环节的主要问题再做一个小分类,即:

  1. 协议实现中的歧义和不规范问题

  2. 协议设定误差问题

协议实现中的歧义和不规范问题

  • 案例一:ICS-20 协议,命名漏洞

漏洞背景:托管地址冲突。GetEscrowAddress() 是截断为 20 字节的 SHA256(端口 ID+ 通道 ID)。这种方法存在三个问题:

1.端口和通道之间没有域分隔,使用字符串串联不会分隔端口和通道的域。例如端口 / 通道组合(「transfer」、「channel」)和(「trans」、「ferchannel」)将给出相同的托管地址,即截断的 SHA256(「transferchannel」)。如果某些具有库功能的模块能够选择端口和通道 ID,则可能会出现漏洞。

2.模块账户地址之间的冲突。在 SHA-256 的前映像中使用任意的字母数字字符串,后映像大小为 160 位。这种小后映像和快速的哈希函数的组合使得生日攻击成为可能,因为其安全性仅降至 80 位。这意味着大约需要 2^80 次猜测即可找到两个不同的托管账户地址之间的碰撞。2018 年,在 Tendermint 的背景下已经进行了详细的攻击 SHA256 截断的成本分析,证明了从成本的角度来看这种攻击是可行的,找到碰撞意味着两个不同的托管账户映射到同一个账户地址。这可能导致存在从托管账户中盗取资金的风险,详情可查看 ICS20 GetEscrowAddress pre-image domain overlaps with public keysT:BUG。

  1. 模块和非模块账户地址之间的冲突。公共账户地址的构造与 Ed25519 公钥的 20 字节 SHA-256 相同。虽然 160 位的安全性足以防止对特定公共地址的冲突攻击,但针对生日攻击的安全性又只有 80 位。这种情况类似于一种半生日攻击模式,其中一个地址由快速 SHA-256 生成,另一个地址由相对较慢的 Ed25519 公钥计算生成。虽然这种情况会更加安全,但它仍然会引发对托管和公共账户的潜在攻击。

项目地址:https://github.com/cosmos/ibc/tree/e01da1d1346e578297148c9833ee4412e1b2f254/spec/ics-020-fungible-token-transfer

漏洞位置:https://github.com/cosmos/cosmos-sdk/blob/6cbbe0d4ef90f886dfc356979b89979ddfcd00d8/x/ibc/applications/transfer/types/keys.go#L40-L47

https://github.com/cosmos/cosmos-sdk/blob/6cbbe0d4ef90f886dfc356979b89979ddfcd00d8/x/ibc/applications/transfer/keeper/relay.go

漏洞代码片段:

协议设定误差问题

  • 案例一:IBC Security Advisory Dragonberry,传输过程漏洞

漏洞背景:IBC 在处理应用数据包时会使用一个 Packet 的结构,根据超时机制,同步和异步的确认机制以及相应的证明验证流程,数据包会分成两个执行流程:

1.正常情况:超时内成功

2.超时情况:超时失败

IBC 应用数据包传输流程图

当发生超时情况时,说明此次传输失败,IBC 协议便会发起退款流程,同时需要注意的是 IBC 具有用户可配置的超时机制。此次的 Dragonberry 漏洞源自 ICS-23(IBC),该漏洞的根本原因在于用户可以伪造验证流程中的不存在证明(即未收到数据包的虚假证明),从而绕过安全校验,伪造出「合理的」IBC 超时情况来欺骗 IBC 协议,导致中继器发送带有虚假证明的超时数据包,并可能会升级为 ICS-20 双花问题,其漏洞的具体触发流程可以看下图。

Dragonberry 漏洞原理流程图

项目地址:https://github.com/cosmos/ibc-go/tree/00a680cda52690a4ba835bf37f53acc41c01bc7a/modules/core/04-channel

漏洞位置:https://github.com/cosmos/ibc-go/blob/00a680cda52690a4ba835bf37f53acc41c01bc7a/modules/core/04-channel/keeper/timeout.go#L117C28-L117C54

漏洞代码片段:

  • 案例二:IBC Security Advisory Huckleberry,传输过程漏洞

漏洞背景:UnreceivedPackets 仅通过查找查询中包含的每个序列号的相应数据包收据来构建响应。这仅适用于无序通道,因为有序通道使用的是 nextSequenceRecv 而不是数据包收据。因此,在有序通道上,通过 GetPacketReceipt 查询序列号不会找到其中的收据。

此问题的严重程度较轻,因为 ICS-20 FT 传输的通道大部分是无序的,并且中继器不依赖这个 grpc 端点来确定触发超时数据包。然而,假如目标链中有大量数据包,同时配置了用于 IBC 传输的有序通道,且没有对 grpc 响应进行分页,这将产生导致服务节点性能下降甚至崩溃的风险。其具体的触发流程可以看下图。

Huckleberry 漏洞原理流程图

项目地址:https://github.com/cosmos/ibc-go/blob/11297aaa61e651c16e6d4147a15be24ce55ba7cc/modules/core/04-channel/

漏洞位置:https://github.com/cosmos/ibc-go/blob/11297aaa61e651c16e6d4147a15be24ce55ba7cc/modules/core/04-channel/keeper/grpc_query.go#L408

漏洞代码片段:

IBC 协议的运用和扩展

  • 案例一:stride airdrop 漏洞,逻辑漏洞

漏洞背景:TryUpdateAirdropClaim 该函数将 IBC 数据包的发送者地址转换为名为 senderStrideAddress 的 Stride 地址,并从数据包元数据中提取 airdropId 和新的空投地址 newStrideAddress。然后调用 UpdateAirdropAddress 来更新 senderStrideAddress 和 ClaimRecord。随着 ClaimRecord 的更新,newStrideAddress 将能够领取空投。然而这里更新函数只校验了 sender 该请求的地址是否为空,未对 newStrideAddress 做校验,由于 ibc 允许 solo machine 连接实现 IBC-enabled 的链,因此这里就存在更新任意其他账户地址作为空投地址的安全风险。

项目地址:https://github.com/Stride-Labs/stride/tree/3a5c7bfcc3b8c5e7dd870f01bebeb9d949492203/x/autopilot

漏洞位置:https://github.com/Stride-Labs/stride/blob/3a5c7bfcc3b8c5e7dd870f01bebeb9d949492203/x/autopilot/module_ibc.go#L119

https://github.com/Stride-Labs/stride/blob/3a5c7bfcc3b8c5e7dd870f01bebeb9d949492203/x/autopilot/keeper/airdrop.go#L17

漏洞代码片段:


  • 案例二:neutron ibc 模块漏洞,gas 消耗漏洞

漏洞背景:智能合约为 IBC 事件的确认 / 超时支付的费用没有得到足够的验证,恶意智能合约可以利用这一点在 OnAcknowledgementPacket 和 OnTimeoutPacket 消息处理期间导致 ErrorOutOfGas 崩溃。这些崩溃不会通过 outOfGasRecovery 执行来恢复,这意味着交易不会包含在区块中,并且会导致 IBC 中继器重复提交消息,最终可能会造成中继器资金流失和网络废弃数据包过多的危害。

项目地址:https://github.com/neutron-org/neutron/blob/64868908b21f648ad5e8a9b48179134619544e2a/

漏洞位置:

https://github.com/neutron-org/neutron/blob/64868908b21f648ad5e8a9b48179134619544e2a/x/interchaintxs/keeper/ibc_handlers.go#L62

漏洞代码片段:

小结

根据上文对 IBC 协议安全问题的研究分析,其实不难发现,IBC 协议的安全问题分布范围广,且问题多样,但主要问题还是出现在 IBC 协议的实现和运用扩展上。在各大应用链逐渐丰富完善自身传统模块功能性的同时,为了贴合自身业务需求,优化运行效果,也在对应的 IBC 模块中添加了不同的代码实现。

除了上文提到 IBC 环节中的安全问题外,其他一些如 IBC 中间件的安全问题也在涌现,相信在未来,IBC 模块方面的安全问题会成为 Cosmos 生态安全中的重要一环。

总结

在针对 Cosmos 生态安全的探索与研究过程中,我们经历了复杂的审计、汇总和分类工作,探讨了关于 Cosmos 生态里最为关键的 Cosmos SDK 和 IBC 协议两者的安全问题,并通过丰富的实践经历,总结出大量通用的审计经验。

本报告突显了在面对支持跨链交互的异构网络时所面临的挑战,由于其组成元件复杂且分散,因此在对这些组件进行安全审计时同样具有挑战性,我们不仅需要通过已有的安全经验去排查固有的一些安全风险,还需要不断面临新的安全场景,分析新的安全问题。

尽管如此,我们依然相信,通过类似本报告所总结的一些通用场景和安全问题,可以逐步提高异构网络 Cosmos 生态整体的安全性。

声明:

  1. 本文转载自[CertiK],著作权归属原作者[CertiK],如对转载有异议,请联系Gate Learn团队,团队会根据相关流程尽速处理。
  2. 免责声明:本文所表达的观点和意见仅代表作者个人观点,不构成任何投资建议。
  3. 文章其他语言版本由Gate Learn团队翻译, 在未提及Gate.io的情况下不得复制、传播或抄袭经翻译文章。
* 投资有风险,入市须谨慎。本文不作为Gate.io提供的投资理财建议或其他任何类型的建议。
* 在未提及Gate.io的情况下,复制、传播或抄袭本文将违反《版权法》,Gate.io有权追究其法律责任。

Cosmos 生态安全指南:解构 Cosmos 生态不同组件的安全场景

进阶1/28/2024, 10:22:34 AM
本​​文解构 Cosmos 生态不同组件的安全场景。

作为全球最大,最为知名的区块链生态之一,Cosmos 专注于提升区块链互操作性,实现不同区块链之间的高效互通。包括 Celestia、dYdX v4 在内的一系列头部项目都基于 Cosmos SDK 和 IBC 协议进行搭建。

随着 Cosmos 开发组件受到更多开发者青睐,Cosmos 生态的安全问题也势必会带来更广泛的影响。例如,此前 Cosmos SDK 的 Dragonfruit 漏洞就影响了多个主流公链的正常运行。由于 Cosmos 生态系统基础组件的分散性,开发者需要根据不同的功能需求使用或者扩展不同的组件,导致 Cosmos 生态中的安全问题也存在分散、多样的特点。一份帮助开发者结构性了解 Cosmos 生态安全现状与应对方案的研究,也就显得十分必要。

CertiK 团队独家发布的《Cosmos 生态安全指南》通过读者友好的分类细致剖析了 Cosmos 生态不同组件的安全场景。此报告不仅包括 Cosmos 生态以往重大安全漏洞的分析,还将一些常见的安全漏洞根据起因,效果,代码位置等分类,最大程度地为 Cosmos 生态开发者提供安全指引,并为安全审计人员提供学习和审计 Cosmos 安全问题的索引资料。

一直以来,CertiK 团队都在通过持续的研究和挖掘,协助提升 Cosmos 与整个 Web3 的生态安全。我们将定期为大家带来各类项目安全报告和技术研究,欢迎持续关注!如有任何疑问,可随时与我们取得联系。

以下是《Cosmos 生态安全指南》全文👇。

概况

Cosmos 是一款开源、开放、高度可扩展的区块链跨链网络,也是全球最为知名的区块链生态之一。Cosmos 是一个由 CometBFT(原 Tendermint 团队)推出的支持跨链交互的异构网络,由多条独立、并行的区块链组成去中心化网络,其愿景是打破信息的孤岛效应,实现不同区块链之间的互操作性。在当前多链时代,实现跨链交互已经成为区块链行业的迫切需求。

Cosmos 提供了一种高效的跨链模式,特别适用于专注特定垂直领域的公链。通过提供模块化的区块链基础设施,Cosmos 为各应用开发者提供了便利,使其能够选择并使用符合其需求的公链。

Cosmos 生态系统中的应用程序和协议采用IBC(区块链间通信协议)进行连接,实现了各个独立区块链之间的跨链交互,使资产和数据能够自由流通。Cosmos 的愿景是建立一个区块链互联网,为大量自主、易于开发的区块链提供扩展和交互的可能性。

长期以来,CertiK 对 Cosmos 生态环境保持了充分的关注和研究。我们在 Cosmos 生态安全问题上积累了充足的经验,在本研究报告中,将介绍我们对 Cosmos 生态系统安全的探索和研究成果,主要将重点集中在 Cosmos SDK 安全、IBC 协议安全、CometBFT 安全和 CosmWasm 安全四个方向,讨论的对象目标会从 Cosmos 基础组件延伸到 Cosmos 基础链或应用链,通过对类似问题的分析和扩展,以自下而上的方式向读者展现 Cosmos 生态中关于链自身涉及到的安全要点。

由于 Cosmos 生态的复杂多样性,存在的安全问题也具备多样性的特征,因此这份研究报告并没有将所有的安全漏洞类型都涵盖其中,仅探讨更具有典型特征且对 Cosmos 生态链存在更大危害性的漏洞。如果想要了解更多关于其他安全问题的详情,欢迎联系 CertiK 安全工程师交流探讨。

背景

  • CometBFT:跨链可扩展性的基石

CometBFT 是一项创新的共识算法,包括底层共识引擎(CometBFT Core)和通用应用程序区块链接口(ABCI)两个主要组件。其共识算法采用了 PBFT+Bonded PoS 混合共识,确保节点同步记录交易。作为 Interchain 可扩展性的核心组成部分,CometBFT 通过验证者共识,维护 Interchain 生态系统的安全性、去中心化和完整性。

  • Cosmos SDK:模块化和新功能

Cosmos SDK 是一个帮助开发者加速开发进程的工具包,提供了模块化和可插拔的特性,利用 Cosmos SDK,开发者可以基于 CometBFT 共识算法构建自己的区块链或功能组件,实现便捷开发并缩短开发周期。目前已在许多区块链项目中得到采用,如 Cronos、Kava 和最近推出的 dYdX V4。未来的发展计划将专注于模块化和引入新功能,使开发人员能够创建更复杂、模块化的应用程序,培育更广泛、更强大的生态系统。

  • IBC 协议:增强互操作性和可扩展性

IBC 协议(区块链间通信协议)能够在区块链之间实现安全、去中心化且无需许可的数据传输。由于 Cosmos 是由多条独立并行的区块链组成的去中心化网络且利用中继技术实现不同区块链之间的跨链,因此 IBC 可以说是整个项目最核心的部分。Interchain 基金会目前重点关注两个主题:可扩展性和可用性。通过提高 IBC 的可扩展性和互操作性,Cosmos 将进一步增强其生态系统的容量,从而实现区块链、应用程序和智能合约之间的无缝交互。

  • CosmWasm:解锁去中心化、无许可部署

CosmWasm(Cosmos WebAssembly)是一个基于 WebAssembly 的智能合约框架,专为 Cosmos 生态系统设计。它使开发人员能够在没有许可要求的情况下部署去中心化应用程序,同时还允许区块链开发人员将其产品开发周期与区块链开发分开,从而降低验证器升级的成本。除此之外它还具有模块化架构,Cosmos SDK 集成,跨链通信等特性。

截止目前,Cosmos SDK,IBC 协议相对成熟,且在目前的 Cosmos 生态系统中使用最为广泛。

从链开发者的角度考虑,目前 Cosmos 上的生态链所需要大部分自定义化的功能都可以依赖 Cosmos SDK 来完成,而为了实现跨链操作过程中一些特殊操作或是出于优化性能等目的,链开发者会对各自 IBC 模块实现定制化,除此之外,也有少部分的链会对 CometBFT Core 等底层引擎做修改定制化,因篇幅限制暂时不在本研究报告中展开,本研究报告将重点剖析 Cosmos SDK 和 IBC 协议这两者的技术要点和安全问题。

Cosmos SDK 安全指南

Cosmos SDK 是一个强大而灵活的框架,用于构建区块链应用程序和去中心化协议。它由 Interchain 基金会开发,是 Cosmos 网络的核心组件,Cosmos 网络是互连区块链的去中心化网络。

Cosmos SDK 旨在简化自定义区块链应用程序的开发,并实现不同区块链之间的无缝互操作性。Cosmos SDK 主要有以下特点:模块化架构、可定制性、基于 CometBFT、实现 IBC 对应接口、开发者友好。Cosmos SDK 通过利用 CometBFT Core 底层共识引擎确保强大的安全性,保护网络免受恶意攻击,为用户的资产和数据提供保护。此外,其模块化性使用户能够轻松设计定制模块。尽管有这些优点,但当开发人员使用 Cosmos SDK 实现自己的应用程序时,仍然可能存在安全漏洞。

从安全审计角度来讲,我们需要对审计目标做到面面俱到,充分考虑到各个角度的安全隐患问题,但从安全研究角度来讲,我们更需要去关注能够造成重大影响的安全漏洞,在更短的时间内尽可能的避免最大安全隐患,为集成服务方提供更有效的帮助。从这个角度考虑,对一些危险程度高、影响范围大的漏洞做出分类,并分析出其漏洞模型是非常必要且有价值的事情。

在贯穿整个 Cosmos 生态的 ABCI 接口中,我们重点关注 BeginBlock、EndBlock、CheckTx、DeliverTx 这四个接口,前两者直接涉及到单个区块的执行逻辑,而后两者涉及到对 sdk.Msg(Cosmos 生态中传输消息的基础数据结构 ) 的具体处理。

由于 Cosmos 生态上各种应用链的实现逻辑都可按照类似 Cosmos SDK 里的模块和样例,因此在分析理解下文的安全漏洞时,需要对 Cosmos SDK 的模块运行流程有个基本概念。

在 Cosmos 生态里,交易最初在用户代理中被创建,然后会被签名并广播到区块链内的节点。节点利用 CheckTx 方法来验证各种交易细节,如签名、发件人的余额、交易序列和提供的燃料等。如果交易通过验证,它将被添加到内存池,等待被包含在一个区块中。另外,如果交易未通过验证,将向用户发送错误消息,导致交易被拒绝。在区块执行期间,会对交易进行进一步检查,这是通过 DeliverTx 方法完成的,以确保一致性和确定性。

在 Cosmos SDK 中,交易的生命周期可以简要描述为如下流程:

1.交易创建:交易是在客户端使用各种工具、CLI 或在前端创建的。

2.添加到内存池:交易被添加到内存池,其中节点发送一个 ABCI 消息 -CheckTx 到应用层,以检查有效性并接收结果 abci.ResponseCheckTx。在 CheckTx 中,交易从字节格式解码为 Tx 格式,然后在 Tx 的每个 sdk.Msg 上调用 ValidateBasic() 进行初步的无状态有效性检查。如果应用程序存在对应的 anteHandler,则会先执行它的内部逻辑,然后调用 runTx 函数,最终会调用到 RunMsgs() 函数来处理 sdk.Msg 的具体内容。如果 CheckTx 成功,消息将添加至本地内存池作为下一个区块的候选,并将通过 P2P 广播到对等 Peer 节点。

  1. 包含在一个提议区块中:每一轮开始时,提议者创建一个包含最新交易的区块,最后由全节点负责共识的验证者,同意接受该区块或者投票一个空区块。

  2. 状态更改:DeliverTx 被调用来迭代区块中的交易,类似于 CheckTx,但它在 Deliver 模式下调用 runTx,并执行状态的变更。MsgServiceRouter 被调用来路由交易中的不同消息到不同的模块,然后执行 Msg Server 中的每个相应消息。之后,在执行消息后运行检查,如果有任何失败,将还原状态。在执行过程中,使用 Gas 计量器来跟踪使用了多少燃料 (gas)。如果发生任何燃料错误(例如,燃料不足),则与执行失败后的后果相同,状态更改将被还原。

  3. 提交区块:当节点接收到足够的验证者投票时,它就会提交一个新的区块以添加到区块链中,并最终确定应用层中的状态转换。

Cosmos 生态上的交易生命周期图

以下是 Cosmos SDK 的具体执行逻辑,在分析下文漏洞触发路径时可以方便查阅理解:

Cosmos SDK 重点 ABCI 的具体执行逻辑

常见漏洞分类

在了解漏洞分类之前,我们需要对漏洞危险程度有一个基本划分,这样有助于更好地识别出危险性大的安全漏洞,尽可能规避潜在的安全风险。

从危险程度和影响范围考虑,我们主要关注 Critical 和 Major 评级的安全漏洞,它们通常可以造成以下风险:

  1. 链停止运行

  2. 资金损失

  3. 影响系统状态或正常运行

而这些危险的起因往往是以下几种类型的安全漏洞:

  1. 拒绝服务

  2. 错误的状态设置

  3. 验证缺失或者不合理

  4. 唯一性问题

  5. 共识算法问题

  6. 实现上的逻辑漏洞

  7. 语言特性问题

漏洞分析

由于 Cosmos 生态模块化的特殊性,各类链条实现上存在大量模块间相互使用,模块内相互调用的案例,因此存在漏洞触发路径与漏洞触发位置变量的可控路径不一致的情况,我们在分析漏洞具体触发原因时不应只关注触发路径,还应该关注漏洞关键变量的可控路径,这样才能帮我们更好地划分定义漏洞模型。

链停止运行

链停止运行的罪魁祸首大多情况下是单个区块执行过程中产生的问题,但在 Cosmos 的历史发展过程中也出现过共识安全漏洞而导致链不得不主动停止来修复的情况,因此这里把影响共识类型的安全漏洞也放到导致链停止运行效果里来讨论,我们会分别来讲这两类问题。

第一类情况常见的是拒绝服务类型的漏洞,其具体原因主要是不当的崩溃处理与循环边界可被用户影响的遍历操作。此类漏洞往往会使得链暂停运行,或者减缓其运行速度等。

前文中有提到 Cosmos SDK 和 CometBFT 作为 Cosmos 生态中关键的基础设施,它们不仅被 Cosmos 中的基础链使用,各类的应用链也都基于其架构实现各自逻辑,因此它们都会遵从 CometBFT 的 ABCI 接口规则,其攻击面重点也是在其 ABCI 接口上,而能够造成的 Chain halt 的安全漏洞大多是可以直接影响到区块代码执行的问题,因此其发生的路径基本都可溯源到 BeginBlock 和 EndBlock 两个接口。

第二类情况是属于影响到共识的漏洞,通常和各类链的实现相关,目前已知的常见于一些逻辑处理验证,时间校准和随机性问题。此类漏洞从本质上会影响到区块链的去中心化原则,直观上看可能并没有太大影响,但假如经过有心者恶意设计,那么依然会产生较大的安全风险。

第一类情况

  • 案例一:SuperNova 项目

漏洞背景:铸币分发操作中缺乏地址验证,从而导致操作失败,资金流失。在铸币模块中,每次 token 铸造都取决于抵押金额。然而,如果池不存在或者合约地址输入错误,铸币模块可能会发生意外情况,导致区块链停止运行。在奖励池模块中,池合约地址没有经过验证。如果分发操作失败,链将直接停止运行。

漏洞位置:https://github.com/Carina-labs/nova/blob/932b23ea391d4c89525c648e4103a3d6ee4531d5/x/mint/keeper/keeper.go#L175

漏洞代码片段:


漏洞触发路径:

BeginBlocker (/x/mint/keeper/abci.go)

Keeper.DistributeMintedCoin

Keeper.distributeLPIncentivePools

PoolIncentiveKeeper.GetAllIncentivePool (/x/mint/keeper/keeper.go)

漏洞补丁:

https://github.com/Carina-labs/nova/commit/538abc771dea68e33fd656031cbcf2b8fe006be0

补丁位于 poolincentive 的消息处理模块 (x/poolincentive/types/msgs.go),而非 mint 模块。

对处理 MsgCreateCandidatePool(即创建 pool)时的消息做了地址校验,是想从根源上杜绝错误地址的可能。

  • 案例二:Cosmos Interchain Security 项目

项目地址:https://github.com/cosmos/interchain-security

漏洞背景:验证者可以通过在同一个区块中提交多个 AssignConsumerKey 消息来减缓提供链的速度。在 x/ccv/provider/keeper/key_assignment.go 中定义的 AssignConsumerKey 函数使验证者能够为经批准的消费链分配不同的 consumerKey。为了执行此操作,consumerAddrsToPrune AddressList 会增加一个元素。由于在 x/ccv/provider/keeper/relay.go 中的 EndBlocker 中会遍历这个 AddressList,攻击者可以利用它来减慢提供链的速度。为执行这种攻击,恶意行为者可以创建具有多个 AssignConsumerKey 消息的交易,并向提供链发送这些交易。consumerAddrsToPrune AddressList 的基数将与发送的 AssignConsumerKey 消息相同。因此,EndBlocker 的执行将花费比预期更多的时间和资源,导致提供链运行速度减缓,甚至停止。

漏洞位置:https://github.com/cosmos/interchain-security/blob/6a856d183cd6fc6f24e856e0080989ab53752102/x/ccv/provider/keeper/key_assignment.go#L378

漏洞代码片段:

漏洞触发路径:

msgServer.AssignConsumerKey

Keeper.AssignConsumerKey

AppModule.EndBlock

EndBlockCIS

HandleLeadingVSCMaturedPackets

HandleVSCMaturedPacket

PruneKeyAssignments

  • 案例三:Quicksilver 项目 -Airdrop 模块

漏洞背景:BeginBlocker 和 EndBlocker 是模块开发人员可以在其模块中实现的可选方法。它们分别在每个区块的开始和结束时触发。在 BeginBlock 和 EndBlock 方法中使用崩溃来处理错误可能会导致链在出现错误时停止。EndBlocker 清算未完成的空投时未考虑模块是否有足够的代币从而触发崩溃的可能,导致链停止运行。

漏洞位置:https://github.com/quicksilver-zone/quicksilver/blob/b4aefa899e024d‍60f4047e2f2f403d67701b030e/x/airdrop/keeper/abci.go#L15

漏洞代码片段:

漏洞触发路径:

AppModule.EndBlock

Keeper.EndBlocker

Keeper.EndZoneDrop

漏洞补丁:https://github.com/quicksilver-zone/quicksilver/blob/20dc658480b1af1cb323b4ab4a8e5925ee79a0ed/x/airdrop/keeper/abci.go#L16

直接去掉了 panic 的处理代码,换成了记录错误日志。

  • 案例四:Cosmos Interchain Security 项目

项目地址:https://github.com/cosmos/interchain-security

漏洞背景:攻击者可以通过向提供链的奖励地址发送多个代币来可以实现拒绝服务攻击。

在消费链的 EndBlocker 执行流程中,在 x/ccv/consumer/keeper/distribution.go 中定义的 SendRewardsToProvider 函数获取 tstProviderAddr 中所有代币的余额,并将它们发送到提供链。为了实现这一点,它必须遍历奖励地址中找到的所有代币,并逐个通过 IBC 发送到提供链。由于任何人都可以向奖励地址发送代币,攻击者可以创建并发送大量不同 denom 的代币,例如使用具有 token 工厂模块的链,来发起拒绝服务攻击。因此,EndBlocker 的执行将花费比预期更多的时间和资源,导致消费链运行速度减缓,甚至停止。

漏洞位置:https://github.com/cosmos/interchain-security/blob/6a856d183cd6fc6f24e856e0080989ab53752102/x/ccv/consumer/keeper/distribution.go#L103

漏洞代码片段:

漏洞触发路径:

AppModule.EndBlock

EndBlock

EndBlockRD

SendRewardsToProvider

第二类情况

这一类共识问题可能并不能带来直观的严重危害,但是从整个区块链本质原则和体系考虑,亦或是从具体的场景去看这些漏洞的话,它们带来的影响和危害并不见得比其他常规漏洞危害小,除此之外,这类漏洞也有存在着共同点。

  • 案例一

漏洞背景:Cosmos SDK Security Advisory Jackfruit

Cosmos SDK 的 x/authz 模块中 ValidateBasic 方法的非确定性行为容易导致共识停止。x/authz 模块的 MsgGrant 消息结构包含一个 Grant 字段,其中包括用户定义的授权所授予的到期时间。在 Grant 结构的 ValidateBasic() 验证处理中,比较其时间信息与节点本地的时间信息而不是区块时间信息,由于本地时间是非确定性的,各个节点的时间戳可能存在差异,因此会导致共识问题。

漏洞公告:

https://forum.cosmos.network/t/cosmos-sdk-security-advisory-jackfruit/5319

https://forum.cosmos.network/t/cosmos-sdk-vulnerability-retrospective-security-advisory-jackfruit-october-12-2021/5349

https://github.com/cosmos/cosmos-sdk/security/advisories/GHSA-2p6r-37p9-89p2

漏洞代码片段:

漏洞补丁:

https://github.com/cosmos/cosmos-sdk/compare/v0.44.1...v0.44.2

像关于时间戳这样的问题不仅会出现在 Cosmos SDK 这样的基础组件中,在各类应用链中也曾出现过类似的漏洞。

  • 案例二

漏洞背景:SuperNova,nova 项目

项目地址:https://github.com/Carina-labs/nova/tree/v0.6.3

使用 time.Now() 返回操作系统的时间戳。本地时间是主观的,因此是非确定性的。由于各个节点的时间戳可能存在小的差异,因此链可能无法达成共识。在 ICAControl 模块中,交易发送函数使用 time.Now() 来获取时间戳。

漏洞位置:https://github.com/Carina-labs/nova/blob/932b23ea391d4c89525c648e4103a3d6ee4531d5/x/icacontrol/keeper/send_msgs.go#L14

漏洞代码片段:

漏洞补丁:

将使用本地时间戳改为了使用区块时间。

timeoutTimestamp := time.Now().Add(time.Minute * 10).UnixNano() _, err = k.IcaControllerKeeper.SendTx(ctx, chanCap, connectionId, portID, packetData, uint64(timeoutTimestamp))

timeoutTimestamp := uint64(ctx.BlockTime().UnixNano() + 10*time.Minute.Nanoseconds()) _, err = k.IcaControllerKeeper.SendTx(ctx, chanCap, connectionId, portID, packetData, uint64(timeoutTimestamp))

  • 案例三

漏洞背景:BandChain 项目的预言机模块

项目地址:https://github.com/bandprotocol/bandchain/

代码库中的注释表明,预言机模块必须在质押之前执行,以便实现违反预言机协议者的惩罚措施。代码中出现的顺序是:在 SetOrderEndBlockers 函数中,质押模块在预言机模块之前运行。如果质押模块在预言机模块之前执行,那么基于预言机模块中完成的验证来惩罚验证者质押等操作将是不可能实现的。

漏洞位置:https://github.com/LeastAuthority/bandchain/blob/master/chain/app/app.go#L221-L225

漏洞代码片段:

可以看到漏洞具体实现和漏洞注释完全是反过来的,预言机模块应该排在质押模块之前。

  • 案例四

漏洞背景:Sei Cosmos 项目的 accesscontrol 模块

项目地址:https://github.com/sei-protocol/sei-cosmos

在 Cosmos 各类代码库的多个实例中,go map iteration 都有使用 go 语言的 map 类型,并对其进行了迭代。由于 go 语言的 map 的迭代是非确定性的,这将导致节点达到不同的状态,这可能会导致共识问题,从而导致链停止运行。比较合适的处理方法是将映射键排序到一个切片中,并迭代排序后的键。此类问题比较普遍,属于是语言特性在运用上引入的问题。

在 x/accesscontrol/keeper/keeper.go 的 BuildDependencyDag 的实现中,节点迭代 anteDepSet。由于 Go 中映射迭代的非确定性行为,ValidateAccessOp 可能会出现两种不同类型的错误,这可能会导致共识失败。

漏洞位置:https://github.com/sei-protocol/sei-cosmos/blob/afe957cab74dd05c213d082d50cae02dd4cb6b73/x/accesscontrol/keeper/keeper.go#L314C9-L314C9

漏洞代码片段:

根据这些案例可以发现,对于使得链被动停止运行的漏洞危害性往往最大,其漏洞起因的逻辑关系都可追溯到直接影响区块链中单个区块运行的执行流程。而像一些共识安全漏洞,往往是链主动停止运行去修复,其漏洞起因的逻辑关系都可追溯到影响区块链整体的运行流程和状态。与我们接下来讨论的造成资金损失类型的漏洞关注点不同,资金损失类型的漏洞通常不会去根据其问题出现的逻辑路径来判断其具体危险影响程度,而是更关注其资金的拥有者、资金量的大小、影响资金的范围以及影响资金的方式等。

资金损失

资金损失类问题常见于对 sdk.Msg 和 IBC 消息的逻辑处理中,当然在能够造成链停止运行的原因中也存在有部分漏洞可以造成链资金损失的效果,具体影响还得看具体漏洞,这里着重讨论前者。此外由于 IBC 是 Cosmos 生态中非常重要的一环,因此难免会涉及到 IBC 的部分漏洞,具体关于 IBC 的攻击面与相对应的漏洞我们放到下一章节去探讨。

资金损失常见于 gas 消耗、资金被锁无法取出、资金传输过程中丢失、计算逻辑错误导致资金损失和资金存储 ID 未保证唯一性等逻辑情况。

这里我们以 SuperNova 项目为例,分析下和它相关的三个漏洞。

  • 漏洞背景:SuperNova 项目

项目地址:https://github.com/Carina-labs/nova

如果区域(zone)的小数位数高于 18,资金可能会被锁定。在该项目代码中,区域的小数位数没有上限,可以超过 18 位。在 ClaimSnMesssage 中,当用户希望索取他们的份额代币时,使用了 ClaimShareToken。然而,如果区域的小数位数高于 18,那么转换将失败,无法从系统中提取资产。因此通过控制区域小数位数,可以直接触发交易崩溃失败。

漏洞位置:https://github.com/Carina-labs/nova/blob/v0.6.3/x/gal/keeper/claim.go#L167

漏洞代码片段:


漏洞触发路径:

msgServer.ClaimSnAsset

Keeper.ClaimShareToken

Keeper.ConvertWAssetToSnAssetDecimal

precisionMultiplier

  • 漏洞背景:SuperNova 项目

项目地址:https://github.com/Carina-labs/nova/

区域的唯一性未经验证。在已注册的区域上,使用区域 ID 来检查基础代币(BaseDenom)的唯一性,每个区域的 BaseDenom 应该是唯一的,如果基础代币的值设置错误,将导致资金损失。该项目在 RegisterZone 中设置基础代币之前,并未确保 BaseDenom 在所有主区域中都是唯一的,否则会存在用户向另一含有同名 BaseDenom 的恶意 zone 存储资金的可能性,从而造成资金损失。

漏洞位置:https://github.com/Carina-labs/nova/blob/v0.6.3/x/icacontrol/keeper/msg_server.go#L99

漏洞代码片段:

漏洞补丁:多了 DenomDuplicateCheck 检查

除此之外上文链停止运行第一种情况中的案例一,是由于崩溃导致铸币失败,也是资金损失的一种形式。

  • 漏洞背景:Supernova 项目

项目地址:https://github.com/Carina-labs/nova/

缺少状态更新。在 IcaWithdraw() 方法中,如果交易失败,版本状态没有修改,会导致 WithdrawRecord 无法访问,对应的资金也无法提取。更通俗的理解就是 state 设置在 SendTx 前,失败后未修改 state,导致该资金回撤失败并且下次无法再次回撤。

漏洞位置:https://github.com/Carina-labs/nova/blob/932b23ea391d4c89525c648e4103a3d6ee4531d5/x/gal/keeper/msg_server.go#L356

漏洞代码片段:

根据这部分的案例可以发现,与资金相关的操作主要实现逻辑,还是取决于对各类消息的处理,当然也存在如第一类情况的案例一在 BeginBlock 执行流程中涉及到的铸币操作,当这些操作失败时也会导致资金损失。整体来说,我们将审计重点放在涉及资金操作的代码模块就可以大幅提高发现此类漏洞的可能性。

影响系统状态或正常运行

此类问题范围比较宽泛,刚才讨论的前两者危害其实也可以认为是影响系统状态或正常运行的漏洞类型的子集。除此之外,危险性更大的更多是一些逻辑类型的漏洞,很大程度上,这类漏洞会根据项目的业务逻辑而产生不同的安全风险,但是由于 Cosmos SDK 组件构造的相似性以及模块化的特点,在具体代码实现时候往往会犯下类似的错误,这里给大家列举下常见的漏洞类型:

sdk.Msg 类型中变量校验不完全

由于各项目基于 sdk.Msg 实现了各式各样的派生类型,但是在 Cosmos SDK 中其实并未对所有已有类型的各个元素做相应的检测,导致疏漏了一些关键的内嵌变量检测,从而存在一定的安全风险。

  • 案例一:Cosmos SDK Security Advisory Barberry

漏洞背景:MsgCreatePeriodicVestingAccount.ValidateBasic 验证机制缺失对账户的存活等状态的判断。在 x/auth 中定义的 PeriodicVestingAccount,攻击者可以将受害者的账户初始化为恶意归属账户,该账户允许存款但不允许取款。当用户将资金存入其账户时,这些资金将被永久锁定,并且用户无法提取。

漏洞补丁:

https://forum.cosmos.network/t/cosmos-sdk-security-advisory-barberry/10825

https://github.com/cosmos/cosmos-sdk/security/advisories/GHSA-j2cr-jc39-wpx5

https://github.com/cosmos/cosmos-sdk/compare/v0.47.3-rc.0...v0.47.3

https://github.com/cosmos/cosmos-sdk/pull/16465

漏洞代码片段:

除此之外,Cosmos-SDK Security Advisory Elderflower、Cosmos-SDK Security Advisory Jackfruit,其实都是在 ValidateBasic 环节出现的问题,前者是直接缺失了对 ValidateBasic 的调用,后者则是在消息内部关于时间戳变量校验出现的问题。而在应用链,此类的问题更是常见,像 ethermint,pstake-native,quicksilver 等项目在处理消息的验证措施上都出现过类似的安全漏洞。

除了验证类型,在 sdk.Msg 的处理逻辑中,也会遇到如涉及到大量 gas 消耗的循环操作,不合理的崩溃处理等,由于针对消息的处理链上具备相应的 recovery 机制,因此它们的危险程度相对于链停止运行会低一些,但依然可以影响到系统的正常运行或是导致链上资金的损失。

常见类型漏洞

除去根据项目业务特有的安全漏洞,还存在一些比较常见的漏洞模型,比如资金损失案例三,就是一个在发送消息前改变状态的操作,这类漏洞和智能合约中的漏洞很相似,在传输资金之前先改变了自身的状态,往往会带来如重入或者遗留的错误状态等问题,像这种状态设置和消息传输紧密结合的场景在区块链中其实十分常见,很多造成重大危险的漏洞都是源于此类问题。除此之外,还有一些计算上的安全漏洞类似于除零漏洞、gas 消耗绕过、使用有漏洞的版本等,这类漏洞都会影响到系统状态或系统正常运行。

唯一性问题

由于区块链上涉及到大量的查找读取存储操作,因此在某些功能实现中,命名的唯一性非常重要。例如前文资金损失案例二,就是唯一性问题,除此之外一些代表 key 等重要因素的 string 或者 byte 数组类型的变量,有时候它们的前缀组成也会存在一定的风险,比如是否存在「/」作为每次命名的结尾等,稍有不慎就可能会导致命名被伪造成另一种含义的字符串,从而导致一系列如资金损失、共识出错等问题。

语言特性问题

这类问题更加宽泛一些,但是比较有特征可循,因此较为容易被发现,比如 golang 的 map 迭代问题、rust 中的一些 panic 机制问题等,建议在使用对应语言前,将这些语言特性本身可能会导致对应风险的点列举出来,在使用或者审计时单独关注即可最大程度上避免此类错误。

小结

根据我们对 Cosmos 生态底层安全问题的探索,其实不难发现,此类问题不仅适用于 Cosmos 生态,有很多漏洞模型同样可以运用在其他的生态链中,以下是有关研究 Cosmos 生态系统安全问题的一些建议和总结:

  • 关注基础设施漏洞:CometBFT 和 Cosmos SDK 的核心组件也可能存在漏洞,因此需要对这些组件进行定期更新和维护,以确保安全性。
  • 及时审查第三方库:Cosmos 开发者通常使用第三方库来扩展其应用程序的功能。然而,这些库可能包含潜在的漏洞,因此需要审查和更新这些库以降低风险。
  • 注意恶意节点攻击:在 Cosmos 生态系统中,共识节点是网络的关键组成部分。节点的拜占庭容错算法可能会受到攻击,因此需要确保节点的安全性以防止不良行为。
  • 注意物理安全:对于运行 Cosmos 节点的硬件和服务器,需要采取物理安全措施以防止未经授权的访问和潜在的攻击。
  • 必要的代码审查:由于 Cosmos SDK 和 CometBFT 生态系统的开放性,开发者和审查员应该对核心代码以及在自定义模块中编写的代码进行审查,以识别和纠正潜在的安全问题。
  • 留意生态系统工具:Cosmos 生态系统包括许多工具和应用程序,这些工具也需要进行安全审查和定期更新,以确保其安全性。

IBC 协议安全指南

本模块将重点探讨 IBC 协议 (The Inter-Blockchain Communication protocol) 方面相关的安全问题。IBC 协议是 Cosmos 中极其重要的一环,它的作用是架起各链之间的交互桥梁,假如说其他各类跨链桥是为一些较为独立的问题提供解决方案,那么 IBC 协议可以说是为链之间的交互问题提供了统一的基础解决方案和底层技术支持。IBC 是一种允许异构区块链以可靠、有序和信任最小化的方式传递任何数据的协议。

自比特币问世以来,区块链领域经历了爆炸性的增长。数不清的新网络纷纷涌现,它们各自拥有独特的价值主张、共识机制、意识形态、支持者和存在理由。在引入 IBC 之前,这些区块链大都处于独立运作的状态,就像存在于封闭的容器中,无法相互通信,然而这种封闭的模式从根本上是不可持续的。

假如将区块链视为各个人口不断增长并充满商业活动的国家,有的区块链擅长农业,而有的在畜牧业方面表现出色,它们自然而然地希望进行互利的贸易和合作,各自发挥自身优势。毫不夸张地说,IBC 开辟了一个充满无限可能性的新世界,使不同的区块链能够互操作、传递价值、交换资产和服务,并建立连接,而不受今天大型区块链网络固有的可扩展性问题所限制。

那么 IBC 是如何满足这些需求,并起到至关重要的作用呢?根本原因在于 IBC 是:

  1. 无需信任的

  2. 可支持异构区块链的

  3. 可在应用层进行自定义的

  4. 经过检验的成熟技术

IBC 协议的基础是轻客户端(light clients)和中继器(relayers)。通过 IBC 进行通信的链 A 和链 B 互相具有对方账本的轻客户端。链 A 无需信任第三方,只需通过验证区块头就可以对链 B 的状态达成共识。通过 IBC(尤其是模块)进行交互的链彼此间不会直接传送消息。相反,链 A 将数据包中的一些消息同步至其状态。随后,中继器会对这些数据包进行检测,并将它们传送给目标链。

总的来说,IBC 协议可分为两层,分别是IBC TAO 和 IBC APP。

IBC TAO:定义数据包的传输、身份验证和排序的标准,即基础设施层。在 ICS 中,这由核心、客户端和中继器类别组成。

IBC APP:定义通过传输层传递的数据包的应用程序处理程序的标准,这些包括但不限于同质化代币转账 (ICS-20)、非同质化代币转账 (ICS-721) 和链间账户 (ICS-27),并且可以在应用程序类别的 ICS 中找到。

IBC 图表 ( 来自 Cosmos Developer Portal)

IBC 协议是 Cosmos 坚持的区块链互联网(Internet of Blockchains)愿景的支柱。从这个意义上说,IBC 的设计选择受到了 TCP/IP 规范的影响。与 TCP/IP 为计算机通信制定标准的方式类似,IBC 也指定了一组通用抽象,通过将其实现可以允许区块链进行通信。TCP/IP 对通过网络中继的数据包的内容不设限制,IBC 也是如此。此外,与 HTTP 和 SMTP 等应用协议在 TCP/IP 上搭建的方式类似,同质化资产 / 非同质化资产传输或跨链智能合约调用等应用实例也将 IBC 协议作为基础层。

目前 IBC 协议出现的主要问题都是在关于通道传输和数据包的处理上,当然也不乏在证明验证等环节出现过比较大的问题,但那些问题相对较少,本文重点讨论 IBC 协议的常见问题。由于 IBC 协议的模块化设计,IBC 应用程序开发人员可以无需关注客户端、连接和证明验证等底层细节。但他们需要实现 IBCModule 接口,以及相对应的 Keeper 处理方法等,因此较多 IBC 协议相关的问题都出现在 IBCModule 关于接收和处理数据包的接口(onRecvPacket, OnAcknowledgementPacket, OnTimeoutPacket 等)代码路径中。

常见漏洞分类

在 Cosmos 生态中,IBC 协议作为连接枢纽,从漏洞种类上来说IBC 协议相关的漏洞更为丰富,出现漏洞的位置更加复杂,由于 IBC 协议的相关实现和 Cosmos-SDK,CometBFT 等模块结合密切,下文中难免会提到一些 Cosmos 生态其他模块的实现。此外,目前 IBC 主要运用在 Cosmos 生态系统中,因此其主流使用语言还是 Golang,详情可见 ibc-go 相关文档。

由于篇幅限制,这里不再针对 IBC 协议中各个环节和组件做细致的分析,只对现有的一些安全漏洞做分类探讨,如果想了解更为细致和全面的分析,欢迎联系我们 CertiK 的安全工程师交流探讨。

常见漏洞分类:

1.命名漏洞

① 字符串处理漏洞

② 字节码处理漏洞

  1. 传输过程漏洞

① 数据包顺序漏洞

② 数据包超时漏洞

③ 数据包认证漏洞

④ 其他数据包漏洞

  1. 逻辑漏洞

① 状态更新漏洞

② 投票共识等漏洞

③ 其他逻辑漏洞

  1. Gas 消耗漏洞

现有的 IBC 协议,在审计和分析其安全性的流程上和 Web2 协议的审计流程上具有较多相似性,这次我们将从协议的制定、实现和运用扩展这样一个完整流程的角度来剖析 IBC 协议上的部分安全问题和潜在风险。由于协议的制定往往是由少数人员和组织去完成的,对于各类区块链组织来说,更多的工作是围绕在协议的实现和运用扩展上,因此本文也将重点讨论这两者的安全问题。这是出于对 IBC 协议安全风险涵盖范围广的考虑,能更好地把协议上不同类型的安全问题划分到对应的环节和模块中。

漏洞分析

IBC 协议的制定

  • 案例一:ICS-07 协议,逻辑漏洞

漏洞背景:解绑期限的错误使用

在代码中存在如下校验:

if currentTimestamp.Sub(consState.Timestamp) >= clientState.UnbondingPeriod {

根据 Tendermint 安全模型来看,时间为 t 的区块(标头)的 NextValidators 中的验证器需要在 t+TrustingPeriod 之前正确运行,在那之后,它们可能会有其他行为。然而这里检查的是 UnbondingPeriod,而不是 TrustingPeriod,其中 UnbondingPeriod>TrustingPeriod。如果 consState 的期限介于 TrustingPeriod 和 UnbondingPeriod 之间,那么将接受该标头作为用于验证构成不当行为的其中一个冲突标头的基准。在此期间,consState.NextValidators 中的验证器不再被认为是值得信任的,敌对的前验证者可以在不冒任何风险的情况下关闭客户端。

项目地址:https://github.com/cosmos/ibc/tree/e01da1d1346e578297148c9833ee4412e1b2f254/spec/ics-007-tendermint-client

漏洞位置:https://github.com/cosmos/ibc/tree/e01da1d1346e578297148c9833ee4412e1b2f254/spec/ics-007-tendermint-client#misbehaviour-predicate

https://github.com/cosmos/cosmos-sdk/blob/6344d626db1fbdba5e0f67425703c1584021bf5b/x/ibc/light-clients/07-tendermint/types/misbehaviour_handle.go#L96

漏洞代码片段:

协议定义函数

代码实现

IBC 协议的实现

IBC 协议的实现环节是比较容易出现问题的地方,因为这个环节起到了承上启下的作用,既要尽可能的避免协议规范中的歧义问题,又需要为了协议后续的运用和扩展实现提供更为基础便捷的接口。因此这里将 IBC 协议实现环节的主要问题再做一个小分类,即:

  1. 协议实现中的歧义和不规范问题

  2. 协议设定误差问题

协议实现中的歧义和不规范问题

  • 案例一:ICS-20 协议,命名漏洞

漏洞背景:托管地址冲突。GetEscrowAddress() 是截断为 20 字节的 SHA256(端口 ID+ 通道 ID)。这种方法存在三个问题:

1.端口和通道之间没有域分隔,使用字符串串联不会分隔端口和通道的域。例如端口 / 通道组合(「transfer」、「channel」)和(「trans」、「ferchannel」)将给出相同的托管地址,即截断的 SHA256(「transferchannel」)。如果某些具有库功能的模块能够选择端口和通道 ID,则可能会出现漏洞。

2.模块账户地址之间的冲突。在 SHA-256 的前映像中使用任意的字母数字字符串,后映像大小为 160 位。这种小后映像和快速的哈希函数的组合使得生日攻击成为可能,因为其安全性仅降至 80 位。这意味着大约需要 2^80 次猜测即可找到两个不同的托管账户地址之间的碰撞。2018 年,在 Tendermint 的背景下已经进行了详细的攻击 SHA256 截断的成本分析,证明了从成本的角度来看这种攻击是可行的,找到碰撞意味着两个不同的托管账户映射到同一个账户地址。这可能导致存在从托管账户中盗取资金的风险,详情可查看 ICS20 GetEscrowAddress pre-image domain overlaps with public keysT:BUG。

  1. 模块和非模块账户地址之间的冲突。公共账户地址的构造与 Ed25519 公钥的 20 字节 SHA-256 相同。虽然 160 位的安全性足以防止对特定公共地址的冲突攻击,但针对生日攻击的安全性又只有 80 位。这种情况类似于一种半生日攻击模式,其中一个地址由快速 SHA-256 生成,另一个地址由相对较慢的 Ed25519 公钥计算生成。虽然这种情况会更加安全,但它仍然会引发对托管和公共账户的潜在攻击。

项目地址:https://github.com/cosmos/ibc/tree/e01da1d1346e578297148c9833ee4412e1b2f254/spec/ics-020-fungible-token-transfer

漏洞位置:https://github.com/cosmos/cosmos-sdk/blob/6cbbe0d4ef90f886dfc356979b89979ddfcd00d8/x/ibc/applications/transfer/types/keys.go#L40-L47

https://github.com/cosmos/cosmos-sdk/blob/6cbbe0d4ef90f886dfc356979b89979ddfcd00d8/x/ibc/applications/transfer/keeper/relay.go

漏洞代码片段:

协议设定误差问题

  • 案例一:IBC Security Advisory Dragonberry,传输过程漏洞

漏洞背景:IBC 在处理应用数据包时会使用一个 Packet 的结构,根据超时机制,同步和异步的确认机制以及相应的证明验证流程,数据包会分成两个执行流程:

1.正常情况:超时内成功

2.超时情况:超时失败

IBC 应用数据包传输流程图

当发生超时情况时,说明此次传输失败,IBC 协议便会发起退款流程,同时需要注意的是 IBC 具有用户可配置的超时机制。此次的 Dragonberry 漏洞源自 ICS-23(IBC),该漏洞的根本原因在于用户可以伪造验证流程中的不存在证明(即未收到数据包的虚假证明),从而绕过安全校验,伪造出「合理的」IBC 超时情况来欺骗 IBC 协议,导致中继器发送带有虚假证明的超时数据包,并可能会升级为 ICS-20 双花问题,其漏洞的具体触发流程可以看下图。

Dragonberry 漏洞原理流程图

项目地址:https://github.com/cosmos/ibc-go/tree/00a680cda52690a4ba835bf37f53acc41c01bc7a/modules/core/04-channel

漏洞位置:https://github.com/cosmos/ibc-go/blob/00a680cda52690a4ba835bf37f53acc41c01bc7a/modules/core/04-channel/keeper/timeout.go#L117C28-L117C54

漏洞代码片段:

  • 案例二:IBC Security Advisory Huckleberry,传输过程漏洞

漏洞背景:UnreceivedPackets 仅通过查找查询中包含的每个序列号的相应数据包收据来构建响应。这仅适用于无序通道,因为有序通道使用的是 nextSequenceRecv 而不是数据包收据。因此,在有序通道上,通过 GetPacketReceipt 查询序列号不会找到其中的收据。

此问题的严重程度较轻,因为 ICS-20 FT 传输的通道大部分是无序的,并且中继器不依赖这个 grpc 端点来确定触发超时数据包。然而,假如目标链中有大量数据包,同时配置了用于 IBC 传输的有序通道,且没有对 grpc 响应进行分页,这将产生导致服务节点性能下降甚至崩溃的风险。其具体的触发流程可以看下图。

Huckleberry 漏洞原理流程图

项目地址:https://github.com/cosmos/ibc-go/blob/11297aaa61e651c16e6d4147a15be24ce55ba7cc/modules/core/04-channel/

漏洞位置:https://github.com/cosmos/ibc-go/blob/11297aaa61e651c16e6d4147a15be24ce55ba7cc/modules/core/04-channel/keeper/grpc_query.go#L408

漏洞代码片段:

IBC 协议的运用和扩展

  • 案例一:stride airdrop 漏洞,逻辑漏洞

漏洞背景:TryUpdateAirdropClaim 该函数将 IBC 数据包的发送者地址转换为名为 senderStrideAddress 的 Stride 地址,并从数据包元数据中提取 airdropId 和新的空投地址 newStrideAddress。然后调用 UpdateAirdropAddress 来更新 senderStrideAddress 和 ClaimRecord。随着 ClaimRecord 的更新,newStrideAddress 将能够领取空投。然而这里更新函数只校验了 sender 该请求的地址是否为空,未对 newStrideAddress 做校验,由于 ibc 允许 solo machine 连接实现 IBC-enabled 的链,因此这里就存在更新任意其他账户地址作为空投地址的安全风险。

项目地址:https://github.com/Stride-Labs/stride/tree/3a5c7bfcc3b8c5e7dd870f01bebeb9d949492203/x/autopilot

漏洞位置:https://github.com/Stride-Labs/stride/blob/3a5c7bfcc3b8c5e7dd870f01bebeb9d949492203/x/autopilot/module_ibc.go#L119

https://github.com/Stride-Labs/stride/blob/3a5c7bfcc3b8c5e7dd870f01bebeb9d949492203/x/autopilot/keeper/airdrop.go#L17

漏洞代码片段:


  • 案例二:neutron ibc 模块漏洞,gas 消耗漏洞

漏洞背景:智能合约为 IBC 事件的确认 / 超时支付的费用没有得到足够的验证,恶意智能合约可以利用这一点在 OnAcknowledgementPacket 和 OnTimeoutPacket 消息处理期间导致 ErrorOutOfGas 崩溃。这些崩溃不会通过 outOfGasRecovery 执行来恢复,这意味着交易不会包含在区块中,并且会导致 IBC 中继器重复提交消息,最终可能会造成中继器资金流失和网络废弃数据包过多的危害。

项目地址:https://github.com/neutron-org/neutron/blob/64868908b21f648ad5e8a9b48179134619544e2a/

漏洞位置:

https://github.com/neutron-org/neutron/blob/64868908b21f648ad5e8a9b48179134619544e2a/x/interchaintxs/keeper/ibc_handlers.go#L62

漏洞代码片段:

小结

根据上文对 IBC 协议安全问题的研究分析,其实不难发现,IBC 协议的安全问题分布范围广,且问题多样,但主要问题还是出现在 IBC 协议的实现和运用扩展上。在各大应用链逐渐丰富完善自身传统模块功能性的同时,为了贴合自身业务需求,优化运行效果,也在对应的 IBC 模块中添加了不同的代码实现。

除了上文提到 IBC 环节中的安全问题外,其他一些如 IBC 中间件的安全问题也在涌现,相信在未来,IBC 模块方面的安全问题会成为 Cosmos 生态安全中的重要一环。

总结

在针对 Cosmos 生态安全的探索与研究过程中,我们经历了复杂的审计、汇总和分类工作,探讨了关于 Cosmos 生态里最为关键的 Cosmos SDK 和 IBC 协议两者的安全问题,并通过丰富的实践经历,总结出大量通用的审计经验。

本报告突显了在面对支持跨链交互的异构网络时所面临的挑战,由于其组成元件复杂且分散,因此在对这些组件进行安全审计时同样具有挑战性,我们不仅需要通过已有的安全经验去排查固有的一些安全风险,还需要不断面临新的安全场景,分析新的安全问题。

尽管如此,我们依然相信,通过类似本报告所总结的一些通用场景和安全问题,可以逐步提高异构网络 Cosmos 生态整体的安全性。

声明:

  1. 本文转载自[CertiK],著作权归属原作者[CertiK],如对转载有异议,请联系Gate Learn团队,团队会根据相关流程尽速处理。
  2. 免责声明:本文所表达的观点和意见仅代表作者个人观点,不构成任何投资建议。
  3. 文章其他语言版本由Gate Learn团队翻译, 在未提及Gate.io的情况下不得复制、传播或抄袭经翻译文章。
* 投资有风险,入市须谨慎。本文不作为Gate.io提供的投资理财建议或其他任何类型的建议。
* 在未提及Gate.io的情况下,复制、传播或抄袭本文将违反《版权法》,Gate.io有权追究其法律责任。
即刻开始交易
注册并交易即可获得
$100
和价值
$5500
理财体验金奖励!