CN117951711A - 一种智能合约升级漏洞的检测方法 - Google Patents

一种智能合约升级漏洞的检测方法 Download PDF

Info

Publication number
CN117951711A
CN117951711A CN202311802367.0A CN202311802367A CN117951711A CN 117951711 A CN117951711 A CN 117951711A CN 202311802367 A CN202311802367 A CN 202311802367A CN 117951711 A CN117951711 A CN 117951711A
Authority
CN
China
Prior art keywords
contract
contracts
code
control flow
program
Prior art date
Legal status (The legal status is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the status listed.)
Pending
Application number
CN202311802367.0A
Other languages
English (en)
Inventor
李志伟
Current Assignee (The listed assignees may be inaccurate. Google has not performed a legal analysis and makes no representation or warranty as to the accuracy of the list.)
Guangdong Qilian Technology Co ltd
Original Assignee
Guangdong Qilian Technology Co ltd
Priority date (The priority date is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the date listed.)
Filing date
Publication date
Application filed by Guangdong Qilian Technology Co ltd filed Critical Guangdong Qilian Technology Co ltd
Priority to CN202311802367.0A priority Critical patent/CN117951711A/zh
Publication of CN117951711A publication Critical patent/CN117951711A/zh
Pending legal-status Critical Current

Links

Landscapes

  • Stored Programmes (AREA)

Abstract

本发明属于合约漏洞检测领域,尤其是一种智能合约升级漏洞的检测方法,针对现有的智能合约无法检测内存冲突和变形智能合约的访问控制问题问题,现提出如下方案,其包括以下步骤:S1:获取合约,S2:生成抽象语法树,获取槽映射关系;S3:编译源代码获得字节码,再反汇编得到操作码特征;S4:根据上述获得的槽映射关系与操作码特征,通过符号执行动态的构建控制流图;本发明能够检测可升级智能合约特有的内存冲突漏洞,也关注到了使用率较低的create2模式下创建的合约的自毁函数权限访问控制漏洞,能够填补这方面漏洞检测的空白,构建出精度更高的控制流图,从而提高漏洞检测的精度。

Description

