实战!使用大语言模型检测 Solidity 智能合约中逻辑重入漏洞的有效性
前言
今天早上,Hash 一反常态地暴躁。它趴在玻璃缸壁上,冲着我张开了它那标志性的橘黄色大嘴——这是它威胁我"赶紧喂食"的经典信号。我一边给它切胡萝卜丁,一边想着:其实智能合约的漏洞检测也是一样,即使看起来风平浪静的代码,底层可能正酝酿着一场重入攻击的"暴躁"。
重入漏洞(Reentrancy Attack)堪称智能合约世界的"头号杀手"。从 2016 年臭名昭著的 The DAO 攻击(损失 360 万 ETH),到 2022 年的 Fei Protocol 攻击(损失 8000 万美元),重入漏洞始终高居 DeFi 安全攻防的榜首。
传统上,开发者用 Slither 做静态分析,用 Mythril 做符号执行检测。但在大模型时代,GPT-4 和 Claude 能否辅助检测这类逻辑漏洞? 它的能力和局限性在哪里?今天瑞瑞就带大家实际测试一下。
一、 重入漏洞底层原理回顾
在让 LLM 出场之前,我们先快速回顾一下重入攻击的核心机制。
sequenceDiagram
participant 攻击者合约
participant 目标合约
participant EVM
攻击者合约->>目标合约: withdraw(amount)
目标合约->>EVM: SLOAD(余额)
目标合约->>EVM: 检查余额是否足够
目标合约->>EVM: SSTORE(更新余额前)
目标合约->>攻击者合约: call.value(amount)("")
攻击者合约->>目标合约: withdraw(amount) ← 重入!
目标合约->>EVM: SLOAD(余额) ← 还没被更新!
目标合约->>攻击者合约: call.value(amount)("")
攻击者合约->>目标合约: withdraw(amount) ← 再重入!
目标合约->>EVM: 最终 SSTORE(更新余额)
重入漏洞的根源在于 「先转账,后更新状态」 的错误顺序。在 EVM 层面,call 操作码会将执行权转交给目标地址,并在目标地址的 fallback 函数中重新进入原函数,而此时原函数的状态变量尚未更新。
二、 LLM 检测重入漏洞的方法论
2.1 传统工具 vs LLM 对比
| 检出原理 | 基于污点传播和预定义规则模式 | 符号执行 + 约束求解 | 上下文理解 + 模式识别 + 逻辑推理 |
| 误报率 | 中等(约 20%~30%) | 较低(约 10%~15%) | 取决于 Prompt 设计 |
| 漏报率 | 较低(约 15%~20%) | 中等(约 10%~25%) | 约 10%~30%(复杂场景不稳定) |
| 速度 | 秒级 | 分钟级(复杂合约可达数十分钟) | 秒级到十秒级 |
| 代码依赖 | 需要合约完整源码 | 需要合约字节码或源码 | 仅需源码片段即可推理 |
| 逻辑漏洞 | ❌ 规则有限 | ❌ 符号路径爆炸时效果差 | ✅ 理解复杂的业务逻辑 |
| 理解业务 | ❌ 做不到 | ❌ 做不到 | ✅ 可以理解如"闪电贷+价格操纵"组合 |
| 成本 | 免费 | 免费 | 按 Token 计费 |
这里的核心区别在于:Slither 是在找"已知的模式",Mythril 是在穷举"所有可能的执行路径",而 LLM 是在进行语义级别的逻辑推理。
2.2 检测流程
graph TD
A["输入合约源码"] –> B["LLM 上下文理解"]
B –> C["识别外部调用点<br/>(call / delegatecall / send)"]
C –> D["跟踪状态变量读写顺序"]
D –> E{"状态更新是否<br/>在外部调用之前?"}
E –>|是| F["标记为:<br/>潜在重入漏洞"]
E –>|否| G["检查是否有<br/>重入锁保护"]
G –>|有锁| H["检查锁的覆盖范围"]
G –>|无锁| I["标记为:<br/>低风险"]
H –>|未完全覆盖| F
H –>|完全覆盖| J["标记为:<br/>安全"]
三、 Prompt 工程策略
想让 LLM 准确检测重入漏洞,Prompt 设计是关键。下面瑞瑞分享经过多次验证的 Prompt 模板。
3.1 基础 Prompt(不推荐)
请检查以下Solidity合约是否有重入漏洞。
❌ 问题:太模糊。LLM 可能只会简单扫描 call 关键词,忽略复杂的跨函数重入和跨合约重入。
3.2 结构化 Prompt(推荐)
你是一位专业的智能合约安全审计专家,精通 EVM 底层机制和 Solidity 安全最佳实践。
请对以下 Solidity 合约进行安全审计,特别关注 **重入漏洞(Reentrancy Vulnerability)**。
请按以下步骤分析:
1. 列出合约中所有外部调用(call / delegatecall / send / transfer)
2. 检查每个外部调用之后的状态变量更新情况
3. 检查是否存在重入锁(如 ReentrancyGuard 或自定义锁)
4. 分析是否有跨函数重入的可能性
5. 给出风险评级(严重 / 高危 / 中危 / 低危 / 安全)
合约代码:
```solidity
// [粘贴合约源码]
请以如下格式输出:
| … | … | … | … | … |
// 修复建议代码
这个 Prompt 通过**角色设定 + 分步指令 + 输出格式约束**三管齐下,大大提升了 LLM 的检测质量。
—
## 四、 实际测试案例
下面瑞瑞用三个真实的测试案例,对比 GPT-4、Claude 与传统工具的表现。
### 测试用例 1:经典的单函数重入
```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract 脆弱代金库 {
mapping(address => uint256) public 余额;
function 存款() external payable {
余额[msg.sender] += msg.value;
}
function 提现(uint256 _数量) external {
require(余额[msg.sender] >= _数量, "余额不足");
// ⚠️ 漏洞:先转账,后更新状态
(bool 成功, ) = msg.sender.call{value: _数量}("");
require(成功, "转账失败");
余额[msg.sender] -= _数量;
}
// 获取合约余额
function 合约余额() external view returns (uint256) {
return address(this).balance;
}
}
检测结果:
| Slither | ✅ | 规则 reentrancy-benign (信息级) | 仅标记为信息级,非高危 |
| Mythril | ✅ | 符号执行发现重入路径 | 需要配置外部调用模式 |
| GPT-4 | ✅ | 直接定位 15~18 行 | 指出提现与余额更新的顺序倒置 |
| Claude | ✅ | 定位并给出固定示例 | 同时指出 call 使用的 Gas 风险 |
LLM 表现:两个模型都 100% 检出,且给出了正确的修复建议——在外部调用前更新余额状态。
测试用例 2:跨函数重入(复杂模式)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract 跨函数重入金库 {
mapping(address => uint256) public 余额;
mapping(address => bool) public 正在处理;
function 存款() external payable {
余额[msg.sender] += msg.value;
}
function 开始处理() external {
require(!正在处理[msg.sender], "处理中");
正在处理[msg.sender] = true;
// 处理逻辑…
uint256 数量 = 余额[msg.sender];
(bool 成功, ) = msg.sender.call{value: 数量}("");
require(成功, "转账失败");
// 这里没有重置正在处理标志
}
function 结算() external {
require(正在处理[msg.sender], "未在处理中");
// ⚠️ 攻击者可以在开始处理的 fallback 中
// 调用结算函数绕过余额更新
uint256 奖励 = 余额[msg.sender] / 10;
余额[msg.sender] = 0;
(bool 成功, ) = msg.sender.call{value: 奖励}("");
require(成功, "转账失败");
正在处理[msg.sender] = false;
}
}
检测结果:
| Slither | ⚠️ 部分检出 | 能发现两个函数都有重入模式,但无法关联跨函数调用链 |
| Mythril | ⚠️ 部分检出 | 受到路径爆炸影响,分析时间较长 |
| GPT-4 | ✅ 完整检出 | 理解了跨函数调用的攻击路径 |
| Claude | ✅ 完整检出 | 给出了详细的攻击步骤说明 |
这个案例中 LLM 的优势非常明显——它理解业务逻辑,能识别出「处理中」标记被滥用导致的跨函数重入,而传统工具难以在数据流关联上完成这种推理。
测试用例 3:带有重入锁但锁覆盖不全
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract 锁覆盖不全 {
using ReentrancyGuard for *; // 假想的锁
bool private _加锁;
modifier 重入保护() {
require(!_加锁, "重入");
_加锁 = true;
_;
_加锁 = false;
}
function 安全函数() external 重入保护 {
// 受保护
(bool 成功, ) = msg.sender.call{value: 1 ether}("");
require(成功, "转账失败");
}
function 危险函数() external { // ⚠️ 没有重入保护
(bool 成功, ) = msg.sender.call{value: 1 ether}("");
require(成功, "转账失败");
}
}
检测结果:
| Slither | ⚠️ | 能发现 危险函数 有外部调用,但不识别锁定方式的语义 |
| Mythril | ✅ | 能检测到缺少保护的执行路径 |
| GPT-4 | ✅ | 指出 危险函数 缺少 重入保护 修饰器 |
| Claude | ✅ | 同时指出自定义锁的潜在重入风险(修改器执行顺序问题) |
五、 LLM 检测重入漏洞的能力边界
5.1 综合评估矩阵
quadrantChart
title LLM 检测重入漏洞能力评估
x-axis 简单场景 –> 复杂场景
y-axis 低准确率 –> 高准确率
quadrant-1 "核心优势区"
quadrant-2 "需人工复核"
quadrant-3 "不适用"
quadrant-4 "潜力区"
"单函数重入": [0.15, 0.95]
"跨函数重入": [0.35, 0.85]
"跨合约重入": [0.55, 0.60]
"闪电贷组合攻击": [0.75, 0.45]
"零知识重入": [0.90, 0.20]
5.2 LLM 的强项
5.3 LLM 的弱项
六、 最佳实践:人机协同的重入检测流程
┌─────────────────────────────────────────────────────┐
│ 第一层:自动化扫描 │
│ Slither + Mythril + 自定义规则引擎 │
│ 快速过滤明显问题,生成初步报告 │
└──────────────────┬──────────────────────────────────┘
▼
┌─────────────────────────────────────────────────────┐
│ 第二层:LLM 深度分析 │
│ GPT-4 / Claude 对可疑函数进行语义层面推理 │
│ 识别跨函数重入、跨合约重入等复杂模式 │
│ 生成修复建议和攻击路径描述 │
└──────────────────┬──────────────────────────────────┘
▼
┌─────────────────────────────────────────────────────┐
│ 第三层:人工审计 │
│ 经验丰富的安全工程师复核 LLM 报告 │
│ 确认或排除误报,评估真实风险 │
│ 对高风险合约进行分层审计 │
└──────────────────┬──────────────────────────────────┘
▼
┌─────────────────────────────────────────────────────┐
│ 第四层:自动化测试 │
│ Foundry fuzz + Echidna 属性测试 │
│ 针对 LLM 识别的攻击路径编写攻击测试 │
│ 验证修复是否生效 │
└─────────────────────────────────────────────────────┘
实际 Prompt 使用建议
| 快速扫描 | 基础 prompt + 要求列出所有外部调用 | Claude(更快) |
| 深度审计 | 结构化 5 步 prompt + 要求分析攻击路径 | GPT-4(更细致) |
| 跨合约审计 | 提供所有相关合约源码,要求绘制调用链 | Claude(更长上下文) |
| 修复验证 | 提供修复后的代码,要求再次审计 | 两者均可 |
七、 总结
我的鬃狮蜥 Hash 现在已经安静了下来,趴在我的显示器旁边,眼睛一眨不眨地看着我写完这些代码。我想它大概明白了一个道理:看起来人畜无害的东西,底下可能藏着危险。
通过今天的实测,我们可以得出几个结论:
最后记住:没有哪个工具是银弹。Slither + LLM + Foundry 测试 + 人工复核,层层递进的防御策略,才能让你的智能合约在链上百毒不侵。
好了,我要去给 Hash 补充维生素粉了。下次见!
技术栈:Solidity · GPT-4 · Claude · Slither · Mythril · EVM · Web3 Security · AI Audit

