Skip to main content

Fetch the Flag CTF 2022 : solution de Treasure Trove

Écrit par

Luke Watts

feature ctf treasure trove

10 novembre 2022

0 minutes de lecture

Merci d’avoir joué à Fetch avec nous ! Félicitations aux milliers de joueurs qui nous ont rejoints pour Fetch the Flag CTF. Et un immense merci aux Snykers qui ont créé, testé et présenté les défis !

Cette année, Fetch the Flag a été une expérience formidable, mais aussi un sacré travail ! Avec 16 défis et un temps limité, toutes les équipes n’ont pas pu les terminer. Si vous n’avez pas réussi à battre la montre, découvrez comment notre équipe a relevé le défi Treasure Trove.

Guide pas à pas

L’énoncé du défi était le suivant : « Le dernier Treasure Trove est sorti, mais où ai-je mis ma clé de licence ? » Pour commencer, un tag indique Reverse Engineering et un fichier obfuscator.js est fourni.

Un site Web est également indiqué. Il contient des champs de saisie de 5 caractères sur 5, un bouton et de superbes illustrations qui me rappellent mes parties de Curse of Monkey Island.

Jeu de navigateur Treasure Trove montrant un coffre enchaîné sur une île tropicale, un bateau pirate, des champs de code et un bouton « Échanger et prendre le large ! »

En examinant le code fourni, vous trouverez un outil qui transforme du code lisible par un humain en charabia.

Examinons ensuite le site Web. Il comporte un point de terminaison swashbuckle.js qui contient une méthode appelée validate. Le code semble correspondre à la sortie générée par l’obfuscateur. Hmm…

En y regardant de plus près, on voit que la méthode validate est disponible sur l’objet window et appelée lors de l’envoi du formulaire. Oh, il semble que la rétro-ingénierie de validate soit la seule solution… Le navigateur pourrait-il nous aider ? Invoquons validate.toString() depuis la console du navigateur. Bingo !

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);
});

}

Le code semble effectuer les étapes suivantes :

  1. Récupérer les valeurs des champs de saisie HTML

  2. Vérifier que les caractères appartiennent à la plage A-Z0-9

  3. Parcourir les caractères, les convertir en charCode et additionner leurs valeurs. La méthode charCodeAt() renvoie un entier compris entre 0 et 65 535 représentant l’unité de code UTF-16 à l’index indiqué. Source

  4. Déclencher une erreur si la valeur n’est pas égale à 1800

  5. Si la valeur est égale à 1800, les valeurs saisies initialement sont envoyées à un point de terminaison d’API

La principale conclusion est que si la valeur n’est pas égale à 1800, le code est invalide.

  1. 1800 / 25 (le nombre total de caractères disponibles)

  2. 72

  3.  String.fromCharCode(72)

  4. Renvoie H

Saisir HHHHH dans chaque champ

Écran d’un jeu sur navigateur intitulé « Treasure Trove » : un coffre au trésor enchaîné sous un palmier sur une île, un bateau pirate et le message « Échangez votre récompense et prenez le large ! »

Et bingo !

Page de navigateur intitulée « Treasure Trove », montrant un coffre enchaîné sur une île bordée de palmiers, un bateau pirate, du texte encodé et cinq champs de saisie

Nous avons réussi à résoudre ce défi sans avoir à examiner le code de l’obfuscateur. Nous avons ainsi eu tout le temps de nous attaquer au défi suivant !

Vous voulez savoir comment nous avons trouvé tous les autres flags ? Consultez notre page Solutions de Fetch the Flag pour découvrir comment nous avons procédé.