Cosmos Hub 链节点崩溃漏洞
北京时间3月11日凌晨,知名区块链项目 Cosmos Hub 的节点客户端 Gaia 发布更新,修复了一个严重漏洞,该漏洞可能造成Cosmos Hub链节点崩溃,影响范围为Gaia <=V4.0.6。
长亭区块链安全团队第一时间跟进分析,现公开分析报告,提醒并帮助相关方尽快检查修复。
漏洞摘要
Gaia项目未限制distribution模块账户作为直接转账收款人。这使得DistributionAccount和FeePoolCommunity之间的平衡可能被打破,从而触发Crisis模块的节点状态异常告警。最终导致链节点崩溃。
经分析,漏洞细节如下:
漏洞详情
Gaia项目中Crisis模块的AssertInvariants函数用于检查节点的状态是否正常。一旦节点状态异常,将会触发panic使节点崩溃。
// AssertInvariants asserts all registered invariants. If any invariant fails,
// the method panics.
func (k Keeper) AssertInvariants(ctx sdk.Context) {
...
for i, ir := range invarRoutes {
...
if res, stop := ir.Invar(ctx); stop {
// TODO: Include app name as part of context to allow for this to be
// variable.
panic(fmt.Errorf("invariant broken: %sn"+
"tCRITICAL please submit the following transaction:n"+
"tt tx crisis invariant-broken %s %s", res, ir.ModuleName, ir.Route))
}
}
...
}
Gaia各模块的状态检测项互不相同,其中我们来看distribution模块做了什么样的检查。检查的对应代码在x/distribution/keeper/invariants.go,L136-L162:
// ModuleAccountInvariant checks that the coins held by the distr ModuleAccount
// is consistent with the sum of validator outstanding rewards
func ModuleAccountInvariant(k Keeper) sdk.Invariant {
return func(ctx sdk.Context) (string, bool) {
...
communityPool := k.GetFeePoolCommunityCoins(ctx)
...
macc := k.GetDistributionAccount(ctx)
balances := k.bankKeeper.GetAllBalances(ctx, macc.GetAddress())
broken := !balances.IsEqual(expectedInt)
return sdk.FormatInvariant(...), broken
}
}
我们看到,正常状态下DistributionAccount的余额应等于FeePoolCommunity要发放的手续费奖励。
如果我们可以向DistributionAccount或FeePoolCommunity中转账,使其不等,就可以触发状态异常,crisis安全检测无法通过,最终导致节点崩溃。
为了实现这个攻击思路,我们需要关注BankKeeper中"向ModuleAccount转账"的功能实现。
稍微阅读一下代码我们可以发现,ModuleAccount会被列入黑名单而无法作为转账的收款地址。
对应的限制代码如下:
// BlockedAddrs returns all the app's module account addresses that are not
// allowed to receive external tokens.
func (app *GaiaApp) BlockedAddrs() map[string]bool {
blockedAddrs := make(map[string]bool)
for acc := range maccPerms {
blockedAddrs[authtypes.NewModuleAddress(acc).String()] = !allowedReceivingModAcc[acc]
}
return blockedAddrs
}
但处于allowedReceivingModAcc中的ModuleAccount被视为特例,并不会被拉黑。
我们跟进allowedReceivingModAcc,看看都有哪些ModuleAccount可以被转账呢。
// module accounts that are allowed to receive tokens
allowedReceivingModAcc = map[string]bool{
distrtypes.ModuleName: true, // ModuleName = "distribution"
}
可以看到,这个被Gaia视为特列,可以作为直接转账的收款地址的ModuleAccount刚好就是DistributionAccount。
这使得我们可以向DistributionAccount转账来打破DistributionAccount和FeePoolCommunity之间的平衡,从而触发panic。
至此,我们分析出了完整的漏洞利用链。就是这里的非预期转账权限,造成了此次链节点崩溃的漏洞。
利用场景
攻击者通过client发布send交易,向DistributionAccount账户地址转账,即可使Gaia节点崩溃。
修复情况
最新版v4.1.0中,漏洞已被修复。
在Gaia Pull Request 755中,将/app/app.go第247行中的app.BlockedAddrs()改为了
app.ModuleAccountAddrs(),将distribution ModuleAccount加入了bank模块转账接收方的黑名单中使其不能作为直接转账的收款地址,修复了该链崩溃漏洞。
应对建议
如果您是Cosmos Hub的参与者,且运行着自己的Gaia节点,那么请及时升级您的Gaia至最新版本(V4.1.0)。
如果您是使用Cosmos-SDK进行公链开发的项目方,请您关闭distribution的被转账权限或者更新Cosmos-SDK版本。
此外,如果您仍然对该漏洞有疑问,或有其他安全顾虑,欢迎联系长亭区块链安全团队,我们可提供专业的安全咨询与审计服务,帮助您完善项目的安全建设。
本文始发于微信公众号(长亭安全课堂):区块链漏洞风险提示|Cosmos Hub 链节点崩溃漏洞
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论