CCSC 2021 Writeups — Lucky Moves

Christos Falas
4 min readApr 20, 2021

Lucky Moves

Lucky Moves was a blockchain challenge. In the challenge, we were given a TCP socket to connect to, along with a zip file containing the python script behind the TCP socket, and a file called LuckyMoves.sol.

When connecting to the TCP socket, we are presented with the actual challenge description. We should focus on the sentence:

Exploit the LuckyMoves.sol contract which is deployed at 0x2ca344d4fb0451F5c681eC741482647E8db73626 on the Ethereum Ropsten Testnet.

We are told that the LuckyMoves.sol file is a smart contract. After some googling (given that I had no idea how Ethereum, or blockchain in general works), I found out that smart contracts for Ethereum are written in a language called Solidity. Even without knowing exactly how everything works, from the file (shown below), we can understand that there is a private function called rand which generates a random number given a seed, and a public function called spin which given a bet, generates a random number, generates a new seed (using the same rand function), and checks if the bet matches the generated random number. If they match, a public counter, specific for my address is incremented

LuckyMoves.sol file

By now I had an idea of what I had to do (predict what the rand function will choose, so that I can send the correct bets 8 times so that the function hasSolved will return true when called by the TCP socket to check if I solved the challenge.

In order to predict what rand will return, I need to understand how it works. From the code, a recent block is selected depending on the seed, and the blockhash of that block is used to generate the number. The solidity documentation for blockhash can be found here.

The next step is to find a way to predict the block that will be used. This was a good time to learn some more about the operation of Ethereum (ie excuse me in advance for anything which is not accurate). In order to call the function spin we create a new block which is added to the blockchain. The block number will be just 1 more than the block of the previous block, which is publicly available. So my first guess was to find the last public block, and use a number greater than that to generate the bet. After trying that, two issues are presented:

  • The block number changes quickly, so by the time that I have the last block, there is already a new block
  • I don’t know what the first seed is (subsequent seeds can be calculated)

After some more googling, I solved the first issue. Everything on blockchain is public, even if not directly accessible. Smart contracts written in Solidity are compiled to bytecode and then run on an “Ethereum Virtual Machine”. Just like a regular executable, we can inspect its memory and see what the seed is. The easiest way that I found to do this after some more googling was using JavaScript and the web3.js library

window.eth.getStorageAt('0x2ca344d4fb0451F5c681eC741482647E8db73626', 0).then(x => {
console.log(x)
})

We getStorageAt the first index (ie 0) of the address of the smart contract. We choose the first index since the seed is the first variable to be declared in the smart contract.

Having the seed, all we had to do is find the correct block to use. After some more googling, I found something which actually makes a lot of sense. If your code is the latest block on the blockchain, then you know the block number of that will be used to generate the random number. In order to do that, I needed to write a smart contract.

I found that you can import a smart contract into another one, so that I can use the spin function directly. In the new smart contract, I copy pasted the original smart contract, added the necessary changes to import the original smart contract and we were off to the races (I also changed all variables to public for easier debugging).

My final smart contract was this:

Final smart contract

In order to run this, I used Remix, and the MetaMask browser extension which provided me with a wallet which I could use to publish my smart contracts on the blockchain. From Remix I created the smart contract, giving it the address of the original smart contract. After that, I used the JS snippet above to get the current seed, used it as an input to my run function and I got my first hit. I repeated the same process another 7 times until I got the hits value to 255. (While I could in theory automate the process of getting the seed and calling the contract, I thought that it wouldn’t be worth it since it’s just 8 times)

Next, I used an online service to sign the message “Gib me flag” with my wallet, and I sent that to the TCP socket which gave me the flag :)

Flag: CCSC{0n_ch41n_r4nd0mn3ss_1s_a_v3ry_r1sky_1d3a!!!}

--

--