Openzeppelin区块链CTF练习——答案和解析【13】Privacy
openzeppelin出的CTF练习题https://ethernaut.openzeppelin.com/level/0x131c3249e115491E83De375171767Af07906eA36
题目
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Privacy {
bool public locked = true;
uint256 public ID = block.timestamp;
uint8 private flattening = 10;
uint8 private denomination = 255;
uint16 private awkwardness = uint16(block.timestamp);
bytes32[3] private data;
constructor(bytes32[3] memory _data) {
data = _data;
}
function unlock(bytes16 _key) public {
require(_key == bytes16(data[2]));
locked = false;
}
/*
A bunch of super advanced solidity algorithms...
,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`
.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,
*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^ ,---/V\
`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*. ~|__(o.o)
^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*' UU UU
*/
}
答案
js运行脚本,其中需要替换两个地方
1、“https://eth-sepolia.g.alchemy.com/v2/YOUR_INFURA_PROJECT_ID”,换成自己的节点链接,没有的去https://eth-sepolia.g.alchemy.com网页申请
2、“0x50f66A8d8693625D9E3F3459905170296c232a5e” 换成自己在题目页面获取的Instance address
const { ethers } = require("hardhat");
// 主部署函数。
async function main() {
// 使用 provider 连接到以太坊节点,要换成自己的节点链接,去https://eth-sepolia.g.alchemy.com网页申请
const provider = new ethers.JsonRpcProvider(
"https://eth-sepolia.g.alchemy.com/v2/YOUR_INFURA_PROJECT_ID"
);
const contractAddress = "0x50f66A8d8693625D9E3F3459905170296c232a5e"; // 替换为你的Instance address
// 读取存储槽 5 的数据
const slot5 = await provider.getStorage(contractAddress, 5);
console.log("Slot 5 data:", slot5); // 包含 ID
}
// 执行主函数并处理可能的结果。
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
解析
即使 data[ ] 是 private,它的值仍然存储在以太坊区块链的存储槽中。你可以通过链上工具(如 Etherscan)或编写脚本直接读取特定的存储槽。
在 Solidity 中,状态变量按照定义顺序分配存储槽。bytes32[3] 会占用连续的 3 个存储槽。如果 data 是合约中的第一个变量,它会存储在 slot 0、slot 1 和 slot 2 中。