# Move语言中的整数溢出漏洞分析## 前言在对Aptos Moveevm进行深入研究后,我们发现了一个新的整数溢出漏洞。这个漏洞的触发过程相对更加有趣,下面我们将对这个漏洞进行深入分析,并介绍一些Move语言的背景知识。通过本文的讲解,相信你会对Move语言有更深入的理解。Move语言在执行字节码之前会验证代码单元。验证过程分为4个步骤,而这个漏洞出现在reference_safety步骤中。## Move中的引用安全Move语言支持两种类型的引用:不可变引用(&)和可变引用(&mut)。不可变引用用于从结构中读取数据,而可变引用用于修改数据。使用适当的引用类型有助于维护安全性并识别读取模块。在Move的引用安全模块中,会以函数为单位,扫描函数中基本块的字节码指令,以验证所有引用操作是否合法。验证引用安全性的主要流程包括执行基本块、生成后置状态、合并前后状态等步骤。## 漏洞分析漏洞出现在引用安全模块的join_函数中。当函数参数长度和局部变量长度之和大于256时,由于使用u8类型表示local变量,会导致整数溢出。虽然Move有校验locals个数的过程,但在check bounds模块中只校验了locals,并未包括参数长度。开发人员似乎意识到需要检查参数和本地值的总和,但代码中只校验了本地变量的个数。## 从整数溢出到DoS攻击利用这个整数溢出漏洞,攻击者可以制造一个循环代码块,改变块的状态。当再次执行execute_block函数时,如果指令需要访问的索引在新的AbstractState locals map中不存在,将导致DoS攻击。在reference safety模块中,MoveLoc/CopyLoc/FreeRef等操作码可能会触发这种情况。例如,在copy_loc函数中,如果LocalIndex不存在会导致panic,进而导致整个节点崩溃。## 漏洞复现可以通过以下PoC代码在git中重现这个漏洞:movepublic fun test(a: u64, b: u64, c: u64, d: u64) { let x = 0; loop { if (x == 1) { break }; x = x + 1; }}触发DoS的步骤如下:1. 第一次执行execute_block函数,设置parameters和locals均为SignatureIndex(0),导致num_locals为264。执行join_函数后,新的locals map长度变为8。2. 第二次执行execute_block函数时,执行move代码第一条指令copyloc(57)。由于此时locals只有长度8,offset 57不存在,导致get(57).unwrap()函数返回None,最终引发panic。## 总结这个漏洞表明没有绝对安全的代码。虽然Move语言在代码执行前进行了静态校验,但仍可能被溢出漏洞绕过。这再次强调了代码审计的重要性。对于Move语言,我们建议在运行时增加更多的检查代码,以防止意外情况发生。目前Move主要在verify阶段进行安全检查,但一旦验证被绕过,运行阶段缺乏足够的安全加固可能导致更严重的问题。作为Move语言安全研究的领导者,我们将继续深入研究Move的安全问题,并在后续分享更多发现。
Move语言整数溢出漏洞分析:从引用安全到DoS攻击
Move语言中的整数溢出漏洞分析
前言
在对Aptos Moveevm进行深入研究后,我们发现了一个新的整数溢出漏洞。这个漏洞的触发过程相对更加有趣,下面我们将对这个漏洞进行深入分析,并介绍一些Move语言的背景知识。通过本文的讲解,相信你会对Move语言有更深入的理解。
Move语言在执行字节码之前会验证代码单元。验证过程分为4个步骤,而这个漏洞出现在reference_safety步骤中。
Move中的引用安全
Move语言支持两种类型的引用:不可变引用(&)和可变引用(&mut)。不可变引用用于从结构中读取数据,而可变引用用于修改数据。使用适当的引用类型有助于维护安全性并识别读取模块。
在Move的引用安全模块中,会以函数为单位,扫描函数中基本块的字节码指令,以验证所有引用操作是否合法。验证引用安全性的主要流程包括执行基本块、生成后置状态、合并前后状态等步骤。
漏洞分析
漏洞出现在引用安全模块的join_函数中。当函数参数长度和局部变量长度之和大于256时,由于使用u8类型表示local变量,会导致整数溢出。
虽然Move有校验locals个数的过程,但在check bounds模块中只校验了locals,并未包括参数长度。开发人员似乎意识到需要检查参数和本地值的总和,但代码中只校验了本地变量的个数。
从整数溢出到DoS攻击
利用这个整数溢出漏洞,攻击者可以制造一个循环代码块,改变块的状态。当再次执行execute_block函数时,如果指令需要访问的索引在新的AbstractState locals map中不存在,将导致DoS攻击。
在reference safety模块中,MoveLoc/CopyLoc/FreeRef等操作码可能会触发这种情况。例如,在copy_loc函数中,如果LocalIndex不存在会导致panic,进而导致整个节点崩溃。
漏洞复现
可以通过以下PoC代码在git中重现这个漏洞:
move public fun test(a: u64, b: u64, c: u64, d: u64) { let x = 0; loop { if (x == 1) { break }; x = x + 1; } }
触发DoS的步骤如下:
第一次执行execute_block函数,设置parameters和locals均为SignatureIndex(0),导致num_locals为264。执行join_函数后,新的locals map长度变为8。
第二次执行execute_block函数时,执行move代码第一条指令copyloc(57)。由于此时locals只有长度8,offset 57不存在,导致get(57).unwrap()函数返回None,最终引发panic。
总结
这个漏洞表明没有绝对安全的代码。虽然Move语言在代码执行前进行了静态校验,但仍可能被溢出漏洞绕过。这再次强调了代码审计的重要性。
对于Move语言,我们建议在运行时增加更多的检查代码,以防止意外情况发生。目前Move主要在verify阶段进行安全检查,但一旦验证被绕过,运行阶段缺乏足够的安全加固可能导致更严重的问题。
作为Move语言安全研究的领导者,我们将继续深入研究Move的安全问题,并在后续分享更多发现。