forked from cadey/xesite
add blogpost explaining the scavenger hunt (#270)
Signed-off-by: Christine Dodrill <me@christine.website>
This commit is contained in:
parent
a6eadb1051
commit
b0ae633c0c
|
@ -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, <br />
|
||||
> rejected by his kin, <br />
|
||||
> for an unintentional sin, <br />
|
||||
> creator of a machine to break <br />
|
||||
> 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
|
||||
<output too big, see https://git.io/Jkyli>
|
||||
```
|
||||
|
||||
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
|
||||
<title>Mara's Realm</title>
|
||||
.headerSubtitle { font-size: 0.6em; font-weight: normal; margin-left: 1em; }
|
||||
<a href="index.html">Mara's Realm</a> <span class="headerSubtitle">sh0rk in the cloud</span>
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
🙂
|
Loading…
Reference in New Issue