Politiets sikkerhetstjeneste (PST) la i desember ut en jobbannonse hvor de søkte en etter «nysgjerrig og løsningsorientert teknisk etterforsker innen digitale spor».
Jobbannonsen inkluderte et limerick, som var en gåte de ville at folk skulle løse. Jeg hørte ikke om annonsen før den var på forsida av mange aviser, med titler av typen «om du løser denne gåten, kan jobben bli din».
Hai-temaet 🦈
Nesten alle deler av mysteriet hadde et hai-tema. Bakgrunnen for det er en flau episode fra oktober 2018, hvor PST plutselig tweeta et bilde av en hai.
Det var det syv år gamle barnet til en av PSTs ansatte som kom borti dele-knappen mens han spilte Hungry Shark Evolution på fars iPad. Dette førte selvfølgelig til spekulasjoner om hvorvidt Twitter-kontoen var hacka.
(Det var ikke en iPad med noe klassifisert informasjon, men en iPad til å oppdatere Twitter hjemmefra (og Twitter-kontoen er stengt for direktebeskjeder).)
Steg 1: Limericken
Limericken i jobbannonsen var følgende:
En oktobermorgen fikk vi pulsen til å øke
var det en hackeR som hadde lykkes med forsøkeT
men en HAI I en TWeeT
er ikke særlig 1337.
løser du gåtEn bør dU vurdere å søke
Fikk du ikke prøvd vår kodekalender?
Du kan fortsatt prøve deg på alle de 24 lukene!
Meningen til limericken i seg selv spiller ingen rolle, men det ligger et mønster i den:
En oktobermorgen fikk vi pulsen til å øke
var det en hackeR som hadde lykkes med forsøkeT
men en HAI I en TWeeT er ikke særlig 1337.
løser du gåtEn bør dU vurdere å søke
De store bokstavene utgjør ERTHAIITWTEU. Som du kanskje vet, er .eu et toppdomene, og du ser kanskje at det bare er ett punktum i limericken. Dette utgjør ERTHAIITWT.EU. Er du kjappere enn meg, ser du kanskje allerede at bokstavene kan omrokkeres til TWITTERHAI.
Omvei 1:
Jeg så ikke at bokstavene kunne omrokkeres, så jeg besøkte erthaiitwt.eu. Her får du opp en hangman som sier at rekkefølgen er feil.
Løsning 1:
Det riktige å gjøre var å besøke twitterhai.eu.
Steg 2: HTML-sida
twitterhai.eu viser et bilde av en hai, og gir et nytt dikt som ber deg se deg omkring. Jeg ville uansett tatt en titt på kildekoden, men jeg så også at det var et rart mellomrom i midten av ordet «være».
Det er et tegn på at det var noe rart i HTML-koden et sted:
Ser du de snodige linjebruddene og hva den første kollonna utgjør? «Shark.html».
Lag din egen static site generator
Omvei 2a:
Jeg pleier å se nærmere på robots.txt, og har til og med laga en fin robots.txt-bookmarklet for å enkelt åpne lenker fra nettopp den fila. Besøker du twitterhai.eu/robots.txt får du et nyttig hint som sier «Use the source, Luke!»
Omvei 2b:
Jeg er vant til filnavn med små bokstaver, så jeg gikk direkte til twitterhai.eu/shark.html. Der fikk jeg hintet «Case matters. Watch your characters».
Løsning 2:
Løsningen på steg 2 var å besøke twitterhai.eu/Shark.html.
Steg 3: Bildet
Jeg antar at noen stoppa å lete mer da de fant twitterhai.eu/Shark.html, som gir deg tips om å skrive en god jobbsøknad. Men, det ligger en HTML-kommentar der om at de har flere gåter om du ser nøyere etter.
Jeg kunne ikke se noen andre spor eller retninger enn bildet fra steg 2. Det som gjorde dette vanskelig for meg, var at verktøyet jeg brukte for å se på Exif metadata ikke avslørte noe. Ettersom jeg forstår det, skjulte ikke løsningen seg i Exif, men i en JPEG-fil-kommentar.
Det finnes verktøy der ute som gir deg mye mer enn bare Exif, og bruker du et Unix-system kan du bruke varianter av file-kommandoen for å finne det du leter etter:
file 1337_shrk.jpg
1337_shrk.jpg: JPEG image data, JFIF standard 1.01, aspect ratio, density 72x72, segment length 16,
Exif Standard: [TIFF image data, big-endian, direntries=3, PhotometricIntepretation=RGB, orientation=upper-left],
comment: "/haitech_secure.html", baseline, precision 8, 851x514, frames 3
Løsning 3:
Løsningen på steg 3 var å besøke twitterhai.eu/haitech_secure.html.
Steg 4: Javascript-et
twitterhai.eu/haitech_secure.html inneholdt noe generell tekst med «tips» for å søke en jobb. Men viktigere: Et passordfelt og en login-knapp.
Kildekoden avslørte en klientside-validering av passordet, som først verifiserte passordet og så brukte passordet som en nøkkel til å dechiffrere en ciphertext.
Javascript-et som gjorde den faktiske verifiseringen så slik ut:
password.charCodeAt(0) == 8 * 8 + 8 &&
password.charCodeAt(1) == Math.pow(9, 2) - 29 &&
password.charCodeAt(2) == Math.pow(10, 2) + Math.pow(3, 2) &&
password.charCodeAt(3) == password.charCodeAt(2) &&
password.substring(4, 5) == 3 &&
password.charCodeAt(5) == 7 * 17 - 5 &&
password.charCodeAt(6) == password.charCodeAt(0) &&
password.charCodeAt(7) == password.charCodeAt(1) &&
password.charCodeAt(8) == 0x69
Passordet var åpenbart ni karakterer langt, og man trengte bare å kalkulere hver karakter. Jeg bare kopierte og limte inn, og brukte dette kjappe Javascript-et i konsollen for å skrive ut passordet og kjøre login-funksjonen, som ga meg et varsel med neste hint:
var password = [];
password[password.length] = 8 * 8 + 8;
password[password.length] = Math.pow(9, 2) - 29;
password[password.length] = Math.pow(10, 2) + Math.pow(3, 2);
password[password.length] = password[password.length - 1];
password[password.length] = '3'.charCodeAt(0);
password[password.length] = 7 * 17 - 5;
password[password.length] = password[0];
password[password.length] = password[1];
password[password.length] = 0x69
for (var i = 0; i < password.length; i++) {
password[i] = String.fromCharCode(password[i]);
}
password = password.join('');
document.getElementById("password").value = password;
console.log(password);
login();
Løsning 4:
Passordet man trengte var H4mm3rH4i (hammerhai).
Steg 5: Caesar-chifferet
Varselboksen viste teksten «Caesar synes at du skal ta turen hit: uggc://gjvggreunv.grpu/unv_gurer.ugzy». Ved å bare se bort fra den siste delen, var det ganske åpenbart at dette var en «Caesar cipher», som måtte være http://ettellerannet.html.
Det er mange steder man kan løse slike koder, men et kjapp Javascript gjorde også susen:
var cipher = 'uggc://gjvggreunv.grpu/unv_gurer.ugzy';
var shift = cipher.charCodeAt(0) - 'h'.charCodeAt(); // Char we suspect to know
var charDistance = 'a'.charCodeAt();
var cleartext = '';
for (var i = 0; i < cipher.length; i++) {
var charCode = cipher.charCodeAt(i) - charDistance;
if (charCode >= 0 && charCode <= 25) { // a-z
cleartext += String.fromCharCode((((charCode + shift) % 26) + charDistance));
} else {
cleartext += cipher[i];
}
}
console.log(shift, charDistance, cleartext);
Løsning 5:
Resultatet ble twitterhai.tech/hai_there.html.
Steg 6: ASCII-kunst og hemmelig mappe
twitterhai.tech/hai_there.html fortalte deg bare at du kunne følge Twitter brukeren twitt3rhai. Deres siste tweet var teksten «#justdoit, or make your ROBOTS do it. Transfer teXt to an ediTor».
Jeg antar dette var et dobbelt hint; enda en tur til robots.txt, og sende resten av Twitter-meldingene til en editor. robots.txt viste til stien /min_hemmelige_mappe/.
Det var 65 andre Twitter-meldinger der, med hai- og fiskerelaterte ord. Det så ut som en slags chiffer, og det beste var å bare kopiere inn alle til en editor:
Tigerhai HvithaiHammerhaiHvalhai Oksehai Domenehai Brugde
Brugde DomenehaiTigerhaiHvithai Hvalhai Hammerhai Oksehai
HammerhaiJaws Fish Hvalhai Oksehai Domenehai Tigerhai
HvithaiHaiene Tail Tigerhai DomenehaiBrugde Hammerhai
HåbrannBrugde Fins HammerhaiBrugde HvithaiHvalhaiJaws
HvithaiHammer Domenehai Tigerhai Oksehai Hvalhai
DomenehaiJaws Mako HåbrannHvithai HvalhaiTigerhaiMako
BrugdeOksehai Apex Tigerhai HvalhaiDomenehaiHammerhai
HvithaiBrugde Jaws HammerhaiOksehai BrugdeTigerhaiHai
Brugde HvalhaiHvithaiDomenehai Oksehai Tigerhai Hammerhai
TigerhaiHvithaiOksehai BrugdeHammerhaiHvalhaiDomenehaiHai
HvithaiHvalhai BrugdeOksehaiDomenehai HammerhaiTigerhai
HvithaiSjøen H TigerhaiOksehai DomenehaiHvalhaiBrugde
Hammerhaien Hai Domenehai HvalhaiBrugdeHvithaiOksehai
HvithaiHai DomenehaiHvalhai Hammerhai Oksehaien
HvithaiHai Havet Oksehai TigerhaiHvalhaiDomenehaiApex
OksehaiHai Sjøen HvalhaiBrugde HvithaiHammerhaiBrugde
BrugdeJaws Finne Brugde HvithaiHvalhaiTigerhai Haiene
HammerhaiDomenehaiBrugdeOksehaiTigerhai HvalhaiHvithaiHai
HvalhaiBrugdeTigerhaiHammerhaiHvithai Oksehai Domenehaien
Domenehaier OksehaiHvithai HammerhaiHvalhai Hai
OksehaiTigerhai HvalhaiDomenehaiHammerhai BrugdeHvithai
DomenehaiBrugde TigerhaiHammerhai HvithaiHvalhaiOksehai
BrugdeHvithaien HammerhaiDomenehaiHvalhai Tigerhai Mako
TigerhaiHvalhai BrugdeDomenehaiHvithai OksehaiHammerhai
BrugdeOksehaien HammerhaiHvalhaiDomenehai HvithaiBrugde
HvithaiJaws HaiHvalhaiHammerhai BrugdeDomenehai
DomenehaiTigerhaiHammerhaiHvithaiBrugdeOksehai HvalhaiHai
TigerhaiHvithaiBrugdeHvalhaiOksehai Domenehai Hammerhaien
BrugdeTigerhaiHammerhai DomenehaiHvalhai OksehaiHvithai
DomenehaiOksehaiSjøen HammerhaiHvalhaiTigerhaiHåbrann
Hammerhai HvithaiBrugde OksehaiHvalhai BrugdeTigerhaien
HvithaiBrugdeOksehaiHai TigerhaiDomenehai HvalhaiBrugde
HvalhaiOksehaiDomenehai TigerhaiBrugde HammerhaiHvithai
Tigerhai HvithaiOksehai HammerhaiDomenehaiBrugdeHvalhai
HvithaiOksehaiBrugde Hammerhai Tigerhai Domenehai
HvalhaiHammerhaiHvithaiBrugdeTigerhai OksehaiDomenehaiHai
DomenehaiHvithaiBrugdeTigerhaiHammerhai Hvalhai Oksehaien
OksehaiBrugdeBrugde Hvithai DomenehaiTigerhaiApex
HvalhaiHvithaiJaws Haier DomenehaiHammerhaiTigerhaien
TigerhaiBrugdeOksehaiSjøen Domenehai HvalhaiHammerhaien
DomenehaiHammerhaiHavet BrugdeOksehai HvithaiTigerhai
HvalhaiHammerhaiHvithaiHai Brugde Oksehaien Domenehaien
DomenehaiBrugdeHai Havet Hammerhai Hvalhai Tigerhaien
HvalhaiOksehaiBrugde BrugdeDomenehaiTigerhaiBrugde
Hvithai DomenehaiBrugdeHammerhaiTigerhaiHvalhai Oksehaien
HvalhaiBrugdeHvithaiDomenehaiOksehai Tigerhai Hammerhaien
BrugdeHvithaiBrugde HammerhaiTigerhaiHvalhaiSjøen
Domenehai Tigerhai Sjøen HvithaiHammerhai Brugde Jaws
OksehaiBrugdeHvalhaiHvitha Domenehai Tigerhai Hammerhai
TigerhaiHammerhaiHavet HvalhaiHvithai BrugdeDomenehai
TigerhaiDomenehaiHammerhai Hvalhai HvithaiOksehaiBrugde
HvithaiDomenehaien Finne HammerhaiHvalhaiBrugdeBrugde
BrugdeOksehaiBrugden Hammerhai Hvithai Domenehaien
HvithaiBrugde TigerhaiOksehaiDomenehaiHammerhai Hvalhaien
DomenehaiHammerhaiOksehaiHvithaiHvalhai Brugde Tigerhaien
HammerhaiTigerhai DomenehaiHvithaiBrugdeHvalhai
HvalhaiBrugdeHvit Haier OksehaiTigerhai Domenehai Hai
OksehaiBrugdeHvithaiJaws HavetDomenehai TigerhaiHvalhai
DomenehaiHvithaiHåbrann Hammerhai Brugde OksehaiHvalhai
DomenehaiHvalhaiBrugde OksehaiBrugdeHammerhai Hvithaien
DomenehaiTigerhaiApex Hammerhai Hvithai Hvalhai Oksehai
OksehaiHammerhaiJaws DomenehaiTigerhaiBrugdeHvalhaiJaws
Hvalhai HvithaiTigerhaiDomenehaiBrugdeHammerhai Oksehaien
Håbrann TigerhaiOksehaiHvithaiBrugdeHvalhaiHammerhaiHavet
Løsning 6:
Det var to ting å hente her. For det første adressen til http://twitterhai.tech/min_hemmelige_mappe/, samt ordet HAI1337 som gjemte seg i alle Twitter-meldingene.
Steg 7: Wireshark-dumpen
Den nevnte URL-en http://twitterhai.tech/min_hemmelige_mappe/ var adressa til en mappe som inneholdt en fil kalt «haimat», og det var jommen haimat.
Igjen var file-kommandoen en kjapp måte å bestemme filtypen:
file haimat
haimat: pcap-ng capture file - version 1.0
- Flere utviklere bør bruke HTTP/2!
En pcap-ng capture-fil inneholder en dump av pakker, fanget fra et nettverk, og ses typisk fra det gode, gamle pakkeanalyse-verktøyet Wireshark.
Jeg er ingen ekspert i Wireshark, men jeg har brukt det av og til for å lytte til nettverkstrafikk. Jeg brukte det masse da jeg bygget appen min for HDL Buspro-smarthjem, for å se hvordan de forskjellige komponentene snakket sammen.
Heldigvis hadde denne dumpen bare rundt 400 pakker. Det kan helt sikkert være at jeg overså noe, men jeg fant to ting. Det første var en nettleser som besøkte rota av en server, og fikk tilbake følgende HTML:
<html>
<head>
<title>Sharky Secret Distributor</title>
</head>
<body>
Her er dataene dine. Passordet har du allerede... <a href="/secret_data.zip">secret_data.zip</a>
</body>
</html>
Sida sa altså «Her er dataene dine. Passordet har du allerede...», og lenka til en ZIP-fil.
Den andre interessante tingen var responsen fra kallet for den faktiske ZIP-fila. Wireshark lar deg enkelt lagre filer som har blitt overført over nettet.
Løsning 7:
Løsningen var å hente ut ZIP-fila.
Steg 8: ZIP-fila
Når man prøvde å pakke ut ZIP-fila, ble man bedt om et passordet for fila insignificant_shark.png.
Løsning 8:
Som hintet sa, hadde vi allerede passordet. Jada; passordet var HAI1337.
Steg 9: Runer og steganografi
Selvfølgelig var bildet av en hai. Den hadde det som så ut som runer på sida, og ser man på en tabell over runealfabetet finner man de tre runene, som oversettes til LSB.
Hva kan LSB bety i konteksten til et bilde? Least significant bit. Det passer også til filnavnet insignificant_shark.png. Steganografi er kunsten å skjule filer, beskjeder, bilder eller video i en annen fil, beskjed, bilde eller video. Og det finnes mange verktøy på nett for å se etter skjulte beskjeder i bilder.
Omvei 9:
Om du dekodet bildet feil fikk du opp en QR-kode, som ga den nyttige teksten «You thought we would hide anything of SIGNIFICANCE? Not the LEAST....».
Løsning 9:
Dekoder du bildet, ved å se på LSB, får du URL-en twitterhai.tech/u_are_th3_winrar.jpg.
Steg 10: WinRAR
Bildet twitterhai.tech/u_are_th3_winrar.jpg har teksten «Do we we have a winner?».
Lag og test universell utforming med WCAG 2.1
Men gåten kan ikke ende med et spørsmål. Så hva skal vi se etter? URL-en sier «winrar», ikke «winner». Og det enkle bildet tar hele 9 megabyte. Det er mulig å gjemme filer i slutten av bilder, og WinRAR er et arkiveringsverktøy for ZIP- og RAR-filer.
Løsning 10:
Løsningen var å bruke for eksempel WinRAR til å pakke ut fila «gratulerer.txt» og «gratulerer.gif» fra bilde-fila.
Vi har en vinner
Det ville ikke overraske meg om det var enda et nivå av gåter og løsninger skjult et sted, men hvem vet.
Fila gratulerer.txt inneholdt en hilsen som sa at alle gåtene nå var løst, inkludert et (hairelatert, såklart) kodeord som kunne brukes for å bevise at man hadde klart hele utfordringen. gratulerer.gif var en GIF fra filmen The Great Gatsby.
«Beviser alt dette at du er klar for å jobbe med digital etterforskning?»
Så beviser alt dette at du er klar for å jobbe med digital etterforskning for et nasjonalt sikkerhetsorgan? Ikke i seg selv, selvfølgelig. Men jeg antar at det er en god start for søkere. Å løse alle bitene viser at man har grunnleggende forståelse for et vidt spekter av temaer, som litt koding, litt grunnleggende kryptografi, litt nettverk og noe generell smarthet.
Søkte du på jobben etter 8. januar måtte du forvente noen ekstra spørsmål om løsningen, da noen løste den på Reddit, og løsningen ligger på Github. 😀 Selv ville jeg vente med å publisere dette til etter søknadsfristen.
Å gi utfordringer som denne hjelper å spre ordet om ledige stillinger, spesielt når den ender opp på så mange avisforsider. Så jeg håper PST fikk noen gode kandidater!
Løsningen på lukene i kodekalenderen
Var det noen du ikke fikk til? Her får du fasit! 💡