一种智能合约升级漏洞的检测方法
技术领域
本发明涉及合约漏洞检测技术领域,尤其涉及一种智能合约升级漏洞的检测方法。
背景技术
区块链是一种分布式存储系统,该系统由多个节点组成。区块链的底层是由许多区块组成的链,每个区块由区块头和区块体构成,根据哈希值将彼此连接在一起。每当一个新区块被生成时,所有区块都会参与到它的验证中,通过验证后才能加入到区块链中。区块链存在于每个节点的服务器中,修改区块链中的信息需要征得半数以上的节点同意并修改所有节点中的信息,因此篡改区块链信息是几乎不可能的事情,区块的内容被认为具有不可篡改性。
在第二代区块链中,智能合约是重要组成部分。智能合约是运行在区块链上的程序代码,是一种计算机化的交易协议,其中的合约条款会在满足条件时自动执行。基于区块链技术,智能合约一旦部署上链就无法篡改,并且所有智能合约都是公开可见的。因此,如果智能合约中存在漏洞,那么就很容易被黑客利用进行恶意攻击,从而使智能合约账户损失虚拟资产。
为了解决部署后的智能合约中发现的漏洞,以及根据需求实现新的拓展功能,人们对于可升级智能合约的需求越来越大,对可升级智能合约的使用变得越来越普遍。目前主流的可升级合约是UUPS代理模式,将一个合约分成两个:代理合约和逻辑合约,代理合约中存储用户数据以及逻辑合约的地址,负责与用户交互,并将用户的调用(例如,出价竞标)委托给包含实际业务逻辑(例如,实际的出价功能函数)的逻辑合约。升级时,开发人员部署一个新的逻辑合约,然后将代理合约中的旧地址替换为新地址即可完成升级。值得注意的是,还有其它实现可升级性的方法。另一种选择是使用CREATE2操作码的变形智能合约,它能够将包含自毁功能的合约部署到预定的地址,升级时只需将旧版本合约销毁,然后将升级版本重新部署到相同的地址。
显然,可升级智能合约的使用在带来方便的同时,也会带来新的安全问题。尽管人们已经开发了许多技术来检测常规的智能合约,对于可升级智能合约的特有漏洞却缺乏相应的检测手段。因此本发明注重于检测可升级智能合约的特有漏洞,以保证智能合约升级的安全性与可靠性。
可升级智能合约越来越普遍,现有技术对于普通智能合约漏洞的检测方法有很多,但是专门针对于可升级智能合约的漏洞检测方法还很少。本发明提出的方法则针对可升级合约的特有漏洞进行检测,填补了这方面的空白。
现有技术基于控制流图对合约进行检测的方法中,都是根据合约字节码和操作码来得到智能合约的子结构特征和关联关系进而构建控制流图。本发明则在此基础上使用符号执行来获取控制流图,因此在构建控制流图的过程中可以获取更多的语义信息以及对应的状态变量的变化关系,并且获得更精确的控制流图,更有效地检测漏洞。
本申请人检索的相近技术方案:
1、申请公布号CN112631611A,公开了一种智能庞氏骗局合约识别方法及装置,包括根据智能合约的字节码,通过反汇编处理方式,提取操作码特征;根据智能合约的字节码提取智能合约对应的控制流图特征;将操作码特征与控制流图特征作为智能合约识别模型的输入,以通过智能合约识别模型的分类运算,得到智能合约对应的智能庞氏骗局合约识别结果。
2、申请公布号CN116028495A,公开了智能合约的检测方法及装置,包括获取智能合约对应的源代码;通过语法分析器解析源代码,并根据解析结果生成源代码对应的抽象语法树,其中,语法分析器用于对未经编译的任意版本的源代码进行语法分析;遍历抽象语法树中的多个树结点;根据预设条件检测多个树结点中是否包含有异常树结点,其中,预设条件用于表征异常函数代码的代码特征,异常函数代码为存在信息安全漏洞的函数代码,异常树结点对应的函数代码的代码特征与预设条件相匹配;在多个树结点中存在异常树结点的情况下,确定智能合约为存在信息安全风险的异常智能合约。
3、申请公布号CN116127480A,公开了一种智能合约检测方法及装置,包括通过反编译分别获取旧智能合约对应的第一操作码记录和新智能合约对应的第二操作码记录,第一操作码记录和第二操作码记录分别用于,记录旧智能合约和新智能合约反编译时,执行的各操作码以及各操作码的执行顺序;根据第一操作码记录和第二操作码记录,分别获取旧智能合约中各第一状态变量各自的第一存储位置信息,以及新智能合约中各第二状态变量各自的第二存储位置信息;分别比较各第一存储位置信息与对应的第二存储位置信息是否存在差异,若存在,则更新失败。上述方法中,可以保证更新后获得的新智能合约,可以继承旧智能合约的服务。
4.授权公告号CN106648818B,公开了一种目标代码控制流图生成系统,公开了一种基于符号执行的目标代码控制流图生成系统,该系统包括预处理模块、反汇编与控制流图生成模块、目标地址分析模块。对间接地址跳转地址进行了分析,其生成的控制流图,相比于一般模块生成的控制流图,具有更加精确、相对完整的特点。
现有技术存在问题:
1.不能检测内存冲突问题。
在可升级智能合约中,因为存在升级这一过程,因此需要对旧合约存储的数据进行正确的继承,才能够在升级后保存原来的用户数据并加以操作。而升级后的合约新添加的功能与变量,也会与原来的用户数据存储在同一存储空间内,因此必须正确分配内存,在不与旧的数据冲突的同时保持原有的“紧凑”布局,以节省打包数据的开销。现有技术只关心了常规智能合约可能发生的漏洞,而不能检测可升级智能合约中最容易发生的内存冲突问题。本发明能够准确的检测在合约升级的过程中,数据能否被正常的继承使用,是否产生内存冲突的漏洞。
2.不能检测变形智能合约的访问控制问题
变形智能合约的升级过程中存在合约自毁这一步骤,而合约自毁会销毁旧合约并转走当前账户的余额,对其的权限控制应非常谨慎。由于这一升级模式的使用率较低,现有技术没有针对此类合约进行必要的访问控制检查。本发明能够准确检测具有自毁功能的合约,是否有对自毁功能的访问权限做出正确的限制,是否存在访问控制漏洞。
发明内容
本发明的目的是为了解决现有技术中存在的智能合约无法检测内存冲突和变形智能合约的访问控制问题,而提出的一种智能合约升级漏洞的检测方法。
为了实现上述目的,本发明采用了如下技术方案:
一种智能合约升级漏洞的检测方法,包括以下步骤:
S1:获取合约;
分别输入UUPS代理合约(或create2工厂合约)、旧版本合约、新版本合约(旧版本合约的更新版本);
S2:生成抽象语法树,获取槽映射关系;
首先通过语法分析器解析源代码,并根据解析结果生成源代码对应的抽象语法树,可以使用Solidity官方依据c++语言编写的编译器solc,或者ANTLR4来生成抽象语法树,抽象语法树中含有合约定义结点以及合约定义结点下的函数声明子结点,每个树结点都表征了智能合约中的一个函数代码的定义信息;
智能合约中的数据可以存储在插槽、内存或calldata中,插槽用于永久数据,而内存用于合约执行期间的临时使用,智能合约中的每个可变的状态变量在编译过程中都会被分配一个槽ID,表示其存储空间,这些槽ID有助于合约在执行期间确定状态变量的确切存储位置;
通过分析抽象语法树,可以静态地获取合约中状态变量的槽ID,并记录它们的名称和数据类型,形成槽映射关系,这有助于在之后符号执行的过程中更方便的监控这些变量的操作码,同时抽象语法树可检查函数声明,通过检查函数关键字,比如“upgradeable”和“proxy”,可以识别出是UUPS模式的代理合约还是create2模式的代理合约;
S3:编译源代码获得字节码,再反汇编得到操作码特征;
S3.1:智能合约编译后的字节码以二进制的形式表示,其中包括了部署代码、runtime代码、auxdata三个部分,而智能合约部署后在链上执行的时runtime代码,我们要提取的操作码特征就在runtime代码中,操作码由以太坊定义,目前已定义了142种操作码,包括算术运算、位运算、存储操作、跳转操作码;
字节码将通过反汇编模块获取汇编代码,再进一步提取操作码,例如在以太坊中,可以使用evm disasm将字节码转化为汇编代码,通过记录执行的各操作码以及各操作码的执行顺序,我们可以知道执行特定操作码时获取的状态变量的槽ID,再根据之前得到的槽映射关系确认该槽ID对应的状态变量,从而将特定操作码与不同的状态变量联系起来;
S3.2:需要特别关注的操作码以及理由如下:;
CREATE2操作码:使用create2方式部署合约的代理合约中,不论是自定义的创建方法还是官方提供的创建方法都要涉及到CREATE2操作码;
调用外部合约操作码CALLCODE:代理合约调用逻辑合约的方式一;
委托调用操作码DELEGATECALL:代理合约调用逻辑合约的方式二;
存储操作码,包括但不限于MSTORE、MLOAD、SSTORE:逻辑合约在执行过程中需要检查并调用用户数据,会对状态变量进行读取、存储、更新等操作,这涉及到存储相关的操作码;
堆栈操作码,包括但不限于PUSH、DUP、SWAP:许多逻辑合约都要管理各自的虚拟资产,因此会有代币授权、转账操作,这涉及到堆栈相关的操作码;
SELFDESTRUCT操作码:要利用create2向同一地址部署合约,则被部署的合约必须存在自毁函数,该函数会涉及到SELFDESTRUCT操作码;
S4:根据上述获得的槽映射关系与操作码特征,通过符号执行动态的构建控制流图;
S4.1:符号执行技术指的是通过程序分析的方法,确定哪些输入向量会导致程序的对应执行结果向量的方法。它的关键思想是把程序的输入值变为符号值,那么经过代码计算后的输出值就会是一个符号输入值的函数,例如,有一个程序执行的路径是true和false条件的序列,这些条件是在分支语句处产生的。在序列的分支位置如果约束值是true,那么意味着当前路径的条件语句走的是then这个分支;反之如果是false就意味着程序执行走的是else分支的路径;
在运行过程中,符号执行会在全局维护两个变量,其一是符号状态σ,它表示的是一个从变量到符号表达式的映射,其二是符号化路径约束PC,用来表示路径约束条件,在符号执行的开始,符号状态σ会先初始化为一个空的映射,而符号化路径约束PC初始化为true,σ和PC在符号执行的过程中会根据分支条件语句的不同而不断更新,在符号执行结束时,PC就会用约束求解器进行求解,以生成实际的输入值。这个实际的输入值如果用程序执行,就会走符号执行过程中探索的那条路径,即此时PC的公式所表示的路径;
S4.2:控制流图是程序代码的一种表征形式,是一个过程或程序的抽象数据结构,代表了一个程序在执行过程中所有会被执行的路径,控制流图是以基本块为节点的有向图G=(N,E),其中N是节点集合,表示程序中的基本块;E是基本块之间边的集合,每个控制流图都存在至少两个指定的块:输入块和输出块;
在控制流图构造的过程中,通常会遭遇到间接地址跳转的问题,间接跳转地址是指目标地址存放在内存或寄存器中的跳转地址,这类值通常无法通过直接的静态分析得到。如果使用近似值的模块对控制流进行扩充,会导致结果相对不够精确,同时会引入不该存在的控制流路径;
在可升级智能合约中,由于逻辑合约与代理合约部署在不同地址,同时对用户数据有大量的调用更新,因此在合约执行的过程中会遇到许多计算变量地址值的情况,相应的也会有存在间接地址跳转的问题。因此在构建可升级智能合约控制流图的过程中,当遇到间接地址跳转问题时,使用符号执行进行辅助可以生成更加精确的控制流图节点;
S4.3:下面是控制流图的基本构建流程参考:
构建控制流图基本块,基本块指的是程序顺序执行的语句序列。对一个基本块来说,执行时只从其入口进入,从其出口退出。遇到第一条指令,结束当前基本块,并将该指令作为一个新块的第一条指令;遇到跳转、分支、循环指令,将该指令作为当前块的最后一条指令,并结束当前块。如果遇到的跳转指令计算的地址值为间接地址,则使用符号执行计算路径条件,得到更加精确的下一目标地址值。遇到其他语句直接将其加入到当前基本块;
构建控制流图有向边,有向边能够显示智能合约内各基本块之间的相互关系、动态执行状态等,如果从基本块A的出口转向基本块B,则从基本块A到B有一条有向边表示从A到B存在一条可执行路径,即在执行完基本块A中的程序后,有可能顺序执行基本块B中的程序;
S4.4:检测漏洞类别;
内存冲突:新合约的存储变量与代理合约的变量是否存在覆盖情况、新合约能否正常继承旧合约的变量;
理由:
在标准计算机程序执行过程中,应妥善控制内存的分配,以便不同的变量和数据结构不会冲突并损坏彼此的数据,通常由内存分配器处理这一项任务,记录通常是"紧凑地"存储,数据不会在地址空间中被随意安排,这也是分配者的责任,但Solidity不具有存储控制分配器,其任务的处理方式也不同,智能合约将状态变量的值存储在插槽中,从插槽0开始递增,基本固定大小值类型(例如uint256)占用一个插槽,此外,多个变量有时可以打包到一个插槽中,在使用时拆包;
对于使用继承的合约,状态变量的顺序由合约的C3线性顺序决定,并从最底层的合约开始,修改这些规则将破坏与之前版本合约的兼容性,因此这一规则在未来也不太可能发生变化;
上述规则是合约中状态变量在存储中的布局,以下简称为存储布局。由此我们可以得知,在可升级智能合约中,代理合约的存储中记录数据的旧版本合约具有自己的变量和存储布局,更新后的新版本合约也具有其自己的存储布局,并且必须能够处理根据以前的存储布局形成的数据,同时不要忘记还有代理合约本身的代码,它也有一个与当前的智能合约版本同时存在的存储布局,新版本合约要正确继承旧合约的存储布局,同时若有定义新的变量则不能与代理合约原有的存储布局发生冲突,即它们不能将相同的插槽用于不同的数据;
自毁函数访问控制漏洞:自毁函数是否有Onlyowner修饰符;
理由:
自毁函数会销毁当前合约,并转走当前账户余额,对其访问权限应谨慎对待,通常认为该功能只应给合约拥有者使用,而以太坊目前最主流的访问控制手段是使用OpenZeppelin代码库提供的Ownable合约来进行管理的onlyOwner模式,它是最常见也是最容易实现的访问控制方法,为智能合约设置了唯一的管理员角色。通过继承Ownable合约,子合约就可以在定义函数时使用onlyOwner修饰符,这些被修饰的函数就要求交易发起账号必须是合约的管理员。
具体检测过程:
正如前面提到的,利用槽映射关系和操作码特征,我们可以在符号执行的过程中找到有漏洞的代码。通过分析抽象语法树,我们得到了槽映射关系,由槽映射关系可以知道各个状态变量与其对应的槽id。在根据操作码序列执行符号执行构建控制流图时,我们可以确认新版本合约在执行特定操作码对应的函数时操作的状态变量,进而做相应的判断:若旧版本合约中有相对应的状态变量,则检查其对应的插槽与旧合约对应的状态变量插槽是否相同,不相同则说明继承错误,程序报告错误;若新合约执行函数时操作的状态变量在旧合约中没有相对应的状态变量,则检查其插槽是否与代理合约中的状态变量的插槽相同,若相同则发生冲突,程序报告错误;
特别的,对于create2模式部署的合约还需检查自毁函数的访问控制,结合SELFDESTRUCT操作码和控制流图检查对应的函数是否有Onlyowner修饰符,若没有则报告错误。
本发明中,分析源代码生成抽象语法树,通过分析抽象语法树获取智能合约中的状态变量与插槽ID的映射关系。结合操作码特征,使用符号执行动态的构建控制流图,并在这个过程中得到特定操作码与对应的状态变量的关系,以便检查漏洞错误。能够检测可升级智能合约中特有的内存冲突漏洞,也能够检测create2合约自毁函数的访问控制漏洞。
本发明重视目前越来越受欢迎的可升级智能合约的安全问题,能够检测可升级智能合约特有的内存冲突漏洞,也关注到了使用率较低的create2模式下创建的合约的自毁函数权限访问控制漏洞,能够填补这方面漏洞检测的空白,在检测过程中使用了抽象语法树,并使用符号执行来构建控制流图,能够获取更详细准确的信息,构建出精度更高的控制流图,从而提高漏洞检测的精度。
附图说明
图1为本发明提出的一种智能合约升级漏洞的检测方法的流程图。
具体实施方式
下面将结合本发明实施例中的附图,对本发明实施例中的技术方案进行清楚、完整地描述,显然,所描述的实施例仅仅是本发明一部分实施例,而不是全部的实施例。
实施例一
参照图1,一种智能合约升级漏洞的检测方法,包括以下步骤:
S1:获取合约;
分别输入UUPS代理合约(或create2工厂合约)、旧版本合约、新版本合约(旧版本合约的更新版本);
S2:生成抽象语法树,获取槽映射关系;
首先通过语法分析器解析源代码,并根据解析结果生成源代码对应的抽象语法树,可以使用Solidity官方依据c++语言编写的编译器solc,或者ANTLR4来生成抽象语法树,抽象语法树中含有合约定义结点以及合约定义结点下的函数声明子结点,每个树结点都表征了智能合约中的一个函数代码的定义信息;
智能合约中的数据可以存储在插槽、内存或calldata中,插槽用于永久数据,而内存用于合约执行期间的临时使用,智能合约中的每个可变的状态变量在编译过程中都会被分配一个槽ID,表示其存储空间,这些槽ID有助于合约在执行期间确定状态变量的确切存储位置;
通过分析抽象语法树,可以静态地获取合约中状态变量的槽ID,并记录它们的名称和数据类型,形成槽映射关系,这有助于在之后符号执行的过程中更方便的监控这些变量的操作码,同时抽象语法树可检查函数声明,通过检查函数关键字,比如“upgradeable”和“proxy”,可以识别出是UUPS模式的代理合约还是create2模式的代理合约;
S3:编译源代码获得字节码,再反汇编得到操作码特征;
S3.1:智能合约编译后的字节码以二进制的形式表示,其中包括了部署代码、runtime代码、auxdata三个部分,而智能合约部署后在链上执行的时runtime代码,我们要提取的操作码特征就在runtime代码中,操作码由以太坊定义,目前已定义了142种操作码,包括算术运算、位运算、存储操作、跳转操作码;
字节码将通过反汇编模块获取汇编代码,再进一步提取操作码,例如在以太坊中,可以使用evm disasm将字节码转化为汇编代码,通过记录执行的各操作码以及各操作码的执行顺序,我们可以知道执行特定操作码时获取的状态变量的槽ID,再根据之前得到的槽映射关系确认该槽ID对应的状态变量,从而将特定操作码与不同的状态变量联系起来;
S3.2:需要特别关注的操作码以及理由如下:;
CREATE2操作码:使用create2方式部署合约的代理合约中,不论是自定义的创建方法还是官方提供的创建方法都要涉及到CREATE2操作码;
调用外部合约操作码CALLCODE:代理合约调用逻辑合约的方式一;
委托调用操作码DELEGATECALL:代理合约调用逻辑合约的方式二;
存储操作码,包括但不限于MSTORE、MLOAD、SSTORE:逻辑合约在执行过程中需要检查并调用用户数据,会对状态变量进行读取、存储、更新等操作,这涉及到存储相关的操作码;
堆栈操作码,包括但不限于PUSH、DUP、SWAP:许多逻辑合约都要管理各自的虚拟资产,因此会有代币授权、转账操作,这涉及到堆栈相关的操作码;
SELFDESTRUCT操作码:要利用create2向同一地址部署合约,则被部署的合约必须存在自毁函数,该函数会涉及到SELFDESTRUCT操作码;
S4:根据上述获得的槽映射关系与操作码特征,通过符号执行动态的构建控制流图;
S4.1:符号执行技术指的是通过程序分析的方法,确定哪些输入向量会导致程序的对应执行结果向量的方法。它的关键思想是把程序的输入值变为符号值,那么经过代码计算后的输出值就会是一个符号输入值的函数,例如,有一个程序执行的路径是true和false条件的序列,这些条件是在分支语句处产生的。在序列的分支位置如果约束值是true,那么意味着当前路径的条件语句走的是then这个分支;反之如果是false就意味着程序执行走的是else分支的路径;
在运行过程中,符号执行会在全局维护两个变量,其一是符号状态σ,它表示的是一个从变量到符号表达式的映射,其二是符号化路径约束PC,用来表示路径约束条件,在符号执行的开始,符号状态σ会先初始化为一个空的映射,而符号化路径约束PC初始化为true,σ和PC在符号执行的过程中会根据分支条件语句的不同而不断更新,在符号执行结束时,PC就会用约束求解器进行求解,以生成实际的输入值。这个实际的输入值如果用程序执行,就会走符号执行过程中探索的那条路径,即此时PC的公式所表示的路径;
S4.2:控制流图是程序代码的一种表征形式,是一个过程或程序的抽象数据结构,代表了一个程序在执行过程中所有会被执行的路径,控制流图是以基本块为节点的有向图G=(N,E),其中N是节点集合,表示程序中的基本块;E是基本块之间边的集合,每个控制流图都存在至少两个指定的块:输入块和输出块;
在控制流图构造的过程中,通常会遭遇到间接地址跳转的问题,间接跳转地址是指目标地址存放在内存或寄存器中的跳转地址,这类值通常无法通过直接的静态分析得到。如果使用近似值的模块对控制流进行扩充,会导致结果相对不够精确,同时会引入不该存在的控制流路径;
在可升级智能合约中,由于逻辑合约与代理合约部署在不同地址,同时对用户数据有大量的调用更新,因此在合约执行的过程中会遇到许多计算变量地址值的情况,相应的也会有存在间接地址跳转的问题。因此在构建可升级智能合约控制流图的过程中,当遇到间接地址跳转问题时,使用符号执行进行辅助可以生成更加精确的控制流图节点;
S4.3:下面是控制流图的基本构建流程参考:
构建控制流图基本块,基本块指的是程序顺序执行的语句序列。对一个基本块来说,执行时只从其入口进入,从其出口退出。遇到第一条指令,结束当前基本块,并将该指令作为一个新块的第一条指令;遇到跳转、分支、循环指令,将该指令作为当前块的最后一条指令,并结束当前块。如果遇到的跳转指令计算的地址值为间接地址,则使用符号执行计算路径条件,得到更加精确的下一目标地址值。遇到其他语句直接将其加入到当前基本块;
构建控制流图有向边,有向边能够显示智能合约内各基本块之间的相互关系、动态执行状态等,如果从基本块A的出口转向基本块B,则从基本块A到B有一条有向边表示从A到B存在一条可执行路径,即在执行完基本块A中的程序后,有可能顺序执行基本块B中的程序;
S4.4:检测漏洞类别;
内存冲突:新合约的存储变量与代理合约的变量是否存在覆盖情况、新合约能否正常继承旧合约的变量;
理由:
在标准计算机程序执行过程中,应妥善控制内存的分配,以便不同的变量和数据结构不会冲突并损坏彼此的数据,通常由内存分配器处理这一项任务,记录通常是"紧凑地"存储,数据不会在地址空间中被随意安排,这也是分配者的责任,但Solidity不具有存储控制分配器,其任务的处理方式也不同,智能合约将状态变量的值存储在插槽中,从插槽0开始递增,基本固定大小值类型(例如uint256)占用一个插槽,此外,多个变量有时可以打包到一个插槽中,在使用时拆包;
对于使用继承的合约,状态变量的顺序由合约的C3线性顺序决定,并从最底层的合约开始,修改这些规则将破坏与之前版本合约的兼容性,因此这一规则在未来也不太可能发生变化;
上述规则是合约中状态变量在存储中的布局,以下简称为存储布局。由此我们可以得知,在可升级智能合约中,代理合约的存储中记录数据的旧版本合约具有自己的变量和存储布局,更新后的新版本合约也具有其自己的存储布局,并且必须能够处理根据以前的存储布局形成的数据,同时不要忘记还有代理合约本身的代码,它也有一个与当前的智能合约版本同时存在的存储布局,新版本合约要正确继承旧合约的存储布局,同时若有定义新的变量则不能与代理合约原有的存储布局发生冲突,即它们不能将相同的插槽用于不同的数据;
自毁函数访问控制漏洞:自毁函数是否有Onlyowner修饰符;
理由:
自毁函数会销毁当前合约,并转走当前账户余额,对其访问权限应谨慎对待,通常认为该功能只应给合约拥有者使用,而以太坊目前最主流的访问控制手段是使用OpenZeppelin代码库提供的Ownable合约来进行管理的onlyOwner模式,它是最常见也是最容易实现的访问控制方法,为智能合约设置了唯一的管理员角色。通过继承Ownable合约,子合约就可以在定义函数时使用onlyOwner修饰符,这些被修饰的函数就要求交易发起账号必须是合约的管理员。
具体检测过程:
正如前面提到的,利用槽映射关系和操作码特征,我们可以在符号执行的过程中找到有漏洞的代码。通过分析抽象语法树,我们得到了槽映射关系,由槽映射关系可以知道各个状态变量与其对应的槽id。在根据操作码序列执行符号执行构建控制流图时,我们可以确认新版本合约在执行特定操作码对应的函数时操作的状态变量,进而做相应的判断:若旧版本合约中有相对应的状态变量,则检查其对应的插槽与旧合约对应的状态变量插槽是否相同,不相同则说明继承错误,程序报告错误;若新合约执行函数时操作的状态变量在旧合约中没有相对应的状态变量,则检查其插槽是否与代理合约中的状态变量的插槽相同,若相同则发生冲突,程序报告错误;
特别的,对于create2模式部署的合约还需检查自毁函数的访问控制,结合SELFDESTRUCT操作码和控制流图检查对应的函数是否有Onlyowner修饰符,若没有则报告错误。
本发明中,分析源代码生成抽象语法树,通过分析抽象语法树获取智能合约中的状态变量与插槽ID的映射关系。结合操作码特征,使用符号执行动态的构建控制流图,并在这个过程中得到特定操作码与对应的状态变量的关系,以便检查漏洞错误。能够检测可升级智能合约中特有的内存冲突漏洞,也能够检测create2合约自毁函数的访问控制漏洞。
本发明重视目前越来越受欢迎的可升级智能合约的安全问题,能够检测可升级智能合约特有的内存冲突漏洞,也关注到了使用率较低的create2模式下创建的合约的自毁函数权限访问控制漏洞,能够填补这方面漏洞检测的空白,在检测过程中使用了抽象语法树,并使用符号执行来构建控制流图,能够获取更详细准确的信息,构建出精度更高的控制流图,从而提高漏洞检测的精度。
以上所述,仅为本发明较佳的具体实施方式,但本发明的保护范围并不局限于此,任何熟悉本技术领域的技术人员在本发明揭露的技术范围内,根据本发明的技术方案及其发明构思加以等同替换或改变,都应涵盖在本发明的保护范围之内。

