slither2
你认为slither找到了unstoppable的漏洞了吗?
Slither 只扫出了这个合约里的「通用风险点/代码不规范」,但完全没命中unstoppable这个场景的「核心致命漏洞」 —— 这也恰恰是你写自定义Slither插件的价值所在(官方Slither对「业务逻辑型漏洞」的检测能力极弱,而这正是DvD系列的核心考点)。
先拆解清楚:
第一步:先明确unstoppable的核心漏洞是什么(DvD里的关键考点)
unstoppable的核心是「非预期的状态篡改导致合约DOS(拒绝服务)」,核心逻辑:
- 金库合约(UnstoppableVault)用
totalAssets()计算资产总量,其中依赖balanceOf(address(this))(金库自己的代币余额)和totalSupply(金库份额总量)的比值; - 攻击者可以直接给金库转账少量代币(不走金库的
deposit函数,而是直接调用ERC20的transfer); - 这会导致
balanceOf(address(this)) > totalSupply,触发金库flashLoan函数里的assert断言失败,整个金库的闪电贷功能彻底卡死(DOS),任何人都无法再调用闪电贷——这才是这个场景的「核心漏洞」。
第二步:看Slither的告警,为什么没命中核心漏洞?
Slither扫出的所有告警,都是「通用型代码风险」,和上述核心漏洞无关:
| Slither告警类型 | 和核心漏洞的关系 | 通俗解释(为什么不是核心) |
|---|---|---|
| arbitrary from in transferFrom | 无关 | 只是transferFrom的from参数可控,和DOS漏洞没关系 |
| controlled delegatecall | 无关 | execute函数用了可控的delegatecall,但这个函数不是漏洞触发点 |
| divide before multiply | 无关 | 数学库的运算顺序问题,不影响核心逻辑 |
| dangerous strict equality | 无关 | ERC4626里的supply == 0严格相等,是规范问题,不是漏洞 |
| unused return | 无关 | 忽略approve/flashLoan返回值,是代码不规范,不导致DOS |
简单说:Slither的检测逻辑是「匹配已知的代码特征(比如transferFrom任意from、忽略返回值)」,但unstoppable的核心漏洞是「业务逻辑设计缺陷」—— 没有对应的“代码特征”(既没有奇怪的调用,也没有不规范的语法),而是「合约对“资产总量计算”的逻辑假设被打破」,所以官方Slither完全识别不出来。
第三步:这恰恰是你写自定义插件的绝佳场景!
你可以基于这个点,写一个「Unstoppable漏洞专属检测器」,核心检测逻辑可以设计成:
- 找到合约中依赖
balanceOf(address(this))计算资产总量的函数(比如totalAssets()); - 检查该函数是否「只认通过
deposit/mint函数增加的资产,而未排除直接转账的资产」; - 检查
flashLoan等核心函数是否依赖totalAssets()的结果做assert/require判断; - 如果满足以上条件,直接标红告警:「资产总量计算未排除外部直接转账,存在DOS风险(Unstoppable漏洞)」。
这个插件写出来后,对比官方Slither的结果——官方Slither没发现核心漏洞,而你的插件能精准命中,这会是你求职时的「高光案例」:
- 能证明你懂「工具的局限性」;
- 能证明你懂「业务逻辑型漏洞的检测思路」;
- 能证明你能「定制工具解决实战问题」—— 这正是初级审计岗最看重的能力。
总结
Slither只是做了「基础的代码体检」,没找到unstoppable的核心漏洞;但这对你来说是好事—— 官方工具的短板,恰恰是你展现自己能力的机会。你把这个场景的插件写出来,就能完美体现「你不仅会用工具,还能弥补工具的不足」,这在面试中会直接拉开和其他候选人的差距。
如果要写这个插件,核心要抓的点是:检测「合约是否将外部直接转账的代币计入资产总量,且基于此做刚性断言」 —— 你之前写0day POC时抓「触发条件」的思路,完全可以复用在这里~
我们现在来看下slither的源代码,哪些是放插件的地方?
Slither的「插件/自定义检测器」核心存放和加载路径非常清晰,结合你的插件开发经验(sqlmap/Xray),我会把「官方检测器位置」「自定义插件位置」「加载逻辑」都讲透,你能直接复刻写插件~
一、先明确:Slither里的「插件」本质是「自定义检测器(Detector)」
Slither没有单独的「plugin」目录,所有漏洞检测逻辑都以「Detector(检测器)」的形式存在——你写的自定义插件,本质就是「继承Slither抽象检测器类的Python脚本」,和你给Xray写POC、给sqlmap写tamper插件的思路完全一致。
二、核心路径拆解(从源码结构到自定义插件)
先看Slither源码的核心目录结构(聚焦检测器相关):
1 | |
1. 官方检测器的位置(参考学习用)
你之前扫unstoppable时看到的告警,对应的检测器都在detectors/下:
arbitrary from in transferFrom→detectors/erc20/arbitrary_from.pycontrolled delegatecall→detectors/delegatecall/controlled_delegatecall.pyunused return→detectors/unused_return/unused_return.py
这些官方检测器是你写插件的「最佳参考模板」—— 比如打开arbitrary_from.py,能直接抄它的「类定义、检测逻辑、告警输出」格式。
2. 自定义插件的存放位置(二选一,推荐第二种)
方式1:直接丢到detectors/下(简单,但和官方检测器混在一起)
把你写的unstoppable_detector.py直接放到slither/detectors/目录下,Slither启动时会自动扫描该目录下所有继承AbstractDetector的类,无需改任何配置。
方式2:创建detectors/custom/目录(推荐,隔离官方和自定义)
① 在slither/detectors/下新建custom文件夹;
② 把你的自定义插件(比如unstoppable_dos.py)放到custom/下;
③ (可选)在custom/下建__init__.py(空文件即可,标记为Python包);
④ Slither会自动递归加载detectors/下所有子目录的检测器,无需额外配置。
👉 对你来说,方式2更清晰——后续你写18个DvD插件时,可在custom/下按漏洞分类(比如custom/reentrancy/、custom/unstoppable/),和你之前给Xray分POC目录的思路一致。
三、自定义插件的「最小可用模板」(直接抄)
基于Slither的抽象基类,写一个检测unstoppable核心漏洞的最小插件模板,你只需填充检测逻辑:
1 | |
四、验证插件是否生效
- 把上述文件放到
detectors/custom/下; - 执行扫描命令:
slither ../unstoppable/ --detect unstoppable-dos; - 如果合约存在该漏洞,Slither会输出你定义的告警信息——这就说明插件加载成功了。
五、关键补充(适配你的开发习惯)
- 复用Slither的工具函数:比如想判断某个函数是否是ERC20的
transfer,可调用slither/utils/erc20.py里的is_erc20_transfer_function,和你复用sqlmap/utils的思路一致; - 调试插件:在
_detect()里加print()(比如print(contract.name)),Slither运行时会输出调试信息,方便定位问题; - 插件参数调用:除了
--detect指定插件,也可以用--detect all让Slither同时运行官方检测器+你的自定义插件。
总结
Slither的插件体系对你来说完全是「轻车熟路」—— 核心就是「继承抽象类+实现detect逻辑+放到detectors目录下」,和你给sqlmap写插件、给Xray写POC的模式几乎一致。你只需聚焦「把DvD漏洞的业务逻辑转化为代码检测规则」,插件的加载/运行Slither都帮你做好了,不用操心底层细节~
如果写插件时卡在「怎么检测balanceOf(this)调用」「怎么筛选目标合约」这类具体问题,随时拆,咱们一步步调~
自定义插件存放方案
结合你的环境(Kali Linux + Damn Vulnerable DeFi项目 + 系统级安装的Slither),推荐两种「自定义插件存放方案」(从易到难,优先选方案1,适配你的求职场景),我会一步步说清楚路径、操作和验证方法,确保你写的插件能被Slither识别并运行。
1 | |
方案1:在DvD项目内建自定义插件目录(推荐,求职/实战友好)
优势:插件和DvD项目绑定,方便后续整理成GitHub项目(求职用),不用改Slither系统配置,不影响全局环境。
步骤1:创建插件目录(和DvD源码同层级,结构清晰)
先回到DvD项目根目录(不是src目录!),然后创建专属插件目录:
1 | |
最终目录结构:
1 | |
步骤2:编写插件时,指定Slither加载这个目录
你写好插件(比如unstoppable_detector.py)放到slither-plugins/custom-detectors/后,扫描DvD合约时,用--detect-paths参数指定插件目录:
1 | |
⚠️ 关键:你的插件代码必须继承Slither的AbstractDetector基类(后面会给模板),否则Slither识别不到。
方案2:放到Slither系统目录(全局生效,适合频繁测试)
优势:任何目录下运行Slither都能自动加载你的插件,不用每次加--detect-paths;缺点:系统目录改起来需要权限,且插件和项目分离,求职展示不如方案1清晰。
步骤1:找到Slither的系统检测器目录
先执行命令找Slither的安装路径(系统级Slither通常在Python的site-packages里):
1 | |
输出示例(你的大概率是这个路径):
1 | |
步骤2:创建自定义检测器子目录
1 | |
步骤3:验证目录权限
1 | |
通用:插件代码模板(以unstoppable为例)
无论选哪种方案,插件代码都要遵循Slither的规范,这里给一个极简的unstoppable_detector.py模板(放到你创建的插件目录里):
1 | |
验证插件是否加载成功
- 把上述模板放到你创建的插件目录(比如方案1的
slither-plugins/custom-detectors/); - 执行扫描命令:如果看到类似下面的输出,说明插件加载成功:
1
2# 方案1的验证命令(DvD根目录下执行)
slither src/unstoppable/ --detect-paths slither-plugins/custom-detectors/ --detect unstoppable-dos1
INFO:Detectors:Unstoppable Vault found DOS vulnerability: UnstoppableVault totalAssets() relies on balanceOf(this) without excluding direct transfers
最终建议
- 求职优先选方案1:把插件和DvD项目绑定,GitHub上展示时目录结构清晰(
slither-plugins/目录+插件+README),面试官能直接看到你的工作; - 测试阶段可以先用方案2:全局加载不用每次输
--detect-paths,效率更高; - 插件命名规范:比如
unstoppable_detector.py、naive_receiver_detector.py,一眼能对应DvD的漏洞场景,求职时更专业。
如果执行命令时遇到「插件加载失败」「权限不足」等问题,直接说,我帮你排查~
用什么参数让运行Slither都能自动加载你的插件?
从你提供的 Slither 帮助文档来看,Slither 本身没有直接的“自动加载插件”参数,但可以通过以下方式实现插件(自定义检测器/打印机)的加载和使用,核心思路是利用 Slither 的扩展机制 + 配置文件/命令行参数:
一、核心前提:Slither 插件的加载逻辑
Slither 的自定义检测器/打印机需要遵循其插件规范(基于 Python 开发,注册到 Slither 的检测器/打印机注册表),加载方式分为两种:
1. 方式1:通过 --config-file 加载配置文件(推荐)
Slither 支持通过 --config-file 指定配置文件(默认 slither.config.json),在配置文件中可以预定义要运行的检测器/打印机、排除项、插件路径等,实现“自动加载”。
步骤:
① 创建 slither.config.json 配置文件,示例(加载自定义检测器+默认配置):
1 | |
② 运行 Slither 时指定配置文件(或默认加载):
1 | |
2. 方式2:通过命令行参数直接指定插件(临时使用)
如果是自定义开发的检测器/打印机,可通过 Python 环境加载后,在命令行直接指定检测器名称:
1 | |
二、关键:如何让 Slither 识别自定义插件
Slither 不会自动扫描插件,必须确保自定义插件被正确注册:
插件开发规范:
自定义检测器需继承slither.detectors.abstract_detector.AbstractDetector,并通过register_detector装饰器注册;
自定义打印机需继承slither.printers.abstract_printer.AbstractPrinter,并通过register_printer装饰器注册。示例自定义检测器(
my_detector.py):1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.core.declarations import Function
@register_detector("my-custom-detector")
class MyCustomDetector(AbstractDetector):
ARGUMENT = "my-custom-detector" # 命令行中使用的名称
HELP = "检测自定义逻辑(例如无权限的管理员函数)"
IMPACT = DetectorClassification.HIGH
CONFIDENCE = DetectorClassification.CERTAIN
def _detect(self):
results = []
for contract in self.slither.contracts:
for function in contract.functions:
if function.name == "admin" and not function.has_modifiers("onlyOwner"):
info = f"合约 {contract.name} 的 admin 函数无权限控制"
results.append(self.generate_result(info))
return results让 Slither 加载插件文件:
- 方式A:将插件所在目录加入 Python 环境变量:
1
2export PYTHONPATH=$PYTHONPATH:/path/to/your/plugins
slither your_contract.sol --detect my-custom-detector - 方式B:在配置文件中指定
plugin_paths(见上文slither.config.json)。
- 方式A:将插件所在目录加入 Python 环境变量:
三、常用“自动加载”参数组合(实战)
如果希望每次运行 Slither 都自动加载插件 + 固定规则,推荐以下命令:
1 | |
四、补充:Slither 官方扩展机制
如果是第三方开源插件(如 slither-analyzer 生态的插件),需先安装插件包,再通过命令行参数调用:
1 | |
总结
Slither 没有专门的 --load-plugin 类参数,“自动加载插件”的核心是:
- 遵循 Slither 插件规范开发自定义检测器/打印机;
- 通过
--config-file配置文件预定义插件路径、要运行的检测器/打印机; - 运行时只需执行
slither target --config-file xxx(或默认加载slither.config.json),即可自动加载插件并执行。
如果你的“插件”是指 Slither 内置的检测器/打印机,只需在 --detect/--print 中指定 all 即可自动加载所有内置插件:
1 | |
github上面难道没有给slither写插件的人或者仓库吗?
当然有!GitHub 上不仅有大量为 Slither(智能合约静态分析工具)开发插件/扩展的开发者,还有专门的插件仓库、示例项目和社区贡献的扩展。以下是具体的资源和方向,帮你快速找到相关内容:
一、官方核心插件/扩展生态
Slither 本身就设计了可扩展的插件系统,官方文档也明确支持自定义检测器(Detector)、打印机(Printer)等扩展,且官方仓库也维护了核心插件相关的示例:
Slither 官方仓库
地址:crytic/slither- 官方代码中自带大量内置检测器(
slither/detectors/目录),是编写自定义插件的最佳参考; - 官方 Wiki 有「Writing a new detector」教程:Slither Docs - Custom Detectors。
- 官方代码中自带大量内置检测器(
官方示例插件仓库
Crytic(Slither 所属团队)提供了插件开发示例:- crytic/slither-examples:包含自定义检测器、打印机的最小示例,新手入门首选。
二、社区贡献的 Slither 插件仓库
GitHub 上有大量开发者分享的自定义 Slither 插件,涵盖不同场景(DeFi、NFT、安全检测等),以下是典型仓库:
1. 通用插件/扩展集合
- **trailofbits/slither-plugins**(Trail of Bits 官方维护)
Trail of Bits 是 Slither 的开发团队,这个仓库包含官方扩展的插件,比如针对特定合约模式的检测器、集成其他工具的插件等。 - 0xKitsune/slither-plugins
包含针对 ERC20/ERC721、Uniswap V2/V3 等 DeFi 合约的自定义检测器,比如检测流动性锁定、授权风险等。 - OpenZeppelin/slither-checks
OpenZeppelin 提供的 Slither 插件,聚焦于符合 OpenZeppelin 安全规范的检测(比如合约继承、权限控制等)。
2. 专项场景插件
- NFT 相关插件:NFT-Infosec/slither-nft-plugins(检测 NFT 合约的常见漏洞,如元数据篡改、铸造限制等);
- DeFi 安全插件:defi-security/slither-defi(针对借贷、DEX 合约的风险检测);
- 审计机构定制插件:很多审计公司(如 CertiK、PeckShield)会开源部分定制 Slither 插件,可搜索关键词
slither certik plugin/slither peckshield detector。
三、搜索技巧:快速找到更多插件
如果上述仓库不够,可在 GitHub 用以下关键词精准搜索:
| 关键词组合 | 适用场景 |
|—————————|——————————|
| slither plugin | 通用 Slither 插件 |
| slither detector | 自定义检测器(最核心的插件类型) |
| slither printer | 自定义打印机(输出合约信息) |
| slither custom rule | 自定义规则插件 |
| slither solidity plugin | Solidity 专属插件 |
| slither defi / slither nft | 场景化插件 |
搜索语法优化:
1 | |
四、如何开发/使用第三方插件
使用现成插件:
多数插件可通过pip install安装,或直接将插件代码放到 Slither 的plugins目录,运行时通过--detect <插件名>调用。开发自定义插件:
参考官方示例,核心步骤:- 继承
slither.detectors.abstract_detector.AbstractDetector; - 实现
detect()方法(定义检测逻辑); - 注册插件(通过
@detector.register装饰器)。
- 继承
总结
GitHub 上有丰富的 Slither 插件资源,核心来源包括:
- Trail of Bits 官方插件仓库;
- 安全审计机构/DeFi 团队开源的定制插件;
- 社区开发者分享的场景化检测器;
- 官方示例和教程仓库。
如果需要特定场景的插件(比如检测某类漏洞、适配某类合约),可以结合上述搜索技巧,或基于官方示例二次开发。