智能合约模糊测试工具推荐——Echidna

一、理论介绍

1. 模糊测试介绍

什么是模糊测试,先来看一下维基百科关于模糊测试的介绍。

模糊测试(fuzz testing, fuzzing)是一种软件测试技术。 其核心思想是将自动或半自动生成的随机数据输入到一个程序中,并监视程序异常,如崩溃,断言(assertion)失败,以发现可能的程序错误,比如内存泄漏。 模糊测试常常用于检测软件或计算机系统的安全漏洞。

在工作实践中,模糊测试通常是一种辅助测试手段,在完成功能测试之后作为补充测试来执行,对发现边界值问题、异常情况、安全漏洞,有不错的辅助效果,用于发现技术人员“意料之外”的软件缺陷。

2. Echidna介绍

这是一款用于对区块链智能合约进行模糊测试的安全检测工具,它可以基于用户自定义的属性,或者断言语句,进行自动的测试,通常用于对智能合约进行安全审计,起到辅助人工审计的作用。

在Echidna的论文中,介绍Echidna支持3种属性类型,分别为:

  • user-defined properties
  • assertion checking
  • gas use estimation

在Echidna的github项目介绍里,Echidna的运行模式有5种:

  • property
  • assertion
  • overflow
  • exploration
  • optimization

其中在进行安全测试时,最常用的是“自定义属性模式”,并且有调查显示使用此模式最多可以检测到被测合约中63%的的严重的可利用漏洞。

此外,Echidna支持对Solidity和Vyper类型的智能合约进行模糊测试,并且支持大多数主流的智能合约框架。

Echidna architecture.png

Echidna的架构设计如上图所示,工具的输入是被测的合约或合约集合,在这些合约中有用户自定义的属性用例,一般来讲就是找到一些属性,这些属性有在某些情况下恒为真的特点,比如用户钱包余额永远小于等于发币总量。Echidna的运行过程可以分为两个阶段:

  • 第一阶段:启动Slither,对合约进行静态扫描,扫描结果将作为第二阶段的输入

  • 第二阶段:模糊测试阶段。这一阶段是一个迭代过程,模糊测试将依赖被测合约的ABI、合约中定义的属性常量以及corpus语料库来生成随机交易。当运行过程中发现了违背自定义属性规律的交易时,会自动生成一个触发此场景的最小化交易序列的失败报告。Echidna会自动生成一系列交易来完成对被测合约的最大化覆盖。

二、工具使用

1.工具安装及使用方法

在对Echidna的工作原理有大概了解之后,进入到工具实践部分。

首先,工具的安装及使用,参考github上的使用说明即可完成。笔者本地环境是Mac M1芯片,安装了0.9.5版本的Slither和2.0.5版本的Echidna

环境OK之后,对Echidna源代码中的测试用例进行试验,比如:

在代码根目录下运行

echidna-test tests/solidity/basic/allContracts.sol --contract B --config tests/solidity/basic/allContracts.yaml

工具正常运行,运行时界面如下:

fuzzing process.png

2.Echidna的五种工作模式

以下例子均来自Echidna的github(github.com/crytic/echi…)中的示例代码,默认在此项目的根目录下执行运行命令

(1)自定义属性

运行命令:echidna-test tests/solidity/basic/array-mutation.sol

e1.png

(2)断言模式

断言模式的示例代码如下

contract Test {
  TestAssert ta;
  constructor() public {
    ta = new TestAssert();
  }

  function f() public {}
}

contract TestAssert { 
  event AssertionFailed(string message);
  function fail(uint val) public {
    if(val > 128)
      emit AssertionFailed("error");
  }
  function g() public { }
}

运行命令:

echidna-test tests/solidity/assert/multi.sol --contract TestAssert --config tests/solidity/assert/multi.yaml

运行结果:

e2.png

(3)overflow模式

在示例中有一个overflow.sol的示例代码,在运行前增加运行模式的配置:

testMode: overflow

运行结果:

e3.png

(4)exploration

关于这个模式,我没有找到特别明确的介绍,个人理解是任何一个智能合约都可以用此模式跑起来,不需要添加特别的测试方法,此模式的设计目的是为了收集覆盖率数据。

在github的issue里有两个相关的issue:
Benchmark mode to run without tests (#420, #409)
当中的描述如下:

We need a special mode to let echidna collect coverage without adding new code (e.g. an echidna_something function). This mode should be enabled using a config keyword (e.g. benchmarkMode: true) but disable by default.

先尝试运行:

echidna-test tests/solidity/basic/allContracts.sol --config tests/solidity/basic/benchmark.yaml

但是不知道coverage data在哪里,于是再增加一个配置:

corpusDir: "./output/”

就可以在output路径下看到覆盖率数据了

(5)optimization

运行命令:

echidna-test tests/solidity/optimize/linear.sol --config tests/solidity/optimize/config.yaml

运行结果:

e5.png

三、使用经验小结

1. 最常用的模式

  • Property,即默认的运行模式

2. Property模式

  • 格式要求:
    echidna_something() returns(bool)

    • 函数必须以“echidna_”开头
    • 不需要对echidna_something函数传入参数
    • 比较容易找到不变量恒为真的条件,并以此来完成echidna_something函数的返回语句
  • 运行特点:

    • 不会对合约产生副作用
    • 如果运行过程中发生了Revert,就会认为运行失败
    • 在统计覆盖率时,添加的echidna_something函数不会有覆盖率统计数据
    • 如果被测的不止一个合约,而是一系列合约,需要在配置文件里加入“multi-abi: true”,或者在运行命令里加上“- -multi-abi”
    • 如果被测的合约中引入了外部依赖module,比如依赖了“@openzeppelin/contracts/token/ERC20/ERC20.sol”,此时需要在配置文件里加入“cryticArgs: [‘–solc-remaps’, ‘@=node_modules/@‘]”,否则会出现编译时找不到依赖项的错误
    • 实践时,可以参考echidna提供的default.yaml的配置说明,按需调节echidna运行配置,以达到更好的运行效果

3. Assertion模式

  • 通过在被测合约代码里加入assert断言语句,然后指定运行模式为assertion,才能进入到此模式运行
  • Assertion模式的特点
    • 提供了简单的函数内检方式
    • 增加的断言语句会被统计到代码覆盖率中去
    • 新增的断言不应该影响原本的代码
    • 容易因为错误的使用断言而影响了原本函数的运行逻辑

参考资料

  1. 《Echidna: Effective, Usable, and Fast Fuzzing for Smart Contracts》
  2. Github:github.com/crytic/echi…

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYMqIfvZ' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片