崩溃的RPC:内存安全区块链RPC节点新型漏洞解析

OKX欧易app

OKX欧易app

欧易交易所app是全球排名第一的虚拟货币交易所,注册领取6万元盲盒礼包!

APP下载   官网注册

CertiK的Skyfall团队最近在Aptos、StarCoin和Sui等多个区块链中发现了基于Rust的RPC节点的多个漏洞。由于RPC节点是连接dApp和底层区块链的关键基础设施组件,其稳健性对于无缝操作至关重要。区块链设计者都知道稳定RPC服务的重要性,因此他们采用Rust等内存安全语言来规避可能破坏RPC节点的常见漏洞。

采用内存安全语言(如Rust)有助于RPC节点避免许多基于内存破坏漏洞的攻击。然而,通过最近的审计,我们发现即使是内存安全的Rust实现,如果没有经过精心设计和审查,也很容易受到某些安全威胁的影响,从而破坏RPC服务的可用性。

本文我们将通过实际案例介绍我们对一系列漏洞的发现。

区块链RPC节点作用

区块链的远程过程调用(RPC)服务是Layer 1区块链的核心基础设施组件。它为用户提供重要的API前端,并作为通向后端区块链网络的网关。然而,区块链RPC服务与传统的RPC服务不同,它方便用户交互无需身份验证。服务的持续可用性至关重要,任何服务中断都会严重影响底层区块链的可用性。

审计角度:传统RPC服务器 VS 区块链RPC服务器

对传统RPC服务器的审计主要集中在输入验证、授权/认证、跨站请求伪造/服务器端请求伪造(CSRF/SSRF)、注入漏洞(如SQL注入、命令注入)和信息泄露等方面进检查。

然而,区块链RPC服务器的情况有所不同。只要交易是签名的,就不需要在RPC层对发起请求的客户端进行身份验证。作为区块链的前端,RPC服务的一个主要目标是保证其可用性。如果它失效,用户就无法与区块链交互,从而阻碍查询链上数据、提交交易或发布合约功能。

因此,区块链RPC服务器最脆弱的方面是“可用性”。如果服务器宕机,用户就失去了与区块链交互的能力。更严重的是,一些攻击会在链上扩散,影响大量节点,甚至导致整个网络瘫痪。

为何新区块链会采用内存安全的RPC

一些著名的Layer 1区块链,如Aptos和Sui,使用内存安全编程语言Rust实现其RPC服务。得益于其强大的安全性和编译时严格的检查,Rust几乎可以使程序免受内存破坏漏洞的影响,如堆栈溢出、和空指针解引用和释放后重引用等漏洞。

为了进一步确保代码库的安全,开发人员需严格遵循最佳实践,例如不引入不安全代码。在源代码中使用#![forbid(unsafe_code)]确保阻拦过滤不安全的代码。

崩溃的RPC:内存安全区块链RPC节点新型漏洞解析

区块链开发者执行Rust编程实践的例子

为了防止整数溢出,开发人员通常使用checked_add、checked_sub、saturating_add、saturating_sub等函数,而不是简单的加法和减法(+、-)。通过设置适当的超时、请求大小限制和请求项数限制来缓解资源耗尽。

Layer 1区块链中内存安全RPC威胁

尽管不存在传统意义上内存不安全的漏洞,但RPC节点会暴露在攻击者容易操纵的输入中。在内存安全RPC实现中,有几种情况会导致拒绝服务。例如,内存放大可能会耗尽服务的内存,而逻辑问题可能会引入无限循环。此外,竞态条件也可能构成威胁,并发操作可能会出现意外的事件序列,从而使系统处于未定义的状态。此外,管理不当的依赖关系和第三方库可能会给系统带来未知漏洞。

在这篇文章中,我们的目的是让人们关注可以触发 Rust 运行时保护的更直接的方式,从而导致服务自行中止。

显式的Rust Panic:一种直接终止RPC 服务的方法

开发人员可以有意或无意地引入显式panic代码。这些代码主要用于处理意外或异常情况。一些常见的例子包括:

assert!():当必须满足一个条件时使用该macro。如果断言的条件失败,程序将 panic,表明代码中存在严重错误。

panic!():当程序遇到无法恢复的错误且无法继续执行时调用该函数。

