Slither 将 Solidity 转换为中间表示 SlithIR,以通过简单的 API 实现高精度分析。

预定义了很多检测器(detectors),支持自定义:https://github.com/crytic/slither/wiki/Detector-Documentation

slither demo.sol
"
--config-file file.config.json
	指定配置文件
--detect detector1,detector2
	指定检测器
--exclude detector1,detector2
	排除探测器
--filter-paths "Migrations.sol|ConvertLib.sol"
	筛选只跟xx文件有关的结果
--checklist
	测试结果以md格式输出
--json file.json
	测试结果导出为json
--print slithir
	输出每个函数的IR
"

# 与编译有关的选项参考:crytic-compile --help
# <https://github.com/crytic/crytic-compile/wiki/Configuration>
"
--solc-remaps @openzeppelin=node_modules/@openzeppelin
	指定import依赖路径
"

# 可以基于solc生成的AST文件运行
slither file.ast.json

配置文件

跟编译有关的配置字段参考 crytic_compilehttps://github.com/crytic/crytic-compile/blob/master/crytic_compile/cryticparser/defaults.py

{
    "detectors_to_run": "detector1,detector2",
    "printers_to_run": "printer1,printer2",
    "detectors_to_exclude": "detector1,detector2",
    "exclude_informational": false,
    "exclude_low": false,
    "exclude_medium": false,
    "exclude_high": false,
    "json": "",
    "disable_color": false,
    "filter_paths": "(mocks/|test/)", # regex
    "legacy_ast": false
}

示例演示

被测合约

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

// This is the age-old reentrancy attack that should make you squirm when you see it
contract EtherStore {
    mapping(address => uint256) public balances;

    function deposit() external payable {
        balances[msg.sender] += msg.value;
    }

    function withdraw() external {
        uint256 balance = balances[msg.sender];
        require(balance > 0);
        (bool success, ) = msg.sender.call{value: balance}("");
        require(success, "Failed to send Ether");
        balances[msg.sender] = 0;
    }

    // Helper function to check the balance of this contract
    function getBalance() external view returns (uint256) {
        return address(this).balance;
    }
}

测试结果

Reentrancy in EtherStore.withdraw() (demo.sol#12-18):
        External calls:
        - (success) = msg.sender.call{value: balance}() (demo.sol#15)
        State variables written after the call(s):
        - balances[msg.sender] = 0 (demo.sol#17)
        EtherStore.balances (demo.sol#6) can be used in cross function reentrancies:
        - EtherStore.balances (demo.sol#6)
        - EtherStore.deposit() (demo.sol#8-10)
        - EtherStore.withdraw() (demo.sol#12-18)
Reference: <https://github.com/crytic/slither/wiki/Detector-Documentation#reentrancy-vulnerabilities>

Pragma version^0.8.9 (demo.sol#2) allows old versions
Reference: <https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-versions-of-solidity>

Low level call in EtherStore.withdraw() (demo.sol#12-18):
        - (success) = msg.sender.call{value: balance}() (demo.sol#15)
Reference: <https://github.com/crytic/slither/wiki/Detector-Documentation#low-level-calls>
demo.sol analyzed (1 contracts with 84 detectors), 3 result(s) found

参考