This summer (2022), we'll kick off a new renaissance by returning in-person high-school hackathons to San Francisco and consequently the rest of the world. Learn more here.
Before the big announcement, however, we created a treasure hunt that would lead to the Assemble reveal letter. In this repository we run through why we created the puzzle, how we created the puzzle, how the puzzle can be solved and a post-mortem on the puzzle's success as a launch tool.
Does open source organising work interest you? Keep an eye out on the #ship
Slack channel as we open source more of Assemble.
Launches are a big part of every summer event. For example, to announce 2021's Zephyr we hosted a community call and to announce 2020's Summer of Making we premiered this kickoff video. For 2022, we choose to make a puzzle for these five reasons:
-
Encourage collaboration. Hackathons are of course a collaborative event, so why not get participants working together before the event event starts? Once we'd released the puzzle, Hack Clubbers immediately got to work together on solving it together. That was amazing to see!
-
Create a community feel. As Hack Clubbers worked together on the puzzle,
#lounge
came alive! The channel had 7.5 times the average amount of daily messages sent in it (measured over the past three months) on that day. -
Build long-lasting "hype". It took about three hours for the first person to solve the puzzle. Then people kept working it for the next twenty-four hours. That's a lot longer than a five-minute video and made sure hackers kept talking about the event for hours.
-
Have fun! Ultimately, hackathons are meant to be fun. And so are puzzles which makes the two a perfect match.
The puzzle was made up of three parts: the video, the image and the website. Here's how we made each of those.
This video was released on our Twitter on June 16. It was made by @bashbaugh without video editing software using JavaScript and PIXI.js, with webGL shaders for the effects. The video opened with an image of the San Francisco bay and an ASCII filter, with resolution slowly increasing until the bridge became visible. This was followed by a flashing text sequence (morse code) and finally, the words "end transmission". The goal was to make a short video to build hype before revealing the first clues - the Golden Gate bridge, #come-together
, and the morse code sequence. You can find the video source in clues/source
.
I knew earlier that the PNG spec allows for any arbitrary data to be appended to the end of a PNG (no clue why tbh), so if I added any text (or base64), the PNG would still be valid and I would be able to hide a clue without changing the actual image pixels! I’ve used this before to add a lot of information to the end of a small 10x10 image so the file size was suspiciously large. In this puzzle, though, I added only a little data to make the puzzle harder ;-)
Speaking of the data we added: it was a plaintext message saying “hmm. what are you looking here for?” (to show the reader they were on the right track), a newline, and then a base64-encoded AES-256 CBC encrypted message with OpenSSL’s default key derivation (U2FsdGVkX19lz81oH05ZO6Ye0idjNeC9rRsN0eQ5RnQKPxzyf3ygw+tb1SlLbWC0=
). This is the most used form of encryption. The data was “https://shhhhhhhh.hackclub.dev/” and the password was g0ld3n (which you’d get from decoding the morse code blinking of the text in
Benjamin's video).
One problem we encountered was that there are several different versions of OpenSSL that have different key derivation algorithms, which means people may not be able to decode the data even if they had the right password. We decided to go with the algorithm that’s preinstalled on macOS.
That’s not all! The image also contained EXIF and PNG metadata (for example, the Author, Description, Copyright Notice etc. fields). We set all of these to “cat” to hint that people should run cat openssl.png
and see the hidden messages.
Try this command to see if you can decode the data too: echo U2FsdGVkX19lz81oH05ZO6Ye0idjNeC9rRsN0eQ5RnQKPxzyf3ygw+tb1SlLbWC0= | openssl enc -d -base64 -aes-256-cbc -k g0ld3n
!
We built the website using Next.js and hosted it on Vercel (with their serverless functions). We used the jsonwebtoken
JavaScript library to interact and generate JWTs. Check out the source in this repo!
Here's a brief walkthrough of all steps involved in cracking the puzzle:
You'll start with a video posted on @hackclub's Twitter as well as in the #announcements
Slack channel.
The video has two key pieces of information:
-
The video mentions
#come-together
which is a Slack channel. -
The video flashes
#come-together
in morse code that translates tog0ld3n
.
In #come-together
, you'll find an image posted by @orpheus:
The next step is to run cat openssl.png
in your terminal. You'll find that the last line includes a base64 string. To point participants towards the cat
command, the image's EXIF data reads cat
.
After getting the clues above, users can run echo $BASE_64_STRING | openssl enc -d -base64 -aes-256-cbc -k g0ld3n
to get the result https://shhhhhhhh.hackclub.dev/
On the website, if you enter any (or no) password it will pass a JWT in the URL query string (this is intentionally insecure). The trick here is to exploit JWT's none
algorithm to grant the viewer access to the letter. You can do this by going to token.dev, pasting the JWT, changing hasAccess
to true
and alg
to none
. Then, paste the modified JWT (with the signature removed) back into the secret URL to access the letter.
The final URL with an unlocked JWT token is here.
The puzzle was a big hit! It has brought a great amount of energy to the Slack around the event. People really enjoyed the technical challenge, which stood out to me. Next time, we'll probably need more clues to solve (people are just too good)!
🎉 Thanks for puzzling with us!