Skip to main content

Capture the Ether - Lotteries write-up



Capture the Ether is a "Capture the Flag" style game in which you hack Ethereum smart contracts to learn about security.

Spoiler Alert !

In this write-up, I will go through the first four challenges in the category labeled "Lotteries". Each of these challenges has its own difficulty level and reward points. Basically you can solve them by "guessing?" the right value of a variable in a given smart contract.


Guess the number

The smart contract for this challenge looks like this:

It has three functions :

GuessTheNumberChallenge(): a payable constructor that tells you how much Ether is required when deploying the smart contract.

isComplete(): it returns true when the smart contract's balance is equal to 0.

guess(uint8 n): It takes a uint8 as an argument and compares it with the variable declared in line 4. If the numbers are equal, you will have your Ethers sent back to your address. Note that this function is payable and requires exactly 1 Ether to be sent when making a call.

Obviously, all we have to do is to invoke guess() with 42 as an argument. I used Web3.js (Ethereum JavaScript API) and MetaMask  for this.

First you'll need to get the smart contract's ABI that will be used to make a contract instance. the Remix IDE will provide you with everything you need to get this done.

Paste in the code shown bellow and click on "Details"



You can then copy the ABI by clicking on the clipboard icon.


Remember that you can still use Remix to compile, deploy and interact with your smart contracts without having to write any code. I kinda preferred using Web3.js because it's more robust.

The final code to invoke the guess() function should look like this:


Notice that the transaction must have exactly 1 ether (1e18 wei) in its value field, otherwise it would fail.

Clicking the "Check the solution" button in the game should give this (nice pixel art btw):



Guess the secret number

The code for this challenge is as follow:


The challenge says :



Same as the previous challenge, but this time we need to find a number that was hashed using the Keccak-256 hashing algorithm.

By looking at the code, you'll notice that guess() takes a uint8 parameter, and according to the documentation, the highest value of this type is smaller than 2000. Makes things easy, right ?

Now we know that the number we're looking for is less than 2000, we'll need to write a quick script to brute force it.

Here is what I came up with :


Executing it would give 170 as an answer:



Guess the random number

The smart contract given in this one looks like this :

As you can see, the answer this time is generated based on the hash of the parent block block.blockhash(block.number - 1) and now which is simply an alias for block.timestamp that represents the current block timestamp. The result keccak256 hash is then being casted to uint8.

Our smart contract was deployed to address 0xd5Ce10BE3745114aABf0382556439bA3Ecb2a524. We can easily lookup the block number in which the transaction was included using Etherscan.


Here is the script I used to calculate the answer using the appropriate parent hash and timestamp :


The answer for this challenge was 73.


Guess the new number

In this challenge, the answer is generated on the fly inside the guess() function.

We need to guess the block hash and timestamp before our transaction is made, which seems nearly impossible. Note that these two elements can still be influenced to some degree (more details), but the solution to this challenge was much simpler than that.

My first approach to solve this was to predict the block timestamp based on the latest block's timestamp and the average block time which was 14 seconds at the time, and using a higher Gas price to ensure that my transaction is included in the next block.

Unfortunately this didn't work. My transactions always ended up being mined 3-5 blocks ahead.

After a few attempts, I realized that I should be doing this from within a smart contract, since we'll have access to the transaction's properties (block.number and block.timestamp).

Here is the smart contract I made to call guess() from the GuessTheNewNumberChallenge contract with the correct values :

Notice that I have declared an unnamed payable function in line 26 which is basically a fallback function. This is what will make our smart contract able to receive Ether through regular transactions. I have also declared a withdraw() function to recover my Ethers later.

https://ropsten.etherscan.io/address/0xeabd25449222897ab4046ee172b0eb9ebbdc0d02#internaltx

And voila, it's done.


Well, that's how far I could get for now. This game was extremely fun and I wish I had more free time to play more.


Comments

Post a Comment

Popular posts from this blog

CSAW CTF 2015 : Forensics 100 - Transfer write-up

Category : Forensics  Points : 100 Challenge Description : I was sniffing some web traffic for a while, I think I finally got something interesting. Help me find flag through all these packets. net_756d631588cb0a400cc16d1848a5f0fb.pcap Opening it up with Wireshark gives some few HTTP packets. After looking through those packets, I noticed that one of them contains the word FLAG. The start of the conversation contains a python script and some random padding at the end which was more likely to be the script's output. Looking through the python script we notice there is a variable called FLAG (censored) that gets encoded with Base64 then looped through one of the following ciphers ROT13, ROT3 and Base64 (randomly chosen).  One thing to mention is that the script keeps the cipher index attached to the encrypted string, this will make it easier for us to reverse the whole thing. I wrote a quick python script to do the decryption : Executi

SU-CTF write-up - steganography 100 challenge

Category : Steganography Points : 100 The description of the challenge was: Hear With Your Eyes In this challenge, we were given a wav file which we somehow had to decrypt to get the flag. This was a pretty easy one to be honest. After hearing the audio, the first thing that came up to my mind was to use a signal analyser. For this matter I used baudline. The output was as follow : The flag was : e5353bb7b575578bd4da1c898a8e2d7667