Skip to main content

Fetch the Flag CTF 2022: Write-up zu Treasure Trove

Artikel von

Luke Watts

feature ctf treasure trove

10. November 2022

0 Min. Lesezeit

Vielen Dank, dass Sie mit uns Fetch gespielt haben! Glückwunsch an die Tausenden Spielerinnen und Spieler, die bei Fetch the Flag CTF dabei waren. Und ein riesiges Dankeschön an die Snykers, die die Herausforderungen entwickelt, getestet und dokumentiert haben!

Fetch the Flag war dieses Jahr ein Riesenspaß, aber auch mit viel Arbeit verbunden! Bei 16 Herausforderungen und begrenzter Zeit konnte nicht jedes Team alle lösen. Wenn Sie die Zeit nicht geschafft haben, sehen wir uns an, wie unser Team die Herausforderung Treasure Trove angegangen ist.

Schritt-für-Schritt-Anleitung

Die Aufgabenstellung lautete: „Der neueste Treasure Trove ist da, aber wo habe ich meinen Lizenzschlüssel hingelegt?“ Als Einstieg gibt es einen Tag mit der Bezeichnung Reverse Engineering sowie eine bereitgestellte Datei obfuscator.js.

Außerdem ist eine Website verlinkt. Sie enthält Eingabefelder für 5 × 5 Zeichen, eine Schaltfläche und ein großartiges Artwork, das mich an das Spielen von Curse of Monkey Island erinnert.

Browsergame „Treasure Trove“ mit einer Truhe an einer Kette auf einer tropischen Insel, einem Piratenschiff, Codefeldern und der Schaltfläche „Einlösen & in See stechen!“

Wenn Sie sich den bereitgestellten Code ansehen, finden Sie ein Tool, das menschenlesbaren Code in unverständlichen Code umwandelt.

Sehen wir uns als Nächstes die Website an. Dort gibt es einen swashbuckle.js-Endpunkt mit einer Methode namens validate. Der dortige Code scheint mit der Ausgabe übereinzustimmen, die der Obfuscator erzeugt. Hmm …

Bei genauerem Hinsehen erkennen wir, dass die Methode validate im Window verfügbar ist und beim Absenden des Formulars aufgerufen wird. Oh wow, Reverse Engineering von validate scheint der einzige Weg zu sein … Vielleicht kann der Browser helfen? Rufen wir validate.toString() über die Browserkonsole auf. Bingpot!

function anonymous(
) {

const segementOne = document.getElementById('seg-1');
const segementTwo = document.getElementById('seg-2');
const segementThree = document.getElementById('seg-3');
const segementFour = document.getElementById('seg-4');
const segementFive = document.getElementById('seg-5');

const setError = (message) => {
  document.getElementById('error-msg').innerText = message;
}

setError('');
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
const key = segementOne.value + segementTwo.value + segementThree.value + segementFour.value + segementFive.value;
if (key.length != 25) {
  setError('Invalid redemtion code!')
  return;
}

let val = 0;
for (let i = 0; i < 25; i++) {
  val += key.charCodeAt(i);
  if (!characters.includes(key[i])) {
    setError('invalid characters');
    return;
  }
}

if (val != 1800) {
  setError('invalid code');
  return;
}

fetch('/api/validatekey/' + key)
.then(async res => {
  const result = await res.json();
  setError('Argg ye got it! ' + result.flag);
});

}

Offenbar führt der Code die folgenden Schritte aus:

  1. Ruft die Werte aus den HTML-Eingabefeldern ab

  2. Prüft, ob die Zeichen dem Bereich A-Z0-9 entsprechen

  3. Durchläuft die Zeichen, wandelt sie in einen charCode um und addiert die Werte. Die charCodeAt() -Methode gibt eine Ganzzahl zwischen 0 und 65535 zurück, die die UTF-16-Codeeinheit am angegebenen Index darstellt. Quelle

  4. Löst einen Fehler aus, wenn der Wert nicht 1800 entspricht

  5. Wenn der Wert 1800 entspricht, werden die ursprünglichen Eingabewerte an einen API-Endpunkt gesendet

Die wichtigste Erkenntnis: Solange der Wert nicht 1800 beträgt, ist der Code ungültig.

  1. 1800 / 25 (die Gesamtzahl der verfügbaren Zeichen)

  2. 72

  3.  String.fromCharCode(72)

  4. Gibt H zurück

In jedes Eingabefeld HHHHH eingeben

Bildschirm eines Browserspiels mit dem Titel „Treasure Trove“: Eine Schatztruhe mit Ketten steht unter einer Palme auf einer Insel. Zu sehen sind außerdem ein Piratenschiff und der Text „Einlösen & auf hohe See stechen!“

Doppel-Bingpot!

Browserseite mit dem Titel „Treasure Trove“: eine Truhe mit Kette auf einer Palmeninsel, ein Piratenschiff, codierter Text und fünf Eingabefelder

Wir konnten diese Herausforderung lösen, ohne uns mit der Codebasis des Obfuscators befassen zu müssen. So blieb uns genug Zeit, mit der nächsten Herausforderung zu beginnen!

Möchten Sie wissen, wie wir alle anderen Flags gefunden haben? Auf unserer Seite Fetch-the-Flag-Lösungen erfahren Sie, wie wir dabei vorgegangen sind.