撰文:BitsLab

 

BitsLab 旗下 TonBit 再次于 TON 虚拟机(TVM)深层代码里挖出一枚「隐形炸弹」——RUNVM 指令非原子状态迁移漏洞。攻击者可借助子虚拟机耗尽 gas 的瞬间,污染父虚拟机的库(libraries)并诱发后续调用失败,最终导致依赖库完整性的合约出现异常行为。下面我们保留技术细节原文,为开发者呈现漏洞发现与验证的完整过程,帮助社区深入理解该问题,并提高对类似风险的防范意识。

 

以下是漏洞详述:

 

TVM 中的 RUNVM 指令可能污染调用者状态并导致库不可用。在 'RUNVM' 指令代码中发现新的漏洞。该漏洞允许污染调用者的状态。相关代码片段如下:

 

 

上述代码负责启动子虚拟机。其功能是将当前 VmState 中的'log'和'libraries'移动到新的 VmState 对象'new_state'中,然后用'new_state'替换当前 VmState。

 

问题在于该操作并非真正的原子操作。在执行'*this = std::move(new_state);'语句之前,虚拟机可能因 gas 耗尽而中止进程,导致'new_state'未能成功替换当前状态。此时'libraries'可能已被移出,使得子虚拟机的库处于被清除(移动)状态。

 

由于 RUNVM 指令通过 isolate_gas 参数实现了子虚拟机与父虚拟机之间的 gas 消耗隔离,这会引发以下场景:

 

即使子虚拟机触发 gas 耗尽异常,父虚拟机仍保留足够的 gas 继续执行。但由于失败的状态转移过程中子虚拟机已经移动/清除了'libraries',导致后续依赖'libraries'的操作都将失败。这种情况会使得某些假定库完整性的合约出现预期之外的行为。

 

漏洞验证(PoC 验证)

 

我们通过以下测试用例成功复现了该漏洞:

 

 

 

关键测试修改说明:

 

为了便于本地观察库状态,我们修改了 NOP 指令以强制注册一个库条目:

 

 

复现步骤:

 

1)将此测试用例添加到 crypto/test/vm.cpp 文件中

2)运行 test-vm 可执行程序

3)观察 XLOAD 指令执行时因空库而抛出的异常

 

预期行为:

 

  • NOP 指令执行后:库中包含 1 个条目

  • RUNVMX 指令执行后:尽管父虚拟机继续运行,但库变为空状态

  • XLOAD 指令执行失败并抛出异常

 

这充分证明了非原子性状态转移与 gas 隔离机制共同作用时,会产生违反执行上下文完整性的不一致状态。

 

本次发现再次体现了BitsLab 旗下TonBit在 TON 生态安全研究中的深厚实力。我们已第一时间将技术细节与缓解方案提交给 TON 基金会,并协助其完成修复。建议所有开发者在官方补丁发布后及时更新依赖库;同时在自研合约中加入更严谨的库完整性验证与 gas 管理逻辑,以防止类似问题被恶意利用。BitsLab 将继续秉持「负责任披露」原则,携手社区共同筑牢 Web 3 安全防线。