unreachable!():当一段代码不应该被执行时使用该macro。如果该macro被调用,则表示存在严重的逻辑错误。

unimplemented!()和todo!():这些宏是尚未实现功能的占位符。如果达到该值,程序将崩溃。

unwrap():该方法用于Option或Result类型,当遇到Err变量或None时会导致程序宕机。

漏洞一:触发Move Verifier中的assert!

Aptos区块链采用Move字节码验证器,通过对字节码的抽象解释进行引用安全分析。execute()函数是TransferFunctions trait实现的一部分,模拟基本块中字节码指令的执行。

崩溃的RPC:内存安全区块链RPC节点新型漏洞解析

函数execute_inner()的任务是解释当前字节码指令并相应地更新状态。如果我们已经执行到基本块中的最后一条指令,如index == last_index所示,函数将调用assert!(self.stack.is_empty())以确保栈为空。此行为背后的意图是保证所有操作都是平衡的,这也意味着每次入栈都有相应的出栈。

在正常的执行流程中,栈在抽象解释过程中始终是平衡的。堆栈平衡检查器(Stack Balance Checker)保证了这一点,它在解释之前对字节码进行了验证。然而,一旦我们将视角扩展到抽象解释器的范围,就会发现堆栈平衡假设并不总是有效的。

崩溃的RPC:内存安全区块链RPC节点新型漏洞解析

AbstractInterpreter中analyze_function漏洞的补丁程序

抽象解释器的核心是在基本块级别中模拟字节码。在其最初的实现中,在execute_block过程中,遇到错误会提示分析过程记录错误,并继续执行控制流图中的下一个块。这可能会造成一种情况:执行块中的错误会导致堆栈不平衡。如果在这种情况下继续执行,就会在堆栈不为空的情况下进行assert!检查,从而引发panic。

这就使得攻击者有机可趁。攻击者可通过在execute_block()中设计特定的字节码来触发错误,随后execute()有可能在堆栈不为空的情况下执行assert,从而导致assert检查失败。这将进一步导致panic并终止RPC服务,从而影响其可用性。

为防止出现这种情况,已实施的修复中,确保了在execute_block函数首次出现错误时会停止整个分析过程,进而避免了因错误导致堆栈不平衡而继续分析时可能发生的后续崩溃风险。这一修改消除了可能引起panic的情况,并有助于提高抽象解释器的健壮性和安全性。

漏洞二:触发StarCoin中的panic!

Starcoin区块链有自己的Move实现分叉。在这个Move repo中,Struct类型的构造函数中存在一个panic! 如果提供的StructDefinition拥有 Native 字段信息,就会显式触发这个panic!。

崩溃的RPC:内存安全区块链RPC节点新型漏洞解析

规范化例程中初始化结构体的显式panic

这种潜在风险存在于重新发布模块的过程中。如果被发布的模块已经存在于数据存储中,则需要对现有模块和攻击者控制的输入模块进行模块规范化处理。在这个过程中,"normalized::Module::new "函数会从攻击者控制的输入模块中构建模块结构,从而触发 "panic!"。

崩溃的RPC:内存安全区块链RPC节点新型漏洞解析

规范化例程的前提条件

通过从客户端提交特制的有效载荷,可以触发该panic。因此,恶意行为者可以破坏RPC服务的可用性。

崩溃的RPC:内存安全区块链RPC节点新型漏洞解析

结构初始化panic补丁

Starcoin的补丁引入了一个新的行为来处理Native情况。现在,它不会引起panic,而是返回一个空的ec。这减少了用户提交数据引起panic的可能性。

隐式 Rust Panic: 一种容易被忽视的终止RPC服务的方法

显式 panic 在源代码中很容易识别,而隐式panic则更可能被开发人员忽略。隐式panic通常发生在使用标准或第三方库提供的API时。开发人员需要彻底阅读和理解API文档,否则他们的Rust程序可能会意外停止。

崩溃的RPC:内存安全区块链RPC节点新型漏洞解析

BTreeMap 中的隐式 panic

让我们以Rust STD中的BTreeMap为例。BTreeMap是一种常用的数据结构,它以排序的二叉树形式组织键值对。BTreeMap提供了两种通过键值检索值的方法:get(&self, key: &Q)和index(&self, key: &Q)。

