Let’s Play — Capture the Ether : Lotteries (Part I)

Forest Fang
5 min readApr 14, 2018

--

This is the second installment of stories on my journey of Capture the Ether, a game where we hack Ethereum Solidity code for fun and learn about smart contract security. Read the introduction post for background, what to expect, and link to other sections.

What is Capture the Ether?

In Capture the Ether, we win points by completing challenges. Each challenge comes with a smart contract to deploy and objectives can be completed by exploiting the contract into a specific state. Challenges are grouped into categories that focus on specific areas of security vulnerabilities in smart contracts.

Spoiler Alert

We will cover Guess the number, Guess the secrete number, and Guess the random number challenges in this article. These challenges demonstrate it is difficult to store private information on a public blockchain or to source randomness from a deterministic programming model in EVM.

I recommend you read, think about, attempt the problem on your own first. For each problem, I will discuss the high level approach followed by detailed solution.

Guess the number

Approach

We simply want n == answer == 42 therefore we just need to call guess(42) on the contract.

Details

You should already be a pro calling smart contraction function using transactions. The only difference this time is that we need to send ether along the function call because require(msg.value == 1 ether) .

Web3.js

To send ether in web3.js, simply add value in the transaction option:

Use options to send ether along a transaction in web3.js

Remix

To send transation with ether in Remix, use Value option on the top right.

You can choose units from the drop down menu from the right.

Guess the secret number

Approach

We would like to find the preimage that hashes into a specific hash using keccak256 , the hash function used by Ethereum. Usually this would be very difficult because a good hash function like keccak256 has good preimage resistance.

In this case, it is trivial because n has type uint8 and can only vary between 0 and 256 (2⁸). What remains is to iterate through all possible values by brute force.

Details

We can run through all possible values using either Solidity directly or via offline tools such as web3.js.

Solidity

We can easily replicate the keccak256 check in a for loop as shown in the GuessTheSecretNumberSolver contract in the above fiddle. You can deploy the contract in EthFiddle which runs an in-browser test EVM that come with accounts loaded with Ether.

Note EthFiddle provides a subset of the functionalities by Remix, where you can also choose built-in EVM from the environment. From hereafter we demonstrate code using EthFiddle as they can be beautifully embedded on Medium.

Because we wrote the function with public view modifiers, we can call it without gas. Shortly after, it should spit out the answer in the box below.

Pay attention that you are using the correct type, in this case, uint8 . Otherwise keccak256 would produce different result as shown in the keccak256Uint function. This is because keccak256 hashes (tightly packed) arguments.

Web3.js

Iterate through uint8 to find preimage collision

web3.sha3 computes keccak256 hash from a string (optionally in hex.) In our case, it is important to pad hex representation of uint8 to correct digits as shown in the last two lines.

Web3.js 1.x will have web3.utils.soliditySha3 that takes care of the type coercion for us.

Guess the random number

Approach

Two ways to solve this problem:

  1. Compute answer using heccak256 based on block hash of the previous block of contract deploy (block.number — 1) and timestamp of the contract deploy block.
  2. Get answer value directly from EVM storage. Even though answer is a private field in the contract, because all transaction need to be validated by all nodes, all fields are in fact publicly readable from an Ethereum node, which can be queried using web3.js.

Details

Calculate Answer from Hash

We first need to find the transaction corresponding to contract creation. Unfortunately I cannot find straightforward API to convert contract address to transaction hash. You can look up this on Etherscan or from the result of your deployment transaction call in Metamask.

With that we can find the block and its timestamp as well as parent block hash. We compute the keccak256 hash as before and truncate the byte32 string to uint8 by taking the last two character and convert it back to integer.

Get Answer from EVM Storage

All persistent contract variables are stored in contract storage and they follow a specific layout as can be found in this documentation. I refer you to this excellent article on how to read contract storage using web3.js.

For the purpose of our exercise, there is only one field in the contract. Therefore we simply need to find the value at slot 0:

Conclusion

In this post, you have learnt to write Solidity code in EthFiddle to test various scenarios without spending gas, use web3.js to compute keccak256 hash and find block information from a transaction hash, and pry open EVM storage to peak private storage variable of a contract.

Next time, we will look at more challenges in the Lotteries section where we will discover more interesting security vulnerabilities in smart contract and how to indirectly interact with other smart contracts using a smart contract. We will also look at how to use Truffle framework to write and test smart contract in a local simulated blockchain.

Capture the Ether is brought to you by @smarx, who blogs about smart contract development at Program the Blockchain.

I am not affiliated with the game itself and the awesome company behind it. Views expressed are solely my own and do not express the views or opinions of any entity with which I have been, am now, and will be affiliated.

--

--

Forest Fang

functional programming advocate; visualization addict; blockchain enthusiast;