Accessing Private Data in Smart contracts | QuillAudits

In solidity, “Private” variables can only be read by the contracts and is not accessible to the outside world. But, it is possible to access these data from outside the blockchain. Let’s see how we can read private data from smart contracts.

Table of Contents:

1. State Variable Visibility
2. Storage layout in EVM
3. Accessing private data using Ethers
4. A small challenge
5. Remediation
6. Reference

State Variable Visibility

According to Solidity Docs, There are three visibility modifiers that users can use: public, internal, or private.

  1. Public: Public means that the variable can be accessed by the contract and by other smart contracts.
  2. Internal: Internal means that the variable can only be used with the contract it is defined in and its subclasses.
  3. Private: Private means that the variable can only be accessed within the contract it is defined. Trying to access it outside this contract gives a compilation error.

In Solidity, “Private” variables are not accessible to the outside world. But wait, if private data can only be accessed within the contract then how can we access these data from outside of the blockchain?
We will come to it but let’s first understand storage layout in solidity.

Storage Layout in EVM:

The EVM (Ethereum Virtual Machine) stores smart contract data in a large array with a length of 2**256 in slots on the blockchain. Each memory slot can hold up to 32 bytes of data. The EVM stores smart contract state variables in the order that they were declared in slots on the blockchain. The default value of each slot is always 0, so we do not need to assign a value to 0 when the new declaration is.

Smart contract storage is optimized to minimize space. If two or more variables fit into a single 32-byte slot, they are packed into the same slot, beginning on the right.

uint8    => 1 byte
uint16 => 2 bytes and so on
uint256 => 32 bytes
bool => 1 byte
address => 20 byte
bytes1 => 1 byte
bytes2 => 2 bytes and so on

Look at the following example for a better understanding of how storage works in EVM.

Storage for Dynamic data types:

Mappings and dynamically-sized array types cannot be stored “in-between” the state variables before and after. Instead, they are considered to occupy only 32 bytes and a different storage slot that is computed using a Keccak-256 hash of the elements they contain.

Accessing Private data from Blockchain:

To access Solidity smart contract private data we can follow the following steps. Here we will be using ethers.js for extracting data.

  1. First, we need to read the contract and understand the order in which the state variables are declared. Let’s suppose we want to access slot0.
  2. We can use ethers.js to read the memory slots of the contract on the blockchain. Use the below function:
    await ethers.provider.getStorageAt(contract_address, 0);
  3. It will return hex encoded value, we can simply decode it or use ethers utils functions or some sort of hex decoder to decode it.

Using Ethers.js Script:

You can also use the following js script to fetch private data from the blockchain.

const {ethers,utils } = require("ethers");
const rpc_url = "https://eth.g.alchemy.com/v2/abcd" //add your rpc_url here
const provider = new ethers.providers.JsonRpcProvider(rpc_url)

async function start() {
const contract_address = //add contract address here
const slot = // add the storage slot of contract you want to access
const data = await provider.getStorageAt(contract_address, slot)
console.log("Private Data :", data)
}

start()

Guide for running script:

  1. Install ethers from npm: npm install ethers
  2. Get a rpc_url of the required network from alchemy and add it to the above script.
  3. Change the contract address and slot in the below script and simply run the js code. Decode the returned hex value.

Using Slither:

We can fetch private variable data using slither tool. It's most the simple and easy way out there.

  1. Install Slither tool from here.
  2. Run the following command:

slither-read-storage <contract_address> --variable-name <variable name> --rpc-url $rpc_url --value

A small challenge:

Goerli link: 0x4c77de8a0ec0390826f87f227bb8762ab2189194

Objective: Change the value of pwned to true. You can use the above script to extract private data.

Remediation:

In the current state of the blockchain, do not keep sensitive private data in smart contracts. The safest method to keep your private information safe is to avoid storing it on a public blockchain.

Further Reads:

https://solidity-by-example.org/hacks/accessing-private-data/
https://docs.soliditylang.org/en/v0.8.11/internals/layout_in_storage.html#

Web3 security- Need of the hour

Why QuillAudits For Web3 Security?
QuillAudits is well-equipped with tools and expertise to provide cybersecurity solutions saving the loss of millions in funds.

Want more Such Security Blogs & Reports?

Connect with QuillAudits on :
Linkedin | Twitter | Website | Newsletter | Discord | Telegram

Partner with QuillAudits :

--

--