方法get(&self, key: &Q)使用键检索值并返回一个Option。Option可以是Some(&V),如果key存在,则返回值的引用,如果在BTreeMap中没有找到key,则返回None。

另一方面,index(&self, key: &Q)直接返回键对应的值的引用。然而,它有一个很大的风险:如果键不存在于BTreeMap中,它会触发隐式panic。如果处理不当,程序可能会意外崩溃,从而成为一个潜在漏洞。

事实上,index(&self, key: &Q)方法是std::ops::Index trait的底层实现。该特质为不可变上下文中的索引操作(即 container[index])提供了方便的语法糖。开发者可以直接使用 btree_map[key],调用 index(&self, key: &Q) 方法。然而,他们可能会忽略这样一个事实:如果找不到key,这种用法可能会触发panic,从而对程序的稳定性造成隐性威胁。

漏洞三:在Sui RPC中触发隐式panic

Sui模块发布例程允许用户通过RPC提交模块有效载荷。在将请求转发给后端验证网络进行字节码验证之前,RPC处理程序使用SuiCommand::Publish函数直接反汇编接收到的模块。

在这个反汇编过程中,提交模块中的code_unit部分被用来构建一个VMControlFlowGraph。该构建过程包括创建基本块,这些块存储在一个名为 "'blocks' "的BTreeMap中。该过程包括创建和操作该Map,在某些条件下,隐式panic会在这里触发。

下面是一段简化的代码:

崩溃的RPC:内存安全区块链RPC节点新型漏洞解析

创建VMControlFlowGraph时的隐式panic

在该代码中,通过遍历代码并为每个代码单元创建一个新的基本块来创建一个新的VMControlFlowGraph。基本块存储在一个名为block的BTreeMap中。

在对堆栈进行迭代的循环中,使用block[&block]对块图进行索引,堆栈已经用ENTRY_BLOCK_ID进行了初始化。这里的假设是,在block映射中至少存在一个ENTRY_BLOCK_ID。

然而,这一假设并不总是成立的。例如,如果提交的代码是空的,那么在“创建基本块”过程之后,“块映射”仍然是空的。当代码稍后尝试使用&blocks[&block].successors中的for succ遍历块映射时,如果未找到key,可能会引起隐式panic。这是因为blocks[&block]表达式本质上是对index()方法的调用,如前所述,如果键不存在于BTreeMap中,index()方法将导致panic。

拥有远程访问权限的攻击者可以通过提交带有空code_unit字段的畸形模块有效载荷来利用该函数的漏洞。这个简单的RPC请求会导致整个JSON-RPC进程崩溃。如果攻击者以最小的代价持续发送此类畸形有效载荷,就会导致服务持续中断。在区块链网络中,这意味着网络可能无法确认新的交易,从而导致拒绝服务(DoS)情况。网络功能和用户对系统的信任将受到严重影响。

崩溃的RPC:内存安全区块链RPC节点新型漏洞解析

Sui的修复:从RPC发布例程中移除反汇编功能

值得注意的是,Move Bytecode Verifier中的CodeUnitVerifier负责确保code_unit部分绝不为空。然而,操作顺序使RPC处理程序暴露于潜在的漏洞中。这是因为验证过程是在Validator节点上进行的,而该节点是在RPC处理输入模块之后的一个阶段。

针对这一问题,Sui通过移除模块发布RPC例程中的反汇编功能来解决该漏洞。这是防止RPC服务处理潜在危险、未经验证的字节码的有效方法。

此外,值得注意的是,与对象查询相关的其他RPC方法也包含反汇编功能,但它们不容易受到使用空代码单元的攻击。这是因为它们总是在查询和反汇编现有的已发布模块。已发布的模块必须已经过验证,因此,在构建VMControlFlowGraph时,非空代码单元的假设始终成立。

对开发人员的建议

在了解了显式和隐式panic对区块链中RPC服务稳定性的威胁后,开发人员必须掌握预防或降低这些风险的策略。这些策略可以降低服务意外中断的可能性,提高系统的弹性。因此CertiK的专家团队提出以下建议,并作为Rust编程的最佳实践为大家列出。

Rust Panic Abstraction: 尽可能考虑使用Rust的catch_unwind函数来捕获panic,并将其转换为错误信息。这可以防止整个程序崩溃,并允许开发人员以可控的方式处理错误。