Claims (1)

1.一种智能合约升级漏洞的检测方法,其特征在于,包括以下步骤:
S1:获取合约;
分别输入UUPS代理合约或create2工厂合约、旧版本合约、新版本合约;
S2:生成抽象语法树,获取槽映射关系;
首先通过语法分析器解析源代码,并根据解析结果生成源代码对应的抽象语法树,可以使用Solidity官方依据c++语言编写的编译器solc或者ANTLR4来生成抽象语法树,抽象语法树中含有合约定义结点以及合约定义结点下的函数声明子结点,每个树结点都表征了智能合约中的一个函数代码的定义信息;
智能合约中的数据可以存储在插槽、内存或calldata中,插槽用于永久数据,而内存用于合约执行期间的临时使用,智能合约中的每个可变的状态变量在编译过程中都会被分配一个槽ID,表示其存储空间,这些槽ID有助于合约在执行期间确定状态变量的确切存储位置;
通过分析抽象语法树,可以静态地获取合约中状态变量的槽ID,并记录它们的名称和数据类型,形成槽映射关系,这有助于在之后符号执行的过程中更方便的监控这些变量的操作码,同时抽象语法树可检查函数声明,通过检查函数关键字,比如“upgradeable”和“proxy”,可以识别出是UUPS模式的代理合约还是create2模式的代理合约;
S3:编译源代码获得字节码,再反汇编得到操作码特征;
S3.1:智能合约编译后的字节码以二进制的形式表示,其中包括了部署代码、runtime代码、auxdata三个部分,而智能合约部署后在链上执行的时runtime代码,我们要提取的操作码特征就在runtime代码中,操作码由以太坊定义,目前已定义了142种操作码,包括算术运算、位运算、存储操作、跳转操作码;
字节码将通过反汇编模块获取汇编代码,再进一步提取操作码;
S3.2:需要特别关注的操作码;
CREATE2操作码:使用create2方式部署合约的代理合约中,不论是自定义的创建方法还是官方提供的创建方法都要涉及到CREATE2操作码;
调用外部合约操作码CALLCODE:代理合约调用逻辑合约的方式一;
委托调用操作码DELEGATECALL:代理合约调用逻辑合约的方式二;
存储操作码,包括但不限于MSTORE、MLOAD、SSTORE:逻辑合约在执行过程中需要检查并调用用户数据,会对状态变量进行读取、存储、更新操作,这涉及到存储相关的操作码;
堆栈操作码,包括但不限于PUSH、DUP、SWAP:许多逻辑合约都要管理各自的虚拟资产,因此会有代币授权、转账操作,这涉及到堆栈相关的操作码;
SELFDESTRUCT操作码:要利用create2向同一地址部署合约,则被部署的合约必须存在自毁函数,该函数会涉及到SELFDESTRUCT操作码;
S4:根据上述获得的槽映射关系与操作码特征,通过符号执行动态的构建控制流图;
S4.1:符号执行技术指的是通过程序分析的方法,确定哪些输入向量会导致程序的对应执行结果向量的方法,它的关键思想是把程序的输入值变为符号值,那么经过代码计算后的输出值就会是一个符号输入值的函数;
S4.2:控制流图是程序代码的一种表征形式,是一个过程或程序的抽象数据结构,代表了一个程序在执行过程中所有会被执行的路径,控制流图是以基本块为节点的有向图G=(N,E),其中N是节点集合,表示程序中的基本块;E是基本块之间边的集合,每个控制流图都存在至少两个指定的块:输入块和输出块;
在控制流图构造的过程中,通常会遭遇到间接地址跳转的问题,间接跳转地址是指目标地址存放在内存或寄存器中的跳转地址,这类值通常无法通过直接的静态分析得到,如果使用近似值的模块对控制流进行扩充,会导致结果相对不够精确,同时会引入不该存在的控制流路径;
在可升级智能合约中,由于逻辑合约与代理合约部署在不同地址,同时对用户数据有大量的调用更新,因此在合约执行的过程中会遇到许多计算变量地址值的情况,相应的也会有存在间接地址跳转的问题,因此在构建可升级智能合约控制流图的过程中,当遇到间接地址跳转问题时,使用符号执行进行辅助可以生成更加精确的控制流图节点;
S4.3:下面是控制流图的基本构建流程:
构建控制流图基本块,基本块指的是程序顺序执行的语句序列,对一个基本块来说,执行时只从其入口进入,从其出口退出,遇到第一条指令,结束当前基本块,并将该指令作为一个新块的第一条指令;遇到跳转、分支、循环指令,将该指令作为当前块的最后一条指令,并结束当前块,如果遇到的跳转指令计算的地址值为间接地址,则使用符号执行计算路径条件,得到更加精确的下一目标地址值,遇到其他语句直接将其加入到当前基本块;
构建控制流图有向边,有向边能够显示智能合约内各基本块之间的相互关系、动态执行状态,如果从基本块A的出口转向基本块B,则从基本块A到B有一条有向边表示从A到B存在一条可执行路径,即在执行完基本块A中的程序后,有可能顺序执行基本块B中的程序;
S4.4:检测漏洞类别;
内存冲突:新合约的存储变量与代理合约的变量是否存在覆盖情况、新合约能否正常继承旧合约的变量;
自毁函数访问控制漏洞:自毁函数是否有Onlyowner修饰符。
CN202311802367.0A 2023-12-26 2023-12-26 一种智能合约升级漏洞的检测方法 Pending CN117951711A (zh)

