--- title: Scavenger Hunt Solution date: 2020-11-25 tags: - ctf - wasm - steganography - stenography --- # Scavenger Hunt Solution On November 22, I sent a [tweet](https://twitter.com/theprincessxena/status/1330532765482311687) that contained the following text: ``` #467662 #207768 #7A7A6C #6B2061 #6F6C20 #6D7079 #7A6120 #616C7A #612E20 #5A6C6C #206F61 #61773A #2F2F6A #6C6168 #6A6C68 #752E6A #736269 #2F6462 #796675 #612E6E #747020 #6D7679 #207476 #796C20 #70756D #767974 #686170 #76752E ``` This was actually the first part of a scavenger hunt/mini CTF that I had set up in order to see who went down the rabbit hole to solve it. I've had nearly a dozen people report back to me telling that they solved all of the puzzles and nearly all of them said they had a lot of fun. Here's how to solve each of the layers of the solution and how I created them. ## Layer 1 The first layer was that encoded tweet. If you notice, everything in it is formatted as HTML color codes. HTML color codes just so happen to be encoded in hexadecimal. Looking at the codes you can see `20` come up a lot, which happens to be the hex-encoded symbol for the spacebar. So, let's turn this into a continuous hex string with `s/#//g` and `s/ //g`: [If you've seen a `%20` in a URL before, that is the URL encoded form of the spacebar!](conversation://Mara/hacker) ``` 4676622077687A7A6C6B20616F6C206D7079 7A6120616C7A612E205A6C6C206F6161773A 2F2F6A6C61686A6C68752E6A7362692F6462 796675612E6E7470206D7679207476796C20 70756D76797468617076752E ``` And then turn it into an ASCII string: > Fvb whzzlk aol mpyza alza. Zll oaaw://jlahjlhu.jsbi/dbyfua.ntp mvy tvyl pumvythapvu. [Wait, what? this doesn't look like much of anything...wait, look at the `oaaw://`. Could that be `http://`?](conversation://Mara/hmm) Indeed it is my perceptive shark friend! Let's decode the rest of the string using the [Caeser Cipher](https://en.wikipedia.org/wiki/Caesar_cipher): > You passed the first test. See http://cetacean.club/wurynt.gmi for more information. Now we're onto something! ## Layer 2 Opening http://cetacean.club/wurynt.gmi we see the following: > wurynt > > a father of modern computing,
> rejected by his kin,
> for an unintentional sin,
> creator of a machine to break
> the cipher that this message is encoded in > > bq cr di ej kw mt os px uz gh > > VI 1 1 > I 17 1 > III 12 1 > > qghja xmbzc fmqsb vcpzc zosah tmmho whyph lvnjj mpdkf gbsjl tnxqf ktqia mwogp > eidny awoxj ggjqz mbrcm tkmyd fogzt sqkga udmbw nmkhp jppqs xerqq gdsle zfxmq > yfdfj kuauk nefdc jkwrs cirut wevji pumqt hrxjr sfioj nbcrc nvxny vrphc r > > Correction for the last bit > > gilmb egdcr sowab igtyq pbzgv gmlsq udftc mzhqz exbmx zaxth isghc hukhc zlrrk > cixhb isokt vftwy rfdyl qenxa nljca kyoej wnbpf uprgc igywv qzuud hrxzw gnhuz > kclku hefzk xtdpk tfjzu byfyi sqmel gweou acwsi ptpwv drhor ahcqd kpzde lguqt > wutvk nqprx gmiad dfdcm dpiwb twegt hjzdf vbkwa qskmf osjtk tcxle mkbnv iqdbe > oejsx lgqc [Hmm, "a father of computing", "rejected by his kin", "an unintentional sin", "creator of a machine to break a cipher" could that mean Alan Turing? He made something to break the Enigma cipher and was rejected by the British government for being gay right?](conversation://Mara/hmm) Indeed. Let's punch these settings into an [online enigma machine](https://cryptii.com/pipes/enigma-machine) and see what we get: ``` congr adula tions forfi gurin goutt hisen igmao famys teryy ouhav egott enfar thert hanan yonee lseha sbefo rehel pmebr eakfr eefol lowth ewhit erabb ittom araht tpyvz vgjiu ztkhf uhvjq roybx dswzz caiaq kgesk hutvx iplwa donio n httpc olons lashs lashw hyvec torze dgamm ajayi ndigo ultra zedfi vetan gokil ohalo fineu ltrah alove ctorj ayqui etrho omega yotta betax raysi xdonu tseve nsupe rwhyz edzed canad aasia indig oasia twoqu ietki logam maeps ilons uperk iloha loult rafou rtang ovect orsev ensix xrayi ndigo place limaw hyasi adelt adoto nion ``` And here is where I messed up with this challenge. Enigma doesn't handle numbers. It was designed to encode the 26 letters of the Latin alphabet. If you look at the last bit of the output you can see `onio n` and `o nion`. This points you to a [Tor hidden service](https://www.linuxjournal.com/content/tor-hidden-services), but because I messed this up the two hints point you at slightly wrong onion addresses (tor hidden service addresses usually have numbers in them). Once I realized this, I made a correction that just gives away the solution so people could move on to the next step. Onwards to http://yvzvgjiuz5tkhfuhvjqroybx6d7swzzcaia2qkgeskhu4tv76xiplwad.onion/! ## Layer 3 Open your [tor browser](https://www.torproject.org/download/) and punch in the onion URL. You should get a page that looks like this: ![Mara's Realm](https://cdn.christine.website/file/christine-static/blog/Screenshot_20201125_101515.png) This shows some confusing combinations of letters and some hexadecimal text. We'll get back to the hexadecimal text in a moment, but let's take a closer look at the letters. There is a hint here to search the plover dictionary. [Plover](http://www.openstenoproject.org/) is a tool that allows hobbyists to learn [stenography](https://en.wikipedia.org/wiki/Stenotype) to type at the rate of human speech. My moonlander has a layer for typing out stenography strokes, so let's enable it and type them out: > Follow the white rabbit > > Go to/test. w a s m Which we can reinterpret as: > Follow the white rabbit > > Go to /test.wasm [The joke here is that many people seem to get stenography and steganography confused, so that's why there's stenography in this steganography challenge!](conversation://Mara/hacker) Going to /test.wasm we get a WebAssembly download. I've uploaded a copy to my blog's CDN [here](https://cdn.christine.website/file/christine-static/blog/test.wasm). ## Layer 4 Going back to that hexadecimal text from above, we see that it says this: > go get tulpa.dev/cadey/hlang This points to the source repo of [hlang](https://h.christine.website), which is a satirical "programming language" that can only print the letter `h` (or the lojbanic h `'` for that sweet sweet internationalisation cred). Something odd about hlang is that it uses [WebAssembly](https://webassembly.org/) to execute all programs written in it (this helps it reach its "no sandboxing required" and "zero* dependencies" goals). Let's decompile this WebAssembly file with [`wasm2wat`](https://webassembly.github.io/wabt/doc/wasm2wat.1.html) ```console $ wasm2wat /data/test.wasm ``` Looking at the decompilation we can see that it imports a host function `h.h` as the hlang documentation suggests and then constantly calls it a bunch of times: ```lisp (module (type (;0;) (func (param i32))) (type (;1;) (func)) (import "h" "h" (func (;0;) (type 0))) (func (;1;) (type 1) i32.const 121 call 0 i32.const 111 call 0 i32.const 117 call 0 ; ... ``` There's a lot of `32` in the output. `32` is the base 10 version of `0x20`, which is the space character in ASCII. Let's try to reformat the numbers to ascii characters and see what we get: > you made it, this is the end of the line however. writing all of this up takes > a lot of time. if you made it this far, email me@christine.website to get your > name entered into the hall of heroes. be well. ## How I Implemented This Each layer was designed independently and then I started building them together later. One of the first steps was to create the website for Mara's Realm. I started by writing out all of the prose into a file called `index.md` and then I ran [sw](https://github.com/jroimartin/sw) using [Pandoc](https://pandoc.org/) for markdown conversion. Then I created the WebAssembly binary by locally hacking a copy of hlang to allow arbitrary strings. I stuck it in the source directory for the website and told `sw` to not try and render it as markdown. Once I had the HTML source, I copied it to a machine on my network at `/srv/http/marahunt` using this command: ```console $ rsync \ -avz \ site.static/ \ root@192.168.0.127:/srv/http/marahunt ``` And then I created a tor hidden service using the [services.tor.hiddenServices](https://search.nixos.org/options?channel=20.09&from=0&size=30&sort=relevance&query=services.tor.hiddenServices) options: ```nix services.tor = { enable = true; hiddenServices = { "hunt" = { name = "hunt"; version = 3; map = [{ port = 80; toPort = 80; }]; }; }; }; ``` Once I pushed this config to that server, I grabbed the hostname from `/var/lib/tor/onion/hunt/hostname` and set up an nginx virtualhost: ```nix services.nginx = { virtualHosts."yvzvgjiuz5tkhfuhvjqroybx6d7swzzcaia2qkgeskhu4tv76xiplwad.onion" = { root = "/srv/http/marahunt"; }; }; ``` And then I pushed the config again and tested it with curl: ```console $ curl -H "Host: yvzvgjiuz5tkhfuhvjqroybx6d7swzzcaia2qkgeskhu4tv76xiplwad.onion" http://127.0.0.1 | grep title % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 3043 100 3043 0 0 2971k 0 --:--:-- --:--:-- --:--:-- 2971k Mara's Realm .headerSubtitle { font-size: 0.6em; font-weight: normal; margin-left: 1em; } Mara's Realm sh0rk in the cloud ``` Once I was satisfied with the HTML, I opened up an enigma encoder and started writing out the message congradulating the user for figuring out "this enigma of a mystery". I also included the onion URL (with the above mistake) in that message. Then I started writing the wurynt page on my [gemini](https://gemini.circumlunar.space/) server. wurynt was coined by blindly pressing 6 keys on my keyboard. I added a little poem about Alan Turing to give a hint that this was an enigma cipher and then copied the Enigma settings on the page just in case. It turned out that I was using the default settings for the [Cryptee Enigma simulator](https://cryptii.com/pipes/enigma-machine), so this was not needed; however it was probably better to include them regardless. This is where I messed up as I mentioned earlier. Once I realized my mistake in trying to encode the onion address twice, I decided it would be best to just give away the answer on the page, so I added the correct onion URL to the end of the enigma message so that it wouldn't break flow for people. The final part was to write and encode the message that I would tweet out. I opened a scratch buffer and wrote out the "You passed the first test" line and then encoded it using the ceasar cipher and encoded the result of that into hex. After a lot of rejiggering and rewriting to make it have a multiple of 3 characters of text, I reformatted it as HTML color codes and tweeted it without context. ## Feedback I Got Some of the emails and twitter DM's I got had some useful and amusing feedback. Here's some of my favorites: > my favourite part was the opportunity to go down different various rabbit > holes (I got to learn about stenography and WASM, which I'd never looked > into!) > I want to sleep. It's 2 AM here, but a friend sent me the link an hour ago and > I'm a cat, so the curiosity killed me. > That was a fun little game. Thanks for putting it together. > oh *noooo* this is going to nerd snipe me > I'm amused that you left the online enigma emulator on default settings. > I swear to god I'm gonna beach your orca ass ## Improvements For Next Time Next time I'd like to try and branch out from just using ascii. I'd like to throw other encodings into the game (maybe even have a stage written in EBCDIC formatted Esperanto or something crazy like that). I was also considering having some public/private key crypto in the mix to stretch people's skillsets. Something I will definitely do next time is make sure that all of the layers are solveable. I really messed up with the enigma step and I had to unblock people by DMing them the answer. Always make sure your puzzles can be solved. ## Hall of Heroes (in no particular order) - Saphire Lattice - Open Skies - Tramoline - AstroSnail - Dominika - pbardera - Max Hollman - Vojtěch - [object Object] - Bytewave Thank you for solving this! I'm happy this turned out so successfully. More to come in the future. 🙂