谨慎使用API:隐式panic通常是由于滥用标准或第三方库提供的API而发生的。因此,充分理解API并学会适当处理潜在错误至关重要。开发人员要始终假设API可能会失效,并为这种情况做好准备。

适当的错误处理:使用Result和Option类型进行错误处理,而非求助于panic。前者提供了一种更可控的方式来处理错误和特殊情况。

添加文档和注释:确保代码文档齐全,并在关键部分(包括可能发生panic的部分)添加注释。这将帮助其他开发人员了解潜在风险并有效处理。

总结

基于Rust的RPC节点在Aptos、StarCoin和Sui等区块链系统中扮演着重要的角色。由于它们用于连接DApp和底层区块链,因此它们的可靠性对于区块链系统的平稳运行至关重要。尽管这些系统使用的是内存安全语言Rust,但仍然存在设计不当的风险。CertiK的研究团队通过现实世界中的例子探讨了这些风险,也足以证明了内存安全编程中需要谨慎和细致的设计。

本站所有软件信息均由用户上传发布,版权归原著所有。如有侵权/违规内容,敬请来信告知邮箱:764327034@qq.com,我们将及时撤销! 转载请注明出处:https://czxurui.com/zx/21521.html

打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023年07月18日
下一篇 2023年07月18日

相关推荐

  • 区块链地址如何查询,查区块链的地址要查什么地址

    一、区块链数据库怎么查询地址(区块链查看地址)如何通过区块链资产地址(数字钱包地址)查看该地址的区块链资产(数字货币)?用区块链浏览器就可以查看。在搜索输入框内输入想查询的钱包地址,如果你输入的地址不完整,但是这个地址之前有在区块链上进行过ETH交易或者被查询

    2024-12-23 08:30:02
    2 0
  • 如何导入比特币私钥,怎么导入区块链私钥信息

    一、【猫说】打开比特币钱包的两把钥匙:私钥、公钥如果不了解区块链,不知道公钥、私钥这些最基本的概念,拥有钱包对币圈新人来讲,就好像拿手指头去捅鳄鱼的脑袋,风险极高。此文谨献给币圈新朋友,帮助大家梳理比特币钱包的基本常识。区块链观察网在《区块链是什么》一文中

    2024-12-23 07:30:02
    2 0
  • 区块链etc能涨到多少,etc区块链是什么

    一、区块链中的硬分叉,以太经典ETC是什么意思以太经典(ETC)简史以太经典始于一个不幸的事件。2016年5月,去中心化自治组织(DAO)举行了一次代币销售,目标是建立一个基于区块链的风险投资,以资助Ethereum生态系统内未来的去中心化应用(DApps)。基本上,DAO是一个去中心化方

    2024-12-23 06:30:01
    4 0
  • 域链什么时间送币,哔哩哔哩区块链代币怎么领

    一、哔哩哔哩区块链代币怎么领***哔哩哔哩怎么拿币***区块链怎么赚钱?区块链是一项革命性的技术,它提供了去中心化、隐私保护以及图灵完备的智能合约技术基础,被誉为下一个“互联网革命”。通过购买区块链项目的数字资产,我们可以合理配置自己的财产,合理投资,依靠代币的

    2024-12-22 23:30:01
    3 0
  • 莱特币怎么进场,区块链怎么进入圈子

    一、区块链怎么挖矿的(区块链挖矿的成本不包括)区块链是什么,怎么用区块链赚钱?区块链是分布式数据存储、点对点传输、共识机制、加密算法等计算机技术的新型应用模式。所谓共识机制是区块链系统中实现不同节点之间建立信任、获取权益的数学算法。区块链的赚钱方法:1、推广

    2024-12-22 20:30:01
    5 0
  • 创世区块是什么,创世区块

    一、创世区块是谁创造的创世区块是由中本聪创建的。中本聪是比特币的创始人,他在2009年1月4日创建了比特币的创世区块,这是比特币区块链的第一个区块。创世区块中包含了初始的比特币奖励和创世交易信息,标志着比特币网络的诞生。中本聪的真实身份至今仍然未知,他选择保持匿

    2024-12-22 18:30:01
    6 0

发表回复

8206
验证码

评论列表(0条)

    暂无评论

ok交易所
已有100万用户加入ok交易所

立即下载