Priority Applications (1)

Application Number Priority Date Filing Date Title
CN202311802367.0A CN117951711A (zh) 2023-12-26 2023-12-26 一种智能合约升级漏洞的检测方法

Applications Claiming Priority (1)

Application Number Priority Date Filing Date Title
CN202311802367.0A CN117951711A (zh) 2023-12-26 2023-12-26 一种智能合约升级漏洞的检测方法

Publications (1)

Publication Number Publication Date
CN117951711A true CN117951711A (zh) 2024-04-30

Family

ID=90793503

Family Applications (1)

Application Number Title Priority Date Filing Date
CN202311802367.0A Pending CN117951711A (zh) 2023-12-26 2023-12-26 一种智能合约升级漏洞的检测方法

Country Status (1)

Country Link
CN (1) CN117951711A (zh)

Similar Documents

Publication Publication Date Title
CN109375899B (zh) 一种形式验证Solidity智能合约的方法
Lu et al. NeuCheck: A more practical Ethereum smart contract security analysis tool
US5812850A (en) Object-oriented symbolic debugger using a compiler driven database and state modeling to control program execution
CN110688122B (zh) 编译和执行智能合约的方法及装置
CN110704063B (zh) 编译和执行智能合约的方法及装置
KR20200021993A (ko) 블록체인 컴파일러
US8141035B2 (en) Method for accessing internal states of objects in object oriented programming
CN110704064B (zh) 编译和执行智能合约的方法及装置
CN107924326A (zh) 对经更新的类型的迁移方法进行覆盖
EP3607432B1 (en) Flow-based scoping
US10083029B2 (en) Detect application defects by correlating contracts in application dependencies
Zhang et al. BDA: practical dependence analysis for binary executables by unbiased whole-program path sampling and per-path abstract interpretation
US20240020109A1 (en) Method and system for supporting smart contracts in a blockchain network
Li et al. Towards verifying Ethereum smart contracts at intermediate language level
Hejderup et al. Präzi: from package-based to call-based dependency networks
US20170075668A1 (en) Methods and Systems for Generating Client-Server Applications for Target Devices
CN111240772A (zh) 一种基于区块链的数据处理方法、装置及存储介质
US11366657B2 (en) Inferring code deprecation from module deprecation
CN117951711A (zh) 一种智能合约升级漏洞的检测方法
US7926022B2 (en) Surrogate-based and extends-based context look-up
CN114174983A (zh) 使用测试向量自动验证高级构造的优化
US8135943B1 (en) Method, apparatus, and computer-readable medium for generating a dispatching function
Wright et al. Using Event-B to construct instruction set architectures
CN117235746B (zh) 一种基于多维ast融合检测的源代码安全管控平台
He et al. Neural-FEBI: Accurate function identification in Ethereum Virtual Machine bytecode

Legal Events

Date Code Title Description
PB01 Publication
SE01 Entry into force of request for substantive examination