uni-due-syssec/eth-reentrancy-attack-patterns
GitHub: uni-due-syssec/eth-reentrancy-attack-patterns
收录论文中多种以太坊智能合约重入攻击模式的可复现示例,用于安全研究及安全工具检测能力评估。
Stars: 115 | Forks: 22
# 重入攻击模式 (Re-Entrancy Attack Patterns)
这些攻击模式是在评估 `Sereum` 时发现的,这是一种针对重入攻击的运行时监控解决方案,它利用污点追踪 (taint tracking) 和动态写锁来检测并防止重入攻击。更多信息请参阅我们的论文 *"Sereum: Protecting Existing Smart Contracts Against Re-Entrancy Attacks"* ([arxiv 预印本](https://arxiv.org/abs/1812.05934))。
对于每种类型的攻击模式,本仓库包含一个易受攻击合约和攻击的小型示例实现。易受攻击的合约和攻击者合约的源代码包含在 `*.sol` 文件中。我们还为每个示例提供了一个 `*_setup.js` 文件,用于在开发区块链上部署合约并利用示例合约中的漏洞。这些脚本假定它们运行在 geth 开发模式区块链 (`geth --dev`) 中。
### 跨函数重入 (Cross-function re-entrancy)
**示例:** `./cross-function.sol`
示例中的 Token 合约容易受到始于 `withdrawAll` 函数的重入攻击。然而,攻击者无法重入 `withdrawAll`。相反,攻击者必须重入合约的 `exchangeAndWithdrawToken` 函数来利用该漏洞并耗尽易受攻击合约中的 ether。
### 委托重入 (Delegated re-entrancy)
**示例:** `./delegated.sol`
`Bank` 合约使用了一个通过 `delegatecall` 调用的库来执行 ether 发送。这掩盖了 `withdraw` 函数中的重入漏洞。任何静态分析工具在仅分析 `Bank` 合约而不分析该合约与其库的组合时,都无法检测到此漏洞。
### 基于 Create 的重入 (Create-based re-entrancy)
**示例:** `./create-based.sol`
在此示例中,多个合约相互交互。`Bank` 合约利用 `CREATE` 指令(即 Solidity 中的 `new`)来创建新的子合约。合约创建会立即触发新创建合约的构造函数的执行。此构造函数可以向未知地址执行外部调用。这可能导致重入场景,即攻击者在子合约构造函数执行期间重入合约。为了使静态分析工具能够发现此类问题,它们必须 (1) 同时分析合约组合,并且 (2) 将 `CREATE` 指令视为外部调用,类似于 `CALL` 指令。
## 已测试工具
下表列出了我们测试的工具和版本。如果工具检测到测试用例,我们用 "Yes" 标记,否则为 "No"。Mythril、Securify 和 Slither 使用保守策略,即标记外部调用之后的每一个状态更新。这将防止所有重入漏洞,但也会导致相当多的误报。例如,对于基于 Create 的重入漏洞,合约创建者极有可能想要修改状态(例如,注册新创建合约的地址)。另一个例子是使用互斥锁 (mutex) 进行手动锁定,这种策略总是会报告此类情况。
| Tool | Version | Simple | Cross-Function | Delegated | Create-based |
| ------------- | ----------- | ---------------------- | ---------------------- | --------- | ------------ |
| Oyente | 0.2.7 | Yes | No | No1 | No |
| Mythril | v0.19.9 | Partial (conservative) | Partial (conservative) | No | Partial (conservative) |
| Securify | 2018-08-01 | Partial (conservative) | Partial (conservative) | No | No |
| Manticore2 | 0.2.2 | Yes | Yes3 | No | No |
| Slither5 | 0.6.4 | Yes (conservative) | Yes (conservative) | Yes (conservative) | No |
| ECFChecker | geth1.8port | Yes | Yes4 | Yes | No |
| Sereum | | Yes | Yes | Yes | Yes |
* 1 Oyente 在库合约中检测到重入。然而,库合约本身可以说不容易受到重入攻击。
* 2 我们评估了启用 `--detect-reentrancy-advanced` 的检测器。另一个检测器 `--detect-reentrancy` 使用类似于 Mythril 和 Securify 的策略。
* 3 然而,其他测试(例如 `manual-lock.sol`)显示 Manticore 有时不够准确,即使实际上不可能发起重入攻击也会报告。
* 4 然而,我们为跨函数重入攻击设计了一个未被 ECFChecker 检测到的不同示例。详情请参阅下一节。
* 5 与其他工具相比,Slither 在 Solidity 源代码级别工作。它具有类似于 Mythril 和 Securify 的策略,即它报告使用低级 Solidity `call` 或 `delegatecall` 函数进行外部调用后的任何状态更新。
## 测试用例:手动锁
文件 `manual-lock.sol` 包含同一合约的多个版本。这些合约可用于评估重入检测工具的质量。
该文件包含三个功能等效的合约:
* `VulnBankNoLock` 容易受到简单的同函数重入攻击。
* `VulnBankBuggyLock` 由于不完整的锁定机制,容易受到跨函数重入攻击。
* `VulnBankSecureLock` 由于锁定机制而不易受到攻击。然而,该锁定机制可能导致误报。
此外,针对所有这些合约实现了两种类型的攻击。
* `MallorySameFunction` 实现了简单的同函数重入
* `MalloryCrossFunction` 实现了跨函数重入攻击
静态分析工具很难正确分析这些合约。Oyente 仅检测简单的重入漏洞,而不报告跨函数重入。另一方面,Manticore 在 BuggyLock 和 SecureLock 版本中都检测到重入错误,从而导致误报。Slither 和 Mythril 将外部调用后的任何状态更新标记为问题,因此报告每个合约都有问题,即使 `SecureLock` 变体是不可利用的。
| Tool \ Testcase | NoLock | BuggyLock | SecureLock |
| --------------- | -------- | --------- | ---------- |
| Oyente | Yes | No | No |
| Manticore | Yes | Yes | Yes |
| Mythril | Yes | Yes | Yes |
| Slither | Yes | Yes | Yes |
| Expected | Yes | Yes | No |
对于动态分析工具,我们使用了易受攻击合约和攻击合约的多种组合。我们验证工具是否检测到针对同函数和跨函数重入攻击的攻击行为。
| Testcase \ Tool | ECFChecker | Sereum | Expected |
| ---------------------------| ---------- | --------- | -------- |
| NoLock + SameFunction | Yes | Yes | Yes |
| NoLock + CrossFunction | No | Yes | Yes |
| BuggyLock + SameFunction | No | Yes | No |
| BuggyLock + CrossFunction | No | Yes | Yes |
| SecureLock + SameFunction | No | Yes | No |
| SecureLock + CrossFunction | No | Yes | No |
Sereum 报告所有合约的原因是,锁定机制本身表现出的模式与重入攻击完全相同。因此 Sereum 报告了对锁变量的重入攻击,因为 Sereum 无法知道锁变量的语义。
## 无条件重入 (Unconditional Re-Entrancy)
**示例:** `./unconditional.sol`
通常,重入攻击会试图破坏应用程序的业务逻辑检查。每个检查(`if`、`require`、`assert` 等)在 EVM 级别都实现为条件跳转 (`JUMPI`)。虽然当然不太可能,但可以编写一个在发送 ether 之前不执行任何检查的合约。在此示例中,该功能转移用户投资的所有 ether。此示例仅可通过重入漏洞被利用。~~目前 Sereum 未检测到此示例,因为我们认为这是一种不太可能的情况。我们计划在未来的 sereum 版本中检测此类漏洞。~~
| Tool | Detected |
| --------------- | --- |
| Oyente | Yes |
| Manticore | Yes |
| Slither | Yes |
| Mythril | Yes |
| ECFChecker | Yes |
| Sereum | ~~No~~ Yes1 |
* 1 我们扩展了 Sereum 以覆盖此类重入,通过追踪从存储变量到调用参数的数据流。
另一个非常简单的示例是以下合约,它部署在 Ethereum 区块链的 [0xb7c5c5aa4d42967efe906e1b66cb8df9cebf04f7](https://etherscan.io/address/0xb7c5c5aa4d42967efe906e1b66cb8df9cebf04f7#code) 处。
## 在学术工作中引用
如果你想在学术工作中引用这些攻击模式,请引用以下论文:
```
@inproceedings{sereum-ndss19,
title = "Sereum: Protecting Existing Smart Contracts Against Re-Entrancy Attacks",
booktitle = "Proceedings of the Network and Distributed System Security Symposium ({NDSS'19})",
author = "Rodler, Michael and Li, Wenting and Karame, Ghassan and Davi, Lucas",
year = 2019
}
```
标签:CISA项目, DEFI安全, Geth, Sereum, Solidity, Write Locks, 以太坊, 动态污点分析, 区块链安全, 基于创建的重入, 委托调用重入, 数据可视化, 智能合约审计, 智能合约漏洞, 自定义脚本, 自定义脚本, 跨函数重入, 重入攻击