Web Exploitation Broken Access Control Information Disclosure Template Injection

Récapitulatif complet du lab Compete

Ce document résume les difficultés rencontrées, les fausses pistes, les découvertes utiles et la chaîne d’exploitation qui a mené jusqu’au flag.

Résultat final : obtention d’un RCE via une Server-Side Template Injection dans quiz_description, puis lecture du flag utilisateur dans /home/local.txt.

Objectif du lab

Le lab annonçait une chaîne de vulnérabilités à exploiter : fuite d’informations, contournement d’authentification, traitement de templates, puis exécution de commandes.

Flag trouvé

flag_943be91e_3ae2_43d8_b0f3_ed4980fdd34d

Le \n vu dans la sortie n’était qu’un retour à la ligne, pas une partie du flag.

1. Les premières difficultés rencontrées

Découverte de plusieurs endpoints sans exploitation immédiate

  • Tu as trouvé /admin, /data, .htaccess, .htpasswd et /server-status.
  • Beaucoup de ces chemins répondaient en 403 ou en redirection, donc ils confirmaient l’existence de ressources, sans offrir un accès direct utile.
  • On savait que ces découvertes servaient surtout à la cartographie de l’application.

Fausses pistes autour du client-side

  • Le panneau admin contenait beaucoup de JavaScript pour gérer les modales et l’interface.
  • Au début, il était tentant de penser que la logique du quiz était surtout côté client.
  • En réalité, les formulaires faisaient bien des POST vers le serveur.

Test d’injection JavaScript non concluant

  • Tu as essayé de casser la structure des données stockées avec un payload du type ";console.log(...);//.
  • Mais le contenu était correctement échappé dans le JSON, donc cette piste ne permettait pas le RCE.

Confusion initiale sur le “template processing”

  • Le code HTML récupéré côté client montrait des htmlEscape() et des htmlspecialchars().
  • Donc les payloads classiques comme {{7*7}} n’étaient pas exécutés dans les vues normales.
  • Il fallait trouver le traitement du template se faisait réellement côté serveur.

2. Les découvertes importantes

Accès admin obtenu

Une étape clé a été la connexion en tant qu’admin. Sans cet accès, la création de quiz et la zone vulnérable n’auraient pas été atteignables.

Découverte du stockage interne dans /data

  • quizzes.json
  • results.json
  • users.json

Cela a confirmé que l’application stockait son état dans des fichiers JSON, ce qui a beaucoup aidé pour suivre l’effet des payloads.

Mise en évidence du paramètre file=

En interceptant une requête, on a vu une URL du type :

/?file=quiz.php&quiz_id=...&action=quiz

Cela a révélé une inclusion locale de fichiers, et donc une surface d’attaque pour lire le code source.

Lecture du code source avec php://filter

Grâce à php://filter/convert.base64-encode/resource=..., tu as pu récupérer le code source de quiz.php, puis de admin.php.

C’était le tournant décisif de l’exploitation.

3. Ce que le code a révélé

Le point critique se trouvait dans admin.php lors de la création d’un quiz :

if ($_POST['quiz_action'] === 'add_quiz') {
    ...
    $description = $_POST['quiz_description'] ?? '';
    $compiled_description = $smarty->fetch('string:' . $description);
    ...
}

Et la classe “Smarty” simplifiée contenait ceci :

$template = preg_replace_callback('/{php}(.*?){\/php}/s', function($matches) {
    ob_start();
    eval($matches[1]);
    $output = ob_get_clean();
    return $output;
}, $template_string);

À partir de là, la vulnérabilité était claire : le champ quiz_description était évalué et tout code entre {php} et {/php} passait dans un eval().

4. La chaîne d’exploitation finale

Étape 1 — Vérification de l’exécution de commande

Payload utilisé dans quiz_description :

{php}system('id');{/php}

Résultat observé dans la description compilée : uid=33(www-data) gid=33(www-data) groups=33(www-data)

Le RCE était confirmé.

Étape 2 — Recherche du flag

Une première recherche avec find / -name "*flag*" a renvoyé énormément de faux positifs comme irqflags, page-flags, etc.

Cela a montré qu’il fallait être plus ciblé dans les chemins ou se référer aux consignes du lab.

Étape 3 — Indice fourni par la plateforme

Le panneau du lab précisait que sur Linux :

  • le flag utilisateur est dans /home/local.txt
  • le flag root est dans /root/proof.txt

Étape 4 — Lecture du flag utilisateur

Payload utilisé :

{php}system('cat /home/local.txt 2>/dev/null');{/php}

La sortie a ensuite été enregistrée dans la description du quiz, ce qui a permis de récupérer directement le flag.

5. Difficultés techniques rencontrées, en résumé

6. Ce qui a permis d’aboutir

7. Conclusion

La réussite ne vient pas d’un seul bug, mais d’un enchaînement logique : reconnaissanceaccès adminlecture du code sourceidentification d’une SSTI/RCE dans le champ descriptionlecture du flag.

La difficulté principale a été de distinguer les pistes décoratives ou secondaires des indices vraiment exploitables. Le moment décisif a été la lecture de admin.php, qui a révélé l’eval().