Last month, ETHworks put together a really fun smart contract contest where players competed to solve all the clues and unlock a 7 ETH reward. While I did not win, I had an absolute blast participating in it and wanted to share my notes in case you want to learn about password cracking and smart contract hacking techniques. If that sounds interesting to you, let’s dive right in.
The address contained a simple smart contract which challenged anyone to guess a plaintext for a stored hash which was hashed twice with KECCAK-256:
The hash was initialized at contract deployment time and could be easily looked up in Etherscan:
The contract itself was interesting in the way it protected players against front-running attacks by first requiring a commit() transaction with a solution hashed once using KECCAK-256, followed by the actual reveal() after a 10 block delay.
My initial approach to solving the puzzle was to load a slightly modified version of the contract on Remix in order to save on gas fees and to keep attempts private:
The modification, simply disables the commit step so I could freely experiment with different solutions. Next, I have initialized the contract with the same hash value as the original:
Trying a few iterations manually, it quickly became clear that a more automated approach will be needed:
KECCAK-256 hash function has readily available implementations in many languages. Instead of trying to crack the hash inside EVM, I rewrote just the relevant portion in Go. Below is a basic implementation of the algorithm which achieves about ~400K hashes per second on my MacBook Air:
A successful hash cracking job requires not only speed, but also the ability to continuously come up with good wordlists. In my failed attempts, I went through popular wordlists such as RockYou, CrackStation, and others. To further increase my chances, I rewrote the above implementation to include multi-threading and even the ability to mutate passwords using Hashcat’s rules engine:
% ./crack hashcat --stdout -r rules/passphrase-rule1.rule -r rules/passphrase-rule2.rule passphrases.txtgee point lake2017
Gee point lake2017
GEE POINT LAKE2017
gEE POINT LAKE2017
With the laptop fan screaming in the middle of the night, it was clear that the puzzle solution is more likely to be a complex passphrase as opposed to a simple password. To crack that, I would need to go way down into the rabbit hole and analyze all the hints.
Down the Rabbit Hole
The 0xPOLAND twitter account served as the main source of announcements and clues for the challenge. The first tweet appeared on November 9th with a simple white rabbit 🐇 emoji. The next few tweets all featured amazing graphics each with a single line clue such as the one below:
Below is a list of tweets before November 17th and my notes on their meaning:
- November 12th: “Adventure AwAits”
- November 13th: “Only in the darkness can you see the stars”
Note: A quote from Martin Luther King Jr.
- November 14th: “the future is already here — it is just unevenly distributed”
Note: A quote from William Gibson.
- November 15th: https://etherscan.io/block/11287961
Note: A countdown timer to November 19th when the block will be mined.
- November 16th: “Smart contract address: 52.217609, 21.014687”
Note: Location of a subway station in Warsaw where the billboard with the smart contract address was initially posted.
The presence of two quotes from William Gibson and Martin Luther King Jr. gave me an idea that the solution is a famous quote. The best collection of quotes that I could find on the internet was on Goodreads.com. Conveniently, someone already wrote a scraper to pull quotes from the site, so with a bit of tweaking I started generating large wordlists of quotes from famous cyberpunk authors, politicians, and freedom fighters. After cleaning up the quotes and mutating different punctuation marks, I generated a list of close to 1,000,000 passphrases which unfortunately did not yield a result.
Pedal to the Metal
This was the point where things started getting strange. On November 19th, just as the Ethereum block 11287961 was mined, 0xPOLAND Twitter account made another post:
Followed by a post the next day with another hash:
The quote above comes from a song by a metal band Elffor called “Into the dark forest”. Looking at the regex hint ^[A-Z].*\., the solution was supposed to start with a capital letter and end with a period. After some time, I found that the hash above corresponds to a single KECCAK-256 iteration of the song title:
Into the dark forest.
Could the solution be a song title? Would the song be in the same genre as Elffor? There was only one way to find out! I put together a song scraper for a metal band database and went to sleep.
The next morning I woke up to a nice collection of ~400K metal song titles with amazing names like “Rites of the Pentagram”, “Suicide Salvation”, and my favorite “Septic Oral Sex”. Next, I ran these through my cracker with different hashcat rules to try different letter cases and making sure there is a period at the end:
I ran the above two rules against the song wordlist as follows:
./crack hashcat -r rules/poland1.rule -r rules/poland2.rule --stdout metalstorm.txt
Unfortunately there were no hits. I dug in to wait for more clues.
The Ultimate Question
The next clue came on November 23rd:
Answer to the Ultimate Question of Life, the Universe, and Everything6e 99 a1 98 4a 9e 92 8f 4a 9c 8b 8c 8c 93 9e 4a 92 99 96 8f 58
This one was easier to solve. The first line referred to the book “The Hitchhiker’s Guide to the Galaxy” and the answer to that is 42. After playing with a few different encodings, I was able to solve this mini-puzzle with a simple Python one-liner:
In : print(''.join([chr(int(b,16)-42) for b in "6e 99 a1 98 4a 9e 92 8f 4a 9c 8b 8c 8c 93 9e 4a 92 99 96 8f 58".split()]))Down the rabbit hole.
Still no dice. A few days later a new countdown was posted waiting for the block 11332799 which was supposed to be mined on November 26th at around midnight in my timezone.
Just as expected, the next clue was posted on November 26th, 12:03 AM:
Half-asleep, I sat in the darkness trying to figure out the cryptic numbers and who I was supposed to call. The first set of numbers corresponded to ISSN number for Gazeta Wyborcza published in Warsaw, Poland. Suddenly a new commit() transaction has appeared on the blockchain:
https://etherscan.io/tx/0xf9fb51e6f9fe3e2440804c85fcf9abfb394b19d5730dbf7515a59334ea723848Function: commit(bytes32 _hash)MethodID: 0xf14fcbc8
It was not the first time that folks attempted to send answers to the contract; however, it quickly became clear that someone did in fact solve it after the reveal() transaction was successfully submitted without a revert:
https://etherscan.io/tx/0x30da280465e7972afbf45287608a7bd15ccec53a1832f138b468c39d46a95de5Function: reveal(string _solution)MethodID: 0x4c261247
20616476656e74757265206177616974732e0000000000000000000000000000With 0xPoland. Into the dark forest. Down the rabbit hole. Where adventure awaits.
It was only later that folks from Warsaw have shared a screenshot from that day’s newspaper edition which contained the last clue:
I could not resist calling the number and got the following recording on the other end:
The message essentially provided the template for the puzzle’s passphrase:
You've come a long way. Congratulations. Here is your solution. With 0xPoland. Into **BEEP**. Down the **BEEP**. Where adventure awaits.
Filling in “the dark forest” and “rabbit hole” into the above produced the correct double KECCAK-256 hash in the puzzle!
During the week of playing the contest, I have learned how to write multi-threaded password crackers and page scrapers, build targeted wordlists and picked up a few smart contract tricks. Most of all I had a ton of fun while revisiting some of my favorite metal bands from the 80s. Sorry Metal Kingdom for knocking down your site a few times, it was for a good cause. While it was a bit disappointing that only someone living in Warsaw could have won the contest, it makes sense what folks at ETHworks were trying to achieve with the local community. And with that, thanks for a great challenge and a nice distraction from this crazy year.