diff --git a/blog/scavenger-hunt-solution-2020-11-25.markdown b/blog/scavenger-hunt-solution-2020-11-25.markdown new file mode 100644 index 0000000..d19d4bd --- /dev/null +++ b/blog/scavenger-hunt-solution-2020-11-25.markdown @@ -0,0 +1,351 @@ +--- +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. + +🙂