ethernaut上有道题叫Vault,要求获取到密码来解锁。先看代码
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;
}
}
}
乍一看,感觉逻辑和计算都没有问题。按照一般说法,这个密码设置为私有是没有任何问题的。那怎么解锁呢?暴利攻击肯定是行不通,逻辑上也没有漏洞。bytes32是可以用==来判断相等,也没有问题。那会不会数据的可见性的问题。我们来看看private的官方解释:
Making something private or internal only prevents other contracts from reading or modifying the information, but it will still be visible to the whole world outside of the blockchain.
这下就明白了,private只是针对外部合约和派生合约的不可见,但是在整个区块链世界中是可以看到的,所以我们就可以使用一些办法查看到这个password值。
使用web3.js或者ethers.js的方法可以获取到password的存储槽上的值,比如:
await web3.eth.getStorageAt('合约地址', 1);
可以通过区块链浏览器查看(在sepolia等测试网上无法查看)
OK,只要获取到密码,执行unlock方法就可以开锁了,hoho
