摘要
Cosmos SDK 在 2019年 5 月底发现存在严重安全漏洞,该团队随后发布了补丁,并与全球验证人共同进行了升级,从收到漏洞报告到修复主网共用了72小时。
攻击者可利用该漏洞绕过委托金赎回时的锁定时间。
在介绍漏洞细节之前,先介绍一下cosmos的投票机制。
staking:投票机制
Cosmos中持币人可以将自己的货币委托给validator,当validator出块时,持币人获得收益。
当持币人遇到了佣金更低、网络状态更好的validator,不想继续委托原来的validator时。
可以unbond之前的validator。这需要等待21天。21天结束之后,委托的货币会被返还,然后持币人就可以委托其他validator了。
redelegation:一键更换validator
redelegation功能 使持币人不用等待21天的unbonding周期,可以立即更换至其他validators。
唯一的限制是21天时间内,最多更换7次validators。
目前 Cosmostation 钱包已经支持redelegation功能。
漏洞介绍
Cosmos重委托漏洞,使得持币人在赎回委托金时,不必再等待21天的时间。
Cosmos 团队的 Jack Zampolin 分享了一个程序,可以发现那些利用漏洞提前撤回委托的恶意交易。
该漏洞导致7250个Atom代币被提前赎回,当时每个Atom价值6美元。
截止2019年5月31日,使用上述恶意方法解除委托的 Atoms 大约为43,500美元。
补丁代码分析
Cosmos SDK 0.34.6 版本发布了重委托漏洞的补丁,并在区块高度 482100 时(大约2019年5月31日早上 10 点)生效。
cosmos重委托漏洞 补丁commit 链接如下:
https://github.com/cosmos/cosmos-sdk/commit/80234baf91a15dd9a7df8dca38677b66b8d148c1
代码修改的重点在于
github.com/cosmos/cosmos-sdk/x/staking/keeper/delegation.go,L585-L638:
Keeper.Undelegate函数
可见Undelegate函数中592行做了一个硬分叉,分叉高度是UndelegatePatchHeight
等于482100
。
在分叉高度前的代码中,有一处关于completeNow
的判断
if completeNow {
balance := sdk.NewCoin(k.BondDenom(ctx), returnAmount)
if !balance.IsZero() {
if _, err := k.bankKeeper.UndelegateCoins(ctx, delAddr, sdk.Coins{balance}); err != nil {
return completionTime, err
}
}
return completionTime, nil
}
如果completeNow等于 True,就直接退还委托的货币,而无需等待21天。
在Keeper.getBeginInfo函数中,我们发现
要使completeNow == True,需要validator.status == sdk.Unbonded
不同的completeTime / completeNow
当持币人想要撤销对validator的委托时,需要等待completeTime后,委托金才会返还给持币人。
对于completeTime,不同情况有不同的值。
- 如果validator此时是Bonded状态,赎回委托金需要经历21天的时间。
- 如果validator处于UnBonding状态,持币人从该validator解绑定需要的锁定期等于该validator的锁定期(小于或等于21天)。
- 如果validator处于UnBonded状态,则不需要锁定期,持币人抵押的股权可立即变回代币。这也就是上面代码中提到的
validator.status == sdk.Unbonded
则completeNow == True
这样设计的本意的是,当validator节点因作恶或意外被Jail后,持币人可以尽快取回抵押的股权,避免造成损失。
漏洞利用方法
攻击者想要撤销对validatorA的委托,拿回委托金。但是又不想等待21天的unbonding。
于是攻击者使用cosmostation钱包提供的redelegation方法,将委托对象立刻转换为一个状态为Unbonded的validator。
接着再进行undelegate操作,Keeper.Undelegate函数收到completeNow == True
便调用k.bankKeeper.UndelegateCoins
立刻归还了委托金。
攻击者便可以绕过锁定期限制,瞬间赎回委托金。
漏洞危害
漏洞不会造成用户的财产损失,但是可以让攻击者绕过21天的委托金锁定。
这会让cosmos设计的经济模型变得不稳定,破坏交易的公平。
总结
cosmos重委托漏洞的本质,是新功能redelegation和旧功能unbonded立刻赎回机制,两者的逻辑出现冲突。
在开发过程中,开发人员需要对新功能可能涉及到的旧代码有充分的了解。
参考资料
Cosmos staking module
Node A-Team 分析文章 Cosmos Hub Security Vulnerability regarding Redelegation and Unbonding
Cosmos攻略:Staking 新手实用工具指南
cosmos源码分析之四Staking模块
jessysaurusrex 记录的几个cosmos 1day
Cosmos的解绑定漏洞分析